summaryrefslogtreecommitdiffstats
path: root/lib/Parse/ParsePragma.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/ParsePragma.cpp')
-rw-r--r--lib/Parse/ParsePragma.cpp313
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";
OpenPOWER on IntegriCloud