aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:49:41 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:49:41 +0000
commit45b533945f0851ec234ca846e1af5ee1e4df0b6e (patch)
tree0a5b74c0b9ca73aded34df95c91fcaf3815230d8 /utils
parent7e86edd64bfae4e324224452e4ea879b3371a4bd (diff)
Notes
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp348
-rw-r--r--utils/TableGen/ClangCommentCommandInfoEmitter.cpp3
-rw-r--r--utils/TableGen/NeonEmitter.cpp83
-rwxr-xr-xutils/analyzer/CmpRuns.py50
-rw-r--r--utils/analyzer/SATestAdd.py54
-rw-r--r--utils/analyzer/SATestBuild.py347
-rw-r--r--utils/analyzer/SumTimerInfo.py5
-rwxr-xr-xutils/analyzer/ubiviz13
-rw-r--r--utils/clang.natvis23
-rw-r--r--utils/perf-training/CMakeLists.txt36
-rw-r--r--utils/perf-training/README.txt6
-rw-r--r--utils/perf-training/cxx/hello_world.cpp7
-rw-r--r--utils/perf-training/lit.cfg37
-rw-r--r--utils/perf-training/lit.site.cfg.in20
-rw-r--r--utils/perf-training/perf-helper.py46
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) &amp; ~(uintptr_t)((1 &lt;&lt; clang::TypeAlignmentInBits) - 1)))-&gt;BaseType}</DisplayString>
+ </Type>
<Type Name="clang::IdentifierInfo">
<DisplayString Condition="Entry != 0">({((llvm::StringMapEntry&lt;clang::IdentifierInfo *&gt;*)Entry)+1,s})</DisplayString>
<Expand>
@@ -24,13 +32,14 @@ or create a symbolic link so it updates automatically.
<Item Condition="(Ptr &amp; PtrMask) == StoredObjCZeroArgSelector" Name="[ObjC Zero Arg Selector]">*(clang::IdentifierInfo *)(Ptr &amp; ~PtrMask)</Item>
<Item Condition="(Ptr &amp; PtrMask) == StoredObjCOneArgSelector" Name="[ObjC One Arg Selector]">*(clang::IdentifierInfo *)(Ptr &amp; ~PtrMask)</Item>
<Item Condition="(Ptr &amp; PtrMask) == StoredDeclarationNameExtra" Name="[Extra]">(clang::DeclarationNameExtra::ExtraKind)((clang::DeclarationNameExtra *)(Ptr &amp; ~PtrMask))-&gt;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()