]> granicus.if.org Git - clang/commitdiff
Adds a Pragma spelling for attributes to tablegen and makes use of it for loop
authorTyler Nowicki <tnowicki@apple.com>
Fri, 13 Jun 2014 17:57:25 +0000 (17:57 +0000)
committerTyler Nowicki <tnowicki@apple.com>
Fri, 13 Jun 2014 17:57:25 +0000 (17:57 +0000)
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

include/clang/Basic/Attr.td
include/clang/Basic/Attributes.h
include/clang/Sema/AttributeList.h
lib/AST/StmtPrinter.cpp
lib/Parse/ParseStmt.cpp
test/Misc/ast-print-pragmas-xfail.cpp [new file with mode: 0644]
test/Misc/ast-print-pragmas.cpp [new file with mode: 0644]
utils/TableGen/ClangAttrEmitter.cpp

index 96704160c06bc051814d92779adc47311346ea66..ab83db206efd36ac9084dcd7329c5d1375a4a283 100644 (file)
@@ -190,6 +190,9 @@ class CXX11<string namespace, string name> : Spelling<name, "CXX11"> {
   string Namespace = namespace;
 }
 class Keyword<string name> : Spelling<name, "Keyword">;
+class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
+  string Namespace = namespace;
+}
 
 // The GCC spelling implies GNU<name, "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;
index 4a7e4629d046d24f23df22b19521918bc0a564cc..5783b3bff51096af928709dcb9a0b51b4dfc6b12 100644 (file)
@@ -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
index 6872ccc98df3319ab26a50689f047d7f96027864..24e4cd41f99a424d67c4e8fe3846f23100014bc1 100644 (file)
@@ -80,7 +80,9 @@ public:
     /// __declspec(...)
     AS_Declspec,
     /// __ptr16, alignas(...), etc.
-    AS_Keyword
+    AS_Keyword,
+    /// #pragma ...
+    AS_Pragma
   };
 
 private:
index 065140561856386a26bfb0b41eea2a06a7b58b45..cd206965fb8599b92024720a9ca54bd31e6f3c48 100644 (file)
@@ -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<LoopHintAttr>(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);
 }
index 8ed5c984fd99387336de6ef1531b3790b9a6480b..da26853d4c485c7d18dde052dac1f3ef20dd2b84 100644 (file)
@@ -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 (file)
index 0000000..994e1fd
--- /dev/null
@@ -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 (file)
index 0000000..25421fc
--- /dev/null
@@ -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++;
+  }
+}
index 11c64eac7b73e83376b746e233484a678807b692..d7ab4fa1b191b96fb340ba4b187f5e108cae6114 100644 (file)
@@ -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<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
-  std::vector<Record *> Declspec, GNU;
+  std::vector<Record *> Declspec, GNU, Pragma;
   std::map<std::string, std::vector<Record *>> 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<bool>(Name)\n";
   GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec");
+  OS << "case AttrSyntax::Pragma:\n";
+  OS << "  return llvm::StringSwitch<bool>(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<std::string, std::vector<Record *>>::iterator I = CXX.begin(),
@@ -1846,17 +1866,17 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
     std::vector<FlattenedSpelling> 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<unsigned>(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<unsigned>(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<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
-  std::vector<StringMatcher::StringPair> GNU, Declspec, CXX11, Keywords;
+  std::vector<StringMatcher::StringPair> GNU, Declspec, CXX11, Keywords, Pragma;
   std::set<std::string> 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<SpellingKind>(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.