diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2012-04-14 14:01:31 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2012-04-14 14:01:31 +0000 |
| commit | dbe13110f59f48b4dbb7552b3ac2935acdeece7f (patch) | |
| tree | be1815eb79b42ff482a8562b13c2dcbf0c5dcbee /utils | |
| parent | 9da628931ebf2609493570f87824ca22402cc65f (diff) | |
Notes
Diffstat (limited to 'utils')
| -rw-r--r-- | utils/C++Tests/LLVM-Code-Compile/lit.local.cfg | 8 | ||||
| -rw-r--r-- | utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg | 8 | ||||
| -rw-r--r-- | utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg | 8 | ||||
| -rwxr-xr-x | utils/FuzzTest | 18 | ||||
| -rw-r--r-- | utils/TableGen/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | utils/TableGen/ClangAttrEmitter.cpp | 318 | ||||
| -rw-r--r-- | utils/TableGen/ClangAttrEmitter.h | 39 | ||||
| -rw-r--r-- | utils/TableGen/ClangDiagnosticsEmitter.cpp | 113 | ||||
| -rw-r--r-- | utils/TableGen/NeonEmitter.cpp | 91 | ||||
| -rw-r--r-- | utils/TableGen/NeonEmitter.h | 34 | ||||
| -rw-r--r-- | utils/TableGen/TableGen.cpp | 26 | ||||
| -rwxr-xr-x | utils/analyzer/CmpRuns.py | 33 | ||||
| -rw-r--r-- | utils/analyzer/SATestAdd.py | 41 | ||||
| -rw-r--r-- | utils/analyzer/SATestBuild.py | 262 | ||||
| -rw-r--r-- | utils/clangVisualizers.txt | 92 | ||||
| -rw-r--r-- | utils/find-unused-diagnostics.sh | 19 |
16 files changed, 908 insertions, 203 deletions
diff --git a/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg b/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg index 6676e311e3ec..c1ac6a9a1f59 100644 --- a/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg +++ b/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg @@ -16,10 +16,7 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-Wno-sign-compare', '-I%s/include' % root.llvm_src_root, '-I%s/include' % root.llvm_obj_root, - '-I%s/lib/Target/Alpha' % root.llvm_src_root, '-I%s/lib/Target/ARM' % root.llvm_src_root, - '-I%s/lib/Target/Blackfin' % root.llvm_src_root, - '-I%s/lib/Target/CBackend' % root.llvm_src_root, '-I%s/lib/Target/CellSPU' % root.llvm_src_root, '-I%s/lib/Target/CppBackend' % root.llvm_src_root, '-I%s/lib/Target/Mips' % root.llvm_src_root, @@ -28,13 +25,9 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-I%s/lib/Target/PIC16' % root.llvm_src_root, '-I%s/lib/Target/PowerPC' % root.llvm_src_root, '-I%s/lib/Target/Sparc' % root.llvm_src_root, - '-I%s/lib/Target/SystemZ' % root.llvm_src_root, '-I%s/lib/Target/X86' % root.llvm_src_root, '-I%s/lib/Target/XCore' % root.llvm_src_root, - '-I%s/lib/Target/Alpha' % target_obj_root, '-I%s/lib/Target/ARM' % target_obj_root, - '-I%s/lib/Target/Blackfin' % target_obj_root, - '-I%s/lib/Target/CBackend' % target_obj_root, '-I%s/lib/Target/CellSPU' % target_obj_root, '-I%s/lib/Target/CppBackend' % target_obj_root, '-I%s/lib/Target/Mips' % target_obj_root, @@ -43,7 +36,6 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-I%s/lib/Target/PIC16' % target_obj_root, '-I%s/lib/Target/PowerPC' % target_obj_root, '-I%s/lib/Target/Sparc' % target_obj_root, - '-I%s/lib/Target/SystemZ' % target_obj_root, '-I%s/lib/Target/X86' % target_obj_root, '-I%s/lib/Target/XCore' % target_obj_root]; diff --git a/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg b/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg index c328a25127d9..7882813d79c6 100644 --- a/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg +++ b/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg @@ -16,10 +16,7 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-Wno-sign-compare', '-I%s/include' % root.llvm_src_root, '-I%s/include' % root.llvm_obj_root, - '-I%s/lib/Target/Alpha' % root.llvm_src_root, '-I%s/lib/Target/ARM' % root.llvm_src_root, - '-I%s/lib/Target/Blackfin' % root.llvm_src_root, - '-I%s/lib/Target/CBackend' % root.llvm_src_root, '-I%s/lib/Target/CellSPU' % root.llvm_src_root, '-I%s/lib/Target/CppBackend' % root.llvm_src_root, '-I%s/lib/Target/Mips' % root.llvm_src_root, @@ -28,13 +25,9 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-I%s/lib/Target/PIC16' % root.llvm_src_root, '-I%s/lib/Target/PowerPC' % root.llvm_src_root, '-I%s/lib/Target/Sparc' % root.llvm_src_root, - '-I%s/lib/Target/SystemZ' % root.llvm_src_root, '-I%s/lib/Target/X86' % root.llvm_src_root, '-I%s/lib/Target/XCore' % root.llvm_src_root, - '-I%s/lib/Target/Alpha' % target_obj_root, '-I%s/lib/Target/ARM' % target_obj_root, - '-I%s/lib/Target/Blackfin' % target_obj_root, - '-I%s/lib/Target/CBackend' % target_obj_root, '-I%s/lib/Target/CellSPU' % target_obj_root, '-I%s/lib/Target/CppBackend' % target_obj_root, '-I%s/lib/Target/Mips' % target_obj_root, @@ -43,7 +36,6 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-I%s/lib/Target/PIC16' % target_obj_root, '-I%s/lib/Target/PowerPC' % target_obj_root, '-I%s/lib/Target/Sparc' % target_obj_root, - '-I%s/lib/Target/SystemZ' % target_obj_root, '-I%s/lib/Target/X86' % target_obj_root, '-I%s/lib/Target/XCore' % target_obj_root]; diff --git a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg index 6e679659c44c..42bec2d767a8 100644 --- a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg +++ b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg @@ -15,10 +15,7 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-D__STDC_CONSTANT_MACROS', '-I%s/include' % root.llvm_src_root, '-I%s/include' % root.llvm_obj_root, - '-I%s/lib/Target/Alpha' % root.llvm_src_root, '-I%s/lib/Target/ARM' % root.llvm_src_root, - '-I%s/lib/Target/Blackfin' % root.llvm_src_root, - '-I%s/lib/Target/CBackend' % root.llvm_src_root, '-I%s/lib/Target/CellSPU' % root.llvm_src_root, '-I%s/lib/Target/CppBackend' % root.llvm_src_root, '-I%s/lib/Target/Mips' % root.llvm_src_root, @@ -27,13 +24,9 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-I%s/lib/Target/PIC16' % root.llvm_src_root, '-I%s/lib/Target/PowerPC' % root.llvm_src_root, '-I%s/lib/Target/Sparc' % root.llvm_src_root, - '-I%s/lib/Target/SystemZ' % root.llvm_src_root, '-I%s/lib/Target/X86' % root.llvm_src_root, '-I%s/lib/Target/XCore' % root.llvm_src_root, - '-I%s/lib/Target/Alpha' % target_obj_root, '-I%s/lib/Target/ARM' % target_obj_root, - '-I%s/lib/Target/Blackfin' % target_obj_root, - '-I%s/lib/Target/CBackend' % target_obj_root, '-I%s/lib/Target/CellSPU' % target_obj_root, '-I%s/lib/Target/CppBackend' % target_obj_root, '-I%s/lib/Target/Mips' % target_obj_root, @@ -42,7 +35,6 @@ cxxflags = ['-D__STDC_LIMIT_MACROS', '-I%s/lib/Target/PIC16' % target_obj_root, '-I%s/lib/Target/PowerPC' % target_obj_root, '-I%s/lib/Target/Sparc' % target_obj_root, - '-I%s/lib/Target/SystemZ' % target_obj_root, '-I%s/lib/Target/X86' % target_obj_root, '-I%s/lib/Target/XCore' % target_obj_root]; diff --git a/utils/FuzzTest b/utils/FuzzTest index 2aa5989a80d4..0e043df7cf08 100755 --- a/utils/FuzzTest +++ b/utils/FuzzTest @@ -156,6 +156,7 @@ def run_one_test(test_application, index, input_files, args): print 'FAIL: %d' % index elif not opts.succinct: print 'PASS: %d' % index + return test_result def main(): global opts @@ -182,7 +183,7 @@ test and then leave the fuzzed inputs in place to examine the failure. For each fuzzed input, %prog will run the test command given on the command line. Each argument in the command is subject to string interpolation before being executed. The syntax is "%(VARIABLE)FORMAT" where FORMAT is a standard -printf format, and VARIBLE is one of: +printf format, and VARIABLE is one of: 'index' - the test index being run 'inputs' - the full list of test inputs @@ -194,6 +195,10 @@ printf format, and VARIBLE is one of: By default, the script will run forever continually picking new tests to run. You can limit the number of tests that are run with '--max-tests <number>', and you can run a particular test with '--test <index>'. + +You can specify '--stop-on-fail' to stop the script on the first failure +without reverting the changes. + """) parser.add_option("-v", "--verbose", help="Show more output", action='store_true', dest="verbose", default=False) @@ -223,7 +228,7 @@ and you can run a particular test with '--test <index>'. type=str, action="append", dest="input_files", default=[]) group.add_option("", "--filelist", metavar="LIST", help="Add a list of inputs files to fuzz (one per line)", - type=int, action="append", dest="filelists", default=[]) + type=str, action="append", dest="filelists", default=[]) parser.add_option_group(group) group = OptionGroup(parser, "Fuzz Options") @@ -244,13 +249,15 @@ and you can run a particular test with '--test <index>'. action='store_false', dest="enable_replace", default=True) group.add_option("", "--no-revert", help="Don't revert changes", action='store_false', dest="revert", default=True) + group.add_option("", "--stop-on-fail", help="Stop on first failure", + action='store_true', dest="stop_on_fail", default=False) parser.add_option_group(group) group = OptionGroup(parser, "Test Selection") group.add_option("", "--test", help="Run a particular test", type=int, dest="test", default=None, metavar="INDEX") group.add_option("", "--max-tests", help="Maximum number of tests", - type=int, dest="max_tests", default=10, metavar="COUNT") + type=int, dest="max_tests", default=None, metavar="COUNT") group.add_option("", "--pick-input", help="Randomly select an input byte as well as fuzzing", action='store_true', dest="pick_input", default=False) @@ -329,7 +336,10 @@ and you can run a particular test with '--test <index>'. ta = TestApplication(tg, t) try: ta.apply() - run_one_test(ta, test, input_files, args) + test_result = run_one_test(ta, test, input_files, args) + if not test_result and opts.stop_on_fail: + opts.revert = False + sys.exit(1) finally: if opts.revert: ta.revert() diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index 75a616700405..0d879214d4a2 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_REQUIRES_EH 1) set(LLVM_REQUIRES_RTTI 1) +set(LLVM_LINK_COMPONENTS Support) add_tablegen(clang-tblgen CLANG ClangASTNodesEmitter.cpp diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 5c236be559f1..7951fc467d20 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -16,6 +16,7 @@ #include "llvm/TableGen/Record.h" #include <algorithm> #include <cctype> +#include <set> using namespace llvm; @@ -33,8 +34,6 @@ getValueAsListOfStrings(Record &R, StringRef FieldName) { assert(*i && "Got a null element in a ListInit"); if (StringInit *S = dynamic_cast<StringInit *>(*i)) Strings.push_back(S->getValue()); - else if (CodeInit *C = dynamic_cast<CodeInit *>(*i)) - Strings.push_back(C->getValue()); else assert(false && "Got a non-string, non-code element in a ListInit"); } @@ -67,6 +66,30 @@ static std::string WritePCHRecord(StringRef type, StringRef name) { .Default("Record.push_back(" + std::string(name) + ");\n"); } +// Normalize attribute name by removing leading and trailing +// underscores. For example, __foo, foo__, __foo__ would +// become foo. +static StringRef NormalizeAttrName(StringRef AttrName) { + if (AttrName.startswith("__")) + AttrName = AttrName.substr(2, AttrName.size()); + + if (AttrName.endswith("__")) + AttrName = AttrName.substr(0, AttrName.size() - 2); + + return AttrName; +} + +// Normalize attribute spelling only if the spelling has both leading +// and trailing underscores. For example, __ms_struct__ will be +// normalized to "ms_struct"; __cdecl will remain intact. +static StringRef NormalizeAttrSpelling(StringRef AttrSpelling) { + if (AttrSpelling.startswith("__") && AttrSpelling.endswith("__")) { + AttrSpelling = AttrSpelling.substr(2, AttrSpelling.size() - 4); + } + + return AttrSpelling; +} + namespace { class Argument { std::string lowerName, upperName; @@ -91,6 +114,8 @@ namespace { virtual void writeAccessors(raw_ostream &OS) const = 0; virtual void writeAccessorDefinitions(raw_ostream &OS) const {} virtual void writeCloneArgs(raw_ostream &OS) const = 0; + virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0; + virtual void writeTemplateInstantiation(raw_ostream &OS) const {} virtual void writeCtorBody(raw_ostream &OS) const {} virtual void writeCtorInitializers(raw_ostream &OS) const = 0; virtual void writeCtorParameters(raw_ostream &OS) const = 0; @@ -98,6 +123,7 @@ namespace { virtual void writePCHReadArgs(raw_ostream &OS) const = 0; virtual void writePCHReadDecls(raw_ostream &OS) const = 0; virtual void writePCHWrite(raw_ostream &OS) const = 0; + virtual void writeValue(raw_ostream &OS) const = 0; }; class SimpleArgument : public Argument { @@ -108,6 +134,8 @@ namespace { : Argument(Arg, Attr), type(T) {} + std::string getType() const { return type; } + void writeAccessors(raw_ostream &OS) const { OS << " " << type << " get" << getUpperName() << "() const {\n"; OS << " return " << getLowerName() << ";\n"; @@ -116,6 +144,9 @@ namespace { void writeCloneArgs(raw_ostream &OS) const { OS << getLowerName(); } + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->get" << getUpperName() << "()"; + } void writeCtorInitializers(raw_ostream &OS) const { OS << getLowerName() << "(" << getUpperName() << ")"; } @@ -136,6 +167,19 @@ namespace { OS << " " << WritePCHRecord(type, "SA->get" + std::string(getUpperName()) + "()"); } + void writeValue(raw_ostream &OS) const { + if (type == "FunctionDecl *") { + OS << "\" << get" << getUpperName() << "()->getNameInfo().getAsString() << \""; + } else if (type == "IdentifierInfo *") { + OS << "\" << get" << getUpperName() << "()->getName() << \""; + } else if (type == "QualType") { + OS << "\" << get" << getUpperName() << "().getAsString() << \""; + } else if (type == "SourceLocation") { + OS << "\" << get" << getUpperName() << "().getRawEncoding() << \""; + } else { + OS << "\" << get" << getUpperName() << "() << \""; + } + } }; class StringArgument : public Argument { @@ -164,6 +208,9 @@ namespace { void writeCloneArgs(raw_ostream &OS) const { OS << "get" << getUpperName() << "()"; } + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->get" << getUpperName() << "()"; + } void writeCtorBody(raw_ostream &OS) const { OS << " std::memcpy(" << getLowerName() << ", " << getUpperName() << ".data(), " << getLowerName() << "Length);"; @@ -190,6 +237,9 @@ namespace { void writePCHWrite(raw_ostream &OS) const { OS << " AddString(SA->get" << getUpperName() << "(), Record);\n"; } + void writeValue(raw_ostream &OS) const { + OS << "\\\"\" << get" << getUpperName() << "() << \"\\\""; + } }; class AlignedArgument : public Argument { @@ -251,6 +301,10 @@ namespace { << "Expr) : " << getLowerName() << "Type"; } + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + // FIXME: move the definition in Sema::InstantiateAttrs to here. + // In the meantime, aligned attributes are cloned. + } void writeCtorBody(raw_ostream &OS) const { OS << " if (is" << getLowerName() << "Expr)\n"; OS << " " << getLowerName() << "Expr = reinterpret_cast<Expr *>(" @@ -293,6 +347,9 @@ namespace { OS << " AddTypeSourceInfo(SA->get" << getUpperName() << "Type(), Record);\n"; } + void writeValue(raw_ostream &OS) const { + OS << "\" << get" << getUpperName() << "(Ctx) << \""; + } }; class VariadicArgument : public Argument { @@ -317,12 +374,17 @@ namespace { << "Size;\n"; OS << " }\n"; OS << " unsigned " << getLowerName() << "_size() const {\n" - << " return " << getLowerName() << "Size;\n;"; + << " return " << getLowerName() << "Size;\n"; OS << " }"; } void writeCloneArgs(raw_ostream &OS) const { OS << getLowerName() << ", " << getLowerName() << "Size"; } + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + // This isn't elegant, but we have to go through public methods... + OS << "A->" << getLowerName() << "_begin(), " + << "A->" << getLowerName() << "_size()"; + } void writeCtorBody(raw_ostream &OS) const { // FIXME: memcpy is not safe on non-trivial types. OS << " std::memcpy(" << getLowerName() << ", " << getUpperName() @@ -362,6 +424,18 @@ namespace { << getLowerName() << "_end(); i != e; ++i)\n"; OS << " " << WritePCHRecord(type, "(*i)"); } + void writeValue(raw_ostream &OS) const { + OS << "\";\n"; + OS << " bool isFirst = true;\n" + << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator i = " << getLowerName() << "_begin(), e = " + << getLowerName() << "_end(); i != e; ++i) {\n" + << " if (isFirst) isFirst = false;\n" + << " else OS << \", \";\n" + << " OS << *i;\n" + << " }\n"; + OS << " OS << \""; + } }; class EnumArgument : public Argument { @@ -382,6 +456,9 @@ namespace { void writeCloneArgs(raw_ostream &OS) const { OS << getLowerName(); } + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->get" << getUpperName() << "()"; + } void writeCtorInitializers(raw_ostream &OS) const { OS << getLowerName() << "(" << getUpperName() << ")"; } @@ -422,6 +499,9 @@ namespace { void writePCHWrite(raw_ostream &OS) const { OS << "Record.push_back(SA->get" << getUpperName() << "());\n"; } + void writeValue(raw_ostream &OS) const { + OS << "\" << get" << getUpperName() << "() << \""; + } }; class VersionArgument : public Argument { @@ -442,6 +522,9 @@ namespace { void writeCloneArgs(raw_ostream &OS) const { OS << "get" << getUpperName() << "()"; } + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->get" << getUpperName() << "()"; + } void writeCtorBody(raw_ostream &OS) const { } void writeCtorInitializers(raw_ostream &OS) const { @@ -463,6 +546,64 @@ namespace { void writePCHWrite(raw_ostream &OS) const { OS << " AddVersionTuple(SA->get" << getUpperName() << "(), Record);\n"; } + void writeValue(raw_ostream &OS) const { + OS << getLowerName() << "=\" << get" << getUpperName() << "() << \""; + } + }; + + class ExprArgument : public SimpleArgument { + public: + ExprArgument(Record &Arg, StringRef Attr) + : SimpleArgument(Arg, Attr, "Expr *") + {} + + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "tempInst" << getUpperName(); + } + + void writeTemplateInstantiation(raw_ostream &OS) const { + OS << " " << getType() << " tempInst" << getUpperName() << ";\n"; + OS << " {\n"; + OS << " EnterExpressionEvaluationContext " + << "Unevaluated(S, Sema::Unevaluated);\n"; + OS << " ExprResult " << "Result = S.SubstExpr(" + << "A->get" << getUpperName() << "(), TemplateArgs);\n"; + OS << " tempInst" << getUpperName() << " = " + << "Result.takeAs<Expr>();\n"; + OS << " }\n"; + } + }; + + class VariadicExprArgument : public VariadicArgument { + public: + VariadicExprArgument(Record &Arg, StringRef Attr) + : VariadicArgument(Arg, Attr, "Expr *") + {} + + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "tempInst" << getUpperName() << ", " + << "A->" << getLowerName() << "_size()"; + } + + void writeTemplateInstantiation(raw_ostream &OS) const { + OS << " " << getType() << " *tempInst" << getUpperName() + << " = new (C, 16) " << getType() + << "[A->" << getLowerName() << "_size()];\n"; + OS << " {\n"; + OS << " EnterExpressionEvaluationContext " + << "Unevaluated(S, Sema::Unevaluated);\n"; + OS << " " << getType() << " *TI = tempInst" << getUpperName() + << ";\n"; + OS << " " << getType() << " *I = A->" << getLowerName() + << "_begin();\n"; + OS << " " << getType() << " *E = A->" << getLowerName() + << "_end();\n"; + OS << " for (; I != E; ++I, ++TI) {\n"; + OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n"; + OS << " *TI = Result.takeAs<Expr>();\n"; + OS << " }\n"; + OS << " }\n"; + } }; } @@ -476,8 +617,7 @@ static Argument *createArgument(Record &Arg, StringRef Attr, if (ArgName == "AlignedArgument") Ptr = new AlignedArgument(Arg, Attr); else if (ArgName == "EnumArgument") Ptr = new EnumArgument(Arg, Attr); - else if (ArgName == "ExprArgument") Ptr = new SimpleArgument(Arg, Attr, - "Expr *"); + else if (ArgName == "ExprArgument") Ptr = new ExprArgument(Arg, Attr); else if (ArgName == "FunctionArgument") Ptr = new SimpleArgument(Arg, Attr, "FunctionDecl *"); else if (ArgName == "IdentifierArgument") @@ -495,7 +635,7 @@ static Argument *createArgument(Record &Arg, StringRef Attr, else if (ArgName == "VariadicUnsignedArgument") Ptr = new VariadicArgument(Arg, Attr, "unsigned"); else if (ArgName == "VariadicExprArgument") - Ptr = new VariadicArgument(Arg, Attr, "Expr *"); + Ptr = new VariadicExprArgument(Arg, Attr); else if (ArgName == "VersionArgument") Ptr = new VersionArgument(Arg, Attr); @@ -511,6 +651,15 @@ static Argument *createArgument(Record &Arg, StringRef Attr, return Ptr; } +static void writeAvailabilityValue(raw_ostream &OS) { + OS << "\" << getPlatform()->getName();\n" + << " if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n" + << " if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n" + << " if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n" + << " if (getUnavailable()) OS << \", unavailable\";\n" + << " OS << \""; +} + void ClangAttrClassEmitter::run(raw_ostream &OS) { OS << "// This file is generated by TableGen. Do not edit.\n\n"; OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n"; @@ -571,19 +720,25 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) { OS << " }\n\n"; OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n"; + OS << " virtual void printPretty(llvm::raw_ostream &OS, ASTContext &Ctx) const;\n"; for (ai = Args.begin(); ai != ae; ++ai) { (*ai)->writeAccessors(OS); OS << "\n\n"; } - OS << R.getValueAsCode("AdditionalMembers"); + OS << R.getValueAsString("AdditionalMembers"); OS << "\n\n"; OS << " static bool classof(const Attr *A) { return A->getKind() == " << "attr::" << R.getName() << "; }\n"; OS << " static bool classof(const " << R.getName() << "Attr *) { return true; }\n"; + + bool LateParsed = R.getValueAsBit("LateParsed"); + OS << " virtual bool isLateParsed() const { return " + << LateParsed << "; }\n"; + OS << "};\n\n"; } @@ -600,6 +755,7 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) { for (; i != e; ++i) { Record &R = **i; std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); + std::vector<StringRef> Spellings = getValueAsListOfStrings(R, "Spellings"); std::vector<Argument*> Args; for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri) Args.push_back(createArgument(**ri, R.getName())); @@ -615,6 +771,24 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) { (*ai)->writeCloneArgs(OS); } OS << ");\n}\n\n"; + + OS << "void " << R.getName() << "Attr::printPretty(" + << "llvm::raw_ostream &OS, ASTContext &Ctx) const {\n"; + if (Spellings.begin() != Spellings.end()) { + OS << " OS << \" __attribute__((" << *Spellings.begin(); + if (Args.size()) OS << "("; + if (*Spellings.begin()=="availability") { + writeAvailabilityValue(OS); + } else { + for (ai = Args.begin(); ai != ae; ++ai) { + if (ai!=Args.begin()) OS <<", "; + (*ai)->writeValue(OS); + } + } + if (Args.size()) OS << ")"; + OS << "))\";\n"; + } + OS << "}\n\n"; } } @@ -786,3 +960,133 @@ void ClangAttrLateParsedListEmitter::run(raw_ostream &OS) { } } } + + +void ClangAttrTemplateInstantiateEmitter::run(raw_ostream &OS) { + OS << "// This file is generated by TableGen. Do not edit.\n\n"; + + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + + OS << "namespace clang {\n" + << "namespace sema {\n\n" + << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " + << "Sema &S,\n" + << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n" + << " switch (At->getKind()) {\n" + << " default:\n" + << " break;\n"; + + for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { + Record &R = **I; + + OS << " case attr::" << R.getName() << ": {\n"; + OS << " const " << R.getName() << "Attr *A = cast<" + << R.getName() << "Attr>(At);\n"; + bool TDependent = R.getValueAsBit("TemplateDependent"); + + if (!TDependent) { + OS << " return A->clone(C);\n"; + OS << " }\n"; + continue; + } + + std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); + std::vector<Argument*> Args; + std::vector<Argument*>::iterator ai, ae; + Args.reserve(ArgRecords.size()); + + for (std::vector<Record*>::iterator ri = ArgRecords.begin(), + re = ArgRecords.end(); + ri != re; ++ri) { + Record &ArgRecord = **ri; + Argument *Arg = createArgument(ArgRecord, R.getName()); + assert(Arg); + Args.push_back(Arg); + } + ae = Args.end(); + + for (ai = Args.begin(); ai != ae; ++ai) { + (*ai)->writeTemplateInstantiation(OS); + } + OS << " return new (C) " << R.getName() << "Attr(A->getLocation(), C"; + for (ai = Args.begin(); ai != ae; ++ai) { + OS << ", "; + (*ai)->writeTemplateInstantiationArgs(OS); + } + OS << ");\n }\n"; + } + OS << " } // end switch\n" + << " llvm_unreachable(\"Unknown attribute!\");\n" + << " return 0;\n" + << "}\n\n" + << "} // end namespace sema\n" + << "} // end namespace clang\n"; +} + +void ClangAttrParsedAttrListEmitter::run(raw_ostream &OS) { + OS << "// This file is generated by TableGen. Do not edit.\n\n"; + + OS << "#ifndef PARSED_ATTR\n"; + OS << "#define PARSED_ATTR(NAME) NAME\n"; + OS << "#endif\n\n"; + + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + std::set<StringRef> ProcessedAttrs; + + for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { + Record &Attr = **I; + + bool SemaHandler = Attr.getValueAsBit("SemaHandler"); + + if (SemaHandler) { + std::vector<StringRef> Spellings = + getValueAsListOfStrings(Attr, "Spellings"); + + for (std::vector<StringRef>::const_iterator I = Spellings.begin(), + E = Spellings.end(); I != E; ++I) { + StringRef AttrName = *I; + + AttrName = NormalizeAttrName(AttrName); + // skip if a normalized version has been processed. + if (ProcessedAttrs.find(AttrName) != ProcessedAttrs.end()) + continue; + else + ProcessedAttrs.insert(AttrName); + + OS << "PARSED_ATTR(" << AttrName << ")\n"; + } + } + } +} + +void ClangAttrParsedAttrKindsEmitter::run(raw_ostream &OS) { + OS << "// This file is generated by TableGen. Do not edit.\n\n"; + + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + + for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { + Record &Attr = **I; + + bool SemaHandler = Attr.getValueAsBit("SemaHandler"); + + if (SemaHandler) { + std::vector<StringRef> Spellings = + getValueAsListOfStrings(Attr, "Spellings"); + + for (std::vector<StringRef>::const_iterator I = Spellings.begin(), + E = Spellings.end(); I != E; ++I) { + StringRef AttrName = *I, Spelling = *I; + + AttrName = NormalizeAttrName(AttrName); + Spelling = NormalizeAttrSpelling(Spelling); + + OS << ".Case(\"" << Spelling << "\", " << "AT_" << AttrName << ")\n"; + } + } + } +} + + diff --git a/utils/TableGen/ClangAttrEmitter.h b/utils/TableGen/ClangAttrEmitter.h index 5acca560f013..d119a094c177 100644 --- a/utils/TableGen/ClangAttrEmitter.h +++ b/utils/TableGen/ClangAttrEmitter.h @@ -109,6 +109,45 @@ class ClangAttrLateParsedListEmitter : public TableGenBackend { void run(raw_ostream &OS); }; +/// ClangAttrTemplateInstantiateEmitter emits code to instantiate dependent +/// attributes on templates. +class ClangAttrTemplateInstantiateEmitter : public TableGenBackend { + RecordKeeper &Records; + + public: + explicit ClangAttrTemplateInstantiateEmitter(RecordKeeper &R) + : Records(R) + {} + + void run(raw_ostream &OS); +}; + +/// ClangAttrParsedAttrListEmitter emits the list of parsed attributes +/// for clang. +class ClangAttrParsedAttrListEmitter : public TableGenBackend { + RecordKeeper &Records; + +public: + explicit ClangAttrParsedAttrListEmitter(RecordKeeper &R) + : Records(R) + {} + + void run(raw_ostream &OS); +}; + +/// ClangAttrParsedAttrKindsEmitter emits the kind list of parsed attributes +/// for clang. +class ClangAttrParsedAttrKindsEmitter : public TableGenBackend { + RecordKeeper &Records; + +public: + explicit ClangAttrParsedAttrKindsEmitter(RecordKeeper &R) + : Records(R) + {} + + void run(raw_ostream &OS); +}; + } #endif diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp index da2fb70b4a57..8a49619c725e 100644 --- a/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -16,13 +16,12 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/Compiler.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/VectorExtras.h" #include <map> #include <algorithm> #include <functional> +#include <set> using namespace llvm; //===----------------------------------------------------------------------===// @@ -51,7 +50,6 @@ public: }; } // end anonymous namespace. - static std::string getCategoryFromDiagGroup(const Record *Group, DiagGroupParentMap &DiagGroupParents) { @@ -120,8 +118,44 @@ namespace { iterator begin() { return CategoryStrings.begin(); } iterator end() { return CategoryStrings.end(); } }; + + struct GroupInfo { + std::vector<const Record*> DiagsInGroup; + std::vector<std::string> SubGroups; + unsigned IDNo; + }; } // end anonymous namespace. +/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many +/// mapping of groups to diags in the group. +static void groupDiagnostics(const std::vector<Record*> &Diags, + const std::vector<Record*> &DiagGroups, + std::map<std::string, GroupInfo> &DiagsInGroup) { + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + const Record *R = Diags[i]; + DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")); + if (DI == 0) continue; + std::string GroupName = DI->getDef()->getValueAsString("GroupName"); + DiagsInGroup[GroupName].DiagsInGroup.push_back(R); + } + + // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty + // groups (these are warnings that GCC supports that clang never produces). + for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { + Record *Group = DiagGroups[i]; + GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; + + std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); + for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) + GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); + } + + // Assign unique ID numbers to the groups. + unsigned IDNo = 0; + for (std::map<std::string, GroupInfo>::iterator + I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) + I->second.IDNo = IDNo; +} //===----------------------------------------------------------------------===// // Warning Tables (.inc file) generation. @@ -130,7 +164,7 @@ namespace { void ClangDiagsDefsEmitter::run(raw_ostream &OS) { // Write the #if guard if (!Component.empty()) { - std::string ComponentName = UppercaseString(Component); + std::string ComponentName = StringRef(Component).upper(); OS << "#ifdef " << ComponentName << "START\n"; OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName << ",\n"; @@ -140,7 +174,13 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { const std::vector<Record*> &Diags = Records.getAllDerivedDefinitions("Diagnostic"); - + + std::vector<Record*> DiagGroups + = Records.getAllDerivedDefinitions("DiagGroup"); + + std::map<std::string, GroupInfo> DiagsInGroup; + groupDiagnostics(Diags, DiagGroups, DiagsInGroup); + DiagCategoryIDMap CategoryIDs(Records); DiagGroupParentMap DGParentMap(Records); @@ -158,12 +198,15 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { OS << ", \""; OS.write_escaped(R.getValueAsString("Text")) << '"'; - // Warning associated with the diagnostic. + // Warning associated with the diagnostic. This is stored as an index into + // the alphabetically sorted warning table. if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) { - OS << ", \""; - OS.write_escaped(DI->getDef()->getValueAsString("GroupName")) << '"'; + std::map<std::string, GroupInfo>::iterator I = + DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName")); + assert(I != DiagsInGroup.end()); + OS << ", " << I->second.IDNo; } else { - OS << ", \"\""; + OS << ", 0"; } // SFINAE bit @@ -196,14 +239,6 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { // Category number. OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); - - // Brief - OS << ", \""; - OS.write_escaped(R.getValueAsString("Brief")) << '"'; - - // Explanation - OS << ", \""; - OS.write_escaped(R.getValueAsString("Explanation")) << '"'; OS << ")\n"; } } @@ -215,56 +250,24 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { static std::string getDiagCategoryEnum(llvm::StringRef name) { if (name.empty()) return "DiagCat_None"; - llvm::SmallString<256> enumName = llvm::StringRef("DiagCat_"); + SmallString<256> enumName = llvm::StringRef("DiagCat_"); for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) enumName += isalnum(*I) ? *I : '_'; return enumName.str(); } -namespace { -struct GroupInfo { - std::vector<const Record*> DiagsInGroup; - std::vector<std::string> SubGroups; - unsigned IDNo; -}; -} // end anonymous namespace. - void ClangDiagGroupsEmitter::run(raw_ostream &OS) { // Compute a mapping from a DiagGroup to all of its parents. DiagGroupParentMap DGParentMap(Records); - // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of - // groups to diags in the group. - std::map<std::string, GroupInfo> DiagsInGroup; - std::vector<Record*> Diags = Records.getAllDerivedDefinitions("Diagnostic"); - for (unsigned i = 0, e = Diags.size(); i != e; ++i) { - const Record *R = Diags[i]; - DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")); - if (DI == 0) continue; - std::string GroupName = DI->getDef()->getValueAsString("GroupName"); - DiagsInGroup[GroupName].DiagsInGroup.push_back(R); - } - // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty - // groups (these are warnings that GCC supports that clang never produces). std::vector<Record*> DiagGroups = Records.getAllDerivedDefinitions("DiagGroup"); - for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { - Record *Group = DiagGroups[i]; - GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; - - std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); - for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) - GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); - } - - // Assign unique ID numbers to the groups. - unsigned IDNo = 0; - for (std::map<std::string, GroupInfo>::iterator - I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) - I->second.IDNo = IDNo; + + std::map<std::string, GroupInfo> DiagsInGroup; + groupDiagnostics(Diags, DiagGroups, DiagsInGroup); // Walk through the groups emitting an array for each diagnostic of the diags // that are mapped to. @@ -304,6 +307,10 @@ void ClangDiagGroupsEmitter::run(raw_ostream &OS) { OS << " { "; OS << I->first.size() << ", "; OS << "\""; + if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#$%^*-+=:?")!=std::string::npos) + throw "Invalid character in diagnostic group '" + I->first + "'"; OS.write_escaped(I->first) << "\"," << std::string(MaxLen-I->first.size()+1, ' '); diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp index 66845ccacb32..e6f2e53aa706 100644 --- a/utils/TableGen/NeonEmitter.cpp +++ b/utils/TableGen/NeonEmitter.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" #include <string> using namespace llvm; @@ -56,7 +57,6 @@ static void ParseTypes(Record *r, std::string &s, default: throw TGError(r->getLoc(), "Unexpected letter: " + std::string(data + len, 1)); - break; } TV.push_back(StringRef(data, len + 1)); data += len + 1; @@ -78,7 +78,6 @@ static char Widen(const char t) { return 'f'; default: throw "unhandled type in widen!"; } - return '\0'; } /// Narrow - Convert a type code into the next smaller type. short -> char, @@ -95,7 +94,6 @@ static char Narrow(const char t) { return 'h'; default: throw "unhandled type in narrow!"; } - return '\0'; } /// For a particular StringRef, return the base type code, and whether it has @@ -266,7 +264,6 @@ static std::string TypeString(const char mod, StringRef typestr) { break; default: throw "unhandled type!"; - break; } if (mod == '2') @@ -449,7 +446,6 @@ static std::string MangleName(const std::string &name, StringRef typestr, break; default: throw "unhandled type!"; - break; } if (ck == ClassB) s += "_v"; @@ -526,12 +522,6 @@ static std::string GenMacroLocals(const std::string &proto, StringRef typestr) { for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { // Do not create a temporary for an immediate argument. // That would defeat the whole point of using a macro! - // FIXME: For other (non-immediate) arguments that are used directly, a - // local temporary (or some other method) is still needed to get the - // correct type checking, even if that temporary is not used for anything. - // This is omitted for now because it turns out the the use of - // "__extension__" in the macro disables any warnings from the pointer - // assignment. if (MacroArgUsedDirectly(proto, i)) continue; generatedLocal = true; @@ -594,7 +584,6 @@ static unsigned GetNumElements(StringRef typestr, bool &quad) { case 'f': nElts = 2; break; default: throw "unhandled type!"; - break; } if (quad) nElts <<= 1; return nElts; @@ -826,14 +815,12 @@ static std::string GenOpString(OpKind op, const std::string &proto, } default: throw "unknown OpKind!"; - break; } return s; } static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { unsigned mod = proto[0]; - unsigned ret = 0; if (mod == 'v' || mod == 'f') mod = proto[1]; @@ -851,35 +838,31 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { // Based on the modifying character, change the type and width if necessary. type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); - if (usgn) - ret |= 0x08; - if (quad && proto[1] != 'g') - ret |= 0x10; - + NeonTypeFlags::EltType ET; switch (type) { case 'c': - ret |= poly ? 5 : 0; + ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8; break; case 's': - ret |= poly ? 6 : 1; + ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16; break; case 'i': - ret |= 2; + ET = NeonTypeFlags::Int32; break; case 'l': - ret |= 3; + ET = NeonTypeFlags::Int64; break; case 'h': - ret |= 7; + ET = NeonTypeFlags::Float16; break; case 'f': - ret |= 4; + ET = NeonTypeFlags::Float32; break; default: throw "unhandled type!"; - break; } - return ret; + NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g'); + return Flags.getFlags(); } // Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a) @@ -1249,10 +1232,7 @@ static unsigned RangeFromType(const char mod, StringRef typestr) { return (1 << (int)quad) - 1; default: throw "unhandled type!"; - break; } - assert(0 && "unreachable"); - return 0; } /// runHeader - Emit a file with sections defining: @@ -1346,14 +1326,57 @@ void NeonEmitter::runHeader(raw_ostream &OS) { mask |= 1 << GetNeonEnum(Proto, TypeVec[ti]); } } - if (mask) + + // Check if the builtin function has a pointer or const pointer argument. + int PtrArgNum = -1; + bool HasConstPtr = false; + for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) { + char ArgType = Proto[arg]; + if (ArgType == 'c') { + HasConstPtr = true; + PtrArgNum = arg - 1; + break; + } + if (ArgType == 'p') { + PtrArgNum = arg - 1; + break; + } + } + // For sret builtins, adjust the pointer argument index. + if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4')) + PtrArgNum += 1; + + // Omit type checking for the pointer arguments of vld1_lane, vld1_dup, + // and vst1_lane intrinsics. Using a pointer to the vector element + // type with one of those operations causes codegen to select an aligned + // load/store instruction. If you want an unaligned operation, + // the pointer argument needs to have less alignment than element type, + // so just accept any pointer type. + if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") { + PtrArgNum = -1; + HasConstPtr = false; + } + + if (mask) { OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[si], ClassB) - << ": mask = " << "0x" << utohexstr(mask) << "; break;\n"; - if (qmask) + << ": mask = " << "0x" << utohexstr(mask); + if (PtrArgNum >= 0) + OS << "; PtrArgNum = " << PtrArgNum; + if (HasConstPtr) + OS << "; HasConstPtr = true"; + OS << "; break;\n"; + } + if (qmask) { OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[qi], ClassB) - << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n"; + << ": mask = " << "0x" << utohexstr(qmask); + if (PtrArgNum >= 0) + OS << "; PtrArgNum = " << PtrArgNum; + if (HasConstPtr) + OS << "; HasConstPtr = true"; + OS << "; break;\n"; + } } OS << "#endif\n\n"; diff --git a/utils/TableGen/NeonEmitter.h b/utils/TableGen/NeonEmitter.h index 708ad3c06a0f..dec745111164 100644 --- a/utils/TableGen/NeonEmitter.h +++ b/utils/TableGen/NeonEmitter.h @@ -86,6 +86,40 @@ enum ClassKind { ClassB // bitcast arguments with enum argument to specify type }; +/// NeonTypeFlags - Flags to identify the types for overloaded Neon +/// builtins. These must be kept in sync with the flags in +/// include/clang/Basic/TargetBuiltins.h. +class NeonTypeFlags { + enum { + EltTypeMask = 0xf, + UnsignedFlag = 0x10, + QuadFlag = 0x20 + }; + uint32_t Flags; + +public: + enum EltType { + Int8, + Int16, + Int32, + Int64, + Poly8, + Poly16, + Float16, + Float32 + }; + + NeonTypeFlags(unsigned F) : Flags(F) {} + NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) { + if (IsUnsigned) + Flags |= UnsignedFlag; + if (IsQuad) + Flags |= QuadFlag; + } + + uint32_t getFlags() const { return Flags; } +}; + namespace llvm { class NeonEmitter : public TableGenBackend { diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 5c016d32ddd7..5ff88db30156 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -36,6 +36,9 @@ enum ActionType { GenClangAttrPCHWrite, GenClangAttrSpellingList, GenClangAttrLateParsedList, + GenClangAttrTemplateInstantiate, + GenClangAttrParsedAttrList, + GenClangAttrParsedAttrKinds, GenClangDiagsDefs, GenClangDiagGroups, GenClangDiagsIndexName, @@ -71,6 +74,15 @@ namespace { clEnumValN(GenClangAttrLateParsedList, "gen-clang-attr-late-parsed-list", "Generate a clang attribute LateParsed list"), + clEnumValN(GenClangAttrTemplateInstantiate, + "gen-clang-attr-template-instantiate", + "Generate a clang template instantiate code"), + clEnumValN(GenClangAttrParsedAttrList, + "gen-clang-attr-parsed-attr-list", + "Generate a clang parsed attribute list"), + clEnumValN(GenClangAttrParsedAttrKinds, + "gen-clang-attr-parsed-attr-kinds", + "Generate a clang parsed attribute kinds"), clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs", "Generate Clang diagnostics definitions"), clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", @@ -96,7 +108,6 @@ namespace { ClangComponent("clang-component", cl::desc("Only use warnings from specified component"), cl::value_desc("component"), cl::Hidden); -} class ClangTableGenAction : public TableGenAction { public: @@ -123,6 +134,15 @@ public: case GenClangAttrLateParsedList: ClangAttrLateParsedListEmitter(Records).run(OS); break; + case GenClangAttrTemplateInstantiate: + ClangAttrTemplateInstantiateEmitter(Records).run(OS); + break; + case GenClangAttrParsedAttrList: + ClangAttrParsedAttrListEmitter(Records).run(OS); + break; + case GenClangAttrParsedAttrKinds: + ClangAttrParsedAttrKindsEmitter(Records).run(OS); + break; case GenClangDiagsDefs: ClangDiagsDefsEmitter(Records, ClangComponent).run(OS); break; @@ -157,14 +177,12 @@ public: case GenArmNeonTest: NeonEmitter(Records).runTests(OS); break; - default: - assert(1 && "Invalid Action"); - return true; } return false; } }; +} int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py index 8eba9ebc7bcd..e68c45df184a 100755 --- a/utils/analyzer/CmpRuns.py +++ b/utils/analyzer/CmpRuns.py @@ -65,18 +65,22 @@ class AnalysisDiagnostic: filename = self.report.run.getSourceName(self.report.files[loc['file']]) line = loc['line'] column = loc['col'] + category = self.data['category'] + description = self.data['description'] # FIXME: Get a report number based on this key, to 'distinguish' # reports, or something. - return '%s:%d:%d' % (filename, line, column) + return '%s:%d:%d, %s: %s' % (filename, line, column, category, + description) def getReportData(self): if self.htmlReport is None: - return "This diagnostic does not have any report data." - - return open(os.path.join(self.report.run.path, - self.htmlReport), "rb").read() + return " " + return os.path.join(self.report.run.path, self.htmlReport) + # We could also dump the report with: + # return open(os.path.join(self.report.run.path, + # self.htmlReport), "rb").read() class AnalysisRun: def __init__(self, path, opts): @@ -153,7 +157,7 @@ def compareResults(A, B): while eltsA and eltsB: a = eltsA.pop() b = eltsB.pop() - if a.data == b.data: + if a.data['location'] == b.data['location']: res.append((a, b, 0)) elif a.data > b.data: neqA.append(a) @@ -189,25 +193,25 @@ def cmpScanBuildResults(dirA, dirB, opts, deleteEmpty=True): auxLog = None diff = compareResults(resultsA, resultsB) - foundDiffs = False + foundDiffs = 0 for res in diff: a,b,confidence = res if a is None: print "ADDED: %r" % b.getReadableName() - foundDiffs = True + foundDiffs += 1 if auxLog: print >>auxLog, ("('ADDED', %r, %r)" % (b.getReadableName(), b.getReportData())) elif b is None: print "REMOVED: %r" % a.getReadableName() - foundDiffs = True + foundDiffs += 1 if auxLog: print >>auxLog, ("('REMOVED', %r, %r)" % (a.getReadableName(), a.getReportData())) elif confidence: print "CHANGED: %r to %r" % (a.getReadableName(), b.getReadableName()) - foundDiffs = True + foundDiffs += 1 if auxLog: print >>auxLog, ("('CHANGED', %r, %r, %r, %r)" % (a.getReadableName(), @@ -217,10 +221,13 @@ def cmpScanBuildResults(dirA, dirB, opts, deleteEmpty=True): else: pass - print "TOTAL REPORTS: %r" % len(resultsB.diagnostics) + TotalReports = len(resultsB.diagnostics) + print "TOTAL REPORTS: %r" % TotalReports + print "TOTAL DIFFERENCES: %r" % foundDiffs if auxLog: - print >>auxLog, "('TOTAL REPORTS', %r)" % len(resultsB.diagnostics) - + print >>auxLog, "('TOTAL NEW REPORTS', %r)" % TotalReports + print >>auxLog, "('TOTAL DIFFERENCES', %r)" % foundDiffs + return foundDiffs def main(): diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py index 9fab07bfa9f0..ce64bc82f756 100644 --- a/utils/analyzer/SATestAdd.py +++ b/utils/analyzer/SATestAdd.py @@ -22,11 +22,18 @@ import os import csv import sys +def isExistingProject(PMapFile, projectID) : + PMapReader = csv.reader(PMapFile) + for I in PMapReader: + if projectID == I[0]: + return True + return False + # Add a new project for testing: build it and add to the Project Map file. # Params: # Dir is the directory where the sources are. # ID is a short string used to identify a project. -def addNewProject(ID) : +def addNewProject(ID, IsScanBuild) : CurDir = os.path.abspath(os.curdir) Dir = SATestBuild.getProjectDir(ID) if not os.path.exists(Dir): @@ -34,7 +41,7 @@ def addNewProject(ID) : sys.exit(-1) # Build the project. - SATestBuild.testProject(ID, True, Dir) + SATestBuild.testProject(ID, True, IsScanBuild, Dir) # Add the project ID to the project map. ProjectMapPath = os.path.join(CurDir, SATestBuild.ProjectMapFile) @@ -44,20 +51,16 @@ def addNewProject(ID) : print "Warning: Creating the Project Map file!!" PMapFile = open(ProjectMapPath, "w+b") try: - PMapReader = csv.reader(PMapFile) - for I in PMapReader: - IID = I[0] - if ID == IID: - print >> sys.stderr, 'Warning: Project with ID \'', ID, \ - '\' already exists.' - sys.exit(-1) - - PMapWriter = csv.writer(PMapFile) - PMapWriter.writerow( (ID, Dir) ); + if (isExistingProject(PMapFile, ID)) : + print >> sys.stdout, 'Warning: Project with ID \'', ID, \ + '\' already exists.' + print >> sys.stdout, "Reference output has been regenerated." + else: + PMapWriter = csv.writer(PMapFile) + PMapWriter.writerow( (ID, int(IsScanBuild)) ); + print "The project map is updated: ", ProjectMapPath finally: PMapFile.close() - - print "The project map is updated: ", ProjectMapPath # TODO: Add an option not to build. @@ -65,7 +68,13 @@ def addNewProject(ID) : if __name__ == '__main__': if len(sys.argv) < 2: print >> sys.stderr, 'Usage: ', sys.argv[0],\ - '[project ID]' + 'project_ID <mode>' \ + 'mode - 0 for single file project; 1 for scan_build' sys.exit(-1) + + IsScanBuild = 1 + if (len(sys.argv) >= 3): + IsScanBuild = int(sys.argv[2]) + assert((IsScanBuild == 0) | (IsScanBuild == 1)) - addNewProject(sys.argv[1]) + addNewProject(sys.argv[1], IsScanBuild) diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index c2209cc93cfc..3fccb9ac1ef1 100644 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -29,7 +29,7 @@ The files which should be kept around for failure investigations: Assumptions (TODO: shouldn't need to assume these.): The script is being run from the Repository Directory. - The compiler for scan-build is in the PATH. + The compiler for scan-build and scan-build are in the PATH. export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH For more logging, set the env variables: @@ -45,18 +45,19 @@ import glob import shutil import time import plistlib -from subprocess import check_call +from subprocess import check_call, CalledProcessError # Project map stores info about all the "registered" projects. ProjectMapFile = "projectMap.csv" # Names of the project specific scripts. # The script that needs to be executed before the build can start. -PreprocessScript = "pre_run_static_analyzer.sh" +CleanupScript = "cleanup_run_static_analyzer.sh" # 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 # displayed when buildbot detects a build failure. @@ -69,8 +70,24 @@ DiffsSummaryFileName = "diffs.txt" SBOutputDirName = "ScanBuildResults" SBOutputDirReferencePrefix = "Ref" +# The list of checkers used during analyzes. +# Currently, consists of all the non experimental checkers. +Checkers="experimental.security.taint,core,deadcode,cplusplus,security,unix,osx,cocoa" + Verbose = 1 +IsReferenceBuild = False + +# Make sure we flush the output after every print statement. +class flushfile(object): + def __init__(self, f): + self.f = f + def write(self, x): + self.f.write(x) + self.f.flush() + +sys.stdout = flushfile(sys.stdout) + def getProjectMapPath(): ProjectMapPath = os.path.join(os.path.abspath(os.curdir), ProjectMapFile) @@ -83,9 +100,15 @@ def getProjectMapPath(): def getProjectDir(ID): return os.path.join(os.path.abspath(os.curdir), ID) +def getSBOutputDirName() : + if IsReferenceBuild == True : + return SBOutputDirReferencePrefix + SBOutputDirName + else : + return SBOutputDirName + # Run pre-processing script if any. -def runPreProcessingScript(Dir, PBuildLogFile): - ScriptPath = os.path.join(Dir, PreprocessScript) +def runCleanupScript(Dir, PBuildLogFile): + ScriptPath = os.path.join(Dir, CleanupScript) if os.path.exists(ScriptPath): try: if Verbose == 1: @@ -109,8 +132,8 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): if not os.path.exists(BuildScriptPath): print "Error: build script is not defined: %s" % BuildScriptPath sys.exit(-1) - SBOptions = "-plist -o " + SBOutputDir + " " - SBOptions += "-enable-checker core,deadcode.DeadStores" + SBOptions = "-plist-html -o " + SBOutputDir + " " + SBOptions += "-enable-checker " + Checkers + " " try: SBCommandFile = open(BuildScriptPath, "r") SBPrefix = "scan-build " + SBOptions + " " @@ -124,34 +147,107 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): except: print "Error: scan-build failed. See ",PBuildLogFile.name,\ " for details." - sys.exit(-1) + raise + +def hasNoExtension(FileName): + (Root, Ext) = os.path.splitext(FileName) + if ((Ext == "")) : + return True + return False + +def isValidSingleInputFile(FileName): + (Root, Ext) = os.path.splitext(FileName) + if ((Ext == ".i") | (Ext == ".ii") | + (Ext == ".c") | (Ext == ".cpp") | + (Ext == ".m") | (Ext == "")) : + return True + return False + +# Run analysis on a set of preprocessed files. +def runAnalyzePreprocessed(Dir, SBOutputDir): + if os.path.exists(os.path.join(Dir, BuildScript)): + print "Error: The preprocessed files project should not contain %s" % \ + BuildScript + raise Exception() + + CmdPrefix = "clang -cc1 -analyze -analyzer-output=plist -w " + CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks " + + 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 + os.path.join(Dir, FileName) + LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b") + try: + if Verbose == 1: + print " Executing: %s" % (Command,) + check_call(Command, cwd = Dir, stderr=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 + finally: + LogFile.close() + + # If command did not fail, erase the log file. + if Failed == False: + os.remove(LogFile.name); -def buildProject(Dir, SBOutputDir): +def buildProject(Dir, SBOutputDir, IsScanBuild): TBegin = time.time() - BuildLogPath = os.path.join(Dir, BuildLogName) + BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName) 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,) + 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: + 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+") - try: - # Clean up scan build results. - if (os.path.exists(SBOutputDir)) : - RmCommand = "rm -r " + SBOutputDir - if Verbose == 1: - print " Executing: %s" % (RmCommand,) - check_call(RmCommand, stderr=PBuildLogFile, - stdout=PBuildLogFile, shell=True) - runPreProcessingScript(Dir, PBuildLogFile) - runScanBuild(Dir, SBOutputDir, PBuildLogFile) + # Build and analyze the project. + try: + runCleanupScript(Dir, PBuildLogFile) + + if IsScanBuild: + runScanBuild(Dir, SBOutputDir, PBuildLogFile) + else: + runAnalyzePreprocessed(Dir, SBOutputDir) + + if IsReferenceBuild : + runCleanupScript(Dir, PBuildLogFile) + finally: PBuildLogFile.close() @@ -185,9 +281,9 @@ def checkBuild(SBOutputDir): return; # Create summary file to display when the build fails. - SummaryPath = os.path.join(SBOutputDir, FailuresSummaryFileName); + SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName) if (Verbose > 0): - print " Creating the failures summary file %s." % (SummaryPath,) + print " Creating the failures summary file %s" % (SummaryPath,) SummaryLog = open(SummaryPath, "w+") try: @@ -212,8 +308,7 @@ def checkBuild(SBOutputDir): finally: SummaryLog.close() - print "Error: Scan-build failed. See ", \ - os.path.join(SBOutputDir, FailuresSummaryFileName) + print "Error: analysis failed. See ", SummaryPath sys.exit(-1) # Auxiliary object to discard stdout. @@ -231,6 +326,11 @@ def runCmpResults(Dir): # We have to go one level down the directory tree. RefList = glob.glob(RefDir + "/*") NewList = glob.glob(NewDir + "/*") + + # Log folders are also located in the results dir, so ignore them. + RefList.remove(os.path.join(RefDir, LogFolderName)) + NewList.remove(os.path.join(NewDir, LogFolderName)) + if len(RefList) == 0 or len(NewList) == 0: return False assert(len(RefList) == len(NewList)) @@ -243,7 +343,7 @@ def runCmpResults(Dir): NewList.sort() # Iterate and find the differences. - HaveDiffs = False + NumDiffs = 0 PairList = zip(RefList, NewList) for P in PairList: RefDir = P[0] @@ -259,16 +359,47 @@ def runCmpResults(Dir): OLD_STDOUT = sys.stdout sys.stdout = Discarder() # Scan the results, delete empty plist files. - HaveDiffs = CmpRuns.cmpScanBuildResults(RefDir, NewDir, Opts, False) + NumDiffs = CmpRuns.cmpScanBuildResults(RefDir, NewDir, Opts, False) sys.stdout = OLD_STDOUT - if HaveDiffs: - print "Warning: difference in diagnostics. See %s" % (DiffsPath,) - HaveDiffs=True + if (NumDiffs > 0) : + print "Warning: %r differences in diagnostics. See %s" % \ + (NumDiffs, DiffsPath,) print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin) - return HaveDiffs + return (NumDiffs > 0) + +def updateSVN(Mode, ProjectsMap): + try: + ProjectsMap.seek(0) + for I in csv.reader(ProjectsMap): + ProjName = I[0] + Path = os.path.join(ProjName, getSBOutputDirName()) + + if Mode == "delete": + Command = "svn delete %s" % (Path,) + else: + Command = "svn add %s" % (Path,) + + if Verbose == 1: + print " Executing: %s" % (Command,) + check_call(Command, shell=True) + + if Mode == "delete": + CommitCommand = "svn commit -m \"[analyzer tests] Remove " \ + "reference results.\"" + else: + CommitCommand = "svn commit -m \"[analyzer tests] Add new " \ + "reference results.\"" + if Verbose == 1: + print " Executing: %s" % (CommitCommand,) + check_call(CommitCommand, shell=True) + except: + print "Error: SVN update failed." + sys.exit(-1) + +def testProject(ID, IsScanBuild, Dir=None): + print " \n\n--- Building project %s" % (ID,) -def testProject(ID, IsReferenceBuild, Dir=None): TBegin = time.time() if Dir is None : @@ -277,13 +408,10 @@ def testProject(ID, IsReferenceBuild, Dir=None): print " Build directory: %s." % (Dir,) # Set the build results directory. - if IsReferenceBuild == True : - SBOutputDir = os.path.join(Dir, SBOutputDirReferencePrefix + \ - SBOutputDirName) - else : - SBOutputDir = os.path.join(Dir, SBOutputDirName) - - buildProject(Dir, SBOutputDir) + RelOutputDir = getSBOutputDirName() + SBOutputDir = os.path.join(Dir, RelOutputDir) + + buildProject(Dir, SBOutputDir, IsScanBuild) checkBuild(SBOutputDir) @@ -293,15 +421,55 @@ def testProject(ID, IsReferenceBuild, Dir=None): print "Completed tests for project %s (time: %.2f)." % \ (ID, (time.time()-TBegin)) -def testAll(IsReferenceBuild=False): +def testAll(InIsReferenceBuild = False, UpdateSVN = False): + global IsReferenceBuild + IsReferenceBuild = InIsReferenceBuild + PMapFile = open(getProjectMapPath(), "rb") - try: - PMapReader = csv.reader(PMapFile) - for I in PMapReader: - print " --- Building project %s" % (I[0],) - testProject(I[0], IsReferenceBuild) + try: + # Validate the input. + for I in csv.reader(PMapFile): + if (len(I) != 2) : + print "Error: Rows in the ProjectMapFile should have 3 entries." + raise Exception() + if (not ((I[1] == "1") | (I[1] == "0"))): + print "Error: Second entry in the ProjectMapFile should be 0 or 1." + raise Exception() + + # When we are regenerating the reference results, we might need to + # update svn. Remove reference results from SVN. + if UpdateSVN == True: + assert(InIsReferenceBuild == True); + updateSVN("delete", PMapFile); + + # Test the projects. + PMapFile.seek(0) + for I in csv.reader(PMapFile): + testProject(I[0], int(I[1])) + + # Add reference results to SVN. + if UpdateSVN == True: + updateSVN("add", PMapFile); + + except: + print "Error occurred. Premature termination." + raise finally: PMapFile.close() if __name__ == '__main__': - testAll() + IsReference = False + UpdateSVN = False + if len(sys.argv) >= 2: + if sys.argv[1] == "-r": + IsReference = True + elif sys.argv[1] == "-rs": + IsReference = True + UpdateSVN = True + else: + print >> sys.stderr, 'Usage: ', sys.argv[0],\ + '[-r|-rs]' \ + 'Use -r to regenerate reference output' \ + 'Use -rs to regenerate reference output and update svn' + + testAll(IsReference, UpdateSVN) diff --git a/utils/clangVisualizers.txt b/utils/clangVisualizers.txt index f9f834b76c50..0fef65f4ed3e 100644 --- a/utils/clangVisualizers.txt +++ b/utils/clangVisualizers.txt @@ -41,4 +41,94 @@ llvm::StringRef{ clang::Token{ preview((clang::tok::TokenKind)(int)$e.Kind) -}
\ No newline at end of file +} + +llvm::PointerIntPair<*,*,*,*>{ + preview ( + #( + ($T1*)($e.Value & $e.PointerBitMask), + " [", + ($T3)(($e.Value >> $e.IntShift) & $e.IntMask), + "]" + ) + ) + + children ( + #( + #([ptr] : ($T1*)($e.Value & $e.PointerBitMask)), + #([int] : ($T3)($e.Value >> $e.IntShift) & $e.IntMask) + ) + ) +} + +llvm::PointerUnion<*,*>{ + preview ( + #if ((($e.Val.Value >> $e.Val.IntShift) & $e.Val.IntMask) == 0) ( + "PT1" + ) #else ( + "PT2" + ) + ) + + children ( + #( + #if ((($e.Val.Value >> $e.Val.IntShift) & $e.Val.IntMask) == 0) ( + #([ptr] : ($T1)($e.Val.Value & $e.Val.PointerBitMask)) + ) #else ( + #([ptr] : ($T2)($e.Val.Value & $e.Val.PointerBitMask)) + ) + ) + ) +} + +llvm::PointerUnion3<*,*,*>{ + preview ( + #if (($e.Val.Val.Value & 0x2) == 2) ( + "PT2" + ) #elif (($e.Val.Val.Value & 0x1) == 1) ( + "PT3" + ) #else ( + "PT1" + ) + ) + + children ( + #( + #if (($e.Val.Val.Value & 0x2) == 2) ( + #([ptr] : ($T2)(($e.Val.Val.Value >> 2) << 2)) + ) #elif (($e.Val.Val.Value & 0x1) == 1) ( + #([ptr] : ($T3)(($e.Val.Val.Value >> 2) << 2)) + ) #else ( + #([ptr] : ($T1)(($e.Val.Val.Value >> 2) << 2)) + ) + ) + ) +} + +llvm::PointerUnion4<*,*,*,*>{ + preview ( + #if (($e.Val.Val.Value & 0x3) == 3) ( + "PT4" + ) #elif (($e.Val.Val.Value & 0x2) == 2) ( + "PT2" + ) #elif (($e.Val.Val.Value & 0x1) == 1) ( + "PT3" + ) #else ( + "PT1" + ) + ) + + children ( + #( + #if (($e.Val.Val.Value & 0x3) == 3) ( + #([ptr] : ($T4)(($e.Val.Val.Value >> 2) << 2)) + ) #elif (($e.Val.Val.Value & 0x2) == 2) ( + #([ptr] : ($T2)(($e.Val.Val.Value >> 2) << 2)) + ) #elif (($e.Val.Val.Value & 0x1) == 1) ( + #([ptr] : ($T3)(($e.Val.Val.Value >> 2) << 2)) + ) #else ( + #([ptr] : ($T1)(($e.Val.Val.Value >> 2) << 2)) + ) + ) + ) +} diff --git a/utils/find-unused-diagnostics.sh b/utils/find-unused-diagnostics.sh new file mode 100644 index 000000000000..89b7f7a700d5 --- /dev/null +++ b/utils/find-unused-diagnostics.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# +# This script produces a list of all diagnostics that are defined +# in Diagnostic*.td files but not used in sources. +# + +ALL_DIAGS=$(mktemp) +ALL_SOURCES=$(mktemp) + +grep -E --only-matching --no-filename '(err_|warn_|ext_|note_)[a-z_]+ ' ./include/clang/Basic/Diagnostic*.td > $ALL_DIAGS +find lib include tools -name \*.cpp -or -name \*.h > $ALL_SOURCES +for DIAG in $(cat $ALL_DIAGS); do + if ! grep -r $DIAG $(cat $ALL_SOURCES) > /dev/null; then + echo $DIAG + fi; +done + +rm $ALL_DIAGS $ALL_SOURCES + |
