[PATCH] Support constant expressions, including non-type template parameters, in pragma loop hints
Aaron Ballman
aaron at aaronballman.com
Fri Aug 1 11:38:02 PDT 2014
On Thu, Jul 31, 2014 at 4:33 PM, Tyler Nowicki <tnowicki at apple.com> wrote:
> I made some changes to the diagnostics to make it more clear what is happening here. I think we can make further changes to unify the diagnostics in a follow-up patch.
>
> I resubmitted the ‘state’ patch so the attached patch is good to apply directly to trunk.
>
> Thanks!
> Index: lib/Parse/ParsePragma.cpp
> ===================================================================
> --- lib/Parse/ParsePragma.cpp (revision 214433)
> +++ lib/Parse/ParsePragma.cpp (working copy)
> @@ -718,16 +718,28 @@
> struct PragmaLoopHintInfo {
> Token PragmaName;
> Token Option;
> - Token Value;
> - bool HasValue;
> - PragmaLoopHintInfo() : HasValue(false) {}
> + Token *Toks;
> + size_t TokSize;
> + PragmaLoopHintInfo() : Toks(nullptr), TokSize(0) {}
> };
>
> +static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
> + std::string PragmaString;
> + if (PragmaName.getIdentifierInfo()->getName() == "loop") {
> + PragmaString = "clang loop ";
> + PragmaString += Option.getIdentifierInfo()->getName();
> + } else {
> + assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
> + "Unexpected pragma name");
> + PragmaString = "unroll";
> + }
> + return PragmaString;
> +}
> +
> bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
> assert(Tok.is(tok::annot_pragma_loop_hint));
> PragmaLoopHintInfo *Info =
> static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
> - ConsumeToken(); // The annotation token.
>
> IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
> Hint.PragmaNameLoc = IdentifierLoc::create(
> @@ -737,50 +749,87 @@
> Hint.OptionLoc = IdentifierLoc::create(
> Actions.Context, Info->Option.getLocation(), OptionInfo);
>
> + Token *Toks = Info->Toks;
> + size_t TokSize = Info->TokSize;
> +
> // Return a valid hint if pragma unroll or nounroll were specified
> // without an argument.
> bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
> bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
> - if (!Info->HasValue && (PragmaUnroll || PragmaNoUnroll)) {
> + if (TokSize == 0 && (PragmaUnroll || PragmaNoUnroll)) {
> + ConsumeToken(); // The annotation token.
> Hint.Range = Info->PragmaName.getLocation();
> return true;
> }
>
> - // If no option is specified the argument is assumed to be numeric.
> + // The constant expression is always followed by an eof token, which increases
> + // the TokSize by 1.
> + assert(TokSize > 0 &&
> + "PragmaLoopHintInfo::Toks must contain at least one token.");
> +
> + // If no option is specified the argument is assumed to be a constant expr.
> bool StateOption = false;
> - if (OptionInfo)
> + if (OptionInfo) // Pragma unroll does not specify an option.
> StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
> .Case("vectorize", true)
> .Case("interleave", true)
> .Case("unroll", true)
> .Default(false);
>
> + // Verify loop hint has an argument.
> + if (Toks[0].is(tok::eof)) {
> + ConsumeToken(); // The annotation token.
> + Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument)
> + << /*StateArgument=*/StateOption << /*FullKeyword=*/PragmaUnroll;
> + return false;
> + }
> +
> // Validate the argument.
> if (StateOption) {
> + ConsumeToken(); // The annotation token.
> bool OptionUnroll = OptionInfo->isStr("unroll");
> - SourceLocation StateLoc = Info->Value.getLocation();
> - IdentifierInfo *StateInfo = Info->Value.getIdentifierInfo();
> + SourceLocation StateLoc = Toks[0].getLocation();
> + IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
> if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full")
> : !StateInfo->isStr("enable")) &&
> !StateInfo->isStr("disable"))) {
> - Diag(StateLoc, diag::err_pragma_invalid_keyword)
> - << /*MissingArgument=*/false << /*FullKeyword=*/OptionUnroll;
> + Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword)
> + << /*FullKeyword=*/OptionUnroll;
> return false;
> }
> + if (TokSize > 2)
> + Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
> + << PragmaLoopHintString(Info->PragmaName, Info->Option);
> Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo);
> } else {
> - // 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 {
> - Diag(Info->Value.getLocation(), diag::err_pragma_loop_numeric_value);
> + // Enter constant expression including eof terminator into token stream.
> + PP.EnterTokenStream(Toks, TokSize, /*DisableMacroExpansion=*/false,
> + /*OwnsTokens=*/false);
> + ConsumeToken(); // The annotation token.
> +
> + ExprResult R = ParseConstantExpression();
> +
> + // Tokens following an error in an ill-formed constant expression will
> + // remain in the token stream and must be removed.
> + if (Tok.isNot(tok::eof)) {
> + Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
> + << PragmaLoopHintString(Info->PragmaName, Info->Option);
> + while (Tok.isNot(tok::eof))
> + ConsumeToken();
> + }
> +
> + ConsumeToken(); // Consume the constant expression eof terminator.
> +
> + if (Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation(),
> + /*AllowValueDependent=*/true))
> return false;
> - }
> +
> + // Argument is a constant expression with an integer type.
> + Hint.ValueExpr = R.get();
> }
>
> - Hint.Range =
> - SourceRange(Info->PragmaName.getLocation(), Info->Value.getLocation());
> + Hint.Range = SourceRange(Info->PragmaName.getLocation(),
> + Info->Toks[TokSize - 1].getLocation());
> return true;
> }
>
> @@ -1786,32 +1835,13 @@
> static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
> Token Option, bool ValueInParens,
> PragmaLoopHintInfo &Info) {
> - if (ValueInParens) {
> - if (Tok.is(tok::r_paren)) {
> - // Nothing between the parentheses.
> - std::string PragmaString;
> - if (PragmaName.getIdentifierInfo()->getName() == "loop") {
> - PragmaString = "clang loop ";
> - PragmaString += Option.getIdentifierInfo()->getName();
> - } else {
> - assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
> - "Unexpected pragma name");
> - PragmaString = "unroll";
> - }
> - // Don't try to emit what the pragma is expecting with the diagnostic
> - // because the logic is non-trivial and we give expected values in sema
> - // diagnostics if an invalid argument is given. Here, just note that the
> - // pragma is missing an argument.
> - PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
> - << PragmaString << /*Expected=*/false;
> - return true;
> - }
> + SmallVector<Token, 1> ValueList;
> + // Read constant expression.
> + while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eod)) {
> + ValueList.push_back(Tok);
> + PP.Lex(Tok);
I don't think this is correct -- it won't handle constant expressions
involving parentheses properly. Eg)
#pragma unroll((2+2)+4)
It produces:
E:\Aaron Ballman\Desktop\test2.cpp:9:21: warning: extra tokens at end
of '#pragma unroll' - ignored
#pragma unroll((2+2)+4)
So that should be fixed, and you should have a test for it as well.
~Aaron
More information about the cfe-commits
mailing list