[PATCH] Add support for unroll pragma

Mark Heffernan meheff at google.com
Tue Jul 8 09:52:17 PDT 2014


On Tue, Jul 8, 2014 at 9:30 AM, Tyler Nowicki <tnowicki at apple.com> wrote:

> Loop hints can also be specified in a single line.
>
> #pragma clang loop vectorize(enable), interleave(enable), unroll(enable)
>
> But if we take out the unroll loop hint then programmers everywhere will
> need to write two directives. It would be unfortunate if that happened.
>

Sounds reasonable.  As I've flip-flopped twice on this, clearly, I don't
have a strong opinion either way :-)  Happy to make it whatever people
think is reasonable.


> Also, I'm sorry but I think there will be a number of collisions between
> this patch and my own for parsing for constant expressions as a loop hint
> argument. Can the CUDA pragma unroll argument be a constant expression as
> well?
>

Thanks for the heads up about the collision.  I glanced at your patch and I
don't think it'll be too hard for me to resolve.

nvcc (nvidia's CUDA compiler) only supports literal constants.  However, I
don't think it's a big issue to have LLVM be more permissive in this
regard.  Another compiler (IBM xlc) which uses the parentheses-wrapped
syntax which would be nice to support for compatibility ("#pragma
unroll(_value_)") does support expressions, so I think we should just
support expressions for all the syntaxes for simplicity and internal
consistency.  Also, I'd baselessly speculate that whatever we implement now
will ultimately be integrated into nvcc (which defines CUDA) as it is based
on llvm.

Mark


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


More information about the cfe-commits mailing list