summaryrefslogtreecommitdiffstats
path: root/lib/Parse
diff options
context:
space:
mode:
authorAdam Nemet <anemet@apple.com>2017-04-04 21:18:36 +0000
committerAdam Nemet <anemet@apple.com>2017-04-04 21:18:36 +0000
commit6abfe5cfd2160d5c1c8594673ae995151afad6f5 (patch)
treec38661f2d72b5a066293aedfdeb3321063c03d80 /lib/Parse
parenta51d8c8b113f752e56cb46d32ce9ce41e452be33 (diff)
Add #pragma clang fp
This adds the new pragma and the first variant, contract(on/off/fast). The pragma has the same block scope rules as STDC FP_CONTRACT, i.e. it can be placed at the beginning of a compound statement or at file scope. Similarly to STDC FP_CONTRACT there is no need to use attributes. First an annotate token is inserted with the parsed details of the pragma. Then the annotate token is parsed in the proper contexts and the Sema is updated with the corresponding FPOptions using the shared ActOn function with STDC FP_CONTRACT. After this the FPOptions from the Sema is propagated into the AST expression nodes. There is no change here. I was going to add a 'default' option besides 'on/off/fast' similar to STDC FP_CONTRACT but then decided against it. I think that we'd have to make option uppercase then to avoid using 'default' the keyword. Also because of the scoped activation of pragma I am not sure there is really a need a for this. Differential Revision: https://reviews.llvm.org/D31276 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@299470 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r--lib/Parse/ParsePragma.cpp151
-rw-r--r--lib/Parse/ParseStmt.cpp9
-rw-r--r--lib/Parse/Parser.cpp3
3 files changed, 162 insertions, 1 deletions
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index c97df85ae1..c8de6b35f9 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -86,6 +86,12 @@ struct PragmaFPContractHandler : public PragmaHandler {
Token &FirstToken) override;
};
+struct PragmaFPHandler : public PragmaHandler {
+ PragmaFPHandler() : PragmaHandler("fp") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
struct PragmaNoOpenMPHandler : public PragmaHandler {
PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
@@ -266,6 +272,9 @@ void Parser::initializePragmaHandlers() {
NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
PP.AddPragmaHandler(NoUnrollHintHandler.get());
+
+ FPHandler.reset(new PragmaFPHandler());
+ PP.AddPragmaHandler("clang", FPHandler.get());
}
void Parser::resetPragmaHandlers() {
@@ -344,6 +353,9 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler(NoUnrollHintHandler.get());
NoUnrollHintHandler.reset();
+
+ PP.RemovePragmaHandler("clang", FPHandler.get());
+ FPHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -454,7 +466,21 @@ void Parser::HandlePragmaFPContract() {
tok::OnOffSwitch OOS =
static_cast<tok::OnOffSwitch>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
- Actions.ActOnPragmaFPContract(OOS);
+
+ LangOptions::FPContractModeKind FPC;
+ switch (OOS) {
+ case tok::OOS_ON:
+ FPC = LangOptions::FPC_On;
+ break;
+ case tok::OOS_OFF:
+ FPC = LangOptions::FPC_Off;
+ break;
+ case tok::OOS_DEFAULT:
+ FPC = getLangOpts().getDefaultFPContractMode();
+ break;
+ }
+
+ Actions.ActOnPragmaFPContract(FPC);
ConsumeToken(); // The annotation token.
}
@@ -1947,6 +1973,129 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
}
+namespace {
+/// Used as the annotation value for tok::annot_pragma_fp.
+struct TokFPAnnotValue {
+ enum FlagKinds { Contract };
+ enum FlagValues { On, Off, Fast };
+
+ FlagKinds FlagKind;
+ FlagValues FlagValue;
+};
+} // end anonymous namespace
+
+void PragmaFPHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ // fp
+ Token PragmaName = Tok;
+ SmallVector<Token, 1> TokenList;
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+ << /*MissingOption=*/true << "";
+ return;
+ }
+
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
+
+ auto FlagKind =
+ llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagKinds>>(
+ OptionInfo->getName())
+ .Case("contract", TokFPAnnotValue::Contract)
+ .Default(None);
+ if (!FlagKind) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+ << /*MissingOption=*/false << OptionInfo;
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Read '('
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName();
+ return;
+ }
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ auto FlagValue =
+ llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagValues>>(
+ II->getName())
+ .Case("on", TokFPAnnotValue::On)
+ .Case("off", TokFPAnnotValue::Off)
+ .Case("fast", TokFPAnnotValue::Fast)
+ .Default(llvm::None);
+
+ if (!FlagValue) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName();
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Read ')'
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ auto *AnnotValue = new (PP.getPreprocessorAllocator())
+ TokFPAnnotValue{*FlagKind, *FlagValue};
+ // Generate the loop hint token.
+ Token FPTok;
+ FPTok.startToken();
+ FPTok.setKind(tok::annot_pragma_fp);
+ FPTok.setLocation(PragmaName.getLocation());
+ FPTok.setAnnotationEndLoc(PragmaName.getLocation());
+ FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
+ TokenList.push_back(FPTok);
+ }
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "clang fp";
+ return;
+ }
+
+ auto TokenArray = llvm::make_unique<Token[]>(TokenList.size());
+ std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
+
+ PP.EnterTokenStream(std::move(TokenArray), TokenList.size(),
+ /*DisableMacroExpansion=*/false);
+}
+
+void Parser::HandlePragmaFP() {
+ assert(Tok.is(tok::annot_pragma_fp));
+ auto *AnnotValue =
+ reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
+
+ LangOptions::FPContractModeKind FPC;
+ switch (AnnotValue->FlagValue) {
+ case TokFPAnnotValue::On:
+ FPC = LangOptions::FPC_On;
+ break;
+ case TokFPAnnotValue::Fast:
+ FPC = LangOptions::FPC_Fast;
+ break;
+ case TokFPAnnotValue::Off:
+ FPC = LangOptions::FPC_Off;
+ break;
+ }
+
+ Actions.ActOnPragmaFPContract(FPC);
+ ConsumeToken(); // The annotation token.
+}
+
/// \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,
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 94f0dadd16..eaff9fe8ee 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -341,6 +341,12 @@ Retry:
ConsumeToken();
return StmtError();
+ case tok::annot_pragma_fp:
+ ProhibitAttributes(Attrs);
+ Diag(Tok, diag::err_pragma_fp_scope);
+ ConsumeToken();
+ return StmtError();
+
case tok::annot_pragma_opencl_extension:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
@@ -900,6 +906,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_fp_contract:
HandlePragmaFPContract();
break;
+ case tok::annot_pragma_fp:
+ HandlePragmaFP();
+ break;
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
break;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 08b7661a8a..81a4580e27 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -670,6 +670,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_fp_contract:
HandlePragmaFPContract();
return nullptr;
+ case tok::annot_pragma_fp:
+ HandlePragmaFP();
+ break;
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return nullptr;