<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div>Loop hints can also be specified in a single line.</div><div><br></div><div>#pragma clang loop vectorize(enable), interleave(enable), unroll(enable)</div><div><br></div><div>But if we take out the unroll loop hint then programmers everywhere will need to write two directives. It would be unfortunate if that happened.</div><div><br></div><div>Also, I’m sorry but I think there will be a number of collisions between this patch and my own for parsing for constant expressions as a loop hint argument. Can the CUDA pragma unroll argument be a constant expression as well?</div><div><br></div><div>Tyler</div><div><br></div><div>On Jul 7, 2014, at 5:23 PM, Hal Finkel <<a href="mailto:hfinkel@anl.gov">hfinkel@anl.gov</a>> wrote:</div><div><br class="Apple-interchange-newline"><blockquote type="cite"><div style="font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">----- Original Message -----<br><blockquote type="cite">From: "Mark Heffernan" <<a href="mailto:meheff@google.com">meheff@google.com</a>><br>To: "Aaron Ballman" <<a href="mailto:aaron.ballman@gmail.com">aaron.ballman@gmail.com</a>><br>Cc:<span class="Apple-converted-space"> </span><a href="mailto:reviews+D4297+public+26d6caf125d429ed@reviews.llvm.org">reviews+D4297+public+26d6caf125d429ed@reviews.llvm.org</a>, "Eli Bendersky" <<a href="mailto:eliben@google.com">eliben@google.com</a>>, "Tyler Nowicki"<br><<a href="mailto:tnowicki@apple.com">tnowicki@apple.com</a>>, "Peter Collingbourne" <<a href="mailto:peter@pcc.me.uk">peter@pcc.me.uk</a>>, "Hal Finkel" <<a href="mailto:hfinkel@anl.gov">hfinkel@anl.gov</a>>, "llvm cfe"<br><<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a>>, "Richard Smith" <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>>, "Chandler Carruth" <<a href="mailto:chandlerc@gmail.com">chandlerc@gmail.com</a>><br>Sent: Monday, July 7, 2014 5:52:33 PM<br>Subject: Re: [PATCH] Add support for unroll pragma<br><br><br><br><br>On Wed, Jul 2, 2014 at 7:54 AM, Aaron Ballman <<br><a href="mailto:aaron.ballman@gmail.com">aaron.ballman@gmail.com</a> > wrote:<br><br><br><br>I may have led you slightly astray on this point. I believe the<br>consensus wound up being that having two different syntaxes for the<br>same thing was okay, and so #pragma loop unroll[_count] should<br>remain.<br>Richard, Chandler, do I have that correct?<br><br><br><br>I think Richard and Chandler (correct me if I'm wrong) were referring<br>to supporting the following "#pragma unroll" syntaxes for<br>compatibility purposes:<br><br><br>#pragma unroll // CUDA, intel, and IBM<br>#pragma unroll N // CUDA<br>#pragma unroll(N) // intel and IBM<br><br><br>However, not much has been said about, in addition, continuing to<br>support the newly added form in the clang pragma namespace:<br><br><br>#pragma clang loop unroll(...) unroll_count(...)<br><br><br>Since you initially voiced objection to having two forms with<br>identical semantics, I've come around and agree. That is, I think we<br>should drop support for the "#pragma clang loop unroll" syntax and<br>only support the "#pragma unroll" one.<br></blockquote><br>I strongly disagree. clang now has a single self-consistent syntax for loop optimization hints. This includes vectorization, interleaving and unrolling (and could include other things in the future). This is not a bad thing. For compatibility with other compilers we might also support other syntaxes, but having to tell users that #pragma clang loop bla is the way to provide loop optimization hints, except for unrolling which has its own special syntax, will only cause confusion.<br><br>-Hal<br><br><blockquote type="cite"><br><br>Mark<br><br><br><br><br>Some comments:<br><br><blockquote type="cite">Index: docs/LanguageExtensions.rst<br>===================================================================<br>--- docs/LanguageExtensions.rst<br>+++ docs/LanguageExtensions.rst<br>@@ -1767,15 +1767,10 @@<br><br>Extensions for loop hint optimizations<br>======================================<br>-<br>The ``#pragma clang loop`` directive is used to specify hints for<br>optimizing the<br>subsequent for, while, do-while, or c++11 range-based for loop. The<br>directive<br>-provides options for vectorization, interleaving, and unrolling.<br>Loop hints can<br>-be specified before any loop and will be ignored if the<br>optimization is not safe<br>-to apply.<br>-<br>-Vectorization and Interleaving<br>-------------------------------<br>+provides options for vectorization and interleaving. Loop hints<br>can be specified<br>+before any loop and will be ignored if the optimization is not<br>safe to apply.<br><br>A vectorized loop performs multiple iterations of the original loop<br>in parallel using vector instructions. The instruction set of the<br>target<br>@@ -1818,43 +1813,6 @@<br>Specifying a width/count of 1 disables the optimization, and is<br>equivalent to<br>``vectorize(disable)`` or ``interleave(disable)``.<br><br>-Loop Unrolling<br>---------------<br>-<br>-Unrolling a loop reduces the loop control overhead and exposes<br>more<br>-opportunities for ILP. Loops can be fully or partially unrolled.<br>Full unrolling<br>-eliminates the loop and replaces it with an enumerated sequence of<br>loop<br>-iterations. Full unrolling is only possible if the loop trip count<br>is known at<br>-compile time. Partial unrolling replicates the loop body within<br>the loop and<br>-reduces the trip count.<br>-<br>-If ``unroll(enable)`` is specified the unroller will attempt to<br>fully unroll the<br>-loop if the trip count is known at compile time. If the loop count<br>is not known<br>-or the fully unrolled code size is greater than the limit<br>specified by the<br>-`-pragma-unroll-threshold` command line option the loop will be<br>partially<br>-unrolled subject to the same limit.<br>-<br>-.. code-block:: c++<br>-<br>- #pragma clang loop unroll(enable)<br>- for(...) {<br>- ...<br>- }<br>-<br>-The unroll count can be specified explicitly with<br>``unroll_count(_value_)`` where<br>-_value_ is a positive integer. If this value is greater than the<br>trip count the<br>-loop will be fully unrolled. Otherwise the loop is partially<br>unrolled subject<br>-to the `-pragma-unroll-threshold` limit.<br>-<br>-.. code-block:: c++<br>-<br>- #pragma clang loop unroll_count(8)<br>- for(...) {<br>- ...<br>- }<br>-<br>-Unrolling of a loop can be prevented by specifying<br>``unroll(disable)``.<br>-<br>Additional Information<br>----------------------<br><br>Index: docs/ReleaseNotes.rst<br>===================================================================<br>--- docs/ReleaseNotes.rst<br>+++ docs/ReleaseNotes.rst<br>@@ -101,10 +101,16 @@<br>-----------------------<br><br>Loop optimization hints can be specified using the new `#pragma<br>clang loop`<br>-directive just prior to the desired loop. The directive allows<br>vectorization,<br>-interleaving, and unrolling to be enabled or disabled. Vector<br>width as well<br>-as interleave and unrolling count can be manually specified. See<br>language<br>-extensions for details.<br>+directive just prior to the desired loop. The directive allows<br>vectorization and<br>+interleaving to be enabled or disabled. Vector width and<br>interleave count can be<br>+manually specified. See language extensions for details.<br>+<br>+Clang now supports the `#pragma unroll` directive to specify loop<br>unrolling<br>+optimization hints. Placed just prior to the desired loop,<br>`#pragma unroll`<br>+directs the loop unroller to attempt to fully unroll the loop. The<br>pragma may<br>+also be specified with a positive integer parameter indicating the<br>desired<br>+unroll count: `#pragma unroll N`. The unroll count parameter can<br>be optionally<br>+enclosed in parentheses.<br><br>C Language Changes in Clang<br>---------------------------<br>Index: include/clang/Basic/Attr.td<br>===================================================================<br>--- include/clang/Basic/Attr.td<br>+++ include/clang/Basic/Attr.td<br>@@ -1772,25 +1772,28 @@<br>/// unroll: unroll loop if 'value != 0'.<br>/// unroll_count: unrolls loop 'value' times.<br><br>- let Spellings = [Pragma<"clang", "loop">];<br>+ let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">];<br><br>/// State of the loop optimization specified by the spelling.<br>let Args = [EnumArgument<"Option", "OptionType",<br>["vectorize", "vectorize_width", "interleave", "interleave_count",<br>"unroll", "unroll_count"],<br>["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",<br>"Unroll", "UnrollCount"]>,<br>- DefaultIntArgument<"Value", 1>];<br>+ DefaultIntArgument<"Value", 1>,<br>+ DefaultBoolArgument<"ValueInParens", 0>];<br></blockquote><br>Hmm... we usually want the arguments to match the syntax of the<br>attribute unless the argument is really key to the semantics.<br>ValueInParens doesn't really fit that model. I would prefer for this<br>to be an AdditionalMembers entry.<br><br><blockquote type="cite"><br>let AdditionalMembers = [{<br>static StringRef getOptionName(int Option) {<br>switch(Option) {<br>case Vectorize: return "vectorize";<br>case VectorizeWidth: return "vectorize_width";<br>case Interleave: return "interleave";<br>case InterleaveCount: return "interleave_count";<br>+ // Unroll and UnrollCount attributes are added for '#pragma<br>unroll'<br>+ // directives which share the option name 'unroll'.<br>case Unroll: return "unroll";<br>- case UnrollCount: return "unroll_count";<br>+ case UnrollCount: return "unroll";<br>}<br>llvm_unreachable("Unhandled LoopHint option.");<br>}<br>@@ -1802,15 +1805,29 @@<br>}<br><br>void printPrettyPragma(raw_ostream &OS, const PrintingPolicy<br>&Policy) const {<br>+ if (option == Unroll) {<br>+ // "#pragma unroll". String "unroll" is already emitted as the<br>+ // pragma name.<br>+ OS << "\n";<br>+ return;<br>+ }<br>+ if (option == UnrollCount) {<br>+ // "#pragma unroll N" or "#pragma unroll(N)".<br>+ if (ValueInParens)<br>+ OS << "(" << value << ")";<br>+ else<br>+ OS << value;<br>+ OS << "\n";<br>+ return;<br>+ }<br>OS << getOptionName(option) << "(";<br>- if (option == VectorizeWidth || option == InterleaveCount ||<br>- option == UnrollCount)<br>+ if (option == VectorizeWidth || option == InterleaveCount)<br>OS << value;<br>else<br>OS << getValueName(value);<br>OS << ")\n";<br>}<br>}];<br><br>- let Documentation = [LoopHintDocs];<br>+ let Documentation = [LoopHintDocs, UnrollHintDocs];<br>}<br>Index: include/clang/Basic/AttrDocs.td<br>===================================================================<br>--- include/clang/Basic/AttrDocs.td<br>+++ include/clang/Basic/AttrDocs.td<br>@@ -1024,3 +1024,45 @@<br>for details.<br>}];<br>}<br>+<br>+def UnrollHintDocs : Documentation {<br>+ let Category = DocCatStmt;<br>+ let Content = [{<br>+Loop unrolling optimization hints can be specified with the<br>``#pragma unroll``<br>+directive. The pragma is placed immediately before a for, while,<br>do-while, or<br>+c++11 range-based for loop. The pragma takes an optional parameter<br>which must<br>+be a positive integer.<br>+<br>+.. code-block:: c++<br>+<br>+ #pragma unroll<br>+ for (...) {<br>+ ...<br>+ }<br>+<br>+If ``#pragma unroll`` is specified without a parameter the loop<br>unroller will<br>+attempt to fully unroll the loop if the trip count is known at<br>compile time. If<br>+the loop count is not known or the fully unrolled code size is<br>greater than the<br>+limit specified by the ``-pragma-unroll-threshold`` command-line<br>option the loop<br>+will be partially unrolled subject to the same limit.<br>+<br>+.. code-block:: c++<br>+<br>+ #pragma unroll 16<br>+ for (...) {<br>+ ...<br>+ }<br>+<br>+ #pragma unroll(16)<br>+ for (...) {<br>+ ...<br>+ }<br>+<br>+Specifying ``#pragma unroll _value_`` where _value_ is a positive<br>integer directs<br>+the unroller to unroll the loop _value_ times. The value may be<br>optionally<br>+enclosed in parentheses such as ``#pragma unroll(_value_)``. If<br>this value is<br>+greater than the trip count the loop will be fully unrolled.<br>Otherwise the loop<br>+is partially unrolled subject to the ``-pragma-unroll-threshold``<br>limit.<br>+ }];<br>+}<br>+<br>Index: include/clang/Basic/DiagnosticParseKinds.td<br>===================================================================<br>--- include/clang/Basic/DiagnosticParseKinds.td<br>+++ include/clang/Basic/DiagnosticParseKinds.td<br>@@ -912,7 +912,7 @@<br>"%select{invalid|missing}0 option%select{ %1|}0; expected<br>vectorize, "<br>"vectorize_width, interleave, interleave_count, unroll, or<br>unroll_count">;<br>def err_pragma_loop_missing_argument : Error<<br>- "missing argument to loop pragma %0">;<br>+ "missing argument to %0 pragma">;<br></blockquote><br>The name of this diagnostic should probably change given how generic<br>the text now is.<br><br><blockquote type="cite">} // end of Parse Issue category.<br><br>let CategoryName = "Modules Issue" in {<br>Index: include/clang/Basic/DiagnosticSemaKinds.td<br>===================================================================<br>--- include/clang/Basic/DiagnosticSemaKinds.td<br>+++ include/clang/Basic/DiagnosticSemaKinds.td<br>@@ -546,11 +546,12 @@<br>"invalid argument; expected a positive integer value">;<br>def err_pragma_loop_invalid_keyword : Error<<br>"invalid argument; expected 'enable' or 'disable'">;<br>-def err_pragma_loop_compatibility : Error<<br>- "%select{incompatible|duplicate}0 directives '%1(%2)' and<br>'%3(%4)'">;<br>+def err_pragma_loop_duplicate : Error<<br>+ "duplicate '%0' directives">;<br>+def err_pragma_loop_incompatible : Error<<br>+ "incompatible directives '%0(%1)' and '%2(%3)'">;<br></blockquote><br>Why was this split into two errors?<br><br><blockquote type="cite">def err_pragma_loop_precedes_nonloop : Error<<br>- "expected a for, while, or do-while loop to follow the '#pragma<br>clang loop' "<br>- "directive">;<br>+ "expected a for, while, or do-while loop to follow the '%0'<br>pragma">;<br><br>/// Objective-C parser diagnostics<br>def err_duplicate_class_def : Error<<br>Index: include/clang/Parse/Parser.h<br>===================================================================<br>--- include/clang/Parse/Parser.h<br>+++ include/clang/Parse/Parser.h<br>@@ -163,6 +163,7 @@<br>std::unique_ptr<PragmaHandler> MSSection;<br>std::unique_ptr<PragmaHandler> OptimizeHandler;<br>std::unique_ptr<PragmaHandler> LoopHintHandler;<br>+ std::unique_ptr<PragmaHandler> UnrollHintHandler;<br><br>std::unique_ptr<CommentHandler> CommentSemaHandler;<br><br>@@ -522,7 +523,7 @@<br>StmtResult HandlePragmaCaptured();<br><br>/// \brief Handle the annotation token produced for<br>- /// #pragma vectorize...<br>+ /// #pragma clang loop...<br>LoopHint HandlePragmaLoopHint();<br><br>/// GetLookAheadToken - This peeks ahead N tokens and returns that<br>token<br>Index: include/clang/Sema/LoopHint.h<br>===================================================================<br>--- include/clang/Sema/LoopHint.h<br>+++ include/clang/Sema/LoopHint.h<br>@@ -17,13 +17,26 @@<br><br>namespace clang {<br><br>-/// \brief Loop hint specified by a pragma loop directive.<br>+/// \brief Loop optimization hint for loop and unroll pragmas.<br>struct LoopHint {<br>+ // Source range of the directive.<br>SourceRange Range;<br>- Expr *ValueExpr;<br>- IdentifierLoc *LoopLoc;<br>- IdentifierLoc *ValueLoc;<br>+ // Identifier corresponding to the name of the pragma. "loop" for<br>+ // "#pragma clang loop" directives and "unroll" for "#pragma<br>unroll"<br>+ // hints.<br>+ IdentifierLoc *PragmaNameLoc;<br>+ // Name of the loop hint. Examples: "unroll", "vectorize". In the<br>unroll<br>+ // case, this is identical to PragmaNameLoc.<br>IdentifierLoc *OptionLoc;<br>+ // Identifier for the hint argument. If null, then the hint has<br>no argument<br>+ // (for example, "#pragma unroll").<br>+ IdentifierLoc *ValueLoc;<br>+ // If the hint argument exists and is contained in parentheses<br>(for example,<br>+ // "vectorize_width(8)") this contains the identifier for the<br>closing<br>+ // parentheses. Value is null otherwise.<br>+ IdentifierLoc *CloseParenLoc;<br>+ // Expression for the hint argument if it exists, null otherwise.<br>+ Expr *ValueExpr;<br>};<br><br>} // end namespace clang<br>Index: lib/Parse/ParsePragma.cpp<br>===================================================================<br>--- lib/Parse/ParsePragma.cpp<br>+++ lib/Parse/ParsePragma.cpp<br>@@ -148,6 +148,12 @@<br>Token &FirstToken) override;<br>};<br><br>+struct PragmaUnrollHintHandler : public PragmaHandler {<br>+ PragmaUnrollHintHandler() : PragmaHandler("unroll") {}<br>+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind<br>Introducer,<br>+ Token &FirstToken) override;<br>+};<br>+<br>} // end namespace<br><br>void Parser::initializePragmaHandlers() {<br>@@ -218,6 +224,9 @@<br><br>LoopHintHandler.reset(new PragmaLoopHintHandler());<br>PP.AddPragmaHandler("clang", LoopHintHandler.get());<br>+<br>+ UnrollHintHandler.reset(new PragmaUnrollHintHandler());<br>+ PP.AddPragmaHandler(UnrollHintHandler.get());<br>}<br><br>void Parser::resetPragmaHandlers() {<br>@@ -278,6 +287,9 @@<br><br>PP.RemovePragmaHandler("clang", LoopHintHandler.get());<br>LoopHintHandler.reset();<br>+<br>+ PP.RemovePragmaHandler(UnrollHintHandler.get());<br>+ UnrollHintHandler.reset();<br>}<br><br>/// \brief Handle the annotation token produced for #pragma<br>unused(...)<br>@@ -600,35 +612,54 @@<br>}<br><br>struct PragmaLoopHintInfo {<br>- Token Loop;<br>- Token Value;<br>+ Token PragmaName;<br>Token Option;<br>+ Token Value;<br>+ Token CloseParen;<br>+ bool HasValue;<br>+ bool ValueInParens;<br>};<br><br>LoopHint Parser::HandlePragmaLoopHint() {<br>assert(<a href="http://Tok.is">Tok.is</a>(tok::annot_pragma_loop_hint));<br>PragmaLoopHintInfo *Info =<br>static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());<br><br>LoopHint Hint;<br>- Hint.LoopLoc =<br>- IdentifierLoc::create(Actions.Context, Info->Loop.getLocation(),<br>- Info->Loop.getIdentifierInfo());<br>+ Hint.PragmaNameLoc =<br>+ IdentifierLoc::create(Actions.Context,<br>Info->PragmaName.getLocation(),<br>+ Info->PragmaName.getIdentifierInfo());<br>Hint.OptionLoc =<br>IdentifierLoc::create(Actions.Context, Info->Option.getLocation(),<br>Info->Option.getIdentifierInfo());<br>- Hint.ValueLoc =<br>- IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),<br>- Info->Value.getIdentifierInfo());<br>- Hint.Range =<br>- SourceRange(Info->Option.getLocation(),<br>Info->Value.getLocation());<br>-<br>- // FIXME: We should allow non-type template parameters for the<br>loop hint<br>- // value. See bug report #19610<br>- if (Info-><a href="http://Value.is">Value.is</a>(tok::numeric_constant))<br>- Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();<br>- else<br>+ if (Info->HasValue) {<br>+ if (Info->ValueInParens) {<br>+ Hint.Range = SourceRange(Info->Option.getLocation(),<br>+ Info->CloseParen.getLocation());<br>+ Hint.CloseParenLoc =<br>+ IdentifierLoc::create(Actions.Context,<br>Info->CloseParen.getLocation(),<br>+ Info->CloseParen.getIdentifierInfo());<br>+ } else {<br>+ Hint.Range =<br>+ SourceRange(Info->Option.getLocation(),<br>Info->Value.getLocation());<br>+ Hint.CloseParenLoc = nullptr;<br>+ }<br>+ Hint.ValueLoc =<br>+ IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),<br>+ Info->Value.getIdentifierInfo());<br>+<br>+ // FIXME: We should allow non-type template parameters for the<br>loop hint<br>+ // value. See bug report #19610<br>+ if (Info-><a href="http://Value.is">Value.is</a>(tok::numeric_constant))<br>+ Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();<br>+ else<br>+ Hint.ValueExpr = nullptr;<br>+ } else {<br>+ Hint.Range = SourceRange(Info->PragmaName.getLocation());<br>+ Hint.ValueLoc = nullptr;<br>Hint.ValueExpr = nullptr;<br>+ Hint.CloseParenLoc = nullptr;<br>+ }<br><br>return Hint;<br>}<br>@@ -1630,6 +1661,47 @@<br>Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());<br>}<br><br>+// Parses loop or unroll pragma hint value and fills in Info.<br>+bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token<br>&PragmaName,<br>+ Token &Option, PragmaLoopHintInfo &Info) {<br>+ bool ValueInParens;<br></blockquote><br>Could simply initialize to <a href="http://Tok.is">Tok.is</a>(tok::l_paren), then not need the<br>else clause at all.<br><br><blockquote type="cite">+ if (<a href="http://Tok.is">Tok.is</a>(tok::l_paren)) {<br>+ ValueInParens = true;<br>+ PP.Lex(Tok);<br>+ if (<a href="http://Tok.is">Tok.is</a>(tok::r_paren)) {<br>+ // Nothing between the parentheses.<br>+ PP.Diag(Tok.getLocation(),<br>diag::err_pragma_loop_missing_argument)<br>+ << PragmaName.getIdentifierInfo();<br>+ return true;<br>+ }<br>+ } else {<br>+ ValueInParens = false;<br>+ }<br>+<br>+ // FIXME: Value should be stored and parsed as a constant<br>expression.<br>+ Token Value = Tok;<br>+<br>+ Token CloseParen;<br>+ if (ValueInParens) {<br>+ PP.Lex(Tok);<br>+ if (Tok.isNot(tok::r_paren)) {<br>+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;<br>+ return true;<br>+ }<br>+ CloseParen = Tok;<br>+ }<br>+<br>+ Info.PragmaName = PragmaName;<br>+ Info.Option = Option;<br>+ Info.Value = Value;<br>+ Info.HasValue = true;<br>+ Info.ValueInParens = ValueInParens;<br>+ if (Info.ValueInParens)<br>+ Info.CloseParen = CloseParen;<br>+<br>+ return false;<br>+}<br>+<br>/// \brief Handle the \#pragma clang loop directive.<br>/// #pragma clang 'loop' loop-hints<br>///<br>@@ -1639,10 +1711,8 @@<br>/// loop-hint:<br>/// 'vectorize' '(' loop-hint-keyword ')'<br>/// 'interleave' '(' loop-hint-keyword ')'<br>-/// 'unroll' '(' loop-hint-keyword ')'<br>/// 'vectorize_width' '(' loop-hint-value ')'<br>/// 'interleave_count' '(' loop-hint-value ')'<br>-/// 'unroll_count' '(' loop-hint-value ')'<br>///<br>/// loop-hint-keyword:<br>/// 'enable'<br>@@ -1660,18 +1730,11 @@<br>/// value of 1 effectively disables vectorization/interleaving,<br>even if it is<br>/// possible and profitable, and 0 is invalid. The loop vectorizer<br>currently<br>/// only works on inner loops.<br>-///<br>-/// The unroll and unroll_count directives control the<br>concatenation<br>-/// unroller. Specifying unroll(enable) instructs llvm to try to<br>-/// unroll the loop completely, and unroll(disable) disables<br>unrolling<br>-/// for the loop. Specifying unroll_count(_value_) instructs llvm<br>to<br>-/// try to unroll the loop the number of times indicated by the<br>value.<br>-/// If unroll(enable) and unroll_count are both specified only<br>-/// unroll_count takes effect.<br>void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,<br>PragmaIntroducerKind Introducer,<br>Token &Tok) {<br>- Token Loop = Tok;<br>+ // Incoming token is "loop" from "#pragma clang loop".<br>+ Token PragmaName = Tok;<br>SmallVector<Token, 1> TokenList;<br><br>// Lex the optimization option and verify it is an identifier.<br>@@ -1687,59 +1750,37 @@<br>IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();<br><br>bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName())<br>- .Case("vectorize", true)<br>- .Case("interleave", true)<br>- .Case("unroll", true)<br>- .Case("vectorize_width", true)<br>- .Case("interleave_count", true)<br>- .Case("unroll_count", true)<br>- .Default(false);<br>+ .Case("vectorize", true)<br>+ .Case("interleave", true)<br>+ .Case("vectorize_width", true)<br>+ .Case("interleave_count", true)<br>+ .Default(false);<br>if (!OptionValid) {<br>PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)<br><< /*MissingOption=*/false << OptionInfo;<br>return;<br>}<br><br>- // Read '('<br>- PP.Lex(Tok);<br>- if (Tok.isNot(tok::l_paren)) {<br>- PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;<br>- return;<br>- }<br>-<br>- // FIXME: All tokens between '(' and ')' should be stored and<br>parsed as a<br>- // constant expression.<br>+ auto *Info = new (PP.getPreprocessorAllocator())<br>PragmaLoopHintInfo;<br>PP.Lex(Tok);<br>- if (<a href="http://Tok.is">Tok.is</a>(tok::r_paren)) {<br>- // Nothing between the parentheses.<br>- PP.Diag(Tok.getLocation(),<br>diag::err_pragma_loop_missing_argument)<br>- << OptionInfo;<br>+ if (ParseLoopHintValue(PP, Tok, PragmaName, Option, *Info))<br>return;<br>- }<br>- Token Value = Tok;<br><br>- // Read ')'<br>- PP.Lex(Tok);<br>- if (Tok.isNot(tok::r_paren)) {<br>- PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;<br>+ if (!Info->ValueInParens) {<br>+ PP.Diag(Info->Value.getLocation(), diag::err_expected) <<<br>tok::l_paren;<br>return;<br>}<br><br>- // Get next optimization option.<br>- PP.Lex(Tok);<br>-<br>- auto *Info = new (PP.getPreprocessorAllocator())<br>PragmaLoopHintInfo;<br>- Info->Loop = Loop;<br>- Info->Option = Option;<br>- Info->Value = Value;<br>-<br>- // Generate the vectorization hint token.<br>+ // Generate the loop hint token.<br>Token LoopHintTok;<br>LoopHintTok.startToken();<br>LoopHintTok.setKind(tok::annot_pragma_loop_hint);<br>- LoopHintTok.setLocation(Loop.getLocation());<br>+ LoopHintTok.setLocation(PragmaName.getLocation());<br>LoopHintTok.setAnnotationValue(static_cast<void *>(Info));<br>TokenList.push_back(LoopHintTok);<br>+<br>+ // Get next optimization option.<br>+ PP.Lex(Tok);<br>}<br><br>if (Tok.isNot(tok::eod)) {<br>@@ -1755,3 +1796,54 @@<br>/*DisableMacroExpansion=*/false,<br>/*OwnsTokens=*/true);<br>}<br>+<br>+/// \brief Handle the loop unroll optimization pragmas.<br>+/// #pragma unroll<br>+/// #pragma unroll unroll-hint-value<br>+/// #pragma unroll '(' unroll-hint-value ')'<br>+///<br>+/// unroll-hint-value:<br>+/// constant-expression<br>+///<br>+/// Loop unrolling hints are specified with '#pragma unroll' and<br>can include a<br>+/// numeric argument optionally contained in parentheses. With no<br>argument the<br>+/// directive instructs llvm to try to unroll the loop completely.<br>A positive<br>+/// integer argument can be specified to indicate the number of<br>times the loop<br>+/// should be unrolled. To maximize compatibility with other<br>compilers the<br>+/// unroll count argument can be specified with or without<br>parentheses.<br>+void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,<br>+ PragmaIntroducerKind Introducer,<br>+ Token &Tok) {<br>+ // Incoming token is "unroll" from "#pragma unroll".<br>+ Token PragmaName = Tok;<br>+ PP.Lex(Tok);<br>+ auto *Info = new (PP.getPreprocessorAllocator())<br>PragmaLoopHintInfo;<br>+ if (<a href="http://Tok.is">Tok.is</a>(tok::eod)) {<br>+ // Bare unroll pragma: "#pragma unroll".<br>+ Info->PragmaName = PragmaName;<br>+ Info->Option = PragmaName;<br>+ Info->HasValue = false;<br>+ Info->ValueInParens = false;<br>+ } else {<br>+ // Unroll pragma with an argument: "#pragma unroll N" or<br>+ // "#pragma unroll(N)".<br>+ if (ParseLoopHintValue(PP, Tok, PragmaName, PragmaName, *Info))<br>+ return;<br>+ PP.Lex(Tok);<br>+<br>+ if (Tok.isNot(tok::eod)) {<br>+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)<br>+ << "unroll";<br>+ return;<br>+ }<br>+ }<br>+<br>+ // Generate the hint token.<br>+ Token *TokenArray = new Token[1];<br>+ TokenArray[0].startToken();<br>+ TokenArray[0].setKind(tok::annot_pragma_loop_hint);<br>+ TokenArray[0].setLocation(PragmaName.getLocation());<br>+ TokenArray[0].setAnnotationValue(static_cast<void *>(Info));<br>+ PP.EnterTokenStream(TokenArray, 1,<br>/*DisableMacroExpansion=*/false,<br>+ /*OwnsTokens=*/true);<br>+}<br>Index: lib/Parse/ParseStmt.cpp<br>===================================================================<br>--- lib/Parse/ParseStmt.cpp<br>+++ lib/Parse/ParseStmt.cpp<br>@@ -1804,18 +1804,16 @@<br>// Create temporary attribute list.<br>ParsedAttributesWithRange TempAttrs(AttrFactory);<br><br>- // Get vectorize hints and consume annotated token.<br>+ // Get loop hints and consume annotated token.<br>while (<a href="http://Tok.is">Tok.is</a>(tok::annot_pragma_loop_hint)) {<br>LoopHint Hint = HandlePragmaLoopHint();<br>ConsumeToken();<br><br>- if (!Hint.LoopLoc || !Hint.OptionLoc || !Hint.ValueLoc)<br>- continue;<br>-<br>- ArgsUnion ArgHints[] = {Hint.OptionLoc, Hint.ValueLoc,<br>- ArgsUnion(Hint.ValueExpr)};<br>- TempAttrs.addNew(Hint.LoopLoc->Ident, Hint.Range, nullptr,<br>- Hint.LoopLoc->Loc, ArgHints, 3, AttributeList::AS_Pragma);<br>+ ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc,<br>Hint.ValueLoc,<br>+ Hint.CloseParenLoc, ArgsUnion(Hint.ValueExpr)};<br>+ TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,<br>+ Hint.PragmaNameLoc->Loc, ArgHints, 5,<br>+ AttributeList::AS_Pragma);<br>}<br><br>// Get the next statement.<br>Index: lib/Sema/SemaStmtAttr.cpp<br>===================================================================<br>--- lib/Sema/SemaStmtAttr.cpp<br>+++ lib/Sema/SemaStmtAttr.cpp<br>@@ -45,35 +45,45 @@<br><br>static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const<br>AttributeList &A,<br>SourceRange) {<br>+ IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);<br>+ IdentifierLoc *OptionLoc = A.getArgAsIdent(1);<br>+ IdentifierInfo *OptionInfo = OptionLoc->Ident;<br>+ IdentifierLoc *ValueLoc = A.getArgAsIdent(2);<br>+ IdentifierInfo *ValueInfo = ValueLoc ? ValueLoc->Ident : nullptr;<br>+ IdentifierLoc *CloseParenLoc = A.getArgAsIdent(3);<br>+ Expr *ValueExpr = A.getArgAsExpr(4);<br>+<br>+ assert(OptionInfo && "Attribute must have valid option info.");<br>+<br>if (St->getStmtClass() != Stmt::DoStmtClass &&<br>St->getStmtClass() != Stmt::ForStmtClass &&<br>St->getStmtClass() != Stmt::CXXForRangeStmtClass &&<br>St->getStmtClass() != Stmt::WhileStmtClass) {<br>- S.Diag(St->getLocStart(),<br>diag::err_pragma_loop_precedes_nonloop);<br>+ S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop)<br>+ << PragmaNameLoc->Ident->getName();<br>return nullptr;<br>}<br><br>- IdentifierLoc *OptionLoc = A.getArgAsIdent(0);<br>- IdentifierInfo *OptionInfo = OptionLoc->Ident;<br>- IdentifierLoc *ValueLoc = A.getArgAsIdent(1);<br>- IdentifierInfo *ValueInfo = ValueLoc->Ident;<br>- Expr *ValueExpr = A.getArgAsExpr(2);<br>-<br>- assert(OptionInfo && "Attribute must have valid option info.");<br>-<br>- LoopHintAttr::OptionType Option =<br>-<br>llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())<br>- .Case("vectorize", LoopHintAttr::Vectorize)<br>- .Case("vectorize_width", LoopHintAttr::VectorizeWidth)<br>- .Case("interleave", LoopHintAttr::Interleave)<br>- .Case("interleave_count", LoopHintAttr::InterleaveCount)<br>- .Case("unroll", LoopHintAttr::Unroll)<br>- .Case("unroll_count", LoopHintAttr::UnrollCount)<br>- .Default(LoopHintAttr::Vectorize);<br>+ LoopHintAttr::OptionType Option;<br>+ LoopHintAttr::Spelling Spelling;<br>+ if (OptionInfo->getName() == "unroll") {<br>+ Option = ValueLoc ? LoopHintAttr::UnrollCount :<br>LoopHintAttr::Unroll;<br>+ Spelling = LoopHintAttr::Pragma_unroll;<br>+ } else {<br>+ Option =<br>llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())<br>+ .Case("vectorize", LoopHintAttr::Vectorize)<br>+ .Case("vectorize_width", LoopHintAttr::VectorizeWidth)<br>+ .Case("interleave", LoopHintAttr::Interleave)<br>+ .Case("interleave_count", LoopHintAttr::InterleaveCount)<br>+ .Default(LoopHintAttr::Vectorize);<br>+ Spelling = LoopHintAttr::Pragma_clang_loop;<br>+ }<br><br>int ValueInt;<br>- if (Option == LoopHintAttr::Vectorize || Option ==<br>LoopHintAttr::Interleave ||<br>- Option == LoopHintAttr::Unroll) {<br>+ if (Option == LoopHintAttr::Unroll) {<br>+ ValueInt = 1;<br>+ } else if (Option == LoopHintAttr::Vectorize ||<br>+ Option == LoopHintAttr::Interleave) {<br>if (!ValueInfo) {<br>S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);<br>return nullptr;<br>@@ -100,12 +110,13 @@<br>} else<br>llvm_unreachable("Unknown loop hint option");<br><br>- return LoopHintAttr::CreateImplicit(S.Context, Option, ValueInt,<br>- A.getRange());<br>+ return LoopHintAttr::CreateImplicit(<br>+ S.Context, Spelling, Option, ValueInt,<br>+ /*ValueInParens=*/CloseParenLoc != nullptr, A.getRange());<br>}<br><br>-static void<br>-CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr<br>*> &Attrs) {<br>+static void CheckForIncompatibleAttributes(<br>+ Sema &S, SmallVectorImpl<const Attr *> &Attrs) {<br></blockquote><br>Attrs should be const.<br><br><blockquote type="cite">// There are 3 categories of loop hints: vectorize, interleave, and<br>// unroll. Each comes in two variants: an enable/disable form and a<br>// form which takes a numeric argument. For example:<br>@@ -159,22 +170,17 @@<br>// Enable|disable hint. For example, vectorize(enable).<br>if (CategoryState.EnabledIsSet) {<br>// Cannot specify enable/disable state twice.<br>- S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)<br>- << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)<br>- << LoopHintAttr::getValueName(CategoryState.Enabled)<br>- << LoopHintAttr::getOptionName(Option)<br>- << LoopHintAttr::getValueName(ValueInt);<br>+ S.Diag(ValueLoc, diag::err_pragma_loop_duplicate)<br>+ << LoopHintAttr::getOptionName(Option);<br>}<br>CategoryState.EnabledIsSet = true;<br>CategoryState.Enabled = ValueInt;<br>} else {<br>- // Numeric hint. For example, unroll_count(8).<br>+ // Numeric hint. For example, vectorize_width(8).<br>if (CategoryState.ValueIsSet) {<br>// Cannot specify numeric hint twice.<br>- S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)<br>- << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)<br>- << CategoryState.Value << LoopHintAttr::getOptionName(Option)<br>- << ValueInt;<br>+ S.Diag(ValueLoc, diag::err_pragma_loop_duplicate)<br>+ << LoopHintAttr::getOptionName(Option);<br>}<br>CategoryState.ValueIsSet = true;<br>CategoryState.Value = ValueInt;<br>@@ -184,8 +190,7 @@<br>CategoryState.ValueIsSet) {<br>// Disable hints are not compatible with numeric hints of the<br>// same category.<br>- S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)<br>- << /*Duplicate=*/false<br>+ S.Diag(ValueLoc, diag::err_pragma_loop_incompatible)<br><< LoopHintAttr::getOptionName(CategoryState.EnableOptionId)<br><< LoopHintAttr::getValueName(CategoryState.Enabled)<br><< LoopHintAttr::getOptionName(CategoryState.NumericOptionId)<br>Index: test/CodeGen/pragma-loop.cpp<br>===================================================================<br>--- test/CodeGen/pragma-loop.cpp<br>+++ test/CodeGen/pragma-loop.cpp<br>@@ -8,7 +8,7 @@<br>#pragma clang loop vectorize(enable)<br>#pragma clang loop interleave_count(4)<br>#pragma clang loop vectorize_width(4)<br>-#pragma clang loop unroll(enable)<br>+#pragma unroll<br>while (i < Length) {<br>// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop<br>![[LOOP_1:.*]]<br>List[i] = i * 2;<br>@@ -20,7 +20,8 @@<br>void do_test(int *List, int Length) {<br>int i = 0;<br><br>-#pragma clang loop vectorize_width(8) interleave_count(4)<br>unroll(disable)<br>+#pragma clang loop vectorize_width(8) interleave_count(4)<br>+#pragma unroll 4<br>do {<br>// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop<br>![[LOOP_2:.*]]<br>List[i] = i * 2;<br>@@ -32,7 +33,7 @@<br>void for_test(int *List, int Length) {<br>#pragma clang loop interleave(enable)<br>#pragma clang loop interleave_count(4)<br>-#pragma clang loop unroll_count(8)<br>+#pragma unroll(8)<br>for (int i = 0; i < Length; i++) {<br>// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop<br>![[LOOP_3:.*]]<br>List[i] = i * 2;<br>@@ -53,7 +54,7 @@<br><br>// Verify disable pragma clang loop directive generates correct<br>metadata<br>void disable_test(int *List, int Length) {<br>-#pragma clang loop vectorize(disable) unroll(disable)<br>+#pragma clang loop vectorize(disable)<br>for (int i = 0; i < Length; i++) {<br>// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop<br>![[LOOP_5:.*]]<br>List[i] = i * 2;<br>@@ -67,7 +68,7 @@<br>// Verify defines are correctly resolved in pragma clang loop<br>directive<br>void for_define_test(int *List, int Length, int Value) {<br>#pragma clang loop vectorize_width(VECWIDTH)<br>interleave_count(INTCOUNT)<br>-#pragma clang loop unroll_count(UNROLLCOUNT)<br>+#pragma unroll(UNROLLCOUNT)<br>for (int i = 0; i < Length; i++) {<br>// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop<br>![[LOOP_6:.*]]<br>List[i] = i * Value;<br>@@ -78,7 +79,8 @@<br>template <typename A><br>void for_template_test(A *List, int Length, A Value) {<br><br>-#pragma clang loop vectorize_width(8) interleave_count(8)<br>unroll_count(8)<br>+#pragma clang loop vectorize_width(8) interleave_count(8)<br>+#pragma unroll 8<br>for (int i = 0; i < Length; i++) {<br>// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop<br>![[LOOP_7:.*]]<br>List[i] = i * Value;<br>@@ -89,7 +91,7 @@<br>template <typename A><br>void for_template_define_test(A *List, int Length, A Value) {<br>#pragma clang loop vectorize_width(VECWIDTH)<br>interleave_count(INTCOUNT)<br>-#pragma clang loop unroll_count(UNROLLCOUNT)<br>+#pragma unroll UNROLLCOUNT<br>for (int i = 0; i < Length; i++) {<br>// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop<br>![[LOOP_8:.*]]<br>List[i] = i * Value;<br>@@ -113,15 +115,15 @@<br>// CHECK: ![[WIDTH_4]] = metadata !{metadata<br>!"llvm.loop.vectorize.width", i32 4}<br>// CHECK: ![[INTERLEAVE_4]] = metadata !{metadata<br>!"llvm.loop.vectorize.unroll", i32 4}<br>// CHECK: ![[INTENABLE_1]] = metadata !{metadata<br>!"llvm.loop.vectorize.enable", i1 true}<br>-// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]],<br>metadata ![[UNROLLENABLE_0:.*]], metadata ![[INTERLEAVE_4:.*]],<br>metadata ![[WIDTH_8:.*]]}<br>-// CHECK: ![[UNROLLENABLE_0]] = metadata !{metadata<br>!"llvm.loop.unroll.enable", i1 false}<br>+// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]],<br>metadata ![[UNROLL_4:.*]], metadata ![[INTERLEAVE_4:.*]], metadata<br>![[WIDTH_8:.*]]}<br>+// CHECK: ![[UNROLL_4]] = metadata !{metadata<br>!"llvm.loop.unroll.count", i32 4}<br>// CHECK: ![[WIDTH_8]] = metadata !{metadata<br>!"llvm.loop.vectorize.width", i32 8}<br>// CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata<br>![[UNROLL_8:.*]], metadata ![[INTERLEAVE_4:.*]], metadata<br>![[ENABLE_1:.*]]}<br>// CHECK: ![[UNROLL_8]] = metadata !{metadata<br>!"llvm.loop.unroll.count", i32 8}<br>// CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata<br>![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}<br>// CHECK: ![[INTERLEAVE_2]] = metadata !{metadata<br>!"llvm.loop.vectorize.unroll", i32 2}<br>// CHECK: ![[WIDTH_2]] = metadata !{metadata<br>!"llvm.loop.vectorize.width", i32 2}<br>-// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata<br>![[UNROLLENABLE_0:.*]], metadata ![[WIDTH_1:.*]]}<br>+// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata<br>![[WIDTH_1:.*]]}<br>// CHECK: ![[WIDTH_1]] = metadata !{metadata<br>!"llvm.loop.vectorize.width", i32 1}<br>// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata<br>![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata<br>![[WIDTH_2:.*]]}<br>// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata<br>![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata<br>![[WIDTH_8:.*]]}<br>Index: test/PCH/pragma-loop.cpp<br>===================================================================<br>--- test/PCH/pragma-loop.cpp<br>+++ test/PCH/pragma-loop.cpp<br>@@ -4,13 +4,13 @@<br>// FIXME: A bug in ParsedAttributes causes the order of the<br>attributes to be<br>// reversed. The checks are consequently in the reverse order<br>below.<br><br>-// CHECK: #pragma clang loop unroll_count(16)<br>+// CHECK: #pragma unroll (16)<br>// CHECK: #pragma clang loop interleave_count(8)<br>// CHECK: #pragma clang loop vectorize_width(4)<br>-// CHECK: #pragma clang loop unroll(disable)<br>+// CHECK: #pragma unroll<br>// CHECK: #pragma clang loop interleave(disable)<br>// CHECK: #pragma clang loop vectorize(enable)<br>-// CHECK: #pragma clang loop unroll(enable)<br>+// CHECK: #pragma unroll 8<br>// CHECK: #pragma clang loop interleave(enable)<br>// CHECK: #pragma clang loop vectorize(disable)<br><br>@@ -23,7 +23,7 @@<br>int i = 0;<br>#pragma clang loop vectorize_width(4)<br>#pragma clang loop interleave_count(8)<br>-#pragma clang loop unroll_count(16)<br>+#pragma unroll(16)<br>while (i < Length) {<br>List[i] = i;<br>i++;<br>@@ -34,7 +34,7 @@<br>int i = 0;<br>#pragma clang loop vectorize(enable)<br>#pragma clang loop interleave(disable)<br>-#pragma clang loop unroll(disable)<br>+#pragma unroll<br>while (i - 1 < Length) {<br>List[i] = i;<br>i++;<br>@@ -45,7 +45,7 @@<br>int i = 0;<br>#pragma clang loop vectorize(disable)<br>#pragma clang loop interleave(enable)<br>-#pragma clang loop unroll(enable)<br>+#pragma unroll 8<br>while (i - 3 < Length) {<br>List[i] = i;<br>i++;<br>Index: test/Parser/pragma-loop.cpp<br>===================================================================<br>--- test/Parser/pragma-loop.cpp<br>+++ test/Parser/pragma-loop.cpp<br>@@ -8,26 +8,26 @@<br><br>#pragma clang loop vectorize(enable)<br>#pragma clang loop interleave(enable)<br>-#pragma clang loop unroll(enable)<br>+#pragma unroll<br>while (i + 1 < Length) {<br>List[i] = i;<br>}<br><br>#pragma clang loop vectorize_width(4)<br>#pragma clang loop interleave_count(8)<br>-#pragma clang loop unroll_count(16)<br>+#pragma unroll 16<br>while (i < Length) {<br>List[i] = i;<br>}<br><br>#pragma clang loop vectorize(disable)<br>#pragma clang loop interleave(disable)<br>-#pragma clang loop unroll(disable)<br>+#pragma unroll(4)<br>while (i - 1 < Length) {<br>List[i] = i;<br>}<br><br>-#pragma clang loop vectorize_width(4) interleave_count(8)<br>unroll_count(16)<br>+#pragma clang loop vectorize_width(4) interleave_count(8)<br>while (i - 2 < Length) {<br>List[i] = i;<br>}<br>@@ -38,81 +38,82 @@<br>}<br><br>int VList[Length];<br>-#pragma clang loop vectorize(disable) interleave(disable)<br>unroll(disable)<br>+#pragma clang loop vectorize(disable) interleave(disable)<br>for (int j : VList) {<br>VList[j] = List[j];<br>}<br><br>/* expected-error {{expected '('}} */ #pragma clang loop vectorize<br>/* expected-error {{expected '('}} */ #pragma clang loop interleave<br>-/* expected-error {{expected '('}} */ #pragma clang loop unroll<br><br>/* expected-error {{expected ')'}} */ #pragma clang loop<br>vectorize(enable<br>/* expected-error {{expected ')'}} */ #pragma clang loop<br>interleave(enable<br>-/* expected-error {{expected ')'}} */ #pragma clang loop<br>unroll(enable<br><br>/* expected-error {{expected ')'}} */ #pragma clang loop<br>vectorize_width(4<br>/* expected-error {{expected ')'}} */ #pragma clang loop<br>interleave_count(4<br>-/* expected-error {{expected ')'}} */ #pragma clang loop<br>unroll_count(4<br>+/* expected-error {{expected ')'}} */ #pragma unroll(4<br><br>-/* expected-error {{missing argument to loop pragma 'vectorize'}}<br>*/ #pragma clang loop vectorize()<br>-/* expected-error {{missing argument to loop pragma<br>'interleave_count'}} */ #pragma clang loop interleave_count()<br>-/* expected-error {{missing argument to loop pragma 'unroll'}} */<br>#pragma clang loop unroll()<br>+/* expected-error {{missing argument to 'loop' pragma}} */ #pragma<br>clang loop vectorize()<br>+/* expected-error {{missing argument to 'loop' pragma}} */ #pragma<br>clang loop interleave_count()<br>+/* expected-error {{missing argument to 'unroll' pragma}} */<br>#pragma unroll()<br><br>/* expected-error {{missing option}} */ #pragma clang loop<br>/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang<br>loop badkeyword<br>/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang<br>loop badkeyword(enable)<br>/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang<br>loop vectorize(enable) badkeyword(4)<br>/* expected-warning {{extra tokens at end of '#pragma clang loop'}}<br>*/ #pragma clang loop vectorize(enable) ,<br>+/* expected-warning {{extra tokens at end of '#pragma unroll'}} */<br>#pragma unroll 1 foobar<br><br>while (i-4 < Length) {<br>List[i] = i;<br>}<br><br>/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop vectorize_width(0)<br>/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop interleave_count(0)<br>-/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop unroll_count(0)<br>+/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma unroll 0<br>while (i-5 < Length) {<br>List[i] = i;<br>}<br><br>/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop vectorize_width(3000000000)<br>/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop interleave_count(3000000000)<br>-/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop unroll_count(3000000000)<br>+/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma unroll 3000000000<br>while (i-6 < Length) {<br>List[i] = i;<br>}<br><br>/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop vectorize_width(badvalue)<br>/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop interleave_count(badvalue)<br>-/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop unroll_count(badvalue)<br>+/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma unroll badvalue<br>while (i-6 < Length) {<br>List[i] = i;<br>}<br><br>/* expected-error {{invalid argument; expected 'enable' or<br>'disable'}} */ #pragma clang loop vectorize(badidentifier)<br>/* expected-error {{invalid argument; expected 'enable' or<br>'disable'}} */ #pragma clang loop interleave(badidentifier)<br>-/* expected-error {{invalid argument; expected 'enable' or<br>'disable'}} */ #pragma clang loop unroll(badidentifier)<br>while (i-7 < Length) {<br>List[i] = i;<br>}<br><br>// PR20069 - Loop pragma arguments that are not identifiers or<br>numeric<br>// constants crash FE.<br>/* expected-error {{invalid argument; expected 'enable' or<br>'disable'}} */ #pragma clang loop vectorize(()<br>/* expected-error {{invalid argument; expected 'enable' or<br>'disable'}} */ #pragma clang loop interleave(*)<br>-/* expected-error {{invalid argument; expected 'enable' or<br>'disable'}} */ #pragma clang loop unroll(=)<br>/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop vectorize_width(^)<br>/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop interleave_count(/)<br>-/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma clang loop unroll_count(==)<br>+/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma unroll(==)<br>+/* expected-error {{invalid argument; expected a positive integer<br>value}} */ #pragma unroll -<br>while (i-8 < Length) {<br>List[i] = i;<br>}<br><br>#pragma clang loop vectorize(enable)<br>-/* expected-error {{expected a for, while, or do-while loop to<br>follow the '#pragma clang loop' directive}} */ int j = Length;<br>+/* expected-error {{expected a for, while, or do-while loop to<br>follow the 'loop' pragma}} */ int j = Length;<br>List[0] = List[1];<br><br>+#pragma unroll<br>+/* expected-error {{expected a for, while, or do-while loop to<br>follow the 'unroll' pragma}} */ List[2] = List[3];<br>+<br>while (j-1 < Length) {<br>List[j] = j;<br>}<br>@@ -126,38 +127,34 @@<br>#pragma clang loop vectorize(disable)<br>/* expected-error {{incompatible directives 'interleave(disable)'<br>and 'interleave_count(4)'}} */ #pragma clang loop<br>interleave_count(4)<br>#pragma clang loop interleave(disable)<br>-/* expected-error {{incompatible directives 'unroll(disable)' and<br>'unroll_count(4)'}} */ #pragma clang loop unroll_count(4)<br>-#pragma clang loop unroll(disable)<br>while (i-8 < Length) {<br>List[i] = i;<br>}<br><br>-/* expected-error {{duplicate directives 'vectorize(disable)' and<br>'vectorize(enable)'}} */ #pragma clang loop vectorize(enable)<br>+/* expected-error {{duplicate 'vectorize' directives}} */ #pragma<br>clang loop vectorize(enable)<br>#pragma clang loop vectorize(disable)<br>-/* expected-error {{duplicate directives 'interleave(disable)' and<br>'interleave(enable)'}} */ #pragma clang loop interleave(enable)<br>-#pragma clang loop interleave(disable)<br>-/* expected-error {{duplicate directives 'unroll(disable)' and<br>'unroll(enable)'}} */ #pragma clang loop unroll(enable)<br>-#pragma clang loop unroll(disable)<br>+/* expected-error {{duplicate 'interleave' directives}} */ #pragma<br>clang loop interleave(enable)<br>+#pragma clang loop interleave(enable)<br>+/* expected-error {{duplicate 'unroll' directives}} */ #pragma<br>unroll<br>+#pragma unroll<br>while (i-9 < Length) {<br>List[i] = i;<br>}<br><br>/* expected-error {{incompatible directives 'vectorize(disable)'<br>and 'vectorize_width(4)'}} */ #pragma clang loop<br>vectorize(disable)<br>#pragma clang loop vectorize_width(4)<br>/* expected-error {{incompatible directives 'interleave(disable)'<br>and 'interleave_count(4)'}} */ #pragma clang loop<br>interleave(disable)<br>#pragma clang loop interleave_count(4)<br>-/* expected-error {{incompatible directives 'unroll(disable)' and<br>'unroll_count(4)'}} */ #pragma clang loop unroll(disable)<br>-#pragma clang loop unroll_count(4)<br>while (i-10 < Length) {<br>List[i] = i;<br>}<br><br>-/* expected-error {{duplicate directives 'vectorize_width(4)' and<br>'vectorize_width(8)'}} */ #pragma clang loop vectorize_width(8)<br>+/* expected-error {{duplicate 'vectorize_width' directives}} */<br>#pragma clang loop vectorize_width(8)<br>#pragma clang loop vectorize_width(4)<br>-/* expected-error {{duplicate directives 'interleave_count(4)' and<br>'interleave_count(8)'}} */ #pragma clang loop interleave_count(8)<br>+/* expected-error {{duplicate 'interleave_count' directives}} */<br>#pragma clang loop interleave_count(8)<br>#pragma clang loop interleave_count(4)<br>-/* expected-error {{duplicate directives 'unroll_count(4)' and<br>'unroll_count(8)'}} */ #pragma clang loop unroll_count(8)<br>-#pragma clang loop unroll_count(4)<br>+/* expected-error {{duplicate 'unroll' directives}} */ #pragma<br>unroll 8<br>+#pragma unroll(4)<br>while (i-11 < Length) {<br>List[i] = i;<br>}<br><br></blockquote><br>~Aaron<br><br><br></blockquote><br>--<span class="Apple-converted-space"> </span><br>Hal Finkel<br>Assistant Computational Scientist<br>Leadership Computing Facility<br>Argonne National Laboratory</div></blockquote></div><br></body></html>