diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:49:41 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:49:41 +0000 |
| commit | 45b533945f0851ec234ca846e1af5ee1e4df0b6e (patch) | |
| tree | 0a5b74c0b9ca73aded34df95c91fcaf3815230d8 /utils | |
| parent | 7e86edd64bfae4e324224452e4ea879b3371a4bd (diff) | |
Notes
Diffstat (limited to 'utils')
| -rw-r--r-- | utils/TableGen/ClangAttrEmitter.cpp | 348 | ||||
| -rw-r--r-- | utils/TableGen/ClangCommentCommandInfoEmitter.cpp | 3 | ||||
| -rw-r--r-- | utils/TableGen/NeonEmitter.cpp | 83 | ||||
| -rwxr-xr-x | utils/analyzer/CmpRuns.py | 50 | ||||
| -rw-r--r-- | utils/analyzer/SATestAdd.py | 54 | ||||
| -rw-r--r-- | utils/analyzer/SATestBuild.py | 347 | ||||
| -rw-r--r-- | utils/analyzer/SumTimerInfo.py | 5 | ||||
| -rwxr-xr-x | utils/analyzer/ubiviz | 13 | ||||
| -rw-r--r-- | utils/clang.natvis | 23 | ||||
| -rw-r--r-- | utils/perf-training/CMakeLists.txt | 36 | ||||
| -rw-r--r-- | utils/perf-training/README.txt | 6 | ||||
| -rw-r--r-- | utils/perf-training/cxx/hello_world.cpp | 7 | ||||
| -rw-r--r-- | utils/perf-training/lit.cfg | 37 | ||||
| -rw-r--r-- | utils/perf-training/lit.site.cfg.in | 20 | ||||
| -rw-r--r-- | utils/perf-training/perf-helper.py | 46 |
15 files changed, 699 insertions, 379 deletions
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index f2aa4002b99f..f70bff2c3b74 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -54,7 +54,7 @@ public: const std::string &nameSpace() const { return NS; } bool knownToGCC() const { return K; } }; -} // namespace +} // end anonymous namespace static std::vector<FlattenedSpelling> GetFlattenedSpellings(const Record &Attr) { @@ -166,17 +166,18 @@ namespace { std::string lowerName, upperName; StringRef attrName; bool isOpt; + bool Fake; public: Argument(const Record &Arg, StringRef Attr) : lowerName(Arg.getValueAsString("Name")), upperName(lowerName), - attrName(Attr), isOpt(false) { + attrName(Attr), isOpt(false), Fake(false) { if (!lowerName.empty()) { lowerName[0] = std::tolower(lowerName[0]); upperName[0] = std::toupper(upperName[0]); } } - virtual ~Argument() {} + virtual ~Argument() = default; StringRef getLowerName() const { return lowerName; } StringRef getUpperName() const { return upperName; } @@ -185,6 +186,9 @@ namespace { bool isOptional() const { return isOpt; } void setOptional(bool set) { isOpt = set; } + bool isFake() const { return Fake; } + void setFake(bool fake) { Fake = fake; } + // These functions print the argument contents formatted in different ways. virtual void writeAccessors(raw_ostream &OS) const = 0; virtual void writeAccessorDefinitions(raw_ostream &OS) const {} @@ -275,6 +279,8 @@ namespace { OS << " OS << \" \";\n"; OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n"; } else if (type == "IdentifierInfo *") { + if (isOptional()) + OS << " if (SA->get" << getUpperName() << "())\n "; OS << " OS << \" \" << SA->get" << getUpperName() << "()->getName();\n"; } else if (type == "TypeSourceInfo *") { @@ -348,7 +354,7 @@ namespace { << "Length])"; } void writeCtorDefaultInitializers(raw_ostream &OS) const override { - OS << getLowerName() << "Length(0)," << getLowerName() << "(0)"; + OS << getLowerName() << "Length(0)," << getLowerName() << "(nullptr)"; } void writeCtorParameters(raw_ostream &OS) const override { OS << "llvm::StringRef " << getUpperName(); @@ -491,7 +497,7 @@ namespace { // The aligned attribute argument expression is optional. OS << " if (is" << getLowerName() << "Expr && " << getLowerName() << "Expr)\n"; - OS << " " << getLowerName() << "Expr->printPretty(OS, 0, Policy);\n"; + OS << " " << getLowerName() << "Expr->printPretty(OS, nullptr, Policy);\n"; OS << " OS << \""; } void writeDump(raw_ostream &OS) const override { @@ -613,7 +619,7 @@ namespace { std::vector<std::string> uniques; std::set<std::string> unique_set(enums.begin(), enums.end()); for (const auto &i : enums) { - std::set<std::string>::iterator set_i = unique_set.find(i); + auto set_i = unique_set.find(i); if (set_i != unique_set.end()) { uniques.push_back(i); unique_set.erase(set_i); @@ -659,8 +665,7 @@ namespace { OS << type << " " << getUpperName(); } void writeDeclarations(raw_ostream &OS) const override { - std::vector<std::string>::const_iterator i = uniques.begin(), - e = uniques.end(); + auto i = uniques.cbegin(), e = uniques.cend(); // The last one needs to not have a comma. --e; @@ -765,8 +770,7 @@ namespace { bool isVariadicEnumArg() const override { return true; } void writeDeclarations(raw_ostream &OS) const override { - std::vector<std::string>::const_iterator i = uniques.begin(), - e = uniques.end(); + auto i = uniques.cbegin(), e = uniques.cend(); // The last one needs to not have a comma. --e; @@ -952,7 +956,7 @@ namespace { } void writeTemplateInstantiation(raw_ostream &OS) const override { - OS << " " << getType() << " *tempInst" << getUpperName() + OS << " auto *tempInst" << getUpperName() << " = new (C, 16) " << getType() << "[A->" << getLowerName() << "_size()];\n"; OS << " {\n"; @@ -1018,7 +1022,7 @@ namespace { getType(), "SA->get" + std::string(getUpperName()) + "Loc()"); } }; -} +} // end anonymous namespace static std::unique_ptr<Argument> createArgument(const Record &Arg, StringRef Attr, @@ -1078,6 +1082,9 @@ createArgument(const Record &Arg, StringRef Attr, if (Ptr && Arg.getValueAsBit("Optional")) Ptr->setOptional(true); + if (Ptr && Arg.getValueAsBit("Fake")) + Ptr->setFake(true); + return Ptr; } @@ -1180,28 +1187,39 @@ writePrettyPrintFunction(Record &R, if (Variety == "Pragma") { OS << " \";\n"; OS << " printPrettyPragma(OS, Policy);\n"; + OS << " OS << \"\\n\";"; OS << " break;\n"; OS << " }\n"; continue; } + // Fake arguments aren't part of the parsed form and should not be + // pretty-printed. + bool hasNonFakeArgs = false; + for (const auto &arg : Args) { + if (arg->isFake()) continue; + hasNonFakeArgs = true; + } + // FIXME: always printing the parenthesis isn't the correct behavior for // attributes which have optional arguments that were not provided. For // instance: __attribute__((aligned)) will be pretty printed as // __attribute__((aligned())). The logic should check whether there is only // a single argument, and if it is optional, whether it has been provided. - if (!Args.empty()) + if (hasNonFakeArgs) OS << "("; if (Spelling == "availability") { writeAvailabilityValue(OS); } else { - for (auto I = Args.begin(), E = Args.end(); I != E; ++ I) { - if (I != Args.begin()) OS << ", "; - (*I)->writeValue(OS); + unsigned index = 0; + for (const auto &arg : Args) { + if (arg->isFake()) continue; + if (index++) OS << ", "; + arg->writeValue(OS); } } - if (!Args.empty()) + if (hasNonFakeArgs) OS << ")"; OS << Suffix + "\";\n"; @@ -1473,10 +1491,19 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { std::vector<std::unique_ptr<Argument>> Args; Args.reserve(ArgRecords.size()); + bool HasOptArg = false; + bool HasFakeArg = false; for (const auto *ArgRecord : ArgRecords) { Args.emplace_back(createArgument(*ArgRecord, R.getName())); Args.back()->writeDeclarations(OS); OS << "\n\n"; + + // For these purposes, fake takes priority over optional. + if (Args.back()->isFake()) { + HasFakeArg = true; + } else if (Args.back()->isOptional()) { + HasOptArg = true; + } } OS << "\npublic:\n"; @@ -1495,69 +1522,53 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { if (!ElideSpelling) OS << CreateSemanticSpellings(Spellings, SemanticToSyntacticMap); - OS << " static " << R.getName() << "Attr *CreateImplicit("; - OS << "ASTContext &Ctx"; - if (!ElideSpelling) - OS << ", Spelling S"; - for (auto const &ai : Args) { - OS << ", "; - ai->writeCtorParameters(OS); - } - OS << ", SourceRange Loc = SourceRange()"; - OS << ") {\n"; - OS << " " << R.getName() << "Attr *A = new (Ctx) " << R.getName(); - OS << "Attr(Loc, Ctx, "; - for (auto const &ai : Args) { - ai->writeImplicitCtorArgs(OS); - OS << ", "; - } - OS << (ElideSpelling ? "0" : "S") << ");\n"; - OS << " A->setImplicit(true);\n"; - OS << " return A;\n }\n\n"; - - OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n"; - - bool HasOpt = false; - for (auto const &ai : Args) { - OS << " , "; - ai->writeCtorParameters(OS); - OS << "\n"; - if (ai->isOptional()) - HasOpt = true; - } - - OS << " , "; - OS << "unsigned SI\n"; + // Emit CreateImplicit factory methods. + auto emitCreateImplicit = [&](bool emitFake) { + OS << " static " << R.getName() << "Attr *CreateImplicit("; + OS << "ASTContext &Ctx"; + if (!ElideSpelling) + OS << ", Spelling S"; + for (auto const &ai : Args) { + if (ai->isFake() && !emitFake) continue; + OS << ", "; + ai->writeCtorParameters(OS); + } + OS << ", SourceRange Loc = SourceRange()"; + OS << ") {\n"; + OS << " auto *A = new (Ctx) " << R.getName(); + OS << "Attr(Loc, Ctx, "; + for (auto const &ai : Args) { + if (ai->isFake() && !emitFake) continue; + ai->writeImplicitCtorArgs(OS); + OS << ", "; + } + OS << (ElideSpelling ? "0" : "S") << ");\n"; + OS << " A->setImplicit(true);\n"; + OS << " return A;\n }\n\n"; + }; - OS << " )\n"; - OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI, " - << R.getValueAsBit("LateParsed") << ", " - << R.getValueAsBit("DuplicatesAllowedWhileMerging") << ")\n"; + // Emit a CreateImplicit that takes all the arguments. + emitCreateImplicit(true); - for (auto const &ai : Args) { - OS << " , "; - ai->writeCtorInitializers(OS); - OS << "\n"; + // Emit a CreateImplicit that takes all the non-fake arguments. + if (HasFakeArg) { + emitCreateImplicit(false); } - OS << " {\n"; - - for (auto const &ai : Args) { - ai->writeCtorBody(OS); - OS << "\n"; - } - OS << " }\n\n"; + // Emit constructors. + auto emitCtor = [&](bool emitOpt, bool emitFake) { + auto shouldEmitArg = [=](const std::unique_ptr<Argument> &arg) { + if (arg->isFake()) return emitFake; + if (arg->isOptional()) return emitOpt; + return true; + }; - // If there are optional arguments, write out a constructor that elides the - // optional arguments as well. - if (HasOpt) { OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n"; for (auto const &ai : Args) { - if (!ai->isOptional()) { - OS << " , "; - ai->writeCtorParameters(OS); - OS << "\n"; - } + if (!shouldEmitArg(ai)) continue; + OS << " , "; + ai->writeCtorParameters(OS); + OS << "\n"; } OS << " , "; @@ -1570,19 +1581,37 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { for (auto const &ai : Args) { OS << " , "; - ai->writeCtorDefaultInitializers(OS); + if (!shouldEmitArg(ai)) { + ai->writeCtorDefaultInitializers(OS); + } else { + ai->writeCtorInitializers(OS); + } OS << "\n"; } OS << " {\n"; for (auto const &ai : Args) { - if (!ai->isOptional()) { - ai->writeCtorBody(OS); - OS << "\n"; - } + if (!shouldEmitArg(ai)) continue; + ai->writeCtorBody(OS); + OS << "\n"; } OS << " }\n\n"; + + }; + + // Emit a constructor that includes all the arguments. + // This is necessary for cloning. + emitCtor(true, true); + + // Emit a constructor that takes all the non-fake arguments. + if (HasFakeArg) { + emitCtor(true, false); + } + + // Emit a constructor that takes all the non-fake, non-optional arguments. + if (HasOptArg) { + emitCtor(false, false); } OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n"; @@ -1604,6 +1633,9 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { ai->writeAccessors(OS); OS << "\n\n"; + // Don't write conversion routines for fake arguments. + if (ai->isFake()) continue; + if (ai->isEnumArg()) static_cast<const EnumArgument *>(ai.get())->writeConversion(OS); else if (ai->isVariadicEnumArg()) @@ -1620,7 +1652,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << "};\n\n"; } - OS << "#endif\n"; + OS << "#endif // LLVM_CLANG_ATTR_CLASSES_INC\n"; } // Emits the class method definitions for attributes. @@ -1695,7 +1727,7 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) { static void EmitAttrList(raw_ostream &OS, StringRef Class, const std::vector<Record*> &AttrList) { - std::vector<Record*>::const_iterator i = AttrList.begin(), e = AttrList.end(); + auto i = AttrList.cbegin(), e = AttrList.cend(); if (i != e) { // Move the end iterator back to emit the last attribute. @@ -1847,7 +1879,7 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) { OS << " case attr::" << R.getName() << ": {\n"; Args = R.getValueAsListOfDefs("Args"); if (R.isSubClassOf(InhClass) || !Args.empty()) - OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName() + OS << " const auto *SA = cast<" << R.getName() << "Attr>(A);\n"; if (R.isSubClassOf(InhClass)) OS << " Record.push_back(SA->isInherited());\n"; @@ -1862,6 +1894,65 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) { OS << " }\n"; } +// Generate a conditional expression to check if the current target satisfies +// the conditions for a TargetSpecificAttr record, and append the code for +// those checks to the Test string. If the FnName string pointer is non-null, +// append a unique suffix to distinguish this set of target checks from other +// TargetSpecificAttr records. +static void GenerateTargetSpecificAttrChecks(const Record *R, + std::vector<std::string> &Arches, + std::string &Test, + std::string *FnName) { + // It is assumed that there will be an llvm::Triple object + // named "T" and a TargetInfo object named "Target" within + // scope that can be used to determine whether the attribute exists in + // a given target. + Test += "("; + + for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) { + std::string Part = *I; + Test += "T.getArch() == llvm::Triple::" + Part; + if (I + 1 != E) + Test += " || "; + if (FnName) + *FnName += Part; + } + Test += ")"; + + // If the attribute is specific to particular OSes, check those. + if (!R->isValueUnset("OSes")) { + // We know that there was at least one arch test, so we need to and in the + // OS tests. + Test += " && ("; + std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes"); + for (auto I = OSes.begin(), E = OSes.end(); I != E; ++I) { + std::string Part = *I; + + Test += "T.getOS() == llvm::Triple::" + Part; + if (I + 1 != E) + Test += " || "; + if (FnName) + *FnName += Part; + } + Test += ")"; + } + + // If one or more CXX ABIs are specified, check those as well. + if (!R->isValueUnset("CXXABIs")) { + Test += " && ("; + std::vector<std::string> CXXABIs = R->getValueAsListOfStrings("CXXABIs"); + for (auto I = CXXABIs.begin(), E = CXXABIs.end(); I != E; ++I) { + std::string Part = *I; + Test += "Target.getCXXABI().getKind() == TargetCXXABI::" + Part; + if (I + 1 != E) + Test += " || "; + if (FnName) + *FnName += Part; + } + Test += ")"; + } +} + static void GenerateHasAttrSpellingStringSwitch( const std::vector<Record *> &Attrs, raw_ostream &OS, const std::string &Variety = "", const std::string &Scope = "") { @@ -1887,37 +1978,12 @@ static void GenerateHasAttrSpellingStringSwitch( } } - // It is assumed that there will be an llvm::Triple object named T within - // scope that can be used to determine whether the attribute exists in - // a given target. std::string Test; if (Attr->isSubClassOf("TargetSpecificAttr")) { const Record *R = Attr->getValueAsDef("Target"); std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches"); + GenerateTargetSpecificAttrChecks(R, Arches, Test, nullptr); - Test += "("; - for (auto AI = Arches.begin(), AE = Arches.end(); AI != AE; ++AI) { - std::string Part = *AI; - Test += "T.getArch() == llvm::Triple::" + Part; - if (AI + 1 != AE) - Test += " || "; - } - Test += ")"; - - std::vector<std::string> OSes; - if (!R->isValueUnset("OSes")) { - Test += " && ("; - std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes"); - for (auto AI = OSes.begin(), AE = OSes.end(); AI != AE; ++AI) { - std::string Part = *AI; - - Test += "T.getOS() == llvm::Triple::" + Part; - if (AI + 1 != AE) - Test += " || "; - } - Test += ")"; - } - // If this is the C++11 variety, also add in the LangOpts test. if (Variety == "CXX11") Test += " && LangOpts.CPlusPlus11"; @@ -1964,6 +2030,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { } } + OS << "const llvm::Triple &T = Target.getTriple();\n"; OS << "switch (Syntax) {\n"; OS << "case AttrSyntax::GNU:\n"; OS << " return llvm::StringSwitch<int>(Name)\n"; @@ -1976,9 +2043,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma"); OS << "case AttrSyntax::CXX: {\n"; // C++11-style attributes are further split out based on the Scope. - for (std::map<std::string, std::vector<Record *>>::iterator I = CXX.begin(), - E = CXX.end(); - I != E; ++I) { + for (auto I = CXX.cbegin(), E = CXX.cend(); I != E; ++I) { if (I != CXX.begin()) OS << " else "; if (I->first.empty()) @@ -2049,7 +2114,7 @@ void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) { OS << " bool Visit" << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n" << " return true; \n" - << " };\n"; + << " }\n"; } OS << "\n#else // ATTR_VISITOR_DECLS_ONLY\n\n"; @@ -2123,12 +2188,12 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { bool ShouldClone = R.getValueAsBit("Clone"); if (!ShouldClone) { - OS << " return NULL;\n"; + OS << " return nullptr;\n"; OS << " }\n"; continue; } - OS << " const " << R.getName() << "Attr *A = cast<" + OS << " const auto *A = cast<" << R.getName() << "Attr>(At);\n"; bool TDependent = R.getValueAsBit("TemplateDependent"); @@ -2157,7 +2222,7 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { } OS << " } // end switch\n" << " llvm_unreachable(\"Unknown attribute!\");\n" - << " return 0;\n" + << " return nullptr;\n" << "}\n\n" << "} // end namespace sema\n" << "} // end namespace clang\n"; @@ -2328,6 +2393,7 @@ static std::string GetSubjectWithSuffix(const Record *R) { return "Decl"; return B + "Decl"; } + static std::string GenerateCustomAppertainsTo(const Record &Subject, raw_ostream &OS) { std::string FnName = "is" + Subject.getName(); @@ -2335,7 +2401,7 @@ static std::string GenerateCustomAppertainsTo(const Record &Subject, // If this code has already been generated, simply return the previous // instance of it. static std::set<std::string> CustomSubjectSet; - std::set<std::string>::iterator I = CustomSubjectSet.find(FnName); + auto I = CustomSubjectSet.find(FnName); if (I != CustomSubjectSet.end()) return *I; @@ -2349,7 +2415,7 @@ static std::string GenerateCustomAppertainsTo(const Record &Subject, } OS << "static bool " << FnName << "(const Decl *D) {\n"; - OS << " if (const " << GetSubjectWithSuffix(Base) << " *S = dyn_cast<"; + OS << " if (const auto *S = dyn_cast<"; OS << GetSubjectWithSuffix(Base); OS << ">(D))\n"; OS << " return " << Subject.getValueAsString("CheckCode") << ";\n"; @@ -2449,7 +2515,7 @@ static std::string GenerateLangOptRequirements(const Record &R, // If this code has already been generated, simply return the previous // instance of it. static std::set<std::string> CustomLangOptsSet; - std::set<std::string>::iterator I = CustomLangOptsSet.find(FnName); + auto I = CustomLangOptsSet.find(FnName); if (I != CustomLangOptsSet.end()) return *I; @@ -2466,7 +2532,7 @@ static std::string GenerateLangOptRequirements(const Record &R, } static void GenerateDefaultTargetRequirements(raw_ostream &OS) { - OS << "static bool defaultTargetRequirements(const llvm::Triple &) {\n"; + OS << "static bool defaultTargetRequirements(const TargetInfo &) {\n"; OS << " return true;\n"; OS << "}\n\n"; } @@ -2505,47 +2571,19 @@ static std::string GenerateTargetRequirements(const Record &Attr, } } - std::string FnName = "isTarget", Test = "("; - for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) { - std::string Part = *I; - Test += "Arch == llvm::Triple::" + Part; - if (I + 1 != E) - Test += " || "; - FnName += Part; - } - Test += ")"; - - // If the target also requires OS testing, generate those tests as well. - bool UsesOS = false; - if (!R->isValueUnset("OSes")) { - UsesOS = true; - - // We know that there was at least one arch test, so we need to and in the - // OS tests. - Test += " && ("; - std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes"); - for (auto I = OSes.begin(), E = OSes.end(); I != E; ++I) { - std::string Part = *I; - - Test += "OS == llvm::Triple::" + Part; - if (I + 1 != E) - Test += " || "; - FnName += Part; - } - Test += ")"; - } + std::string FnName = "isTarget"; + std::string Test; + GenerateTargetSpecificAttrChecks(R, Arches, Test, &FnName); // If this code has already been generated, simply return the previous // instance of it. static std::set<std::string> CustomTargetSet; - std::set<std::string>::iterator I = CustomTargetSet.find(FnName); + auto I = CustomTargetSet.find(FnName); if (I != CustomTargetSet.end()) return *I; - OS << "static bool " << FnName << "(const llvm::Triple &T) {\n"; - OS << " llvm::Triple::ArchType Arch = T.getArch();\n"; - if (UsesOS) - OS << " llvm::Triple::OSType OS = T.getOS();\n"; + OS << "static bool " << FnName << "(const TargetInfo &Target) {\n"; + OS << " const llvm::Triple &T = Target.getTriple();\n"; OS << " return " << Test << ";\n"; OS << "}\n\n"; @@ -2758,13 +2796,13 @@ void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) { Args = R.getValueAsListOfDefs("Args"); if (!Args.empty()) { - OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName() + OS << " const auto *SA = cast<" << R.getName() << "Attr>(A);\n"; for (const auto *Arg : Args) createArgument(*Arg, R.getName())->writeDump(OS); - for (auto AI = Args.begin(), AE = Args.end(); AI != AE; ++AI) - createArgument(**AI, R.getName())->writeDumpChildren(OS); + for (const auto *AI : Args) + createArgument(*AI, R.getName())->writeDumpChildren(OS); } OS << " break;\n" diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp index 3349030466fc..3522cd472d9d 100644 --- a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp +++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp @@ -72,7 +72,7 @@ void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) { OS << "const CommandInfo *CommandTraits::getBuiltinCommandInfo(\n" << " StringRef Name) {\n"; StringMatcher("Name", Matches, OS).Emit(); - OS << " return NULL;\n" + OS << " return nullptr;\n" << "}\n\n"; } @@ -123,4 +123,3 @@ void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) { } } } // end namespace clang - diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp index 7644ae2c04da..6e7bc9057fd7 100644 --- a/utils/TableGen/NeonEmitter.cpp +++ b/utils/TableGen/NeonEmitter.cpp @@ -36,6 +36,7 @@ #include "llvm/TableGen/SetTheory.h" #include "llvm/TableGen/TableGenBackend.h" #include <algorithm> +#include <deque> #include <map> #include <sstream> #include <string> @@ -393,7 +394,7 @@ public: /// Return true if the prototype has a scalar argument. /// This does not return true for the "splat" code ('a'). - bool protoHasScalar(); + bool protoHasScalar() const; /// Return the index that parameter PIndex will sit at /// in a generated function call. This is often just PIndex, @@ -431,9 +432,9 @@ public: /// Return the name, mangled with type information. /// If ForceClassS is true, use ClassS (u32/s32) instead /// of the intrinsic's own type class. - std::string getMangledName(bool ForceClassS = false); + std::string getMangledName(bool ForceClassS = false) const; /// Return the type code for a builtin function call. - std::string getInstTypeCode(Type T, ClassKind CK); + std::string getInstTypeCode(Type T, ClassKind CK) const; /// Return the type string for a BUILTIN() macro in Builtins.def. std::string getBuiltinTypeStr(); @@ -444,7 +445,7 @@ public: void indexBody(); private: - std::string mangleName(std::string Name, ClassKind CK); + std::string mangleName(std::string Name, ClassKind CK) const; void initVariables(); std::string replaceParamsIn(std::string S); @@ -494,7 +495,7 @@ private: class NeonEmitter { RecordKeeper &Records; DenseMap<Record *, ClassKind> ClassMap; - std::map<std::string, std::vector<Intrinsic *>> IntrinsicMap; + std::map<std::string, std::deque<Intrinsic>> IntrinsicMap; unsigned UniqueNumber; void createIntrinsic(Record *R, SmallVectorImpl<Intrinsic *> &Out); @@ -507,7 +508,7 @@ class NeonEmitter { public: /// Called by Intrinsic - this attempts to get an intrinsic that takes /// the given types as arguments. - Intrinsic *getIntrinsic(StringRef Name, ArrayRef<Type> Types); + Intrinsic &getIntrinsic(StringRef Name, ArrayRef<Type> Types); /// Called by Intrinsic - returns a globally-unique number. unsigned getUniqueNumber() { return UniqueNumber++; } @@ -836,10 +837,6 @@ void Type::applyModifier(char Mod) { Float = true; break; case 'f': - // Special case - if we're half-precision, a floating - // point argument needs to be 128-bits (double size). - if (isHalf()) - Bitwidth = 128; Float = true; ElementBitwidth = 32; break; @@ -954,7 +951,7 @@ void Type::applyModifier(char Mod) { // Intrinsic implementation //===----------------------------------------------------------------------===// -std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) { +std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) const { char typeCode = '\0'; bool printNumber = true; @@ -992,6 +989,10 @@ std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) { return S; } +static bool isFloatingPointProtoModifier(char Mod) { + return Mod == 'F' || Mod == 'f'; +} + std::string Intrinsic::getBuiltinTypeStr() { ClassKind LocalCK = getClassKind(true); std::string S; @@ -1013,7 +1014,7 @@ std::string Intrinsic::getBuiltinTypeStr() { if (!RetT.isScalar() && !RetT.isSigned()) RetT.makeSigned(); - bool ForcedVectorFloatingType = Proto[0] == 'F' || Proto[0] == 'f'; + bool ForcedVectorFloatingType = isFloatingPointProtoModifier(Proto[0]); if (LocalCK == ClassB && !RetT.isScalar() && !ForcedVectorFloatingType) // Cast to vector of 8-bit elements. RetT.makeInteger(8, true); @@ -1026,7 +1027,7 @@ std::string Intrinsic::getBuiltinTypeStr() { if (T.isPoly()) T.makeInteger(T.getElementSizeInBits(), false); - bool ForcedFloatingType = Proto[I + 1] == 'F' || Proto[I + 1] == 'f'; + bool ForcedFloatingType = isFloatingPointProtoModifier(Proto[I + 1]); if (LocalCK == ClassB && !T.isScalar() && !ForcedFloatingType) T.makeInteger(8, true); // Halves always get converted to 8-bit elements. @@ -1049,7 +1050,7 @@ std::string Intrinsic::getBuiltinTypeStr() { return S; } -std::string Intrinsic::getMangledName(bool ForceClassS) { +std::string Intrinsic::getMangledName(bool ForceClassS) const { // Check if the prototype has a scalar operand with the type of the vector // elements. If not, bitcasting the args will take care of arg checking. // The actual signedness etc. will be taken care of with special enums. @@ -1060,12 +1061,12 @@ std::string Intrinsic::getMangledName(bool ForceClassS) { return mangleName(Name, ForceClassS ? ClassS : LocalCK); } -std::string Intrinsic::mangleName(std::string Name, ClassKind LocalCK) { +std::string Intrinsic::mangleName(std::string Name, ClassKind LocalCK) const { std::string typeCode = getInstTypeCode(BaseType, LocalCK); std::string S = Name; - if (Name == "vcvt_f32_f16" || Name == "vcvt_f32_f64" || - Name == "vcvt_f64_f32") + if (Name == "vcvt_f16_f32" || Name == "vcvt_f32_f16" || + Name == "vcvt_f32_f64" || Name == "vcvt_f64_f32") return Name; if (typeCode.size() > 0) { @@ -1278,7 +1279,7 @@ void Intrinsic::emitShadowedArgs() { // We don't check 'a' in this function, because for builtin function the // argument matching to 'a' uses a vector type splatted from a scalar type. -bool Intrinsic::protoHasScalar() { +bool Intrinsic::protoHasScalar() const { return (Proto.find('s') != std::string::npos || Proto.find('z') != std::string::npos || Proto.find('r') != std::string::npos || @@ -1363,7 +1364,7 @@ void Intrinsic::emitBodyAsBuiltinCall() { // Extra constant integer to hold type class enum for this function, e.g. s8 if (getClassKind(true) == ClassB) { Type ThisTy = getReturnType(); - if (Proto[0] == 'v' || Proto[0] == 'f' || Proto[0] == 'F') + if (Proto[0] == 'v' || isFloatingPointProtoModifier(Proto[0])) ThisTy = getParamType(0); if (ThisTy.isPointer()) ThisTy = getParamType(1); @@ -1491,15 +1492,14 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCall(DagInit *DI) { N = SI->getAsUnquotedString(); else N = emitDagArg(DI->getArg(0), "").second; - Intrinsic *Callee = Intr.Emitter.getIntrinsic(N, Types); - assert(Callee && "getIntrinsic should not return us nullptr!"); + Intrinsic &Callee = Intr.Emitter.getIntrinsic(N, Types); // Make sure the callee is known as an early def. - Callee->setNeededEarly(); - Intr.Dependencies.insert(Callee); + Callee.setNeededEarly(); + Intr.Dependencies.insert(&Callee); // Now create the call itself. - std::string S = CallPrefix.str() + Callee->getMangledName(true) + "("; + std::string S = CallPrefix.str() + Callee.getMangledName(true) + "("; for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) { if (I != 0) S += ", "; @@ -1507,7 +1507,7 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCall(DagInit *DI) { } S += ")"; - return std::make_pair(Callee->getReturnType(), S); + return std::make_pair(Callee.getReturnType(), S); } std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCast(DagInit *DI, @@ -1855,11 +1855,11 @@ void Intrinsic::indexBody() { // NeonEmitter implementation //===----------------------------------------------------------------------===// -Intrinsic *NeonEmitter::getIntrinsic(StringRef Name, ArrayRef<Type> Types) { +Intrinsic &NeonEmitter::getIntrinsic(StringRef Name, ArrayRef<Type> Types) { // First, look up the name in the intrinsic map. assert_with_loc(IntrinsicMap.find(Name.str()) != IntrinsicMap.end(), ("Intrinsic '" + Name + "' not found!").str()); - std::vector<Intrinsic *> &V = IntrinsicMap[Name.str()]; + auto &V = IntrinsicMap.find(Name.str())->second; std::vector<Intrinsic *> GoodVec; // Create a string to print if we end up failing. @@ -1874,35 +1874,35 @@ Intrinsic *NeonEmitter::getIntrinsic(StringRef Name, ArrayRef<Type> Types) { // Now, look through each intrinsic implementation and see if the types are // compatible. - for (auto *I : V) { - ErrMsg += " - " + I->getReturnType().str() + " " + I->getMangledName(); + for (auto &I : V) { + ErrMsg += " - " + I.getReturnType().str() + " " + I.getMangledName(); ErrMsg += "("; - for (unsigned A = 0; A < I->getNumParams(); ++A) { + for (unsigned A = 0; A < I.getNumParams(); ++A) { if (A != 0) ErrMsg += ", "; - ErrMsg += I->getParamType(A).str(); + ErrMsg += I.getParamType(A).str(); } ErrMsg += ")\n"; - if (I->getNumParams() != Types.size()) + if (I.getNumParams() != Types.size()) continue; bool Good = true; for (unsigned Arg = 0; Arg < Types.size(); ++Arg) { - if (I->getParamType(Arg) != Types[Arg]) { + if (I.getParamType(Arg) != Types[Arg]) { Good = false; break; } } if (Good) - GoodVec.push_back(I); + GoodVec.push_back(&I); } assert_with_loc(GoodVec.size() > 0, "No compatible intrinsic found - " + ErrMsg); assert_with_loc(GoodVec.size() == 1, "Multiple overloads found - " + ErrMsg); - return GoodVec.front(); + return *GoodVec.front(); } void NeonEmitter::createIntrinsic(Record *R, @@ -1947,13 +1947,12 @@ void NeonEmitter::createIntrinsic(Record *R, std::sort(NewTypeSpecs.begin(), NewTypeSpecs.end()); NewTypeSpecs.erase(std::unique(NewTypeSpecs.begin(), NewTypeSpecs.end()), NewTypeSpecs.end()); + auto &Entry = IntrinsicMap[Name]; for (auto &I : NewTypeSpecs) { - Intrinsic *IT = new Intrinsic(R, Name, Proto, I.first, I.second, CK, Body, - *this, Guard, IsUnavailable, BigEndianSafe); - - IntrinsicMap[Name].push_back(IT); - Out.push_back(IT); + Entry.emplace_back(R, Name, Proto, I.first, I.second, CK, Body, *this, + Guard, IsUnavailable, BigEndianSafe); + Out.push_back(&Entry.back()); } CurrentRecord = nullptr; @@ -2023,8 +2022,8 @@ void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS, uint64_t Mask = 0ULL; Type Ty = Def->getReturnType(); - if (Def->getProto()[0] == 'v' || Def->getProto()[0] == 'f' || - Def->getProto()[0] == 'F') + if (Def->getProto()[0] == 'v' || + isFloatingPointProtoModifier(Def->getProto()[0])) Ty = Def->getParamType(0); if (Ty.isPointer()) Ty = Def->getParamType(1); diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py index ce5ddfb3add4..2d1f44f6880c 100755 --- a/utils/analyzer/CmpRuns.py +++ b/utils/analyzer/CmpRuns.py @@ -5,7 +5,7 @@ CmpRuns - A simple tool for comparing two static analyzer runs to determine which reports have been added, removed, or changed. This is designed to support automated testing using the static analyzer, from -two perspectives: +two perspectives: 1. To monitor changes in the static analyzer's reports on real code bases, for regression testing. @@ -19,11 +19,11 @@ Usage: # resultsA = loadResultsFromSingleRun(singleRunInfoA, deleteEmpty) resultsB = loadResultsFromSingleRun(singleRunInfoB, deleteEmpty) - - # Generate a relation from diagnostics in run A to diagnostics in run B - # to obtain a list of triples (a, b, confidence). + + # Generate a relation from diagnostics in run A to diagnostics in run B + # to obtain a list of triples (a, b, confidence). diff = compareResults(resultsA, resultsB) - + """ import os @@ -32,7 +32,7 @@ import CmpRuns # Information about analysis run: # path - the analysis output directory -# root - the name of the root directory, which will be disregarded when +# root - the name of the root directory, which will be disregarded when # determining the source file name class SingleRunInfo: def __init__(self, path, root="", verboseLog=None): @@ -56,7 +56,7 @@ class AnalysisDiagnostic: def getLine(self): return self._loc['line'] - + def getColumn(self): return self._loc['col'] @@ -70,8 +70,8 @@ class AnalysisDiagnostic: id = self.getFileName() + "+" if 'issue_context' in self._data : id += self._data['issue_context'] + "+" - if 'issue_hash' in self._data : - id += str(self._data['issue_hash']) + if 'issue_hash_content_of_line_in_context' in self._data : + id += str(self._data['issue_hash_content_of_line_in_context']) return id def getReport(self): @@ -80,12 +80,12 @@ class AnalysisDiagnostic: return os.path.join(self._report.run.path, self._htmlReport) def getReadableName(self): - return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(), - self.getColumn(), self.getCategory(), + return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(), + self.getColumn(), self.getCategory(), self.getDescription()) - - # Note, the data format is not an API and may change from one analyzer - # version to another. + + # Note, the data format is not an API and may change from one analyzer + # version to another. def getRawData(self): return self._data @@ -94,7 +94,7 @@ class multidict: self.data = {} for key,value in elts: self[key] = value - + def __getitem__(self, item): return self.data[item] def __setitem__(self, key, value): @@ -134,15 +134,15 @@ class AnalysisRun: # Cumulative list of all diagnostics from all the reports. self.diagnostics = [] self.clang_version = None - + def getClangVersion(self): return self.clang_version def readSingleFile(self, p, deleteEmpty): data = plistlib.readPlist(p) - # We want to retrieve the clang version even if there are no - # reports. Assume that all reports were created using the same + # We want to retrieve the clang version even if there are no + # reports. Assume that all reports were created using the same # clang version (this is always true and is more efficient). if 'clang_version' in data: if self.clang_version == None: @@ -166,9 +166,9 @@ class AnalysisRun: htmlFiles.append(d.pop('HTMLDiagnostics_files')[0]) else: htmlFiles = [None] * len(data['diagnostics']) - + report = AnalysisReport(self, data.pop('files')) - diagnostics = [AnalysisDiagnostic(d, report, h) + diagnostics = [AnalysisDiagnostic(d, report, h) for d,h in zip(data.pop('diagnostics'), htmlFiles)] @@ -179,7 +179,7 @@ class AnalysisRun: self.diagnostics.extend(diagnostics) -# Backward compatibility API. +# Backward compatibility API. def loadResults(path, opts, root = "", deleteEmpty=True): return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog), deleteEmpty) @@ -257,7 +257,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True): # Load the run results. resultsA = loadResults(dirA, opts, opts.rootA, deleteEmpty) resultsB = loadResults(dirB, opts, opts.rootB, deleteEmpty) - + # Open the verbose log, if given. if opts.verboseLog: auxLog = open(opts.verboseLog, "wb") @@ -285,7 +285,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True): b.getReadableName()) foundDiffs += 1 if auxLog: - print >>auxLog, ("('CHANGED', %r, %r, %r, %r)" + print >>auxLog, ("('CHANGED', %r, %r, %r, %r)" % (a.getReadableName(), b.getReadableName(), a.getReport(), @@ -299,7 +299,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True): if auxLog: print >>auxLog, "('TOTAL NEW REPORTS', %r)" % TotalReports print >>auxLog, "('TOTAL DIFFERENCES', %r)" % foundDiffs - + return foundDiffs, len(resultsA.diagnostics), len(resultsB.diagnostics) def main(): @@ -322,7 +322,7 @@ def main(): dirA,dirB = args - dumpScanBuildResultsDiff(dirA, dirB, opts) + dumpScanBuildResultsDiff(dirA, dirB, opts) if __name__ == '__main__': main() diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py index 64ff4ff65683..4b94a109ce64 100644 --- a/utils/analyzer/SATestAdd.py +++ b/utils/analyzer/SATestAdd.py @@ -1,20 +1,44 @@ #!/usr/bin/env python """ -Static Analyzer qualification infrastructure: adding a new project to +Static Analyzer qualification infrastructure: adding a new project to the Repository Directory. Add a new project for testing: build it and add to the Project Map file. Assumes it's being run from the Repository Directory. - The project directory should be added inside the Repository Directory and + The project directory should be added inside the Repository Directory and have the same name as the project ID - + The project should use the following files for set up: - - pre_run_static_analyzer.sh - prepare the build environment. + - cleanup_run_static_analyzer.sh - prepare the build environment. Ex: make clean can be a part of it. - run_static_analyzer.cmd - a list of commands to run through scan-build. Each command should be on a separate line. - Choose from: configure, make, xcodebuild + Choose from: configure, make, xcodebuild + - download_project.sh - download the project into the CachedSource/ + directory. For example, download a zip of + the project source from GitHub, unzip it, + and rename the unzipped directory to + 'CachedSource'. This script is not called + when 'CachedSource' is already present, + so an alternative is to check the + 'CachedSource' directory into the + repository directly. + - CachedSource/ - An optional directory containing the source of the + project being analyzed. If present, + download_project.sh will not be called. + - changes_for_analyzer.patch - An optional patch file for any local changes + (e.g., to adapt to newer version of clang) + that should be applied to CachedSource + before analysis. To construct this patch, + run the the download script to download + the project to CachedSource, copy the + CachedSource to another directory (for + example, PatchedSource) and make any needed + modifications to the the copied source. + Then run: + diff -ur CachedSource PatchedSource \ + > changes_for_analyzer.patch """ import SATestBuild @@ -27,7 +51,7 @@ def isExistingProject(PMapFile, projectID) : for I in PMapReader: if projectID == I[0]: return True - return False + return False # Add a new project for testing: build it and add to the Project Map file. # Params: @@ -39,7 +63,7 @@ def addNewProject(ID, BuildMode) : if not os.path.exists(Dir): print "Error: Project directory is missing: %s" % Dir sys.exit(-1) - + # Build the project. SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True, Dir=Dir) @@ -51,19 +75,19 @@ def addNewProject(ID, BuildMode) : print "Warning: Creating the Project Map file!!" PMapFile = open(ProjectMapPath, "w+b") try: - if (isExistingProject(PMapFile, ID)) : + if (isExistingProject(PMapFile, ID)) : print >> sys.stdout, 'Warning: Project with ID \'', ID, \ '\' already exists.' print >> sys.stdout, "Reference output has been regenerated." - else: + else: PMapWriter = csv.writer(PMapFile) PMapWriter.writerow( (ID, int(BuildMode)) ); print "The project map is updated: ", ProjectMapPath finally: PMapFile.close() - -# TODO: Add an option not to build. + +# TODO: Add an option not to build. # TODO: Set the path to the Repository directory. if __name__ == '__main__': if len(sys.argv) < 2: @@ -73,10 +97,10 @@ if __name__ == '__main__': '1 for scan_build; ' \ '2 for single file c++11 project' sys.exit(-1) - - BuildMode = 1 + + BuildMode = 1 if (len(sys.argv) >= 3): - BuildMode = int(sys.argv[2]) + BuildMode = int(sys.argv[2]) assert((BuildMode == 0) | (BuildMode == 1) | (BuildMode == 2)) - + addNewProject(sys.argv[1], BuildMode) diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index 2d91ba41e24c..d0503c6389c9 100644 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -6,8 +6,8 @@ Static Analyzer qualification infrastructure. The goal is to test the analyzer against different projects, check for failures, compare results, and measure performance. -Repository Directory will contain sources of the projects as well as the -information on how to build them and the expected output. +Repository Directory will contain sources of the projects as well as the +information on how to build them and the expected output. Repository Directory structure: - ProjectMap file - Historical Performance Data @@ -19,16 +19,16 @@ Repository Directory structure: Note that the build tree must be inside the project dir. To test the build of the analyzer one would: - - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that + - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that the build directory does not pollute the repository to min network traffic). - Build all projects, until error. Produce logs to report errors. - - Compare results. + - Compare results. -The files which should be kept around for failure investigations: +The files which should be kept around for failure investigations: RepositoryCopy/Project DirI/ScanBuildResults - RepositoryCopy/Project DirI/run_static_analyzer.log - -Assumptions (TODO: shouldn't need to assume these.): + RepositoryCopy/Project DirI/run_static_analyzer.log + +Assumptions (TODO: shouldn't need to assume these.): The script is being run from the Repository Directory. The compiler for scan-build and scan-build are in the PATH. export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH @@ -36,6 +36,10 @@ Assumptions (TODO: shouldn't need to assume these.): For more logging, set the env variables: zaks:TI zaks$ export CCC_ANALYZER_LOG=1 zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1 + +The list of checkers tested are hardcoded in the Checkers variable. +For testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment +variable. It should contain a comma separated list. """ import CmpRuns @@ -48,7 +52,7 @@ import shutil import time import plistlib import argparse -from subprocess import check_call, CalledProcessError +from subprocess import check_call, check_output, CalledProcessError #------------------------------------------------------------------------------ # Helper functions. @@ -116,16 +120,16 @@ class flushfile(object): sys.stdout = flushfile(sys.stdout) def getProjectMapPath(): - ProjectMapPath = os.path.join(os.path.abspath(os.curdir), + ProjectMapPath = os.path.join(os.path.abspath(os.curdir), ProjectMapFile) if not os.path.exists(ProjectMapPath): print "Error: Cannot find the Project Map file " + ProjectMapPath +\ "\nRunning script for the wrong directory?" - sys.exit(-1) - return ProjectMapPath + sys.exit(-1) + return ProjectMapPath def getProjectDir(ID): - return os.path.join(os.path.abspath(os.curdir), ID) + return os.path.join(os.path.abspath(os.curdir), ID) def getSBOutputDirName(IsReferenceBuild) : if IsReferenceBuild == True : @@ -150,15 +154,17 @@ Jobs = int(math.ceil(detectCPUs() * 0.75)) ProjectMapFile = "projectMap.csv" # Names of the project specific scripts. +# The script that downloads the project. +DownloadScript = "download_project.sh" # The script that needs to be executed before the build can start. CleanupScript = "cleanup_run_static_analyzer.sh" -# This is a file containing commands for scan-build. +# This is a file containing commands for scan-build. BuildScript = "run_static_analyzer.cmd" # The log file name. LogFolderName = "Logs" BuildLogName = "run_static_analyzer.log" -# Summary file - contains the summary of the failures. Ex: This info can be be +# Summary file - contains the summary of the failures. Ex: This info can be be # displayed when buildbot detects a build failure. NumOfFailuresInSummary = 10 FailuresSummaryFileName = "failures.txt" @@ -169,6 +175,21 @@ DiffsSummaryFileName = "diffs.txt" SBOutputDirName = "ScanBuildResults" SBOutputDirReferencePrefix = "Ref" +# The name of the directory storing the cached project source. If this directory +# does not exist, the download script will be executed. That script should +# create the "CachedSource" directory and download the project source into it. +CachedSourceDirName = "CachedSource" + +# The name of the directory containing the source code that will be analyzed. +# Each time a project is analyzed, a fresh copy of its CachedSource directory +# will be copied to the PatchedSource directory and then the local patches +# in PatchfileName will be applied (if PatchfileName exists). +PatchedSourceDirName = "PatchedSource" + +# The name of the patchfile specifying any changes that should be applied +# to the CachedSource before analyzing. +PatchfileName = "changes_for_analyzer.patch" + # The list of checkers used during analyzes. # Currently, consists of all the non-experimental checkers, plus a few alpha # checkers we don't want to regress on. @@ -182,35 +203,93 @@ Verbose = 1 # Run pre-processing script if any. def runCleanupScript(Dir, PBuildLogFile): + Cwd = os.path.join(Dir, PatchedSourceDirName) ScriptPath = os.path.join(Dir, CleanupScript) + runScript(ScriptPath, PBuildLogFile, Cwd) + +# Run the script to download the project, if it exists. +def runDownloadScript(Dir, PBuildLogFile): + ScriptPath = os.path.join(Dir, DownloadScript) + runScript(ScriptPath, PBuildLogFile, Dir) + +# Run the provided script if it exists. +def runScript(ScriptPath, PBuildLogFile, Cwd): if os.path.exists(ScriptPath): try: - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (ScriptPath,) - check_call("chmod +x %s" % ScriptPath, cwd = Dir, + check_call("chmod +x %s" % ScriptPath, cwd = Cwd, stderr=PBuildLogFile, - stdout=PBuildLogFile, - shell=True) - check_call(ScriptPath, cwd = Dir, stderr=PBuildLogFile, - stdout=PBuildLogFile, + stdout=PBuildLogFile, + shell=True) + check_call(ScriptPath, cwd = Cwd, stderr=PBuildLogFile, + stdout=PBuildLogFile, shell=True) except: - print "Error: The pre-processing step failed. See ", \ - PBuildLogFile.name, " for details." + print "Error: Running %s failed. See %s for details." % (ScriptPath, + PBuildLogFile.name) sys.exit(-1) -# Build the project with scan-build by reading in the commands and +# Download the project and apply the local patchfile if it exists. +def downloadAndPatch(Dir, PBuildLogFile): + CachedSourceDirPath = os.path.join(Dir, CachedSourceDirName) + + # If the we don't already have the cached source, run the project's + # download script to download it. + if not os.path.exists(CachedSourceDirPath): + runDownloadScript(Dir, PBuildLogFile) + if not os.path.exists(CachedSourceDirPath): + print "Error: '%s' not found after download." % (CachedSourceDirPath) + exit(-1) + + PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName) + + # Remove potentially stale patched source. + if os.path.exists(PatchedSourceDirPath): + shutil.rmtree(PatchedSourceDirPath) + + # Copy the cached source and apply any patches to the copy. + shutil.copytree(CachedSourceDirPath, PatchedSourceDirPath, symlinks=True) + applyPatch(Dir, PBuildLogFile) + +def applyPatch(Dir, PBuildLogFile): + PatchfilePath = os.path.join(Dir, PatchfileName) + PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName) + if not os.path.exists(PatchfilePath): + print " No local patches." + return + + print " Applying patch." + try: + check_call("patch -p1 < %s" % (PatchfilePath), + cwd = PatchedSourceDirPath, + stderr=PBuildLogFile, + stdout=PBuildLogFile, + shell=True) + except: + print "Error: Patch failed. See %s for details." % (PBuildLogFile.name) + sys.exit(-1) + +# Build the project with scan-build by reading in the commands and # prefixing them with the scan-build options. def runScanBuild(Dir, SBOutputDir, PBuildLogFile): BuildScriptPath = os.path.join(Dir, BuildScript) if not os.path.exists(BuildScriptPath): print "Error: build script is not defined: %s" % BuildScriptPath sys.exit(-1) + + AllCheckers = Checkers + if os.environ.has_key('SA_ADDITIONAL_CHECKERS'): + AllCheckers = AllCheckers + ',' + os.environ['SA_ADDITIONAL_CHECKERS'] + + # Run scan-build from within the patched source directory. + SBCwd = os.path.join(Dir, PatchedSourceDirName) + SBOptions = "--use-analyzer " + Clang + " " SBOptions += "-plist-html -o " + SBOutputDir + " " - SBOptions += "-enable-checker " + Checkers + " " + SBOptions += "-enable-checker " + AllCheckers + " " SBOptions += "--keep-empty " - # Always use ccc-analyze to ensure that we can locate the failures + # Always use ccc-analyze to ensure that we can locate the failures # directory. SBOptions += "--override-compiler " try: @@ -227,11 +306,11 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): "-j" not in Command: Command += " -j%d" % Jobs SBCommand = SBPrefix + Command - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (SBCommand,) - check_call(SBCommand, cwd = Dir, stderr=PBuildLogFile, - stdout=PBuildLogFile, - shell=True) + check_call(SBCommand, cwd = SBCwd, stderr=PBuildLogFile, + stdout=PBuildLogFile, + shell=True) except: print "Error: scan-build failed. See ",PBuildLogFile.name,\ " for details." @@ -245,97 +324,114 @@ def hasNoExtension(FileName): def isValidSingleInputFile(FileName): (Root, Ext) = os.path.splitext(FileName) - if ((Ext == ".i") | (Ext == ".ii") | - (Ext == ".c") | (Ext == ".cpp") | + if ((Ext == ".i") | (Ext == ".ii") | + (Ext == ".c") | (Ext == ".cpp") | (Ext == ".m") | (Ext == "")) : return True return False - + +# Get the path to the SDK for the given SDK name. Returns None if +# the path cannot be determined. +def getSDKPath(SDKName): + if which("xcrun") is None: + return None + + Cmd = "xcrun --sdk " + SDKName + " --show-sdk-path" + return check_output(Cmd, shell=True).rstrip() + # Run analysis on a set of preprocessed files. def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): if os.path.exists(os.path.join(Dir, BuildScript)): print "Error: The preprocessed files project should not contain %s" % \ BuildScript - raise Exception() + raise Exception() + + CmdPrefix = Clang + " -cc1 " + + # For now, we assume the preprocessed files should be analyzed + # with the OS X SDK. + SDKPath = getSDKPath("macosx") + if SDKPath is not None: + CmdPrefix += "-isysroot " + SDKPath + " " + + CmdPrefix += "-analyze -analyzer-output=plist -w " + CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks " - CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w " - CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks " - if (Mode == 2) : - CmdPrefix += "-std=c++11 " - + CmdPrefix += "-std=c++11 " + PlistPath = os.path.join(Dir, SBOutputDir, "date") FailPath = os.path.join(PlistPath, "failures"); os.makedirs(FailPath); - + for FullFileName in glob.glob(Dir + "/*"): FileName = os.path.basename(FullFileName) Failed = False - + # Only run the analyzes on supported files. if (hasNoExtension(FileName)): continue if (isValidSingleInputFile(FileName) == False): print "Error: Invalid single input file %s." % (FullFileName,) raise Exception() - + # Build and call the analyzer command. OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist " Command = CmdPrefix + OutputOption + FileName LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b") try: - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (Command,) check_call(Command, cwd = Dir, stderr=LogFile, - stdout=LogFile, + stdout=LogFile, shell=True) except CalledProcessError, e: print "Error: Analyzes of %s failed. See %s for details." \ "Error code %d." % \ (FullFileName, LogFile.name, e.returncode) - Failed = True + Failed = True finally: - LogFile.close() - + LogFile.close() + # If command did not fail, erase the log file. if Failed == False: os.remove(LogFile.name); def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): - TBegin = time.time() + TBegin = time.time() BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName) - print "Log file: %s" % (BuildLogPath,) + print "Log file: %s" % (BuildLogPath,) print "Output directory: %s" %(SBOutputDir, ) - + # Clean up the log file. if (os.path.exists(BuildLogPath)) : RmCommand = "rm " + BuildLogPath if Verbose == 1: print " Executing: %s" % (RmCommand,) check_call(RmCommand, shell=True) - + # Clean up scan build results. if (os.path.exists(SBOutputDir)) : RmCommand = "rm -r " + SBOutputDir - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (RmCommand,) check_call(RmCommand, shell=True) assert(not os.path.exists(SBOutputDir)) os.makedirs(os.path.join(SBOutputDir, LogFolderName)) - + # Open the log file. PBuildLogFile = open(BuildLogPath, "wb+") - + # Build and analyze the project. try: - runCleanupScript(Dir, PBuildLogFile) - if (ProjectBuildMode == 1): + downloadAndPatch(Dir, PBuildLogFile) + runCleanupScript(Dir, PBuildLogFile) runScanBuild(Dir, SBOutputDir, PBuildLogFile) else: runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode) - + if IsReferenceBuild : runCleanupScript(Dir, PBuildLogFile) @@ -346,32 +442,36 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): continue Plist = os.path.join(DirPath, F) Data = plistlib.readPlist(Plist) - Paths = [SourceFile[len(Dir)+1:] if SourceFile.startswith(Dir)\ - else SourceFile for SourceFile in Data['files']] + PathPrefix = Dir + if (ProjectBuildMode == 1): + PathPrefix = os.path.join(Dir, PatchedSourceDirName) + Paths = [SourceFile[len(PathPrefix)+1:]\ + if SourceFile.startswith(PathPrefix)\ + else SourceFile for SourceFile in Data['files']] Data['files'] = Paths plistlib.writePlist(Data, Plist) - + finally: PBuildLogFile.close() - + print "Build complete (time: %.2f). See the log for more details: %s" % \ - ((time.time()-TBegin), BuildLogPath) - + ((time.time()-TBegin), BuildLogPath) + # A plist file is created for each call to the analyzer(each source file). -# We are only interested on the once that have bug reports, so delete the rest. +# We are only interested on the once that have bug reports, so delete the rest. def CleanUpEmptyPlists(SBOutputDir): for F in glob.glob(SBOutputDir + "/*/*.plist"): P = os.path.join(SBOutputDir, F) - + Data = plistlib.readPlist(P) # Delete empty reports. if not Data['files']: os.remove(P) continue -# Given the scan-build output directory, checks if the build failed -# (by searching for the failures directories). If there are failures, it -# creates a summary file in the output directory. +# Given the scan-build output directory, checks if the build failed +# (by searching for the failures directories). If there are failures, it +# creates a summary file in the output directory. def checkBuild(SBOutputDir): # Check if there are failures. Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt") @@ -382,37 +482,37 @@ def checkBuild(SBOutputDir): print "Number of bug reports (non-empty plist files) produced: %d" %\ len(Plists) return; - + # Create summary file to display when the build fails. SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName) if (Verbose > 0): print " Creating the failures summary file %s" % (SummaryPath,) - + SummaryLog = open(SummaryPath, "w+") try: SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,)) if TotalFailed > NumOfFailuresInSummary: - SummaryLog.write("See the first %d below.\n" + SummaryLog.write("See the first %d below.\n" % (NumOfFailuresInSummary,)) # TODO: Add a line "See the results folder for more." - + FailuresCopied = NumOfFailuresInSummary Idx = 0 for FailLogPathI in Failures: if Idx >= NumOfFailuresInSummary: break; - Idx += 1 + Idx += 1 SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,)); FailLogI = open(FailLogPathI, "r"); - try: + try: shutil.copyfileobj(FailLogI, SummaryLog); finally: FailLogI.close() finally: SummaryLog.close() - + print "Error: analysis failed. See ", SummaryPath - sys.exit(-1) + sys.exit(-1) # Auxiliary object to discard stdout. class Discarder(object): @@ -424,46 +524,47 @@ class Discarder(object): # 0 - success if there are no crashes or analyzer failure. # 1 - success if there are no difference in the number of reported bugs. # 2 - success if all the bug reports are identical. -def runCmpResults(Dir, Strictness = 0): - TBegin = time.time() +def runCmpResults(Dir, Strictness = 0): + TBegin = time.time() RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName) NewDir = os.path.join(Dir, SBOutputDirName) - + # We have to go one level down the directory tree. - RefList = glob.glob(RefDir + "/*") + RefList = glob.glob(RefDir + "/*") NewList = glob.glob(NewDir + "/*") - + # Log folders are also located in the results dir, so ignore them. RefLogDir = os.path.join(RefDir, LogFolderName) if RefLogDir in RefList: RefList.remove(RefLogDir) NewList.remove(os.path.join(NewDir, LogFolderName)) - + if len(RefList) == 0 or len(NewList) == 0: return False assert(len(RefList) == len(NewList)) - # There might be more then one folder underneath - one per each scan-build + # There might be more then one folder underneath - one per each scan-build # command (Ex: one for configure and one for make). if (len(RefList) > 1): # Assume that the corresponding folders have the same names. RefList.sort() NewList.sort() - + # Iterate and find the differences. NumDiffs = 0 - PairList = zip(RefList, NewList) - for P in PairList: - RefDir = P[0] + PairList = zip(RefList, NewList) + for P in PairList: + RefDir = P[0] NewDir = P[1] - - assert(RefDir != NewDir) - if Verbose == 1: + + assert(RefDir != NewDir) + if Verbose == 1: print " Comparing Results: %s %s" % (RefDir, NewDir) - + DiffsPath = os.path.join(NewDir, DiffsSummaryFileName) - Opts = CmpRuns.CmpOptions(DiffsPath, "", Dir) + PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName) + Opts = CmpRuns.CmpOptions(DiffsPath, "", PatchedSourceDirPath) # Discard everything coming out of stdout (CmpRun produces a lot of them). OLD_STDOUT = sys.stdout sys.stdout = Discarder() @@ -476,70 +577,70 @@ def runCmpResults(Dir, Strictness = 0): (NumDiffs, DiffsPath,) if Strictness >= 2 and NumDiffs > 0: print "Error: Diffs found in strict mode (2)." - sys.exit(-1) + sys.exit(-1) elif Strictness >= 1 and ReportsInRef != ReportsInNew: print "Error: The number of results are different in strict mode (1)." - sys.exit(-1) - - print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin) + sys.exit(-1) + + print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin) return (NumDiffs > 0) - + def updateSVN(Mode, ProjectsMap): try: - ProjectsMap.seek(0) + ProjectsMap.seek(0) for I in csv.reader(ProjectsMap): - ProjName = I[0] + ProjName = I[0] Path = os.path.join(ProjName, getSBOutputDirName(True)) - + if Mode == "delete": Command = "svn delete %s" % (Path,) else: Command = "svn add %s" % (Path,) - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (Command,) - check_call(Command, shell=True) - + check_call(Command, shell=True) + if Mode == "delete": CommitCommand = "svn commit -m \"[analyzer tests] Remove " \ - "reference results.\"" + "reference results.\"" else: CommitCommand = "svn commit -m \"[analyzer tests] Add new " \ "reference results.\"" - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (CommitCommand,) - check_call(CommitCommand, shell=True) + check_call(CommitCommand, shell=True) except: print "Error: SVN update failed." sys.exit(-1) - + def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictness = 0): print " \n\n--- Building project %s" % (ID,) - TBegin = time.time() + TBegin = time.time() if Dir is None : - Dir = getProjectDir(ID) - if Verbose == 1: + Dir = getProjectDir(ID) + if Verbose == 1: print " Build directory: %s." % (Dir,) - + # Set the build results directory. RelOutputDir = getSBOutputDirName(IsReferenceBuild) SBOutputDir = os.path.join(Dir, RelOutputDir) - + buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild) checkBuild(SBOutputDir) - + if IsReferenceBuild == False: runCmpResults(Dir, Strictness) - + print "Completed tests for project %s (time: %.2f)." % \ (ID, (time.time()-TBegin)) - + def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0): PMapFile = open(getProjectMapPath(), "rb") - try: + try: # Validate the input. for I in csv.reader(PMapFile): if (len(I) != 2) : @@ -548,16 +649,16 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0): if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))): print "Error: Second entry in the ProjectMapFile should be 0" \ " (single file), 1 (project), or 2(single file c++11)." - raise Exception() + raise Exception() - # When we are regenerating the reference results, we might need to + # When we are regenerating the reference results, we might need to # update svn. Remove reference results from SVN. if UpdateSVN == True: assert(IsReferenceBuild == True); updateSVN("delete", PMapFile); - + # Test the projects. - PMapFile.seek(0) + PMapFile.seek(0) for I in csv.reader(PMapFile): testProject(I[0], int(I[1]), IsReferenceBuild, None, Strictness) @@ -567,10 +668,10 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0): except: print "Error occurred. Premature termination." - raise + raise finally: - PMapFile.close() - + PMapFile.close() + if __name__ == '__main__': # Parse command line arguments. Parser = argparse.ArgumentParser(description='Test the Clang Static Analyzer.') diff --git a/utils/analyzer/SumTimerInfo.py b/utils/analyzer/SumTimerInfo.py index 4ef1ceb4cec5..0c3585bbc279 100644 --- a/utils/analyzer/SumTimerInfo.py +++ b/utils/analyzer/SumTimerInfo.py @@ -3,7 +3,7 @@ """ Script to Summarize statistics in the scan-build output. -Statistics are enabled by passing '-internal-stats' option to scan-build +Statistics are enabled by passing '-internal-stats' option to scan-build (or '-analyzer-stats' to the analyzer). """ @@ -69,7 +69,7 @@ if __name__ == '__main__': if ((") Total" in line) and (Mode == 1)) : s = line.split() TotalTime = TotalTime + float(s[6]) - + print "TU Count %d" % (Count) print "Time %f" % (Time) print "Warnings %d" % (Warnings) @@ -81,4 +81,3 @@ if __name__ == '__main__': print "MaxTime %f" % (MaxTime) print "TotalTime %f" % (TotalTime) print "Max CFG Size %d" % (MaxCFGSize) -
\ No newline at end of file diff --git a/utils/analyzer/ubiviz b/utils/analyzer/ubiviz index 1582797c63f9..9d821c3c10a0 100755 --- a/utils/analyzer/ubiviz +++ b/utils/analyzer/ubiviz @@ -18,7 +18,7 @@ import sys def Error(message): print >> sys.stderr, 'ubiviz: ' + message sys.exit(1) - + def StreamData(filename): file = open(filename) for ln in file: @@ -55,20 +55,19 @@ def Display(G, data): def main(args): if len(args) == 0: - Error('no input files') + Error('no input files') server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2') G = server.ubigraph - + for arg in args: G.clear() for x in StreamData(arg): Display(G,x) - + sys.exit(0) - + if __name__ == '__main__': main(sys.argv[1:]) - -
\ No newline at end of file + diff --git a/utils/clang.natvis b/utils/clang.natvis index 107af502f7d0..a0004e9b0163 100644 --- a/utils/clang.natvis +++ b/utils/clang.natvis @@ -6,6 +6,14 @@ Put this file into "%USERPROFILE%\Documents\Visual Studio 2012\Visualizers" or create a symbolic link so it updates automatically.
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+ <Type Name="clang::Type">
+ <DisplayString Condition="(clang::Type::TypeClass)TypeBits.TC == clang::Type::Builtin">Builtin Type={(clang::BuiltinType::Kind)BuiltinTypeBits.Kind}</DisplayString>
+ <DisplayString Condition="(clang::Type::TypeClass)TypeBits.TC == clang::Type::Attributed">Modified Type={((clang::AttributedType*)this)->ModifiedType} Attribute={(clang::AttributedType::Kind)AttributedTypeBits.AttrKind}</DisplayString>
+ <DisplayString>Type Class={(clang::Type::TypeClass)TypeBits.TC}</DisplayString>
+ </Type>
+ <Type Name="clang::QualType">
+ <DisplayString>{((clang::ExtQualsTypeCommonBase *)(((uintptr_t)Value.Value) & ~(uintptr_t)((1 << clang::TypeAlignmentInBits) - 1)))->BaseType}</DisplayString>
+ </Type>
<Type Name="clang::IdentifierInfo">
<DisplayString Condition="Entry != 0">({((llvm::StringMapEntry<clang::IdentifierInfo *>*)Entry)+1,s})</DisplayString>
<Expand>
@@ -24,13 +32,14 @@ or create a symbolic link so it updates automatically. <Item Condition="(Ptr & PtrMask) == StoredObjCZeroArgSelector" Name="[ObjC Zero Arg Selector]">*(clang::IdentifierInfo *)(Ptr & ~PtrMask)</Item>
<Item Condition="(Ptr & PtrMask) == StoredObjCOneArgSelector" Name="[ObjC One Arg Selector]">*(clang::IdentifierInfo *)(Ptr & ~PtrMask)</Item>
<Item Condition="(Ptr & PtrMask) == StoredDeclarationNameExtra" Name="[Extra]">(clang::DeclarationNameExtra::ExtraKind)((clang::DeclarationNameExtra *)(Ptr & ~PtrMask))->ExtraKindOrNumArgs</Item>
- </Expand>
- </Type>
- <Type Name="clang::Token">
- <DisplayString>{(clang::tok::TokenKind)Kind}</DisplayString>
- </Type>
- <Type Name="clang::DeclSpec">
- <DisplayString>[{(clang::DeclSpec::SCS)StorageClassSpec}], [{(clang::TypeSpecifierType)TypeSpecType}]</DisplayString>
+ </Expand> + </Type> + <Type Name="clang::Token"> + <DisplayString Condition="Kind != clang::tok::identifier">{(clang::tok::TokenKind)Kind}</DisplayString> + <DisplayString Condition="Kind == clang::tok::identifier">{{Identifier ({*(clang::IdentifierInfo *)(PtrData)})}}</DisplayString> + </Type> + <Type Name="clang::DeclSpec"> + <DisplayString>[{(clang::DeclSpec::SCS)StorageClassSpec}], [{(clang::TypeSpecifierType)TypeSpecType}]</DisplayString> </Type>
<Type Name="clang::PragmaHandler">
<DisplayString>{Name,s}</DisplayString>
diff --git a/utils/perf-training/CMakeLists.txt b/utils/perf-training/CMakeLists.txt new file mode 100644 index 000000000000..ccedcf5d5163 --- /dev/null +++ b/utils/perf-training/CMakeLists.txt @@ -0,0 +1,36 @@ +if(LLVM_BUILD_INSTRUMENTED) + if (CMAKE_CFG_INTDIR STREQUAL ".") + set(LLVM_BUILD_MODE ".") + else () + set(LLVM_BUILD_MODE "%(build_mode)s") + endif () + + string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} CLANG_TOOLS_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) + + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + ) + + add_lit_testsuite(generate-profraw "Generating clang PGO data" + ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS clang clear-profraw + ) + + add_custom_target(clear-profraw + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py clean ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Clearing old profraw data") + + if(NOT LLVM_PROFDATA) + find_program(LLVM_PROFDATA llvm-profdata) + endif() + + if(NOT LLVM_PROFDATA) + message(FATAL_ERROR "Must set LLVM_PROFDATA to point to llvm-profdata to use for merging PGO data") + endif() + + add_custom_target(generate-profdata + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py merge ${LLVM_PROFDATA} ${CMAKE_CURRENT_BINARY_DIR}/clang.profdata ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Merging profdata" + DEPENDS generate-profraw) +endif() diff --git a/utils/perf-training/README.txt b/utils/perf-training/README.txt new file mode 100644 index 000000000000..cfbce40ca3ef --- /dev/null +++ b/utils/perf-training/README.txt @@ -0,0 +1,6 @@ +========================== + Performance Training Data +========================== + +This directory contains simple source files for use as training data for +generating PGO data and linker order files for clang. diff --git a/utils/perf-training/cxx/hello_world.cpp b/utils/perf-training/cxx/hello_world.cpp new file mode 100644 index 000000000000..66e00d00d261 --- /dev/null +++ b/utils/perf-training/cxx/hello_world.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cpp -c %s +#include <iostream> + +int main(int, char**) { + std::cout << "Hello, World!"; + return 0; +} diff --git a/utils/perf-training/lit.cfg b/utils/perf-training/lit.cfg new file mode 100644 index 000000000000..af4b43b78b09 --- /dev/null +++ b/utils/perf-training/lit.cfg @@ -0,0 +1,37 @@ +# -*- Python -*- + +from lit import Test +import lit.formats +import lit.util + +def getSysrootFlagsOnDarwin(config, lit_config): + # On Darwin, support relocatable SDKs by providing Clang with a + # default system root path. + if 'darwin' in config.target_triple: + try: + out = lit.util.capture(['xcrun', '--show-sdk-path']).strip() + res = 0 + except OSError: + res = -1 + if res == 0 and out: + sdk_path = out + lit_config.note('using SDKROOT: %r' % sdk_path) + return '-isysroot %s' % sdk_path + return '' + +sysroot_flags = getSysrootFlagsOnDarwin(config, lit_config) + +config.clang = lit.util.which('clang', config.clang_tools_dir).replace('\\', '/') + +config.name = 'Clang Perf Training' +config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap'] + +use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") +config.test_format = lit.formats.ShTest(use_lit_shell == "0") +config.substitutions.append( ('%clang_cpp', ' %s --driver-mode=cpp %s ' % (config.clang, sysroot_flags))) +config.substitutions.append( ('%clang_cc1', ' %s -cc1 %s ' % (config.clang, sysroot_flags))) +config.substitutions.append( ('%clang', ' %s %s ' % (config.clang, sysroot_flags) ) ) +config.substitutions.append( ('%test_root', config.test_exec_root ) ) + +config.environment['LLVM_PROFILE_FILE'] = 'perf-training-%p.profraw' + diff --git a/utils/perf-training/lit.site.cfg.in b/utils/perf-training/lit.site.cfg.in new file mode 100644 index 000000000000..9dc380242e52 --- /dev/null +++ b/utils/perf-training/lit.site.cfg.in @@ -0,0 +1,20 @@ +import sys + +## Autogenerated by LLVM/Clang configuration. +# Do not edit! +config.clang_tools_dir = "@CLANG_TOOLS_DIR@" +config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" +config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" +config.target_triple = "@TARGET_TRIPLE@" + +# Support substitution of the tools and libs dirs with user parameters. This is +# used when we can't determine the tool dir at configuration time. +try: + config.clang_tools_dir = config.clang_tools_dir % lit_config.params +except KeyError: + e = sys.exc_info()[1] + key, = e.args + lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key)) + +# Let the main config do the real work. +lit_config.load_config(config, "@CLANG_SOURCE_DIR@/utils/perf-training/lit.cfg") diff --git a/utils/perf-training/perf-helper.py b/utils/perf-training/perf-helper.py new file mode 100644 index 000000000000..448801133e0a --- /dev/null +++ b/utils/perf-training/perf-helper.py @@ -0,0 +1,46 @@ +#===- perf-helper.py - Clang Python Bindings -----------------*- python -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +import sys +import os +import subprocess + +def findProfrawFiles(path): + profraw_files = [] + for root, dirs, files in os.walk(path): + for filename in files: + if filename.endswith(".profraw"): + profraw_files.append(os.path.join(root, filename)) + return profraw_files + +def clean(args): + if len(args) != 1: + print 'Usage: %s clean <path>\n\tRemoves all *.profraw files from <path>.' % __file__ + return 1 + for profraw in findProfrawFiles(args[0]): + os.remove(profraw) + return 0 + +def merge(args): + if len(args) != 3: + print 'Usage: %s clean <llvm-profdata> <output> <path>\n\tMerges all profraw files from path into output.' % __file__ + return 1 + cmd = [args[0], 'merge', '-o', args[1]] + cmd.extend(findProfrawFiles(args[2])) + subprocess.check_call(cmd) + return 0 + +commands = {'clean' : clean, 'merge' : merge} + +def main(): + f = commands[sys.argv[1]] + sys.exit(f(sys.argv[2:])) + +if __name__ == '__main__': + main() |
