<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Jul 2, 2014 at 7:54 AM, Aaron Ballman <span dir="ltr"><<a href="mailto:aaron.ballman@gmail.com" target="_blank">aaron.ballman@gmail.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div>I may have led you slightly astray on this point. I believe the<br>

</div>
consensus wound up being that having two different syntaxes for the<br>
same thing was okay, and so #pragma loop unroll[_count] should remain.<br>
Richard, Chandler, do I have that correct?<br></blockquote><div><br></div><div>I think Richard and Chandler (correct me if I'm wrong) were referring to supporting the following "#pragma unroll" syntaxes for compatibility purposes:</div>
<div><br></div><div>#pragma unroll  // CUDA, intel, and IBM</div><div>#pragma unroll N  // CUDA</div><div>#pragma unroll(N)  // intel and IBM</div><div><br></div><div>However, not much has been said about, in addition, continuing to support the newly added form in the clang pragma namespace:</div>
<div><br></div><div>#pragma clang loop unroll(...) unroll_count(...)</div><div><br></div><div>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.</div>
<div><br></div><div>Mark</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<br>
Some comments:<br>
<br>
> 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 optimizing the<br>
>  subsequent for, while, do-while, or c++11 range-based for loop. The directive<br>
> -provides options for vectorization, interleaving, and unrolling. Loop hints can<br>
> -be specified before any loop and will be ignored if the optimization is not safe<br>
> -to apply.<br>
> -<br>
> -Vectorization and Interleaving<br>
> -------------------------------<br>
> +provides options for vectorization and interleaving. Loop hints can be specified<br>
> +before any loop and will be ignored if the optimization is not 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 target<br>
> @@ -1818,43 +1813,6 @@<br>
>  Specifying a width/count of 1 disables the optimization, and is 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 more<br>
> -opportunities for ILP. Loops can be fully or partially unrolled. Full unrolling<br>
> -eliminates the loop and replaces it with an enumerated sequence of loop<br>
> -iterations. Full unrolling is only possible if the loop trip count is known at<br>
> -compile time. Partial unrolling replicates the loop body within the loop and<br>
> -reduces the trip count.<br>
> -<br>
> -If ``unroll(enable)`` is specified the unroller will attempt to fully unroll the<br>
> -loop if the trip count is known at compile time. If the loop count is not known<br>
> -or the fully unrolled code size is greater than the limit specified by the<br>
> -`-pragma-unroll-threshold` command line option the loop will be 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 ``unroll_count(_value_)`` where<br>
> -_value_ is a positive integer. If this value is greater than the trip count the<br>
> -loop will be fully unrolled. Otherwise the loop is partially 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 ``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 clang loop`<br>
> -directive just prior to the desired loop. The directive allows vectorization,<br>
> -interleaving, and unrolling to be enabled or disabled. Vector width as well<br>
> -as interleave and unrolling count can be manually specified.  See language<br>
> -extensions for details.<br>
> +directive just prior to the desired loop. The directive allows vectorization and<br>
> +interleaving to be enabled or disabled. Vector width and interleave count can be<br>
> +manually specified.  See language extensions for details.<br>
> +<br>
> +Clang now supports the `#pragma unroll` directive to specify loop unrolling<br>
> +optimization hints.  Placed just prior to the desired loop, `#pragma unroll`<br>
> +directs the loop unroller to attempt to fully unroll the loop.  The pragma may<br>
> +also be specified with a positive integer parameter indicating the desired<br>
> +unroll count: `#pragma unroll N`.  The unroll count parameter can 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>
<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>
><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 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 &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 ``#pragma unroll``<br>
> +directive.  The pragma is placed immediately before a for, while, do-while, or<br>
> +c++11 range-based for loop.  The pragma takes an optional parameter 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 unroller will<br>
> +attempt to fully unroll the loop if the trip count is known at compile time.  If<br>
> +the loop count is not known or the fully unrolled code size is greater than the<br>
> +limit specified by the ``-pragma-unroll-threshold`` command-line 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 integer directs<br>
> +the unroller to unroll the loop _value_ times.  The value may be optionally<br>
> +enclosed in parentheses such as ``#pragma unroll(_value_)``.  If this value is<br>
> +greater than the trip count the loop will be fully unrolled. Otherwise the loop<br>
> +is partially unrolled subject to the ``-pragma-unroll-threshold`` 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 vectorize, "<br>
>    "vectorize_width, interleave, interleave_count, unroll, or unroll_count">;<br>
>  def err_pragma_loop_missing_argument : Error<<br>
> -  "missing argument to loop pragma %0">;<br>
> +  "missing argument to %0 pragma">;<br>
<br>
The name of this diagnostic should probably change given how generic<br>
the text now is.<br>
<br>
>  } // 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 '%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>
<br>
Why was this split into two errors?<br>
<br>
>  def err_pragma_loop_precedes_nonloop : Error<<br>
> -  "expected a for, while, or do-while loop to follow the '#pragma clang loop' "<br>
> -  "directive">;<br>
> +  "expected a for, while, or do-while loop to follow the '%0' 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 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 unroll"<br>
> +  // hints.<br>
> +  IdentifierLoc *PragmaNameLoc;<br>
> +  // Name of the loop hint.  Examples: "unroll", "vectorize".  In the unroll<br>
> +  // case, this is identical to PragmaNameLoc.<br>
>    IdentifierLoc *OptionLoc;<br>
> +  // Identifier for the hint argument.  If null, then the hint has no argument<br>
> +  // (for example, "#pragma unroll").<br>
> +  IdentifierLoc *ValueLoc;<br>
> +  // If the hint argument exists and is contained in parentheses (for example,<br>
> +  // "vectorize_width(8)") this contains the identifier for the 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 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 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(Tok.is(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, 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(), Info->Value.getLocation());<br>
> -<br>
> -  // FIXME: We should allow non-type template parameters for the loop hint<br>
> -  // value. See bug report #19610<br>
> -  if (Info->Value.is(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, Info->CloseParen.getLocation(),<br>
> +                                Info->CloseParen.getIdentifierInfo());<br>
> +    } else {<br>
> +      Hint.Range =<br>
> +          SourceRange(Info->Option.getLocation(), 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 loop hint<br>
> +    // value. See bug report #19610<br>
> +    if (Info->Value.is(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 &PragmaName,<br>
> +                        Token &Option, PragmaLoopHintInfo &Info) {<br>
> +  bool ValueInParens;<br>
<br>
Could simply initialize to Tok.is(tok::l_paren), then not need the<br>
else clause at all.<br>
<br>
> +  if (Tok.is(tok::l_paren)) {<br>
> +    ValueInParens = true;<br>
> +    PP.Lex(Tok);<br>
> +    if (Tok.is(tok::r_paren)) {<br>
> +      // Nothing between the parentheses.<br>
> +      PP.Diag(Tok.getLocation(), 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 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, even if it is<br>
>  /// possible and profitable, and 0 is invalid. The loop vectorizer currently<br>
>  /// only works on inner loops.<br>
> -///<br>
> -/// The unroll and unroll_count directives control the concatenation<br>
> -/// unroller. Specifying unroll(enable) instructs llvm to try to<br>
> -/// unroll the loop completely, and unroll(disable) disables unrolling<br>
> -/// for the loop. Specifying unroll_count(_value_) instructs llvm to<br>
> -/// try to unroll the loop the number of times indicated by the 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 parsed as a<br>
> -    // constant expression.<br>
> +    auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;<br>
>      PP.Lex(Tok);<br>
> -    if (Tok.is(tok::r_paren)) {<br>
> -      // Nothing between the parentheses.<br>
> -      PP.Diag(Tok.getLocation(), 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) << tok::l_paren;<br>
>        return;<br>
>      }<br>
><br>
> -    // Get next optimization option.<br>
> -    PP.Lex(Tok);<br>
> -<br>
> -    auto *Info = new (PP.getPreprocessorAllocator()) 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 can include a<br>
> +/// numeric argument optionally contained in parentheses.  With no argument the<br>
> +/// directive instructs llvm to try to unroll the loop completely. A positive<br>
> +/// integer argument can be specified to indicate the number of times the loop<br>
> +/// should be unrolled.  To maximize compatibility with other compilers the<br>
> +/// unroll count argument can be specified with or without 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()) PragmaLoopHintInfo;<br>
> +  if (Tok.is(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, /*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 (Tok.is(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, 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 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(), 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>
> -      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 : LoopHintAttr::Unroll;<br>
> +    Spelling = LoopHintAttr::Pragma_unroll;<br>
> +  } else {<br>
> +    Option = 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 == 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 *> &Attrs) {<br>
> +static void CheckForIncompatibleAttributes(<br>
> +    Sema &S, SmallVectorImpl<const Attr *> &Attrs) {<br>
<br>
Attrs should be const.<br>
<br>
>    // 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 ![[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) 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 ![[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 ![[LOOP_3:.*]]<br>
>      List[i] = i * 2;<br>
> @@ -53,7 +54,7 @@<br>
><br>
>  // Verify disable pragma clang loop directive generates correct 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 ![[LOOP_5:.*]]<br>
>      List[i] = i * 2;<br>
> @@ -67,7 +68,7 @@<br>
>  // Verify defines are correctly resolved in pragma clang loop directive<br>
>  void for_define_test(int *List, int Length, int Value) {<br>
>  #pragma clang loop vectorize_width(VECWIDTH) 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 ![[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) 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 ![[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) 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 ![[LOOP_8:.*]]<br>
>      List[i] = i * Value;<br>
> @@ -113,15 +115,15 @@<br>
>  // CHECK: ![[WIDTH_4]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 4}<br>
>  // CHECK: ![[INTERLEAVE_4]] = metadata !{metadata !"llvm.loop.vectorize.unroll", i32 4}<br>
>  // CHECK: ![[INTENABLE_1]] = metadata !{metadata !"llvm.loop.vectorize.enable", i1 true}<br>
> -// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata ![[UNROLLENABLE_0:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[WIDTH_8:.*]]}<br>
> -// CHECK: ![[UNROLLENABLE_0]] = metadata !{metadata !"llvm.loop.unroll.enable", i1 false}<br>
> +// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata ![[UNROLL_4:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[WIDTH_8:.*]]}<br>
> +// CHECK: ![[UNROLL_4]] = metadata !{metadata !"llvm.loop.unroll.count", i32 4}<br>
>  // CHECK: ![[WIDTH_8]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 8}<br>
>  // CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[ENABLE_1:.*]]}<br>
>  // CHECK: ![[UNROLL_8]] = metadata !{metadata !"llvm.loop.unroll.count", i32 8}<br>
>  // CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}<br>
>  // CHECK: ![[INTERLEAVE_2]] = metadata !{metadata !"llvm.loop.vectorize.unroll", i32 2}<br>
>  // CHECK: ![[WIDTH_2]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 2}<br>
> -// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[UNROLLENABLE_0:.*]], metadata ![[WIDTH_1:.*]]}<br>
> +// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[WIDTH_1:.*]]}<br>
>  // CHECK: ![[WIDTH_1]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 1}<br>
>  // CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}<br>
>  // CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata ![[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 attributes to be<br>
>  // reversed. The checks are consequently in the reverse order 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) 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) 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 vectorize(enable<br>
>  /* expected-error {{expected ')'}} */ #pragma clang loop interleave(enable<br>
> -/* expected-error {{expected ')'}} */ #pragma clang loop unroll(enable<br>
><br>
>  /* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(4<br>
>  /* expected-error {{expected ')'}} */ #pragma clang loop interleave_count(4<br>
> -/* expected-error {{expected ')'}} */ #pragma clang loop unroll_count(4<br>
> +/* expected-error {{expected ')'}} */ #pragma unroll(4<br>
><br>
> -/* expected-error {{missing argument to loop pragma 'vectorize'}} */ #pragma clang loop vectorize()<br>
> -/* expected-error {{missing argument to loop pragma 'interleave_count'}} */ #pragma clang loop interleave_count()<br>
> -/* expected-error {{missing argument to loop pragma 'unroll'}} */ #pragma clang loop unroll()<br>
> +/* expected-error {{missing argument to 'loop' pragma}} */ #pragma clang loop vectorize()<br>
> +/* expected-error {{missing argument to 'loop' pragma}} */ #pragma clang loop interleave_count()<br>
> +/* expected-error {{missing argument to 'unroll' pragma}} */ #pragma unroll()<br>
><br>
>  /* expected-error {{missing option}} */ #pragma clang loop<br>
>  /* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword<br>
>  /* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword(enable)<br>
>  /* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop vectorize(enable) badkeyword(4)<br>
>  /* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize(enable) ,<br>
> +/* expected-warning {{extra tokens at end of '#pragma unroll'}} */ #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 value}} */ #pragma clang loop vectorize_width(0)<br>
>  /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(0)<br>
> -/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(0)<br>
> +/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 0<br>
>    while (i-5 < Length) {<br>
>      List[i] = i;<br>
>    }<br>
><br>
>  /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(3000000000)<br>
>  /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(3000000000)<br>
> -/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(3000000000)<br>
> +/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 3000000000<br>
>    while (i-6 < Length) {<br>
>      List[i] = i;<br>
>    }<br>
><br>
>  /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(badvalue)<br>
>  /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(badvalue)<br>
> -/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(badvalue)<br>
> +/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll badvalue<br>
>    while (i-6 < Length) {<br>
>      List[i] = i;<br>
>    }<br>
><br>
>  /* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize(badidentifier)<br>
>  /* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop interleave(badidentifier)<br>
> -/* expected-error {{invalid argument; expected 'enable' or '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 numeric<br>
>  // constants crash FE.<br>
>  /* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize(()<br>
>  /* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop interleave(*)<br>
> -/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop unroll(=)<br>
>  /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(^)<br>
>  /* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(/)<br>
> -/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(==)<br>
> +/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(==)<br>
> +/* expected-error {{invalid argument; expected a positive integer 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 follow the '#pragma clang loop' directive}} */ int j = Length;<br>
> +/* expected-error {{expected a for, while, or do-while loop to 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 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)' and 'interleave_count(4)'}} */ #pragma clang loop interleave_count(4)<br>
>  #pragma clang loop interleave(disable)<br>
> -/* expected-error {{incompatible directives 'unroll(disable)' and '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 'vectorize(enable)'}} */ #pragma clang loop vectorize(enable)<br>
> +/* expected-error {{duplicate 'vectorize' directives}} */ #pragma clang loop vectorize(enable)<br>
>  #pragma clang loop vectorize(disable)<br>
> -/* expected-error {{duplicate directives 'interleave(disable)' and 'interleave(enable)'}} */ #pragma clang loop interleave(enable)<br>
> -#pragma clang loop interleave(disable)<br>
> -/* expected-error {{duplicate directives 'unroll(disable)' and 'unroll(enable)'}} */ #pragma clang loop unroll(enable)<br>
> -#pragma clang loop unroll(disable)<br>
> +/* expected-error {{duplicate 'interleave' directives}} */ #pragma clang loop interleave(enable)<br>
> +#pragma clang loop interleave(enable)<br>
> +/* expected-error {{duplicate 'unroll' directives}} */ #pragma unroll<br>
> +#pragma unroll<br>
>    while (i-9 < Length) {<br>
>      List[i] = i;<br>
>    }<br>
><br>
>  /* expected-error {{incompatible directives 'vectorize(disable)' and 'vectorize_width(4)'}} */ #pragma clang loop vectorize(disable)<br>
>  #pragma clang loop vectorize_width(4)<br>
>  /* expected-error {{incompatible directives 'interleave(disable)' and 'interleave_count(4)'}} */ #pragma clang loop interleave(disable)<br>
>  #pragma clang loop interleave_count(4)<br>
> -/* expected-error {{incompatible directives 'unroll(disable)' and '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 'vectorize_width(8)'}} */ #pragma clang loop vectorize_width(8)<br>
> +/* expected-error {{duplicate 'vectorize_width' directives}} */ #pragma clang loop vectorize_width(8)<br>
>  #pragma clang loop vectorize_width(4)<br>
> -/* expected-error {{duplicate directives 'interleave_count(4)' and 'interleave_count(8)'}} */ #pragma clang loop interleave_count(8)<br>
> +/* expected-error {{duplicate 'interleave_count' directives}} */ #pragma clang loop interleave_count(8)<br>
>  #pragma clang loop interleave_count(4)<br>
> -/* expected-error {{duplicate directives 'unroll_count(4)' and 'unroll_count(8)'}} */ #pragma clang loop unroll_count(8)<br>
> -#pragma clang loop unroll_count(4)<br>
> +/* expected-error {{duplicate 'unroll' directives}} */ #pragma unroll 8<br>
> +#pragma unroll(4)<br>
>    while (i-11 < Length) {<br>
>      List[i] = i;<br>
>    }<br>
><br>
<span><font color="#888888"><br>
~Aaron<br>
</font></span></blockquote></div><br></div></div>