[PATCH] Add support for unroll pragma

Hal Finkel hfinkel at anl.gov
Mon Jul 7 17:23:26 PDT 2014


----- Original Message -----
> From: "Mark Heffernan" <meheff at google.com>
> To: "Aaron Ballman" <aaron.ballman at gmail.com>
> Cc: reviews+D4297+public+26d6caf125d429ed at reviews.llvm.org, "Eli Bendersky" <eliben at google.com>, "Tyler Nowicki"
> <tnowicki at apple.com>, "Peter Collingbourne" <peter at pcc.me.uk>, "Hal Finkel" <hfinkel at anl.gov>, "llvm cfe"
> <cfe-commits at cs.uiuc.edu>, "Richard Smith" <richard at metafoo.co.uk>, "Chandler Carruth" <chandlerc at gmail.com>
> Sent: Monday, July 7, 2014 5:52:33 PM
> Subject: Re: [PATCH] Add support for unroll pragma
> 
> 
> 
> 
> On Wed, Jul 2, 2014 at 7:54 AM, Aaron Ballman <
> aaron.ballman at gmail.com > wrote:
> 
> 
> 
> I may have led you slightly astray on this point. I believe the
> consensus wound up being that having two different syntaxes for the
> same thing was okay, and so #pragma loop unroll[_count] should
> remain.
> Richard, Chandler, do I have that correct?
> 
> 
> 
> I think Richard and Chandler (correct me if I'm wrong) were referring
> to supporting the following "#pragma unroll" syntaxes for
> compatibility purposes:
> 
> 
> #pragma unroll // CUDA, intel, and IBM
> #pragma unroll N // CUDA
> #pragma unroll(N) // intel and IBM
> 
> 
> However, not much has been said about, in addition, continuing to
> support the newly added form in the clang pragma namespace:
> 
> 
> #pragma clang loop unroll(...) unroll_count(...)
> 
> 
> Since you initially voiced objection to having two forms with
> identical semantics, I've come around and agree. That is, I think we
> should drop support for the "#pragma clang loop unroll" syntax and
> only support the "#pragma unroll" one.

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.

 -Hal

> 
> 
> Mark
> 
> 
> 
> 
> Some comments:
> 
> > Index: docs/LanguageExtensions.rst
> > ===================================================================
> > --- docs/LanguageExtensions.rst
> > +++ docs/LanguageExtensions.rst
> > @@ -1767,15 +1767,10 @@
> > 
> > Extensions for loop hint optimizations
> > ======================================
> > -
> > The ``#pragma clang loop`` directive is used to specify hints for
> > optimizing the
> > subsequent for, while, do-while, or c++11 range-based for loop. The
> > directive
> > -provides options for vectorization, interleaving, and unrolling.
> > Loop hints can
> > -be specified before any loop and will be ignored if the
> > optimization is not safe
> > -to apply.
> > -
> > -Vectorization and Interleaving
> > -------------------------------
> > +provides options for vectorization and interleaving. Loop hints
> > can be specified
> > +before any loop and will be ignored if the optimization is not
> > safe to apply.
> > 
> > A vectorized loop performs multiple iterations of the original loop
> > in parallel using vector instructions. The instruction set of the
> > target
> > @@ -1818,43 +1813,6 @@
> > Specifying a width/count of 1 disables the optimization, and is
> > equivalent to
> > ``vectorize(disable)`` or ``interleave(disable)``.
> > 
> > -Loop Unrolling
> > ---------------
> > -
> > -Unrolling a loop reduces the loop control overhead and exposes
> > more
> > -opportunities for ILP. Loops can be fully or partially unrolled.
> > Full unrolling
> > -eliminates the loop and replaces it with an enumerated sequence of
> > loop
> > -iterations. Full unrolling is only possible if the loop trip count
> > is known at
> > -compile time. Partial unrolling replicates the loop body within
> > the loop and
> > -reduces the trip count.
> > -
> > -If ``unroll(enable)`` is specified the unroller will attempt to
> > fully unroll the
> > -loop if the trip count is known at compile time. If the loop count
> > is not known
> > -or the fully unrolled code size is greater than the limit
> > specified by the
> > -`-pragma-unroll-threshold` command line option the loop will be
> > partially
> > -unrolled subject to the same limit.
> > -
> > -.. code-block:: c++
> > -
> > - #pragma clang loop unroll(enable)
> > - for(...) {
> > - ...
> > - }
> > -
> > -The unroll count can be specified explicitly with
> > ``unroll_count(_value_)`` where
> > -_value_ is a positive integer. If this value is greater than the
> > trip count the
> > -loop will be fully unrolled. Otherwise the loop is partially
> > unrolled subject
> > -to the `-pragma-unroll-threshold` limit.
> > -
> > -.. code-block:: c++
> > -
> > - #pragma clang loop unroll_count(8)
> > - for(...) {
> > - ...
> > - }
> > -
> > -Unrolling of a loop can be prevented by specifying
> > ``unroll(disable)``.
> > -
> > Additional Information
> > ----------------------
> > 
> > Index: docs/ReleaseNotes.rst
> > ===================================================================
> > --- docs/ReleaseNotes.rst
> > +++ docs/ReleaseNotes.rst
> > @@ -101,10 +101,16 @@
> > -----------------------
> > 
> > Loop optimization hints can be specified using the new `#pragma
> > clang loop`
> > -directive just prior to the desired loop. The directive allows
> > vectorization,
> > -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.
> > +directive just prior to the desired loop. The directive allows
> > vectorization and
> > +interleaving to be enabled or disabled. Vector width and
> > interleave 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 N`. The unroll count parameter can
> > be optionally
> > +enclosed in parentheses.
> > 
> > C Language Changes in Clang
> > ---------------------------
> > Index: include/clang/Basic/Attr.td
> > ===================================================================
> > --- include/clang/Basic/Attr.td
> > +++ include/clang/Basic/Attr.td
> > @@ -1772,25 +1772,28 @@
> > /// unroll: unroll loop if 'value != 0'.
> > /// unroll_count: unrolls loop 'value' times.
> > 
> > - let Spellings = [Pragma<"clang", "loop">];
> > + let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">];
> > 
> > /// State of the loop optimization specified by the spelling.
> > let Args = [EnumArgument<"Option", "OptionType",
> > ["vectorize", "vectorize_width", "interleave", "interleave_count",
> > "unroll", "unroll_count"],
> > ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",
> > "Unroll", "UnrollCount"]>,
> > - DefaultIntArgument<"Value", 1>];
> > + DefaultIntArgument<"Value", 1>,
> > + DefaultBoolArgument<"ValueInParens", 0>];
> 
> Hmm... we usually want the arguments to match the syntax of the
> attribute unless the argument is really key to the semantics.
> ValueInParens doesn't really fit that model. I would prefer for this
> to be an AdditionalMembers entry.
> 
> > 
> > let AdditionalMembers = [{
> > static StringRef getOptionName(int Option) {
> > switch(Option) {
> > case Vectorize: return "vectorize";
> > case VectorizeWidth: return "vectorize_width";
> > case Interleave: return "interleave";
> > case InterleaveCount: return "interleave_count";
> > + // Unroll and UnrollCount attributes are added for '#pragma
> > unroll'
> > + // directives which share the option name 'unroll'.
> > case Unroll: return "unroll";
> > - case UnrollCount: return "unroll_count";
> > + case UnrollCount: return "unroll";
> > }
> > llvm_unreachable("Unhandled LoopHint option.");
> > }
> > @@ -1802,15 +1805,29 @@
> > }
> > 
> > void printPrettyPragma(raw_ostream &OS, const PrintingPolicy
> > &Policy) const {
> > + if (option == Unroll) {
> > + // "#pragma unroll". String "unroll" is already emitted as the
> > + // pragma name.
> > + OS << "\n";
> > + return;
> > + }
> > + if (option == UnrollCount) {
> > + // "#pragma unroll N" or "#pragma unroll(N)".
> > + if (ValueInParens)
> > + OS << "(" << value << ")";
> > + else
> > + OS << value;
> > + OS << "\n";
> > + return;
> > + }
> > OS << getOptionName(option) << "(";
> > - if (option == VectorizeWidth || option == InterleaveCount ||
> > - option == UnrollCount)
> > + if (option == VectorizeWidth || option == InterleaveCount)
> > OS << value;
> > else
> > OS << getValueName(value);
> > OS << ")\n";
> > }
> > }];
> > 
> > - let Documentation = [LoopHintDocs];
> > + let Documentation = [LoopHintDocs, UnrollHintDocs];
> > }
> > Index: include/clang/Basic/AttrDocs.td
> > ===================================================================
> > --- include/clang/Basic/AttrDocs.td
> > +++ include/clang/Basic/AttrDocs.td
> > @@ -1024,3 +1024,45 @@
> > for details.
> > }];
> > }
> > +
> > +def UnrollHintDocs : Documentation {
> > + let Category = DocCatStmt;
> > + let Content = [{
> > +Loop unrolling optimization hints can be specified with the
> > ``#pragma unroll``
> > +directive. The pragma is placed immediately before a for, while,
> > do-while, or
> > +c++11 range-based for loop. The pragma takes an optional parameter
> > which must
> > +be a positive integer.
> > +
> > +.. code-block:: c++
> > +
> > + #pragma unroll
> > + for (...) {
> > + ...
> > + }
> > +
> > +If ``#pragma unroll`` is specified without a parameter the loop
> > unroller will
> > +attempt to fully unroll the loop if the trip count is known at
> > compile time. If
> > +the loop count is not known or the fully unrolled code size is
> > greater than the
> > +limit specified by the ``-pragma-unroll-threshold`` command-line
> > option the loop
> > +will be partially unrolled subject to the same limit.
> > +
> > +.. code-block:: c++
> > +
> > + #pragma unroll 16
> > + for (...) {
> > + ...
> > + }
> > +
> > + #pragma unroll(16)
> > + for (...) {
> > + ...
> > + }
> > +
> > +Specifying ``#pragma unroll _value_`` where _value_ is a positive
> > integer directs
> > +the unroller to unroll the loop _value_ times. The value may be
> > optionally
> > +enclosed in parentheses such as ``#pragma unroll(_value_)``. If
> > this value is
> > +greater than the trip count the loop will be fully unrolled.
> > Otherwise the loop
> > +is partially unrolled subject to the ``-pragma-unroll-threshold``
> > limit.
> > + }];
> > +}
> > +
> > Index: include/clang/Basic/DiagnosticParseKinds.td
> > ===================================================================
> > --- include/clang/Basic/DiagnosticParseKinds.td
> > +++ include/clang/Basic/DiagnosticParseKinds.td
> > @@ -912,7 +912,7 @@
> > "%select{invalid|missing}0 option%select{ %1|}0; expected
> > vectorize, "
> > "vectorize_width, interleave, interleave_count, unroll, or
> > unroll_count">;
> > def err_pragma_loop_missing_argument : Error<
> > - "missing argument to loop pragma %0">;
> > + "missing argument to %0 pragma">;
> 
> The name of this diagnostic should probably change given how generic
> the text now is.
> 
> > } // end of Parse Issue category.
> > 
> > let CategoryName = "Modules Issue" in {
> > Index: include/clang/Basic/DiagnosticSemaKinds.td
> > ===================================================================
> > --- include/clang/Basic/DiagnosticSemaKinds.td
> > +++ include/clang/Basic/DiagnosticSemaKinds.td
> > @@ -546,11 +546,12 @@
> > "invalid argument; expected a positive integer value">;
> > def err_pragma_loop_invalid_keyword : Error<
> > "invalid argument; expected 'enable' or 'disable'">;
> > -def err_pragma_loop_compatibility : Error<
> > - "%select{incompatible|duplicate}0 directives '%1(%2)' and
> > '%3(%4)'">;
> > +def err_pragma_loop_duplicate : Error<
> > + "duplicate '%0' directives">;
> > +def err_pragma_loop_incompatible : Error<
> > + "incompatible directives '%0(%1)' and '%2(%3)'">;
> 
> Why was this split into two errors?
> 
> > def err_pragma_loop_precedes_nonloop : Error<
> > - "expected a for, while, or do-while loop to follow the '#pragma
> > clang loop' "
> > - "directive">;
> > + "expected a for, while, or do-while loop to follow the '%0'
> > pragma">;
> > 
> > /// Objective-C parser diagnostics
> > def err_duplicate_class_def : Error<
> > Index: include/clang/Parse/Parser.h
> > ===================================================================
> > --- include/clang/Parse/Parser.h
> > +++ include/clang/Parse/Parser.h
> > @@ -163,6 +163,7 @@
> > std::unique_ptr<PragmaHandler> MSSection;
> > std::unique_ptr<PragmaHandler> OptimizeHandler;
> > std::unique_ptr<PragmaHandler> LoopHintHandler;
> > + std::unique_ptr<PragmaHandler> UnrollHintHandler;
> > 
> > std::unique_ptr<CommentHandler> CommentSemaHandler;
> > 
> > @@ -522,7 +523,7 @@
> > StmtResult HandlePragmaCaptured();
> > 
> > /// \brief Handle the annotation token produced for
> > - /// #pragma vectorize...
> > + /// #pragma clang loop...
> > LoopHint HandlePragmaLoopHint();
> > 
> > /// GetLookAheadToken - This peeks ahead N tokens and returns that
> > token
> > Index: include/clang/Sema/LoopHint.h
> > ===================================================================
> > --- include/clang/Sema/LoopHint.h
> > +++ include/clang/Sema/LoopHint.h
> > @@ -17,13 +17,26 @@
> > 
> > namespace clang {
> > 
> > -/// \brief Loop hint specified by a pragma loop directive.
> > +/// \brief Loop optimization hint for loop and unroll pragmas.
> > struct LoopHint {
> > + // Source range of the directive.
> > SourceRange Range;
> > - Expr *ValueExpr;
> > - IdentifierLoc *LoopLoc;
> > - IdentifierLoc *ValueLoc;
> > + // Identifier corresponding to the name of the pragma. "loop" for
> > + // "#pragma clang loop" directives and "unroll" for "#pragma
> > unroll"
> > + // hints.
> > + IdentifierLoc *PragmaNameLoc;
> > + // Name of the loop hint. Examples: "unroll", "vectorize". In the
> > unroll
> > + // case, this is identical to PragmaNameLoc.
> > IdentifierLoc *OptionLoc;
> > + // Identifier for the hint argument. If null, then the hint has
> > no argument
> > + // (for example, "#pragma unroll").
> > + IdentifierLoc *ValueLoc;
> > + // If the hint argument exists and is contained in parentheses
> > (for example,
> > + // "vectorize_width(8)") this contains the identifier for the
> > closing
> > + // parentheses. Value is null otherwise.
> > + IdentifierLoc *CloseParenLoc;
> > + // Expression for the hint argument if it exists, null otherwise.
> > + Expr *ValueExpr;
> > };
> > 
> > } // end namespace clang
> > Index: lib/Parse/ParsePragma.cpp
> > ===================================================================
> > --- lib/Parse/ParsePragma.cpp
> > +++ lib/Parse/ParsePragma.cpp
> > @@ -148,6 +148,12 @@
> > Token &FirstToken) override;
> > };
> > 
> > +struct PragmaUnrollHintHandler : public PragmaHandler {
> > + PragmaUnrollHintHandler() : PragmaHandler("unroll") {}
> > + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind
> > Introducer,
> > + Token &FirstToken) override;
> > +};
> > +
> > } // end namespace
> > 
> > void Parser::initializePragmaHandlers() {
> > @@ -218,6 +224,9 @@
> > 
> > LoopHintHandler.reset(new PragmaLoopHintHandler());
> > PP.AddPragmaHandler("clang", LoopHintHandler.get());
> > +
> > + UnrollHintHandler.reset(new PragmaUnrollHintHandler());
> > + PP.AddPragmaHandler(UnrollHintHandler.get());
> > }
> > 
> > void Parser::resetPragmaHandlers() {
> > @@ -278,6 +287,9 @@
> > 
> > PP.RemovePragmaHandler("clang", LoopHintHandler.get());
> > LoopHintHandler.reset();
> > +
> > + PP.RemovePragmaHandler(UnrollHintHandler.get());
> > + UnrollHintHandler.reset();
> > }
> > 
> > /// \brief Handle the annotation token produced for #pragma
> > unused(...)
> > @@ -600,35 +612,54 @@
> > }
> > 
> > struct PragmaLoopHintInfo {
> > - Token Loop;
> > - Token Value;
> > + Token PragmaName;
> > Token Option;
> > + Token Value;
> > + Token CloseParen;
> > + bool HasValue;
> > + bool ValueInParens;
> > };
> > 
> > LoopHint Parser::HandlePragmaLoopHint() {
> > assert(Tok.is(tok::annot_pragma_loop_hint));
> > PragmaLoopHintInfo *Info =
> > static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
> > 
> > LoopHint Hint;
> > - Hint.LoopLoc =
> > - IdentifierLoc::create(Actions.Context, Info->Loop.getLocation(),
> > - Info->Loop.getIdentifierInfo());
> > + Hint.PragmaNameLoc =
> > + IdentifierLoc::create(Actions.Context,
> > Info->PragmaName.getLocation(),
> > + Info->PragmaName.getIdentifierInfo());
> > Hint.OptionLoc =
> > IdentifierLoc::create(Actions.Context, Info->Option.getLocation(),
> > Info->Option.getIdentifierInfo());
> > - Hint.ValueLoc =
> > - IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),
> > - Info->Value.getIdentifierInfo());
> > - Hint.Range =
> > - SourceRange(Info->Option.getLocation(),
> > Info->Value.getLocation());
> > -
> > - // FIXME: We should allow non-type template parameters for the
> > loop hint
> > - // value. See bug report #19610
> > - if (Info->Value.is(tok::numeric_constant))
> > - Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
> > - else
> > + if (Info->HasValue) {
> > + if (Info->ValueInParens) {
> > + Hint.Range = SourceRange(Info->Option.getLocation(),
> > + Info->CloseParen.getLocation());
> > + Hint.CloseParenLoc =
> > + IdentifierLoc::create(Actions.Context,
> > Info->CloseParen.getLocation(),
> > + Info->CloseParen.getIdentifierInfo());
> > + } else {
> > + Hint.Range =
> > + SourceRange(Info->Option.getLocation(),
> > Info->Value.getLocation());
> > + Hint.CloseParenLoc = nullptr;
> > + }
> > + Hint.ValueLoc =
> > + IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),
> > + Info->Value.getIdentifierInfo());
> > +
> > + // FIXME: We should allow non-type template parameters for the
> > loop hint
> > + // value. See bug report #19610
> > + if (Info->Value.is(tok::numeric_constant))
> > + Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
> > + else
> > + Hint.ValueExpr = nullptr;
> > + } else {
> > + Hint.Range = SourceRange(Info->PragmaName.getLocation());
> > + Hint.ValueLoc = nullptr;
> > Hint.ValueExpr = nullptr;
> > + Hint.CloseParenLoc = nullptr;
> > + }
> > 
> > return Hint;
> > }
> > @@ -1630,6 +1661,47 @@
> > Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
> > }
> > 
> > +// Parses loop or unroll pragma hint value and fills in Info.
> > +bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token
> > &PragmaName,
> > + Token &Option, PragmaLoopHintInfo &Info) {
> > + bool ValueInParens;
> 
> Could simply initialize to Tok.is(tok::l_paren), then not need the
> else clause at all.
> 
> > + if (Tok.is(tok::l_paren)) {
> > + ValueInParens = true;
> > + PP.Lex(Tok);
> > + if (Tok.is(tok::r_paren)) {
> > + // Nothing between the parentheses.
> > + PP.Diag(Tok.getLocation(),
> > diag::err_pragma_loop_missing_argument)
> > + << PragmaName.getIdentifierInfo();
> > + return true;
> > + }
> > + } else {
> > + ValueInParens = false;
> > + }
> > +
> > + // FIXME: Value should be stored and parsed as a constant
> > expression.
> > + Token Value = Tok;
> > +
> > + Token CloseParen;
> > + if (ValueInParens) {
> > + PP.Lex(Tok);
> > + if (Tok.isNot(tok::r_paren)) {
> > + PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
> > + return true;
> > + }
> > + CloseParen = Tok;
> > + }
> > +
> > + Info.PragmaName = PragmaName;
> > + Info.Option = Option;
> > + Info.Value = Value;
> > + Info.HasValue = true;
> > + Info.ValueInParens = ValueInParens;
> > + if (Info.ValueInParens)
> > + Info.CloseParen = CloseParen;
> > +
> > + return false;
> > +}
> > +
> > /// \brief Handle the \#pragma clang loop directive.
> > /// #pragma clang 'loop' loop-hints
> > ///
> > @@ -1639,10 +1711,8 @@
> > /// loop-hint:
> > /// 'vectorize' '(' loop-hint-keyword ')'
> > /// 'interleave' '(' loop-hint-keyword ')'
> > -/// 'unroll' '(' loop-hint-keyword ')'
> > /// 'vectorize_width' '(' loop-hint-value ')'
> > /// 'interleave_count' '(' loop-hint-value ')'
> > -/// 'unroll_count' '(' loop-hint-value ')'
> > ///
> > /// loop-hint-keyword:
> > /// 'enable'
> > @@ -1660,18 +1730,11 @@
> > /// value of 1 effectively disables vectorization/interleaving,
> > even if it is
> > /// possible and profitable, and 0 is invalid. The loop vectorizer
> > currently
> > /// only works on inner loops.
> > -///
> > -/// The unroll and unroll_count directives control the
> > concatenation
> > -/// unroller. Specifying unroll(enable) instructs llvm to try to
> > -/// unroll the loop completely, and unroll(disable) disables
> > unrolling
> > -/// for the loop. Specifying unroll_count(_value_) instructs llvm
> > to
> > -/// try to unroll the loop the number of times indicated by the
> > value.
> > -/// If unroll(enable) and unroll_count are both specified only
> > -/// unroll_count takes effect.
> > void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
> > PragmaIntroducerKind Introducer,
> > Token &Tok) {
> > - Token Loop = Tok;
> > + // Incoming token is "loop" from "#pragma clang loop".
> > + Token PragmaName = Tok;
> > SmallVector<Token, 1> TokenList;
> > 
> > // Lex the optimization option and verify it is an identifier.
> > @@ -1687,59 +1750,37 @@
> > IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
> > 
> > bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName())
> > - .Case("vectorize", true)
> > - .Case("interleave", true)
> > - .Case("unroll", true)
> > - .Case("vectorize_width", true)
> > - .Case("interleave_count", true)
> > - .Case("unroll_count", true)
> > - .Default(false);
> > + .Case("vectorize", true)
> > + .Case("interleave", true)
> > + .Case("vectorize_width", true)
> > + .Case("interleave_count", true)
> > + .Default(false);
> > if (!OptionValid) {
> > PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
> > << /*MissingOption=*/false << OptionInfo;
> > return;
> > }
> > 
> > - // Read '('
> > - PP.Lex(Tok);
> > - if (Tok.isNot(tok::l_paren)) {
> > - PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
> > - return;
> > - }
> > -
> > - // FIXME: All tokens between '(' and ')' should be stored and
> > parsed as a
> > - // constant expression.
> > + auto *Info = new (PP.getPreprocessorAllocator())
> > PragmaLoopHintInfo;
> > PP.Lex(Tok);
> > - if (Tok.is(tok::r_paren)) {
> > - // Nothing between the parentheses.
> > - PP.Diag(Tok.getLocation(),
> > diag::err_pragma_loop_missing_argument)
> > - << OptionInfo;
> > + if (ParseLoopHintValue(PP, Tok, PragmaName, Option, *Info))
> > return;
> > - }
> > - Token Value = Tok;
> > 
> > - // Read ')'
> > - PP.Lex(Tok);
> > - if (Tok.isNot(tok::r_paren)) {
> > - PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
> > + if (!Info->ValueInParens) {
> > + PP.Diag(Info->Value.getLocation(), diag::err_expected) <<
> > tok::l_paren;
> > return;
> > }
> > 
> > - // Get next optimization option.
> > - PP.Lex(Tok);
> > -
> > - auto *Info = new (PP.getPreprocessorAllocator())
> > PragmaLoopHintInfo;
> > - Info->Loop = Loop;
> > - Info->Option = Option;
> > - Info->Value = Value;
> > -
> > - // Generate the vectorization hint token.
> > + // Generate the loop hint token.
> > Token LoopHintTok;
> > LoopHintTok.startToken();
> > LoopHintTok.setKind(tok::annot_pragma_loop_hint);
> > - LoopHintTok.setLocation(Loop.getLocation());
> > + LoopHintTok.setLocation(PragmaName.getLocation());
> > LoopHintTok.setAnnotationValue(static_cast<void *>(Info));
> > TokenList.push_back(LoopHintTok);
> > +
> > + // Get next optimization option.
> > + PP.Lex(Tok);
> > }
> > 
> > if (Tok.isNot(tok::eod)) {
> > @@ -1755,3 +1796,54 @@
> > /*DisableMacroExpansion=*/false,
> > /*OwnsTokens=*/true);
> > }
> > +
> > +/// \brief Handle the loop unroll optimization pragmas.
> > +/// #pragma unroll
> > +/// #pragma unroll unroll-hint-value
> > +/// #pragma unroll '(' unroll-hint-value ')'
> > +///
> > +/// unroll-hint-value:
> > +/// constant-expression
> > +///
> > +/// Loop unrolling hints are specified with '#pragma unroll' and
> > can include 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.
> > +void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
> > + PragmaIntroducerKind Introducer,
> > + Token &Tok) {
> > + // Incoming token is "unroll" from "#pragma unroll".
> > + Token PragmaName = Tok;
> > + PP.Lex(Tok);
> > + auto *Info = new (PP.getPreprocessorAllocator())
> > PragmaLoopHintInfo;
> > + if (Tok.is(tok::eod)) {
> > + // Bare unroll pragma: "#pragma unroll".
> > + Info->PragmaName = PragmaName;
> > + Info->Option = PragmaName;
> > + Info->HasValue = false;
> > + Info->ValueInParens = false;
> > + } else {
> > + // Unroll pragma with an argument: "#pragma unroll N" or
> > + // "#pragma unroll(N)".
> > + if (ParseLoopHintValue(PP, Tok, PragmaName, PragmaName, *Info))
> > + return;
> > + PP.Lex(Tok);
> > +
> > + if (Tok.isNot(tok::eod)) {
> > + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
> > + << "unroll";
> > + return;
> > + }
> > + }
> > +
> > + // Generate the hint token.
> > + Token *TokenArray = new Token[1];
> > + TokenArray[0].startToken();
> > + TokenArray[0].setKind(tok::annot_pragma_loop_hint);
> > + TokenArray[0].setLocation(PragmaName.getLocation());
> > + TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
> > + PP.EnterTokenStream(TokenArray, 1,
> > /*DisableMacroExpansion=*/false,
> > + /*OwnsTokens=*/true);
> > +}
> > Index: lib/Parse/ParseStmt.cpp
> > ===================================================================
> > --- lib/Parse/ParseStmt.cpp
> > +++ lib/Parse/ParseStmt.cpp
> > @@ -1804,18 +1804,16 @@
> > // Create temporary attribute list.
> > ParsedAttributesWithRange TempAttrs(AttrFactory);
> > 
> > - // Get vectorize hints and consume annotated token.
> > + // Get loop hints and consume annotated token.
> > while (Tok.is(tok::annot_pragma_loop_hint)) {
> > LoopHint Hint = HandlePragmaLoopHint();
> > ConsumeToken();
> > 
> > - if (!Hint.LoopLoc || !Hint.OptionLoc || !Hint.ValueLoc)
> > - continue;
> > -
> > - ArgsUnion ArgHints[] = {Hint.OptionLoc, Hint.ValueLoc,
> > - ArgsUnion(Hint.ValueExpr)};
> > - TempAttrs.addNew(Hint.LoopLoc->Ident, Hint.Range, nullptr,
> > - Hint.LoopLoc->Loc, ArgHints, 3, AttributeList::AS_Pragma);
> > + ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc,
> > Hint.ValueLoc,
> > + Hint.CloseParenLoc, ArgsUnion(Hint.ValueExpr)};
> > + TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,
> > + Hint.PragmaNameLoc->Loc, ArgHints, 5,
> > + AttributeList::AS_Pragma);
> > }
> > 
> > // Get the next statement.
> > Index: lib/Sema/SemaStmtAttr.cpp
> > ===================================================================
> > --- lib/Sema/SemaStmtAttr.cpp
> > +++ lib/Sema/SemaStmtAttr.cpp
> > @@ -45,35 +45,45 @@
> > 
> > static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const
> > AttributeList &A,
> > SourceRange) {
> > + IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
> > + IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
> > + IdentifierInfo *OptionInfo = OptionLoc->Ident;
> > + IdentifierLoc *ValueLoc = A.getArgAsIdent(2);
> > + IdentifierInfo *ValueInfo = ValueLoc ? ValueLoc->Ident : nullptr;
> > + IdentifierLoc *CloseParenLoc = A.getArgAsIdent(3);
> > + Expr *ValueExpr = A.getArgAsExpr(4);
> > +
> > + assert(OptionInfo && "Attribute must have valid option info.");
> > +
> > if (St->getStmtClass() != Stmt::DoStmtClass &&
> > St->getStmtClass() != Stmt::ForStmtClass &&
> > St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
> > St->getStmtClass() != Stmt::WhileStmtClass) {
> > - S.Diag(St->getLocStart(),
> > diag::err_pragma_loop_precedes_nonloop);
> > + S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop)
> > + << PragmaNameLoc->Ident->getName();
> > return nullptr;
> > }
> > 
> > - IdentifierLoc *OptionLoc = A.getArgAsIdent(0);
> > - IdentifierInfo *OptionInfo = OptionLoc->Ident;
> > - IdentifierLoc *ValueLoc = A.getArgAsIdent(1);
> > - IdentifierInfo *ValueInfo = ValueLoc->Ident;
> > - Expr *ValueExpr = A.getArgAsExpr(2);
> > -
> > - assert(OptionInfo && "Attribute must have valid option info.");
> > -
> > - LoopHintAttr::OptionType Option =
> > -
> > llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
> > - .Case("vectorize", LoopHintAttr::Vectorize)
> > - .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
> > - .Case("interleave", LoopHintAttr::Interleave)
> > - .Case("interleave_count", LoopHintAttr::InterleaveCount)
> > - .Case("unroll", LoopHintAttr::Unroll)
> > - .Case("unroll_count", LoopHintAttr::UnrollCount)
> > - .Default(LoopHintAttr::Vectorize);
> > + LoopHintAttr::OptionType Option;
> > + LoopHintAttr::Spelling Spelling;
> > + if (OptionInfo->getName() == "unroll") {
> > + Option = ValueLoc ? LoopHintAttr::UnrollCount :
> > LoopHintAttr::Unroll;
> > + Spelling = LoopHintAttr::Pragma_unroll;
> > + } else {
> > + Option =
> > llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
> > + .Case("vectorize", LoopHintAttr::Vectorize)
> > + .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
> > + .Case("interleave", LoopHintAttr::Interleave)
> > + .Case("interleave_count", LoopHintAttr::InterleaveCount)
> > + .Default(LoopHintAttr::Vectorize);
> > + Spelling = LoopHintAttr::Pragma_clang_loop;
> > + }
> > 
> > int ValueInt;
> > - if (Option == LoopHintAttr::Vectorize || Option ==
> > LoopHintAttr::Interleave ||
> > - Option == LoopHintAttr::Unroll) {
> > + if (Option == LoopHintAttr::Unroll) {
> > + ValueInt = 1;
> > + } else if (Option == LoopHintAttr::Vectorize ||
> > + Option == LoopHintAttr::Interleave) {
> > if (!ValueInfo) {
> > S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
> > return nullptr;
> > @@ -100,12 +110,13 @@
> > } else
> > llvm_unreachable("Unknown loop hint option");
> > 
> > - return LoopHintAttr::CreateImplicit(S.Context, Option, ValueInt,
> > - A.getRange());
> > + return LoopHintAttr::CreateImplicit(
> > + S.Context, Spelling, Option, ValueInt,
> > + /*ValueInParens=*/CloseParenLoc != nullptr, A.getRange());
> > }
> > 
> > -static void
> > -CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr
> > *> &Attrs) {
> > +static void CheckForIncompatibleAttributes(
> > + Sema &S, SmallVectorImpl<const Attr *> &Attrs) {
> 
> Attrs should be const.
> 
> > // There are 3 categories of loop hints: vectorize, interleave, and
> > // unroll. Each comes in two variants: an enable/disable form and a
> > // form which takes a numeric argument. For example:
> > @@ -159,22 +170,17 @@
> > // Enable|disable hint. For example, vectorize(enable).
> > if (CategoryState.EnabledIsSet) {
> > // Cannot specify enable/disable state twice.
> > - S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
> > - << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)
> > - << LoopHintAttr::getValueName(CategoryState.Enabled)
> > - << LoopHintAttr::getOptionName(Option)
> > - << LoopHintAttr::getValueName(ValueInt);
> > + S.Diag(ValueLoc, diag::err_pragma_loop_duplicate)
> > + << LoopHintAttr::getOptionName(Option);
> > }
> > CategoryState.EnabledIsSet = true;
> > CategoryState.Enabled = ValueInt;
> > } else {
> > - // Numeric hint. For example, unroll_count(8).
> > + // Numeric hint. For example, vectorize_width(8).
> > if (CategoryState.ValueIsSet) {
> > // Cannot specify numeric hint twice.
> > - S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
> > - << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)
> > - << CategoryState.Value << LoopHintAttr::getOptionName(Option)
> > - << ValueInt;
> > + S.Diag(ValueLoc, diag::err_pragma_loop_duplicate)
> > + << LoopHintAttr::getOptionName(Option);
> > }
> > CategoryState.ValueIsSet = true;
> > CategoryState.Value = ValueInt;
> > @@ -184,8 +190,7 @@
> > CategoryState.ValueIsSet) {
> > // Disable hints are not compatible with numeric hints of the
> > // same category.
> > - S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
> > - << /*Duplicate=*/false
> > + S.Diag(ValueLoc, diag::err_pragma_loop_incompatible)
> > << LoopHintAttr::getOptionName(CategoryState.EnableOptionId)
> > << LoopHintAttr::getValueName(CategoryState.Enabled)
> > << LoopHintAttr::getOptionName(CategoryState.NumericOptionId)
> > Index: test/CodeGen/pragma-loop.cpp
> > ===================================================================
> > --- test/CodeGen/pragma-loop.cpp
> > +++ test/CodeGen/pragma-loop.cpp
> > @@ -8,7 +8,7 @@
> > #pragma clang loop vectorize(enable)
> > #pragma clang loop interleave_count(4)
> > #pragma clang loop vectorize_width(4)
> > -#pragma clang loop unroll(enable)
> > +#pragma unroll
> > while (i < Length) {
> > // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
> > ![[LOOP_1:.*]]
> > List[i] = i * 2;
> > @@ -20,7 +20,8 @@
> > void do_test(int *List, int Length) {
> > int i = 0;
> > 
> > -#pragma clang loop vectorize_width(8) interleave_count(4)
> > unroll(disable)
> > +#pragma clang loop vectorize_width(8) interleave_count(4)
> > +#pragma unroll 4
> > do {
> > // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
> > ![[LOOP_2:.*]]
> > List[i] = i * 2;
> > @@ -32,7 +33,7 @@
> > void for_test(int *List, int Length) {
> > #pragma clang loop interleave(enable)
> > #pragma clang loop interleave_count(4)
> > -#pragma clang loop unroll_count(8)
> > +#pragma unroll(8)
> > for (int i = 0; i < Length; i++) {
> > // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
> > ![[LOOP_3:.*]]
> > List[i] = i * 2;
> > @@ -53,7 +54,7 @@
> > 
> > // Verify disable pragma clang loop directive generates correct
> > metadata
> > void disable_test(int *List, int Length) {
> > -#pragma clang loop vectorize(disable) unroll(disable)
> > +#pragma clang loop vectorize(disable)
> > for (int i = 0; i < Length; i++) {
> > // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
> > ![[LOOP_5:.*]]
> > List[i] = i * 2;
> > @@ -67,7 +68,7 @@
> > // Verify defines are correctly resolved in pragma clang loop
> > directive
> > void for_define_test(int *List, int Length, int Value) {
> > #pragma clang loop vectorize_width(VECWIDTH)
> > interleave_count(INTCOUNT)
> > -#pragma clang loop unroll_count(UNROLLCOUNT)
> > +#pragma unroll(UNROLLCOUNT)
> > for (int i = 0; i < Length; i++) {
> > // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
> > ![[LOOP_6:.*]]
> > List[i] = i * Value;
> > @@ -78,7 +79,8 @@
> > template <typename A>
> > void for_template_test(A *List, int Length, A Value) {
> > 
> > -#pragma clang loop vectorize_width(8) interleave_count(8)
> > unroll_count(8)
> > +#pragma clang loop vectorize_width(8) interleave_count(8)
> > +#pragma unroll 8
> > for (int i = 0; i < Length; i++) {
> > // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
> > ![[LOOP_7:.*]]
> > List[i] = i * Value;
> > @@ -89,7 +91,7 @@
> > template <typename A>
> > void for_template_define_test(A *List, int Length, A Value) {
> > #pragma clang loop vectorize_width(VECWIDTH)
> > interleave_count(INTCOUNT)
> > -#pragma clang loop unroll_count(UNROLLCOUNT)
> > +#pragma unroll UNROLLCOUNT
> > for (int i = 0; i < Length; i++) {
> > // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
> > ![[LOOP_8:.*]]
> > List[i] = i * Value;
> > @@ -113,15 +115,15 @@
> > // CHECK: ![[WIDTH_4]] = metadata !{metadata
> > !"llvm.loop.vectorize.width", i32 4}
> > // CHECK: ![[INTERLEAVE_4]] = metadata !{metadata
> > !"llvm.loop.vectorize.unroll", i32 4}
> > // CHECK: ![[INTENABLE_1]] = metadata !{metadata
> > !"llvm.loop.vectorize.enable", i1 true}
> > -// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]],
> > metadata ![[UNROLLENABLE_0:.*]], metadata ![[INTERLEAVE_4:.*]],
> > metadata ![[WIDTH_8:.*]]}
> > -// CHECK: ![[UNROLLENABLE_0]] = metadata !{metadata
> > !"llvm.loop.unroll.enable", i1 false}
> > +// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]],
> > metadata ![[UNROLL_4:.*]], metadata ![[INTERLEAVE_4:.*]], metadata
> > ![[WIDTH_8:.*]]}
> > +// CHECK: ![[UNROLL_4]] = metadata !{metadata
> > !"llvm.loop.unroll.count", i32 4}
> > // CHECK: ![[WIDTH_8]] = metadata !{metadata
> > !"llvm.loop.vectorize.width", i32 8}
> > // CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata
> > ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_4:.*]], metadata
> > ![[ENABLE_1:.*]]}
> > // CHECK: ![[UNROLL_8]] = metadata !{metadata
> > !"llvm.loop.unroll.count", i32 8}
> > // CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata
> > ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
> > // CHECK: ![[INTERLEAVE_2]] = metadata !{metadata
> > !"llvm.loop.vectorize.unroll", i32 2}
> > // CHECK: ![[WIDTH_2]] = metadata !{metadata
> > !"llvm.loop.vectorize.width", i32 2}
> > -// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata
> > ![[UNROLLENABLE_0:.*]], metadata ![[WIDTH_1:.*]]}
> > +// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata
> > ![[WIDTH_1:.*]]}
> > // CHECK: ![[WIDTH_1]] = metadata !{metadata
> > !"llvm.loop.vectorize.width", i32 1}
> > // CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata
> > ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata
> > ![[WIDTH_2:.*]]}
> > // CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata
> > ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata
> > ![[WIDTH_8:.*]]}
> > Index: test/PCH/pragma-loop.cpp
> > ===================================================================
> > --- test/PCH/pragma-loop.cpp
> > +++ test/PCH/pragma-loop.cpp
> > @@ -4,13 +4,13 @@
> > // 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 unroll_count(16)
> > +// CHECK: #pragma unroll (16)
> > // CHECK: #pragma clang loop interleave_count(8)
> > // CHECK: #pragma clang loop vectorize_width(4)
> > -// CHECK: #pragma clang loop unroll(disable)
> > +// CHECK: #pragma unroll
> > // CHECK: #pragma clang loop interleave(disable)
> > // CHECK: #pragma clang loop vectorize(enable)
> > -// CHECK: #pragma clang loop unroll(enable)
> > +// CHECK: #pragma unroll 8
> > // CHECK: #pragma clang loop interleave(enable)
> > // CHECK: #pragma clang loop vectorize(disable)
> > 
> > @@ -23,7 +23,7 @@
> > int i = 0;
> > #pragma clang loop vectorize_width(4)
> > #pragma clang loop interleave_count(8)
> > -#pragma clang loop unroll_count(16)
> > +#pragma unroll(16)
> > while (i < Length) {
> > List[i] = i;
> > i++;
> > @@ -34,7 +34,7 @@
> > int i = 0;
> > #pragma clang loop vectorize(enable)
> > #pragma clang loop interleave(disable)
> > -#pragma clang loop unroll(disable)
> > +#pragma unroll
> > while (i - 1 < Length) {
> > List[i] = i;
> > i++;
> > @@ -45,7 +45,7 @@
> > int i = 0;
> > #pragma clang loop vectorize(disable)
> > #pragma clang loop interleave(enable)
> > -#pragma clang loop unroll(enable)
> > +#pragma unroll 8
> > while (i - 3 < Length) {
> > List[i] = i;
> > i++;
> > Index: test/Parser/pragma-loop.cpp
> > ===================================================================
> > --- test/Parser/pragma-loop.cpp
> > +++ test/Parser/pragma-loop.cpp
> > @@ -8,26 +8,26 @@
> > 
> > #pragma clang loop vectorize(enable)
> > #pragma clang loop interleave(enable)
> > -#pragma clang loop unroll(enable)
> > +#pragma unroll
> > while (i + 1 < Length) {
> > List[i] = i;
> > }
> > 
> > #pragma clang loop vectorize_width(4)
> > #pragma clang loop interleave_count(8)
> > -#pragma clang loop unroll_count(16)
> > +#pragma unroll 16
> > while (i < Length) {
> > List[i] = i;
> > }
> > 
> > #pragma clang loop vectorize(disable)
> > #pragma clang loop interleave(disable)
> > -#pragma clang loop unroll(disable)
> > +#pragma unroll(4)
> > while (i - 1 < Length) {
> > List[i] = i;
> > }
> > 
> > -#pragma clang loop vectorize_width(4) interleave_count(8)
> > unroll_count(16)
> > +#pragma clang loop vectorize_width(4) interleave_count(8)
> > while (i - 2 < Length) {
> > List[i] = i;
> > }
> > @@ -38,81 +38,82 @@
> > }
> > 
> > int VList[Length];
> > -#pragma clang loop vectorize(disable) interleave(disable)
> > unroll(disable)
> > +#pragma clang loop vectorize(disable) interleave(disable)
> > for (int j : VList) {
> > VList[j] = List[j];
> > }
> > 
> > /* expected-error {{expected '('}} */ #pragma clang loop vectorize
> > /* expected-error {{expected '('}} */ #pragma clang loop interleave
> > -/* expected-error {{expected '('}} */ #pragma clang loop unroll
> > 
> > /* expected-error {{expected ')'}} */ #pragma clang loop
> > vectorize(enable
> > /* expected-error {{expected ')'}} */ #pragma clang loop
> > interleave(enable
> > -/* expected-error {{expected ')'}} */ #pragma clang loop
> > unroll(enable
> > 
> > /* expected-error {{expected ')'}} */ #pragma clang loop
> > vectorize_width(4
> > /* expected-error {{expected ')'}} */ #pragma clang loop
> > interleave_count(4
> > -/* expected-error {{expected ')'}} */ #pragma clang loop
> > unroll_count(4
> > +/* expected-error {{expected ')'}} */ #pragma unroll(4
> > 
> > -/* expected-error {{missing argument to loop pragma 'vectorize'}}
> > */ #pragma clang loop vectorize()
> > -/* expected-error {{missing argument to loop pragma
> > 'interleave_count'}} */ #pragma clang loop interleave_count()
> > -/* expected-error {{missing argument to loop pragma 'unroll'}} */
> > #pragma clang loop unroll()
> > +/* expected-error {{missing argument to 'loop' pragma}} */ #pragma
> > clang loop vectorize()
> > +/* expected-error {{missing argument to 'loop' pragma}} */ #pragma
> > clang loop interleave_count()
> > +/* expected-error {{missing argument to 'unroll' pragma}} */
> > #pragma unroll()
> > 
> > /* expected-error {{missing option}} */ #pragma clang loop
> > /* expected-error {{invalid option 'badkeyword'}} */ #pragma clang
> > loop badkeyword
> > /* expected-error {{invalid option 'badkeyword'}} */ #pragma clang
> > loop badkeyword(enable)
> > /* expected-error {{invalid option 'badkeyword'}} */ #pragma clang
> > loop vectorize(enable) badkeyword(4)
> > /* expected-warning {{extra tokens at end of '#pragma clang loop'}}
> > */ #pragma clang loop vectorize(enable) ,
> > +/* expected-warning {{extra tokens at end of '#pragma unroll'}} */
> > #pragma unroll 1 foobar
> > 
> > while (i-4 < Length) {
> > List[i] = i;
> > }
> > 
> > /* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop vectorize_width(0)
> > /* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop interleave_count(0)
> > -/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop unroll_count(0)
> > +/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma unroll 0
> > while (i-5 < Length) {
> > List[i] = i;
> > }
> > 
> > /* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop vectorize_width(3000000000)
> > /* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop interleave_count(3000000000)
> > -/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop unroll_count(3000000000)
> > +/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma unroll 3000000000
> > while (i-6 < Length) {
> > List[i] = i;
> > }
> > 
> > /* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop vectorize_width(badvalue)
> > /* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop interleave_count(badvalue)
> > -/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop unroll_count(badvalue)
> > +/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma unroll badvalue
> > while (i-6 < Length) {
> > List[i] = i;
> > }
> > 
> > /* expected-error {{invalid argument; expected 'enable' or
> > 'disable'}} */ #pragma clang loop vectorize(badidentifier)
> > /* expected-error {{invalid argument; expected 'enable' or
> > 'disable'}} */ #pragma clang loop interleave(badidentifier)
> > -/* expected-error {{invalid argument; expected 'enable' or
> > 'disable'}} */ #pragma clang loop unroll(badidentifier)
> > while (i-7 < Length) {
> > List[i] = i;
> > }
> > 
> > // PR20069 - Loop pragma arguments that are not identifiers or
> > numeric
> > // constants crash FE.
> > /* expected-error {{invalid argument; expected 'enable' or
> > 'disable'}} */ #pragma clang loop vectorize(()
> > /* expected-error {{invalid argument; expected 'enable' or
> > 'disable'}} */ #pragma clang loop interleave(*)
> > -/* expected-error {{invalid argument; expected 'enable' or
> > 'disable'}} */ #pragma clang loop unroll(=)
> > /* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop vectorize_width(^)
> > /* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop interleave_count(/)
> > -/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma clang loop unroll_count(==)
> > +/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma unroll(==)
> > +/* expected-error {{invalid argument; expected a positive integer
> > value}} */ #pragma unroll -
> > while (i-8 < Length) {
> > List[i] = i;
> > }
> > 
> > #pragma clang loop vectorize(enable)
> > -/* expected-error {{expected a for, while, or do-while loop to
> > follow the '#pragma clang loop' directive}} */ int j = Length;
> > +/* expected-error {{expected a for, while, or do-while loop to
> > follow the 'loop' pragma}} */ int j = Length;
> > List[0] = List[1];
> > 
> > +#pragma unroll
> > +/* expected-error {{expected a for, while, or do-while loop to
> > follow the 'unroll' pragma}} */ List[2] = List[3];
> > +
> > while (j-1 < Length) {
> > List[j] = j;
> > }
> > @@ -126,38 +127,34 @@
> > #pragma clang loop vectorize(disable)
> > /* expected-error {{incompatible directives 'interleave(disable)'
> > and 'interleave_count(4)'}} */ #pragma clang loop
> > interleave_count(4)
> > #pragma clang loop interleave(disable)
> > -/* expected-error {{incompatible directives 'unroll(disable)' and
> > 'unroll_count(4)'}} */ #pragma clang loop unroll_count(4)
> > -#pragma clang loop unroll(disable)
> > while (i-8 < Length) {
> > List[i] = i;
> > }
> > 
> > -/* expected-error {{duplicate directives 'vectorize(disable)' and
> > 'vectorize(enable)'}} */ #pragma clang loop vectorize(enable)
> > +/* expected-error {{duplicate 'vectorize' directives}} */ #pragma
> > clang loop vectorize(enable)
> > #pragma clang loop vectorize(disable)
> > -/* expected-error {{duplicate directives 'interleave(disable)' and
> > 'interleave(enable)'}} */ #pragma clang loop interleave(enable)
> > -#pragma clang loop interleave(disable)
> > -/* expected-error {{duplicate directives 'unroll(disable)' and
> > 'unroll(enable)'}} */ #pragma clang loop unroll(enable)
> > -#pragma clang loop unroll(disable)
> > +/* expected-error {{duplicate 'interleave' directives}} */ #pragma
> > clang loop interleave(enable)
> > +#pragma clang loop interleave(enable)
> > +/* expected-error {{duplicate 'unroll' directives}} */ #pragma
> > unroll
> > +#pragma unroll
> > while (i-9 < Length) {
> > List[i] = i;
> > }
> > 
> > /* expected-error {{incompatible directives 'vectorize(disable)'
> > and 'vectorize_width(4)'}} */ #pragma clang loop
> > vectorize(disable)
> > #pragma clang loop vectorize_width(4)
> > /* expected-error {{incompatible directives 'interleave(disable)'
> > and 'interleave_count(4)'}} */ #pragma clang loop
> > interleave(disable)
> > #pragma clang loop interleave_count(4)
> > -/* expected-error {{incompatible directives 'unroll(disable)' and
> > 'unroll_count(4)'}} */ #pragma clang loop unroll(disable)
> > -#pragma clang loop unroll_count(4)
> > while (i-10 < Length) {
> > List[i] = i;
> > }
> > 
> > -/* expected-error {{duplicate directives 'vectorize_width(4)' and
> > 'vectorize_width(8)'}} */ #pragma clang loop vectorize_width(8)
> > +/* expected-error {{duplicate 'vectorize_width' directives}} */
> > #pragma clang loop vectorize_width(8)
> > #pragma clang loop vectorize_width(4)
> > -/* expected-error {{duplicate directives 'interleave_count(4)' and
> > 'interleave_count(8)'}} */ #pragma clang loop interleave_count(8)
> > +/* expected-error {{duplicate 'interleave_count' directives}} */
> > #pragma clang loop interleave_count(8)
> > #pragma clang loop interleave_count(4)
> > -/* expected-error {{duplicate directives 'unroll_count(4)' and
> > 'unroll_count(8)'}} */ #pragma clang loop unroll_count(8)
> > -#pragma clang loop unroll_count(4)
> > +/* expected-error {{duplicate 'unroll' directives}} */ #pragma
> > unroll 8
> > +#pragma unroll(4)
> > while (i-11 < Length) {
> > List[i] = i;
> > }
> > 
> 
> ~Aaron
> 
> 

-- 
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory



More information about the cfe-commits mailing list