]> granicus.if.org Git - clang/commitdiff
Add support for #pragma nounroll.
authorMark Heffernan <meheff@google.com>
Thu, 24 Jul 2014 18:09:38 +0000 (18:09 +0000)
committerMark Heffernan <meheff@google.com>
Thu, 24 Jul 2014 18:09:38 +0000 (18:09 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@213885 91177308-0d34-0410-b5e6-96231b3b80d8

docs/ReleaseNotes.rst
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Parse/Parser.h
include/clang/Sema/LoopHint.h
lib/Parse/ParsePragma.cpp
lib/Sema/SemaStmtAttr.cpp
test/CodeGen/pragma-unroll.cpp
test/PCH/pragma-loop.cpp
test/Parser/pragma-unroll.cpp

index f17a1a4b161517ac584916fb97710ba33b3f7736..6544a3da8166745e07a8e85582918fc9dd38a9fa 100644 (file)
@@ -111,12 +111,13 @@ interleaving, and unrolling to be enabled or disabled. Vector width as well
 as interleave and unrolling count can be manually specified.  See language
 extensions for details.
 
-Clang now supports the `#pragma unroll` directive to specify loop unrolling
-optimization hints.  Placed just prior to the desired loop, `#pragma unroll`
-directs the loop unroller to attempt to fully unroll the loop.  The pragma may
-also be specified with a positive integer parameter indicating the desired
-unroll count: `#pragma unroll _value_`.  The unroll count parameter can be
-optionally enclosed in parentheses.
+Clang now supports the `#pragma unroll` and `#pragma nounroll` directives to
+specify loop unrolling optimization hints.  Placed just prior to the desired
+loop, `#pragma unroll` directs the loop unroller to attempt to fully unroll the
+loop.  The pragma may also be specified with a positive integer parameter
+indicating the desired unroll count: `#pragma unroll _value_`.  The unroll count
+parameter can be optionally enclosed in parentheses. The directive `#pragma
+nounroll` indicates that the loop should not be unrolled.
 
 C Language Changes in Clang
 ---------------------------
index 708f4f49bdbabdbf581b0a3fb49cc102c4137213..0af6f97504c5ab7ed80166d4fd42fbe6f4d9a5d9 100644 (file)
@@ -1791,7 +1791,8 @@ def LoopHint : Attr {
   /// unroll: fully unroll loop if 'value != 0'.
   /// unroll_count: unrolls loop 'value' times.
 
-  let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">];
+  let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">,
+                   Pragma<"", "nounroll">];
 
   /// State of the loop optimization specified by the spelling.
   let Args = [EnumArgument<"Option", "OptionType",
@@ -1822,9 +1823,13 @@ def LoopHint : Attr {
 
   void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
     unsigned SpellingIndex = getSpellingListIndex();
+    // For "#pragma unroll" and "#pragma nounroll" the string "unroll" or
+    // "nounroll" is already emitted as the pragma name.
+    if (SpellingIndex == Pragma_nounroll) {
+      OS << "\n";
+      return;
+    }
     if (SpellingIndex == Pragma_unroll) {
-      // String "unroll" of "#pragma unroll" is already emitted as the
-      // pragma name.
       if (option == UnrollCount)
         printArgument(OS);
       OS << "\n";
@@ -1858,11 +1863,12 @@ def LoopHint : Attr {
     std::string DiagnosticName;
     llvm::raw_string_ostream OS(DiagnosticName);
     unsigned SpellingIndex = getSpellingListIndex();
-    if (SpellingIndex == Pragma_unroll && option == Unroll)
-      OS << "#pragma unroll";
-    else if (SpellingIndex == Pragma_unroll && option == UnrollCount) {
+    if (SpellingIndex == Pragma_nounroll)
+      OS << "#pragma nounroll";
+    else if (SpellingIndex == Pragma_unroll) {
       OS << "#pragma unroll";
-      printArgument(OS);
+      if (option == UnrollCount)
+        printArgument(OS);
     } else {
       assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
       OS << getOptionName(option);
index 34dd1b0c45f974af89c1bc7b6e34eab5066371cc..b04afa794d3a67843898c710b2b7fa5a12c75bae 100644 (file)
@@ -1065,11 +1065,11 @@ for details.
 
 def UnrollHintDocs : Documentation {
   let Category = DocCatStmt;
-  let Heading = "#pragma unroll";
+  let Heading = "#pragma unroll, #pragma nounroll";
   let Content = [{
-Loop unrolling optimization hints can be specified with ``#pragma unroll``. The
-pragma is placed immediately before a for, while, do-while, or c++11 range-based
-for loop.
+Loop unrolling optimization hints can be specified with ``#pragma unroll`` and
+``#pragma nounroll``. The pragma is placed immediately before a for, while,
+do-while, or c++11 range-based for loop.
 
 Specifying ``#pragma unroll`` without a parameter directs the loop unroller to
 attempt to fully unroll the loop if the trip count is known at compile time:
@@ -1097,9 +1097,20 @@ enclosed in parentheses:
     ...
   }
 
+Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled:
+
+.. code-block:: c++
+
+  #pragma nounroll
+  for (...) {
+    ...
+  }
+
 ``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to
-``#pragma clang loop unroll(full)`` and ``#pragma clang loop
-unroll_count(_value_)`` respectively. See `language extensions
+``#pragma clang loop unroll(full)`` and
+``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll``
+is equivalent to ``#pragma clang loop unroll(disable)``.  See
+`language extensions
 <http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
 for further details including limitations of the unroll hints.
   }];
index 5b5f8eb967b8f13076d8a7adfc9ebf50628dcb0a..3dccee7660d74657d3a499aa02a25ca204789125 100644 (file)
@@ -164,6 +164,7 @@ class Parser : public CodeCompletionHandler {
   std::unique_ptr<PragmaHandler> OptimizeHandler;
   std::unique_ptr<PragmaHandler> LoopHintHandler;
   std::unique_ptr<PragmaHandler> UnrollHintHandler;
+  std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
 
   std::unique_ptr<CommentHandler> CommentSemaHandler;
 
index d4b985df544c9782ba845b914b4865b0ae3ab2f5..a0bc45572f7f81ae37ff8eecf8235a55cc844db8 100644 (file)
@@ -26,7 +26,8 @@ struct LoopHint {
   // hints.
   IdentifierLoc *PragmaNameLoc;
   // Name of the loop hint.  Examples: "unroll", "vectorize".  In the
-  // "#pragma unroll" case, this is identical to PragmaNameLoc.
+  // "#pragma unroll" and "#pragma nounroll" cases, this is identical to
+  // PragmaNameLoc.
   IdentifierLoc *OptionLoc;
   // Identifier for the hint argument.  If null, then the hint has no argument
   // such as for "#pragma unroll".
index 5fb999d749c6cf4f9fa8a3cedce9bb25612a6fe6..20b87d92b7831ab30f9eeab54e30ab47fee4eb83 100644 (file)
@@ -227,6 +227,9 @@ void Parser::initializePragmaHandlers() {
 
   UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll"));
   PP.AddPragmaHandler(UnrollHintHandler.get());
+
+  NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
+  PP.AddPragmaHandler(NoUnrollHintHandler.get());
 }
 
 void Parser::resetPragmaHandlers() {
@@ -290,6 +293,9 @@ void Parser::resetPragmaHandlers() {
 
   PP.RemovePragmaHandler(UnrollHintHandler.get());
   UnrollHintHandler.reset();
+
+  PP.RemovePragmaHandler(NoUnrollHintHandler.get());
+  NoUnrollHintHandler.reset();
 }
 
 /// \brief Handle the annotation token produced for #pragma unused(...)
@@ -1908,29 +1914,36 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
 ///  #pragma unroll
 ///  #pragma unroll unroll-hint-value
 ///  #pragma unroll '(' unroll-hint-value ')'
+///  #pragma nounroll
 ///
 ///  unroll-hint-value:
 ///    constant-expression
 ///
-/// Loop unrolling hints are specified with '#pragma unroll'. '#pragma unroll'
-/// can take a numeric argument optionally contained in parentheses. With no
-/// argument the directive instructs llvm to try to unroll the loop
-/// completely. A positive integer argument can be specified to indicate the
-/// number of times the loop should be unrolled.  To maximize compatibility with
-/// other compilers the unroll count argument can be specified with or without
-/// parentheses.
+/// Loop unrolling hints can be specified with '#pragma unroll' or
+/// '#pragma nounroll'. '#pragma unroll' can take a numeric argument optionally
+/// contained in parentheses. With no argument the directive instructs llvm to
+/// try to unroll the loop completely. A positive integer argument can be
+/// specified to indicate the number of times the loop should be unrolled.  To
+/// maximize compatibility with other compilers the unroll count argument can be
+/// specified with or without parentheses.  Specifying, '#pragma nounroll'
+/// disables unrolling of the loop.
 void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
                                            PragmaIntroducerKind Introducer,
                                            Token &Tok) {
-  // Incoming token is "unroll" of "#pragma unroll".
+  // Incoming token is "unroll" for "#pragma unroll", or "nounroll" for
+  // "#pragma nounroll".
   Token PragmaName = Tok;
   PP.Lex(Tok);
   auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
   if (Tok.is(tok::eod)) {
-    // Unroll pragma without an argument.
+    // nounroll or unroll pragma without an argument.
     Info->PragmaName = PragmaName;
     Info->Option = PragmaName;
     Info->HasValue = false;
+  } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+        << "nounroll";
+    return;
   } else {
     // Unroll pragma with an argument: "#pragma unroll N" or
     // "#pragma unroll(N)".
index 603581d117be0a7e0922d40aa515e5b1ae3d5469..86c487b4cd9eedafb91ee4e6605c5b834ef0f4d9 100644 (file)
@@ -58,9 +58,11 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
       St->getStmtClass() != Stmt::ForStmtClass &&
       St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
       St->getStmtClass() != Stmt::WhileStmtClass) {
-    const char *Pragma = PragmaNameLoc->Ident->getName() == "unroll"
-                             ? "#pragma unroll"
-                             : "#pragma clang loop";
+    const char *Pragma =
+        llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
+            .Case("unroll", "#pragma unroll")
+            .Case("nounroll", "#pragma nounroll")
+            .Default("#pragma clang loop");
     S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
     return nullptr;
   }
@@ -70,6 +72,9 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
   if (PragmaNameLoc->Ident->getName() == "unroll") {
     Option = ValueLoc ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
     Spelling = LoopHintAttr::Pragma_unroll;
+  } else if (PragmaNameLoc->Ident->getName() == "nounroll") {
+    Option = LoopHintAttr::Unroll;
+    Spelling = LoopHintAttr::Pragma_nounroll;
   } else {
     Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
                  .Case("vectorize", LoopHintAttr::Vectorize)
@@ -86,6 +91,9 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
   if (Option == LoopHintAttr::Unroll &&
       Spelling == LoopHintAttr::Pragma_unroll) {
     ValueInt = 1;
+  } else if (Option == LoopHintAttr::Unroll &&
+             Spelling == LoopHintAttr::Pragma_nounroll) {
+    ValueInt = 0;
   } else if (Option == LoopHintAttr::Vectorize ||
              Option == LoopHintAttr::Interleave ||
              Option == LoopHintAttr::Unroll) {
index 9c3617e564c9269cf5f401f59338b1644249a675..05d17331c5521ef1f6ab32d835e2422ad4f08507 100644 (file)
@@ -17,7 +17,7 @@ void while_test(int *List, int Length) {
 void do_test(int *List, int Length) {
   int i = 0;
 
-#pragma unroll 16
+#pragma nounroll
   do {
     // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_2:.*]]
     List[i] = i * 2;
@@ -88,8 +88,8 @@ void template_test(double *List, int Length) {
 
 // CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata ![[UNROLL_FULL:.*]]}
 // CHECK: ![[UNROLL_FULL]] = metadata !{metadata !"llvm.loop.unroll.full"}
-// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata ![[UNROLL_16:.*]]}
-// CHECK: ![[UNROLL_16]] = metadata !{metadata !"llvm.loop.unroll.count", i32 16}
+// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata ![[UNROLL_DISABLE:.*]]}
+// CHECK: ![[UNROLL_DISABLE]] = metadata !{metadata !"llvm.loop.unroll.disable"}
 // CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata ![[UNROLL_8:.*]]}
 // CHECK: ![[UNROLL_8]] = metadata !{metadata !"llvm.loop.unroll.count", i32 8}
 // CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata ![[UNROLL_4:.*]]}
index 670830d912a7a28c0c45561773da497ab813aa71..3eb1f60d96b7ef84b38bcba6311691ae49481c26 100644 (file)
@@ -15,6 +15,7 @@
 // CHECK: #pragma clang loop vectorize(disable)
 // CHECK: #pragma unroll
 // CHECK: #pragma unroll (32)
+// CHECK: #pragma nounroll
 
 #ifndef HEADER
 #define HEADER
@@ -71,8 +72,16 @@ public:
       i++;
     }
   }
-};
 
+  inline void run6(int *List, int Length) {
+    int i = 0;
+#pragma nounroll
+    while (i - 3 < Length) {
+      List[i] = i;
+      i++;
+    }
+  }
+};
 #else
 
 void test() {
@@ -85,6 +94,7 @@ void test() {
   pt.run3(List, 100);
   pt.run4(List, 100);
   pt.run5(List, 100);
+  pt.run6(List, 100);
 }
 
 #endif
index 1fa23ef4673b7a59d50cc237ee1f273814dc3710..5d28dae2d84dda4325b49757823a0e0c90d3dccb 100644 (file)
@@ -11,6 +11,11 @@ void test(int *List, int Length) {
     List[i] = i;
   }
 
+#pragma nounroll
+  while (i < Length) {
+    List[i] = i;
+  }
+
 #pragma unroll 4
   while (i - 1 < Length) {
     List[i] = i;
@@ -28,6 +33,11 @@ void test(int *List, int Length) {
     List[i] = i;
   }
 
+/* expected-warning {{extra tokens at end of '#pragma nounroll'}} */ #pragma nounroll 1
+  while (i-7 < Length) {
+    List[i] = i;
+  }
+
 /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(()
 /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll -
 /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(0)
@@ -42,6 +52,8 @@ void test(int *List, int Length) {
 /* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll'}} */ int j = Length;
 #pragma unroll 4
 /* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll'}} */ int k = Length;
+#pragma nounroll
+/* expected-error {{expected a for, while, or do-while loop to follow '#pragma nounroll'}} */ int l = Length;
 
 /* expected-error {{incompatible directives 'unroll(disable)' and '#pragma unroll(4)'}} */ #pragma unroll 4
 #pragma clang loop unroll(disable)
@@ -61,6 +73,18 @@ void test(int *List, int Length) {
     List[i] = i;
   }
 
+/* expected-error {{incompatible directives '#pragma nounroll' and 'unroll_count(4)'}} */ #pragma clang loop unroll_count(4)
+#pragma nounroll
+  while (i-12 < Length) {
+    List[i] = i;
+  }
+
+/* expected-error {{duplicate directives '#pragma nounroll' and '#pragma nounroll'}} */ #pragma nounroll
+#pragma nounroll
+  while (i-13 < Length) {
+    List[i] = i;
+  }
+
 /* expected-error {{duplicate directives '#pragma unroll' and '#pragma unroll'}} */ #pragma unroll
 #pragma unroll
   while (i-14 < Length) {