diff options
Diffstat (limited to 'lib/Parse/ParsePragma.cpp')
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 313 |
1 files changed, 215 insertions, 98 deletions
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index d3777f3..473be54 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "RAIIObjectsForParser.h" +#include "clang/AST/ASTContext.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" @@ -228,6 +229,9 @@ void Parser::initializePragmaHandlers() { UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll")); PP.AddPragmaHandler(UnrollHintHandler.get()); + + NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll")); + PP.AddPragmaHandler(NoUnrollHintHandler.get()); } void Parser::resetPragmaHandlers() { @@ -291,6 +295,9 @@ void Parser::resetPragmaHandlers() { PP.RemovePragmaHandler(UnrollHintHandler.get()); UnrollHintHandler.reset(); + + PP.RemovePragmaHandler(NoUnrollHintHandler.get()); + NoUnrollHintHandler.reset(); } /// \brief Handle the annotation token produced for #pragma unused(...) @@ -525,36 +532,50 @@ bool Parser::HandlePragmaMSSection(StringRef PragmaName, << PragmaName; return false; } - int SectionFlags = 0; + int SectionFlags = ASTContext::PSF_Read; + bool SectionFlagsAreDefault = true; while (Tok.is(tok::comma)) { PP.Lex(Tok); // , + // Ignore "long" and "short". + // They are undocumented, but widely used, section attributes which appear + // to do nothing. + if (Tok.is(tok::kw_long) || Tok.is(tok::kw_short)) { + PP.Lex(Tok); // long/short + continue; + } + if (!Tok.isAnyIdentifier()) { PP.Diag(PragmaLocation, diag::warn_pragma_expected_action_or_r_paren) << PragmaName; return false; } - Sema::PragmaSectionFlag Flag = - llvm::StringSwitch<Sema::PragmaSectionFlag>( + ASTContext::PragmaSectionFlag Flag = + llvm::StringSwitch<ASTContext::PragmaSectionFlag>( Tok.getIdentifierInfo()->getName()) - .Case("read", Sema::PSF_Read) - .Case("write", Sema::PSF_Write) - .Case("execute", Sema::PSF_Execute) - .Case("shared", Sema::PSF_Invalid) - .Case("nopage", Sema::PSF_Invalid) - .Case("nocache", Sema::PSF_Invalid) - .Case("discard", Sema::PSF_Invalid) - .Case("remove", Sema::PSF_Invalid) - .Default(Sema::PSF_None); - if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) { - PP.Diag(PragmaLocation, Flag == Sema::PSF_None + .Case("read", ASTContext::PSF_Read) + .Case("write", ASTContext::PSF_Write) + .Case("execute", ASTContext::PSF_Execute) + .Case("shared", ASTContext::PSF_Invalid) + .Case("nopage", ASTContext::PSF_Invalid) + .Case("nocache", ASTContext::PSF_Invalid) + .Case("discard", ASTContext::PSF_Invalid) + .Case("remove", ASTContext::PSF_Invalid) + .Default(ASTContext::PSF_None); + if (Flag == ASTContext::PSF_None || Flag == ASTContext::PSF_Invalid) { + PP.Diag(PragmaLocation, Flag == ASTContext::PSF_None ? diag::warn_pragma_invalid_specific_action : diag::warn_pragma_unsupported_action) << PragmaName << Tok.getIdentifierInfo()->getName(); return false; } SectionFlags |= Flag; + SectionFlagsAreDefault = false; PP.Lex(Tok); // Identifier } + // If no section attributes are specified, the section will be marked as + // read/write. + if (SectionFlagsAreDefault) + SectionFlags |= ASTContext::PSF_Write; if (Tok.isNot(tok::r_paren)) { PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName; return false; @@ -718,42 +739,124 @@ bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName, struct PragmaLoopHintInfo { Token PragmaName; Token Option; - Token Value; - bool HasValue; + Token *Toks; + size_t TokSize; + PragmaLoopHintInfo() : Toks(nullptr), TokSize(0) {} }; -LoopHint Parser::HandlePragmaLoopHint() { +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()); - LoopHint Hint; - Hint.PragmaNameLoc = - IdentifierLoc::create(Actions.Context, Info->PragmaName.getLocation(), - Info->PragmaName.getIdentifierInfo()); - Hint.OptionLoc = - IdentifierLoc::create(Actions.Context, Info->Option.getLocation(), - Info->Option.getIdentifierInfo()); - if (Info->HasValue) { - Hint.Range = - SourceRange(Info->Option.getLocation(), Info->Value.getLocation()); - 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; + IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo(); + Hint.PragmaNameLoc = IdentifierLoc::create( + Actions.Context, Info->PragmaName.getLocation(), PragmaNameInfo); + + // It is possible that the loop hint has no option identifier, such as + // #pragma unroll(4). + IdentifierInfo *OptionInfo = Info->Option.is(tok::identifier) + ? Info->Option.getIdentifierInfo() + : nullptr; + 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 (TokSize == 0 && (PragmaUnroll || PragmaNoUnroll)) { + ConsumeToken(); // The annotation token. + Hint.Range = Info->PragmaName.getLocation(); + return true; + } + + // 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) { // 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 = Toks[0].getLocation(); + IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo(); + if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full") + : !StateInfo->isStr("enable")) && + !StateInfo->isStr("disable"))) { + 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 { - Hint.Range = SourceRange(Info->PragmaName.getLocation()); - Hint.ValueLoc = nullptr; - Hint.ValueExpr = nullptr; + // 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)) + ConsumeAnyToken(); + } + + ConsumeToken(); // Consume the constant expression eof terminator. + + if (R.isInvalid() || + Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation())) + return false; + + // Argument is a constant expression with an integer type. + Hint.ValueExpr = R.get(); } - return Hint; + Hint.Range = SourceRange(Info->PragmaName.getLocation(), + Info->Toks[TokSize - 1].getLocation()); + return true; } // #pragma GCC visibility comes in two variants: @@ -1725,8 +1828,7 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, PP.Lex(Tok); if (Tok.is(tok::eod)) { PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) - << "clang optimize" - << "'on' or 'off'"; + << "clang optimize" << /*Expected=*/true << "'on' or 'off'"; return; } if (Tok.isNot(tok::identifier)) { @@ -1756,44 +1858,48 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, } /// \brief Parses loop or unroll pragma hint value and fills in Info. -static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName, - Token &Option, bool &ValueInParens, +static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName, + Token Option, bool ValueInParens, PragmaLoopHintInfo &Info) { - ValueInParens = Tok.is(tok::l_paren); - if (ValueInParens) { - PP.Lex(Tok); - 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"; - } - PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) - << PragmaString << "a positive integer value"; - return true; + SmallVector<Token, 1> ValueList; + int OpenParens = ValueInParens ? 1 : 0; + // Read constant expression. + while (Tok.isNot(tok::eod)) { + if (Tok.is(tok::l_paren)) + OpenParens++; + else if (Tok.is(tok::r_paren)) { + OpenParens--; + if (OpenParens == 0 && ValueInParens) + break; } - } - // FIXME: Value should be stored and parsed as a constant expression. - Token Value = Tok; + ValueList.push_back(Tok); + PP.Lex(Tok); + } if (ValueInParens) { - PP.Lex(Tok); + // Read ')' if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; return true; } + PP.Lex(Tok); } + Token EOFTok; + EOFTok.startToken(); + EOFTok.setKind(tok::eof); + EOFTok.setLocation(Tok.getLocation()); + ValueList.push_back(EOFTok); // Terminates expression for parsing. + + Token *TokenArray = (Token *)PP.getPreprocessorAllocator().Allocate( + ValueList.size() * sizeof(Token), llvm::alignOf<Token>()); + std::copy(ValueList.begin(), ValueList.end(), TokenArray); + Info.Toks = TokenArray; + Info.TokSize = ValueList.size(); + Info.PragmaName = PragmaName; Info.Option = Option; - Info.Value = Value; - Info.HasValue = true; return false; } @@ -1806,7 +1912,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName, /// loop-hint: /// 'vectorize' '(' loop-hint-keyword ')' /// 'interleave' '(' loop-hint-keyword ')' -/// 'unroll' '(' loop-hint-keyword ')' +/// 'unroll' '(' unroll-hint-keyword ')' /// 'vectorize_width' '(' loop-hint-value ')' /// 'interleave_count' '(' loop-hint-value ')' /// 'unroll_count' '(' loop-hint-value ')' @@ -1815,6 +1921,10 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName, /// 'enable' /// 'disable' /// +/// unroll-hint-keyword: +/// 'full' +/// 'disable' +/// /// loop-hint-value: /// constant-expression /// @@ -1829,12 +1939,10 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName, /// only works on inner loops. /// /// The unroll and unroll_count directives control the concatenation -/// unroller. Specifying unroll(enable) instructs llvm to try to +/// unroller. Specifying unroll(full) 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) { @@ -1867,17 +1975,19 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, << /*MissingOption=*/false << OptionInfo; return; } - - auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; PP.Lex(Tok); - bool ValueInParens; - if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info)) - return; - if (!ValueInParens) { - PP.Diag(Info->Value.getLocation(), diag::err_expected) << tok::l_paren; + // Read '(' + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; return; } + PP.Lex(Tok); + + auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; + if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true, + *Info)) + return; // Generate the loop hint token. Token LoopHintTok; @@ -1886,9 +1996,6 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, 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)) { @@ -1909,44 +2016,54 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, /// #pragma unroll /// #pragma unroll unroll-hint-value /// #pragma unroll '(' unroll-hint-value ')' +/// #pragma nounroll /// /// unroll-hint-value: /// constant-expression /// -/// Loop unrolling hints are specified with '#pragma unroll'. '#pragma unroll' -/// can take 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. +/// Loop unrolling hints can be specified with '#pragma unroll' or +/// '#pragma nounroll'. '#pragma unroll' can take 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. Specifying, '#pragma nounroll' +/// disables unrolling of the loop. void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) { - // Incoming token is "unroll" of "#pragma unroll". + // Incoming token is "unroll" for "#pragma unroll", or "nounroll" for + // "#pragma nounroll". Token PragmaName = Tok; PP.Lex(Tok); auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; if (Tok.is(tok::eod)) { - // Unroll pragma without an argument. + // nounroll or unroll pragma without an argument. Info->PragmaName = PragmaName; - Info->Option = PragmaName; - Info->HasValue = false; + Info->Option.startToken(); + } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "nounroll"; + return; } else { // Unroll pragma with an argument: "#pragma unroll N" or // "#pragma unroll(N)". - bool ValueInParens; - if (ParseLoopHintValue(PP, Tok, PragmaName, PragmaName, ValueInParens, - *Info)) + // Read '(' if it exists. + bool ValueInParens = Tok.is(tok::l_paren); + if (ValueInParens) + PP.Lex(Tok); + + Token Option; + Option.startToken(); + if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info)) return; // In CUDA, the argument to '#pragma unroll' should not be contained in // parentheses. if (PP.getLangOpts().CUDA && ValueInParens) - PP.Diag(Info->Value.getLocation(), + PP.Diag(Info->Toks[0].getLocation(), diag::warn_pragma_unroll_cuda_value_in_parens); - PP.Lex(Tok); if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "unroll"; |