[PATCH] Add support for unroll pragma
Aaron Ballman
aaron.ballman at gmail.com
Wed Jul 2 07:54:21 PDT 2014
On Tue, Jul 1, 2014 at 6:59 PM, Mark Heffernan <meheff at google.com> wrote:
> Thanks all for your comments. This patch reduces much of the implementation duplication from the previous patch. Unroll and loop optimization hints now both share the same attribute.
>
> Also, the loop unroll pragma now replaces the "#pragma clang loop unroll/unroll_count" directives which have been removed. The following unroll pragma forms are supported:
>
> #pragma unroll
> #pragma unroll N
> #pragma unroll(N)
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?
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
More information about the cfe-commits
mailing list