From: Tyler Nowicki Date: Fri, 13 Jun 2014 17:57:25 +0000 (+0000) Subject: Adds a Pragma spelling for attributes to tablegen and makes use of it for loop X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fe84cfe70015f94322e3517b4bf3e5cbf29811d4;p=clang Adds a Pragma spelling for attributes to tablegen and makes use of it for loop hint attributes. Includes tests for pragma printing and for attribute order which is incorrectly reversed by ParsedAttributes. Reviewed by Aaron Ballman git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@210925 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 96704160c0..ab83db206e 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -190,6 +190,9 @@ class CXX11 : Spelling { string Namespace = namespace; } class Keyword : Spelling; +class Pragma : Spelling { + string Namespace = namespace; +} // The GCC spelling implies GNU and CXX11<"gnu", name> and also // sets KnownToGCC to 1. This spelling should be used for any GCC-compatible @@ -1769,9 +1772,7 @@ def LoopHint : Attr { /// unroll: unroll loop if 'value != 0'. /// unroll_count: unrolls loop 'value' times. - /// FIXME: Add Pragma spelling to tablegen and - /// use it here. - let Spellings = [Keyword<"loop">]; + let Spellings = [Pragma<"clang", "loop">]; /// State of the loop optimization specified by the spelling. let Args = [EnumArgument<"Option", "OptionType", @@ -1800,9 +1801,8 @@ def LoopHint : Attr { return "disable"; } - // FIXME: Modify pretty printer to print this pragma. - void print(raw_ostream &OS, const PrintingPolicy &Policy) const { - OS << "#pragma clang loop " << getOptionName(option) << "("; + void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const { + OS << getOptionName(option) << "("; if (option == VectorizeWidth || option == InterleaveCount || option == UnrollCount) OS << value; diff --git a/include/clang/Basic/Attributes.h b/include/clang/Basic/Attributes.h index 4a7e4629d0..5783b3bff5 100644 --- a/include/clang/Basic/Attributes.h +++ b/include/clang/Basic/Attributes.h @@ -25,7 +25,9 @@ enum class AttrSyntax { /// Is the identifier known as a __declspec-style attribute? Declspec, // Is the identifier known as a C++-style attribute? - CXX + CXX, + // Is the identifier known as a pragma attribute? + Pragma }; /// \brief Return true if we recognize and implement the attribute specified by diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 6872ccc98d..24e4cd41f9 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -80,7 +80,9 @@ public: /// __declspec(...) AS_Declspec, /// __ptr16, alignas(...), etc. - AS_Keyword + AS_Keyword, + /// #pragma ... + AS_Pragma }; private: diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 0651405618..cd206965fb 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -168,21 +168,9 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { } void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { - std::string raw_attr_os; - llvm::raw_string_ostream AttrOS(raw_attr_os); for (const auto *Attr : Node->getAttrs()) { - // FIXME: This hack will be removed when printPretty - // has been modified to print pretty pragmas - if (const LoopHintAttr *LHA = dyn_cast(Attr)) { - LHA->print(OS, Policy); - } else - Attr->printPretty(AttrOS, Policy); - } - - // Print attributes after pragmas. - StringRef AttrStr = AttrOS.str(); - if (!AttrStr.empty()) - OS << AttrStr; + Attr->printPretty(OS, Policy); + } PrintStmt(Node->getSubStmt(), 0); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 8ed5c984fd..da26853d4c 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1765,9 +1765,8 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement, ArgsUnion ArgHints[] = {Hint.OptionLoc, Hint.ValueLoc, ArgsUnion(Hint.ValueExpr)}; - // FIXME: Replace AS_Keyword with Pragma spelling AS_Pragma. TempAttrs.addNew(Hint.LoopLoc->Ident, Hint.Range, nullptr, - Hint.LoopLoc->Loc, ArgHints, 3, AttributeList::AS_Keyword); + Hint.LoopLoc->Loc, ArgHints, 3, AttributeList::AS_Pragma); } // Get the next statement. diff --git a/test/Misc/ast-print-pragmas-xfail.cpp b/test/Misc/ast-print-pragmas-xfail.cpp new file mode 100644 index 0000000000..994e1fda32 --- /dev/null +++ b/test/Misc/ast-print-pragmas-xfail.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 %s -ast-print -o - | FileCheck %s + +// FIXME: Test fails because attribute order is reversed by ParsedAttributes. +// XFAIL: * + +void run1(int *List, int Length) { + int i = 0; +// CEHCK: #pragma loop vectorize(4) +// CHECK-NEXT: #pragma loop interleave(8) +// CHECK-NEXT: #pragma loop vectorize(enable) +// CHECK-NEXT: #pragma loop interleave(enable) +#pragma loop vectorize(4) +#pragma loop interleave(8) +#pragma loop vectorize(enable) +#pragma loop interleave(enable) +// CHECK-NEXT: while (i < Length) + while (i < Length) { + List[i] = i; + i++; + } +} diff --git a/test/Misc/ast-print-pragmas.cpp b/test/Misc/ast-print-pragmas.cpp new file mode 100644 index 0000000000..25421fcd0c --- /dev/null +++ b/test/Misc/ast-print-pragmas.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -ast-print %s -o - | FileCheck %s + +// FIXME: A bug in ParsedAttributes causes the order of the attributes to be +// reversed. The checks are consequently in the reverse order below. + +// CHECK: #pragma clang loop interleave_count(8) +// CHECK-NEXT: #pragma clang loop vectorize_width(4) + +void test(int *List, int Length) { + int i = 0; +#pragma clang loop vectorize_width(4) +#pragma clang loop interleave_count(8) +// CHECK-NEXT: while (i < Length) + while (i < Length) { + List[i] = i * 2; + i++; + } + +// CHECK: #pragma clang loop interleave(disable) +// CHECK-NEXT: #pragma clang loop vectorize(enable) + +#pragma clang loop vectorize(enable) +#pragma clang loop interleave(disable) +// CHECK-NEXT: while (i - 1 < Length) + while (i - 1 < Length) { + List[i] = i * 2; + i++; + } + +// CHECK: #pragma clang loop interleave(enable) +// CHECK-NEXT: #pragma clang loop vectorize(disable) + +#pragma clang loop vectorize(disable) +#pragma clang loop interleave(enable) +// CHECK-NEXT: while (i - 2 < Length) + while (i - 2 < Length) { + List[i] = i * 2; + i++; + } +} diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 11c64eac7b..d7ab4fa1b1 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -41,7 +41,7 @@ public: assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been" "flattened!"); - if (V == "CXX11") + if (V == "CXX11" || V == "Pragma") NS = Spelling.getValueAsString("Namespace"); bool Unset; K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset); @@ -1055,7 +1055,7 @@ writePrettyPrintFunction(Record &R, OS << "void " << R.getName() << "Attr::printPretty(" << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n"; - if (Spellings.size() == 0) { + if (Spellings.empty()) { OS << "}\n\n"; return; } @@ -1082,7 +1082,7 @@ writePrettyPrintFunction(Record &R, Prefix = " [["; Suffix = "]]"; std::string Namespace = Spellings[I].nameSpace(); - if (Namespace != "") { + if (!Namespace.empty()) { Spelling += Namespace; Spelling += "::"; } @@ -1092,6 +1092,14 @@ writePrettyPrintFunction(Record &R, } else if (Variety == "Keyword") { Prefix = " "; Suffix = ""; + } else if (Variety == "Pragma") { + Prefix = "#pragma "; + Suffix = "\n"; + std::string Namespace = Spellings[I].nameSpace(); + if (!Namespace.empty()) { + Spelling += Namespace; + Spelling += " "; + } } else { llvm_unreachable("Unknown attribute syntax variety!"); } @@ -1102,6 +1110,14 @@ writePrettyPrintFunction(Record &R, " case " << I << " : {\n" " OS << \"" + Prefix.str() + Spelling.str(); + if (Variety == "Pragma") { + OS << " \";\n"; + OS << " printPrettyPragma(OS, Policy);\n"; + OS << " break;\n"; + OS << " }\n"; + continue; + } + if (!Args.empty()) OS << "("; if (Spelling == "availability") { @@ -1782,7 +1798,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { // Separate all of the attributes out into four group: generic, C++11, GNU, // and declspecs. Then generate a big switch statement for each of them. std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector Declspec, GNU; + std::vector Declspec, GNU, Pragma; std::map> CXX; // Walk over the list of all attributes, and split them out based on the @@ -1795,9 +1811,10 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { GNU.push_back(R); else if (Variety == "Declspec") Declspec.push_back(R); - else if (Variety == "CXX11") { + else if (Variety == "CXX11") CXX[SI.nameSpace()].push_back(R); - } + else if (Variety == "Pragma") + Pragma.push_back(R); } } @@ -1811,6 +1828,9 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { OS << "case AttrSyntax::Declspec:\n"; OS << " return llvm::StringSwitch(Name)\n"; GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec"); + OS << "case AttrSyntax::Pragma:\n"; + OS << " return llvm::StringSwitch(Name)\n"; + GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma"); OS << "case AttrSyntax::CXX: {\n"; // C++11-style attributes are further split out based on the Scope. for (std::map>::iterator I = CXX.begin(), @@ -1846,17 +1866,17 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) { std::vector Spellings = GetFlattenedSpellings(R); OS << " case AT_" << I.first << ": {\n"; for (unsigned I = 0; I < Spellings.size(); ++ I) { - OS << " if (Name == \"" - << Spellings[I].name() << "\" && " - << "SyntaxUsed == " - << StringSwitch(Spellings[I].variety()) - .Case("GNU", 0) - .Case("CXX11", 1) - .Case("Declspec", 2) - .Case("Keyword", 3) - .Default(0) - << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n" - << " return " << I << ";\n"; + OS << " if (Name == \"" << Spellings[I].name() << "\" && " + << "SyntaxUsed == " + << StringSwitch(Spellings[I].variety()) + .Case("GNU", 0) + .Case("CXX11", 1) + .Case("Declspec", 2) + .Case("Keyword", 3) + .Case("Pragma", 4) + .Default(0) + << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n" + << " return " << I << ";\n"; } OS << " break;\n"; @@ -2476,7 +2496,7 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("Attribute name matcher", OS); std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector GNU, Declspec, CXX11, Keywords; + std::vector GNU, Declspec, CXX11, Keywords, Pragma; std::set Seen; for (const auto *A : Attrs) { const Record &Attr = *A; @@ -2519,6 +2539,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { Matches = &Declspec; else if (Variety == "Keyword") Matches = &Keywords; + else if (Variety == "Pragma") + Matches = &Pragma; assert(Matches && "Unsupported spelling variety found"); @@ -2543,6 +2565,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { StringMatcher("Name", CXX11, OS).Emit(); OS << " } else if (AttributeList::AS_Keyword == Syntax) {\n"; StringMatcher("Name", Keywords, OS).Emit(); + OS << " } else if (AttributeList::AS_Pragma == Syntax) {\n"; + StringMatcher("Name", Pragma, OS).Emit(); OS << " }\n"; OS << " return AttributeList::UnknownAttribute;\n" << "}\n"; @@ -2648,7 +2672,8 @@ enum SpellingKind { GNU = 1 << 0, CXX11 = 1 << 1, Declspec = 1 << 2, - Keyword = 1 << 3 + Keyword = 1 << 3, + Pragma = 1 << 4 }; static void WriteDocumentation(const DocumentationData &Doc, @@ -2693,10 +2718,11 @@ static void WriteDocumentation(const DocumentationData &Doc, unsigned SupportedSpellings = 0; for (const auto &I : Spellings) { SpellingKind Kind = StringSwitch(I.variety()) - .Case("GNU", GNU) - .Case("CXX11", CXX11) - .Case("Declspec", Declspec) - .Case("Keyword", Keyword); + .Case("GNU", GNU) + .Case("CXX11", CXX11) + .Case("Declspec", Declspec) + .Case("Keyword", Keyword) + .Case("Pragma", Pragma); // Mask in the supported spelling. SupportedSpellings |= Kind; @@ -2731,7 +2757,8 @@ static void WriteDocumentation(const DocumentationData &Doc, // List what spelling syntaxes the attribute supports. OS << ".. csv-table:: Supported Syntaxes\n"; - OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\"\n\n"; + OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\","; + OS << " \"Pragma\"\n\n"; OS << " \""; if (SupportedSpellings & GNU) OS << "X"; OS << "\",\""; @@ -2741,6 +2768,8 @@ static void WriteDocumentation(const DocumentationData &Doc, OS << "\",\""; if (SupportedSpellings & Keyword) OS << "X"; OS << "\"\n\n"; + if (SupportedSpellings & Pragma) OS << "X"; + OS << "\"\n\n"; // If the attribute is deprecated, print a message about it, and possibly // provide a replacement attribute.