Add support for #pragma nounroll.
llvm-svn: 213885
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f17a1a4..6544a3d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -111,12 +111,13 @@
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
---------------------------
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 708f4f4..0af6f97 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1791,7 +1791,8 @@
/// 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 @@
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 @@
std::string DiagnosticName;
llvm::raw_string_ostream OS(DiagnosticName);
unsigned SpellingIndex = getSpellingListIndex();
- if (SpellingIndex == Pragma_unroll && option == Unroll)
+ if (SpellingIndex == Pragma_nounroll)
+ OS << "#pragma nounroll";
+ else if (SpellingIndex == Pragma_unroll) {
OS << "#pragma unroll";
- else if (SpellingIndex == Pragma_unroll && option == UnrollCount) {
- OS << "#pragma unroll";
- printArgument(OS);
+ if (option == UnrollCount)
+ printArgument(OS);
} else {
assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
OS << getOptionName(option);
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 34dd1b0..b04afa7 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -1065,11 +1065,11 @@
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 @@
...
}
+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.
}];
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 5b5f8eb..3dccee7 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -164,6 +164,7 @@
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;
diff --git a/clang/include/clang/Sema/LoopHint.h b/clang/include/clang/Sema/LoopHint.h
index d4b985d..a0bc455 100644
--- a/clang/include/clang/Sema/LoopHint.h
+++ b/clang/include/clang/Sema/LoopHint.h
@@ -26,7 +26,8 @@
// 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".
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 5fb999d..20b87d9 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -227,6 +227,9 @@
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 @@
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 @@
/// #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)".
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 603581d..86c487b 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -58,9 +58,11 @@
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 @@
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 @@
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) {
diff --git a/clang/test/CodeGen/pragma-unroll.cpp b/clang/test/CodeGen/pragma-unroll.cpp
index 9c3617e..05d1733 100644
--- a/clang/test/CodeGen/pragma-unroll.cpp
+++ b/clang/test/CodeGen/pragma-unroll.cpp
@@ -17,7 +17,7 @@
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 @@
// 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:.*]]}
diff --git a/clang/test/PCH/pragma-loop.cpp b/clang/test/PCH/pragma-loop.cpp
index 670830d..3eb1f60 100644
--- a/clang/test/PCH/pragma-loop.cpp
+++ b/clang/test/PCH/pragma-loop.cpp
@@ -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 @@
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 @@
pt.run3(List, 100);
pt.run4(List, 100);
pt.run5(List, 100);
+ pt.run6(List, 100);
}
#endif
diff --git a/clang/test/Parser/pragma-unroll.cpp b/clang/test/Parser/pragma-unroll.cpp
index 1fa23ef..5d28dae 100644
--- a/clang/test/Parser/pragma-unroll.cpp
+++ b/clang/test/Parser/pragma-unroll.cpp
@@ -11,6 +11,11 @@
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 @@
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 @@
/* 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 @@
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) {