[PATCH] Add support for unroll pragma

Mark Heffernan meheff at google.com
Mon Jul 7 15:52:33 PDT 2014


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.

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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140707/b731311a/attachment.html>


More information about the cfe-commits mailing list