diff options
author | Adam Nemet <anemet@apple.com> | 2017-04-04 21:18:36 +0000 |
---|---|---|
committer | Adam Nemet <anemet@apple.com> | 2017-04-04 21:18:36 +0000 |
commit | 6abfe5cfd2160d5c1c8594673ae995151afad6f5 (patch) | |
tree | c38661f2d72b5a066293aedfdeb3321063c03d80 /lib/Parse | |
parent | a51d8c8b113f752e56cb46d32ce9ce41e452be33 (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.cpp | 151 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 3 |
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; |