Update aosp/master Clang for rebase to r222490.
Change-Id: Ic557ac55e97fbf6ee08771c7b7c3594777b0aefd
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 2b248cc..473be54 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
@@ -148,6 +150,12 @@
Token &FirstToken) override;
};
+struct PragmaUnrollHintHandler : public PragmaHandler {
+ PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
} // end namespace
void Parser::initializePragmaHandlers() {
@@ -218,6 +226,12 @@
LoopHintHandler.reset(new PragmaLoopHintHandler());
PP.AddPragmaHandler("clang", LoopHintHandler.get());
+
+ UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll"));
+ PP.AddPragmaHandler(UnrollHintHandler.get());
+
+ NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
+ PP.AddPragmaHandler(NoUnrollHintHandler.get());
}
void Parser::resetPragmaHandlers() {
@@ -278,6 +292,12 @@
PP.RemovePragmaHandler("clang", LoopHintHandler.get());
LoopHintHandler.reset();
+
+ PP.RemovePragmaHandler(UnrollHintHandler.get());
+ UnrollHintHandler.reset();
+
+ PP.RemovePragmaHandler(NoUnrollHintHandler.get());
+ NoUnrollHintHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -467,11 +487,12 @@
PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true);
SourceLocation PragmaLocation = ConsumeToken(); // The annotation token.
assert(Tok.isAnyIdentifier());
- llvm::StringRef PragmaName = Tok.getIdentifierInfo()->getName();
+ StringRef PragmaName = Tok.getIdentifierInfo()->getName();
PP.Lex(Tok); // pragma kind
+
// Figure out which #pragma we're dealing with. The switch has no default
// because lex shouldn't emit the annotation token for unrecognized pragmas.
- typedef unsigned (Parser::*PragmaHandler)(llvm::StringRef, SourceLocation);
+ typedef bool (Parser::*PragmaHandler)(StringRef, SourceLocation);
PragmaHandler Handler = llvm::StringSwitch<PragmaHandler>(PragmaName)
.Case("data_seg", &Parser::HandlePragmaMSSegment)
.Case("bss_seg", &Parser::HandlePragmaMSSegment)
@@ -479,79 +500,118 @@
.Case("code_seg", &Parser::HandlePragmaMSSegment)
.Case("section", &Parser::HandlePragmaMSSection)
.Case("init_seg", &Parser::HandlePragmaMSInitSeg);
- if (auto DiagID = (this->*Handler)(PragmaName, PragmaLocation)) {
- PP.Diag(PragmaLocation, DiagID) << PragmaName;
+
+ if (!(this->*Handler)(PragmaName, PragmaLocation)) {
+ // Pragma handling failed, and has been diagnosed. Slurp up the tokens
+ // until eof (really end of line) to prevent follow-on errors.
while (Tok.isNot(tok::eof))
PP.Lex(Tok);
PP.Lex(Tok);
}
}
-unsigned Parser::HandlePragmaMSSection(llvm::StringRef PragmaName,
- SourceLocation PragmaLocation) {
- if (Tok.isNot(tok::l_paren))
- return diag::warn_pragma_expected_lparen;
+bool Parser::HandlePragmaMSSection(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // (
// Parsing code for pragma section
- if (Tok.isNot(tok::string_literal))
- return diag::warn_pragma_expected_section_name;
- StringLiteral *SegmentName =
- cast<StringLiteral>(ParseStringLiteralExpression().get());
- int SectionFlags = 0;
+ if (Tok.isNot(tok::string_literal)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_section_name)
+ << PragmaName;
+ return false;
+ }
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false; // Already diagnosed.
+ StringLiteral *SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
+ int SectionFlags = ASTContext::PSF_Read;
+ bool SectionFlagsAreDefault = true;
while (Tok.is(tok::comma)) {
PP.Lex(Tok); // ,
- if (!Tok.isAnyIdentifier())
- return diag::warn_pragma_expected_action_or_r_paren;
- Sema::PragmaSectionFlag Flag =
- llvm::StringSwitch<Sema::PragmaSectionFlag>(
+ // 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;
+ }
+ 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 ?
- diag::warn_pragma_invalid_specific_action :
- diag::warn_pragma_unsupported_action)
+ .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();
- while (Tok.isNot(tok::eof))
- PP.Lex(Tok);
- PP.Lex(Tok);
- return 0;
+ return false;
}
SectionFlags |= Flag;
+ SectionFlagsAreDefault = false;
PP.Lex(Tok); // Identifier
}
- if (Tok.isNot(tok::r_paren))
- return diag::warn_pragma_expected_rparen;
+ // 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;
+ }
PP.Lex(Tok); // )
- if (Tok.isNot(tok::eof))
- return diag::warn_pragma_extra_tokens_at_eol;
+ if (Tok.isNot(tok::eof)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // eof
Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName);
- return 0;
+ return true;
}
-unsigned Parser::HandlePragmaMSSegment(llvm::StringRef PragmaName,
- SourceLocation PragmaLocation) {
- if (Tok.isNot(tok::l_paren))
- return diag::warn_pragma_expected_lparen;
+bool Parser::HandlePragmaMSSegment(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // (
Sema::PragmaMsStackAction Action = Sema::PSK_Reset;
- llvm::StringRef SlotLabel;
+ StringRef SlotLabel;
if (Tok.isAnyIdentifier()) {
- llvm::StringRef PushPop = Tok.getIdentifierInfo()->getName();
+ StringRef PushPop = Tok.getIdentifierInfo()->getName();
if (PushPop == "push")
Action = Sema::PSK_Push;
else if (PushPop == "pop")
Action = Sema::PSK_Pop;
- else
- return diag::warn_pragma_expected_section_push_pop_or_name;
+ else {
+ PP.Diag(PragmaLocation,
+ diag::warn_pragma_expected_section_push_pop_or_name)
+ << PragmaName;
+ return false;
+ }
if (Action != Sema::PSK_Reset) {
PP.Lex(Tok); // push | pop
if (Tok.is(tok::comma)) {
@@ -562,75 +622,241 @@
PP.Lex(Tok); // identifier
if (Tok.is(tok::comma))
PP.Lex(Tok);
- else if (Tok.isNot(tok::r_paren))
- return diag::warn_pragma_expected_punc;
+ else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc)
+ << PragmaName;
+ return false;
+ }
}
- } else if (Tok.isNot(tok::r_paren))
- return diag::warn_pragma_expected_punc;
+ } else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc) << PragmaName;
+ return false;
+ }
}
}
// Grab the string literal for our section name.
StringLiteral *SegmentName = nullptr;
if (Tok.isNot(tok::r_paren)) {
- if (Tok.isNot(tok::string_literal))
- return Action != Sema::PSK_Reset ? !SlotLabel.empty() ?
+ if (Tok.isNot(tok::string_literal)) {
+ unsigned DiagID = Action != Sema::PSK_Reset ? !SlotLabel.empty() ?
diag::warn_pragma_expected_section_name :
diag::warn_pragma_expected_section_label_or_name :
diag::warn_pragma_expected_section_push_pop_or_name;
- SegmentName = cast<StringLiteral>(ParseStringLiteralExpression().get());
+ PP.Diag(PragmaLocation, DiagID) << PragmaName;
+ return false;
+ }
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false; // Already diagnosed.
+ SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
// Setting section "" has no effect
if (SegmentName->getLength())
Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
}
- if (Tok.isNot(tok::r_paren))
- return diag::warn_pragma_expected_rparen;
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // )
- if (Tok.isNot(tok::eof))
- return diag::warn_pragma_extra_tokens_at_eol;
+ if (Tok.isNot(tok::eof)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaName;
+ return false;
+ }
PP.Lex(Tok); // eof
Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel,
SegmentName, PragmaName);
- return 0;
+ return true;
}
-unsigned Parser::HandlePragmaMSInitSeg(llvm::StringRef PragmaName,
- SourceLocation PragmaLocation) {
- return PP.getDiagnostics().getCustomDiagID(
- DiagnosticsEngine::Error, "'#pragma %0' not implemented.");
+// #pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )
+bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (getTargetInfo().getTriple().getEnvironment() != llvm::Triple::MSVC) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_init_seg_unsupported_target);
+ return false;
+ }
+
+ if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen,
+ PragmaName))
+ return false;
+
+ // Parse either the known section names or the string section name.
+ StringLiteral *SegmentName = nullptr;
+ if (Tok.isAnyIdentifier()) {
+ auto *II = Tok.getIdentifierInfo();
+ StringRef Section = llvm::StringSwitch<StringRef>(II->getName())
+ .Case("compiler", "\".CRT$XCC\"")
+ .Case("lib", "\".CRT$XCL\"")
+ .Case("user", "\".CRT$XCU\"")
+ .Default("");
+
+ if (!Section.empty()) {
+ // Pretend the user wrote the appropriate string literal here.
+ Token Toks[1];
+ Toks[0].startToken();
+ Toks[0].setKind(tok::string_literal);
+ Toks[0].setLocation(Tok.getLocation());
+ Toks[0].setLiteralData(Section.data());
+ Toks[0].setLength(Section.size());
+ SegmentName =
+ cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get());
+ PP.Lex(Tok);
+ }
+ } else if (Tok.is(tok::string_literal)) {
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false;
+ SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
+ // FIXME: Add support for the '[, func-name]' part of the pragma.
+ }
+
+ if (!SegmentName) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_init_seg) << PragmaName;
+ return false;
+ }
+
+ if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen,
+ PragmaName) ||
+ ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol,
+ PragmaName))
+ return false;
+
+ Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName);
+ return true;
}
struct PragmaLoopHintInfo {
- Token Loop;
- Token Value;
+ Token PragmaName;
Token Option;
+ 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.LoopLoc =
- IdentifierLoc::create(Actions.Context, Info->Loop.getLocation(),
- Info->Loop.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());
+ IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
+ Hint.PragmaNameLoc = IdentifierLoc::create(
+ Actions.Context, Info->PragmaName.getLocation(), PragmaNameInfo);
- // 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;
+ // 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);
- return Hint;
+ 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 {
+ // 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();
+ }
+
+ Hint.Range = SourceRange(Info->PragmaName.getLocation(),
+ Info->Toks[TokSize - 1].getLocation());
+ return true;
}
// #pragma GCC visibility comes in two variants:
@@ -1601,7 +1827,8 @@
Token Tok;
PP.Lex(Tok);
if (Tok.is(tok::eod)) {
- PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_missing_argument);
+ PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
+ << "clang optimize" << /*Expected=*/true << "'on' or 'off'";
return;
}
if (Tok.isNot(tok::identifier)) {
@@ -1630,6 +1857,52 @@
Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
}
+/// \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,
+ PragmaLoopHintInfo &Info) {
+ 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;
+ }
+
+ ValueList.push_back(Tok);
+ PP.Lex(Tok);
+ }
+
+ if (ValueInParens) {
+ // 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;
+ return false;
+}
+
/// \brief Handle the \#pragma clang loop directive.
/// #pragma clang 'loop' loop-hints
///
@@ -1639,7 +1912,7 @@
/// 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 ')'
@@ -1648,6 +1921,10 @@
/// 'enable'
/// 'disable'
///
+/// unroll-hint-keyword:
+/// 'full'
+/// 'disable'
+///
/// loop-hint-value:
/// constant-expression
///
@@ -1662,16 +1939,15 @@
/// 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) {
- 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,57 +1963,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("unroll", true)
+ .Case("vectorize_width", true)
+ .Case("interleave_count", true)
+ .Case("unroll_count", true)
+ .Default(false);
if (!OptionValid) {
PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
<< /*MissingOption=*/false << OptionInfo;
return;
}
+ PP.Lex(Tok);
// 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.
- PP.Lex(Tok);
- if (Tok.is(tok::r_paren)) {
- // Nothing between the parentheses.
- PP.Diag(Tok.getLocation(), diag::err_pragma_loop_missing_argument)
- << OptionInfo;
- return;
- }
- Token Value = Tok;
-
- // Read ')'
- PP.Lex(Tok);
- if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
- return;
- }
-
- // Get next optimization option.
PP.Lex(Tok);
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
- Info->Loop = Loop;
- Info->Option = Option;
- Info->Value = Value;
+ if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true,
+ *Info))
+ return;
- // 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);
}
@@ -1755,3 +2011,72 @@
/*DisableMacroExpansion=*/false,
/*OwnsTokens=*/true);
}
+
+/// \brief Handle the loop unroll optimization pragmas.
+/// #pragma unroll
+/// #pragma unroll unroll-hint-value
+/// #pragma unroll '(' unroll-hint-value ')'
+/// #pragma nounroll
+///
+/// unroll-hint-value:
+/// constant-expression
+///
+/// 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" 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)) {
+ // nounroll or unroll pragma without an argument.
+ Info->PragmaName = PragmaName;
+ 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)".
+ // 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->Toks[0].getLocation(),
+ diag::warn_pragma_unroll_cuda_value_in_parens);
+
+ 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);
+}