https://github.com/spavloff updated https://github.com/llvm/llvm-project/pull/92699
>From f8cd2539fb7f0388d7f3955f58b61b09da03bf0c Mon Sep 17 00:00:00 2001 From: Serge Pavlov <sepavl...@gmail.com> Date: Sun, 19 May 2024 18:43:08 +0700 Subject: [PATCH 1/2] [clang] Macro for constant rounding mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The forthcoming C standard defines pragma FENV_ROUND to support constant rounding mode. It also requires some functions to be evaluated with such mode, N3096 7.6.2p4 states: Within the scope of an FENV_ROUND pragma establishing a mode other than FE_DYNAMIC ... invocations of functions indicated in the table below, for which macro replacement has not been suppressed (7.1.4), shall be evaluated according to the specified constant rounding mode ... . Invocations of functions for which macro replacement has been suppressed and invocations of functions other than those indicated in the table below shall not be affected by constant rounding modes – they are affected by (and affect) only the dynamic mode. The way this requirement is formulated indicates that it could be implemented using preprocessor facility. Such implementation would require a builtin macro that is set in the region where pragma FENV_ROUND is in effect and reflects constant rounding mode. This change introduces macro __ROUNDING_MODE__, which is a string dependent on the constant rounding mode: FE_TOWARDZERO "_rtz" FE_TONEAREST "_rte" FE_DOWNWARD "_rtp" FE_UPWARD "_rtn" FE_TONEARESTFROMZERO "_rta" FE_DYNAMIC empty string All these values except "_rta" are OpenCL rounding mode modifiers. Default value, when no pragma FENV_ROUND is specified, is empty string. Concatenation of a function name with the builtin macro can be used to obtain name of the function variant for particular rounding mode, like "sin_rtz", or "__builtin_cos_rtd". The test "macro_rounding_mode.c" added in this change provides an example of possible use. The macro is implemented in the same way as FLT_EVAL_METHOD, which also depends on the results of semantic analysis. --- clang/include/clang/Lex/Preprocessor.h | 12 ++++ clang/lib/Lex/PPMacroExpansion.cpp | 25 +++++++++ clang/lib/Sema/Sema.cpp | 1 + clang/lib/Sema/SemaAttr.cpp | 1 + clang/test/Preprocessor/macro_rounding_mode.c | 55 +++++++++++++++++++ 5 files changed, 94 insertions(+) create mode 100644 clang/test/Preprocessor/macro_rounding_mode.c diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index c0850a8fa9f7f..295633b2e3c73 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -181,6 +181,7 @@ class Preprocessor { IdentifierInfo *Ident__is_target_variant_os; IdentifierInfo *Ident__is_target_variant_environment; IdentifierInfo *Ident__FLT_EVAL_METHOD__; // __FLT_EVAL_METHOD + IdentifierInfo *Ident__ROUNDING_MODE__; // __ROUNDING_MODE__ // Weak, only valid (and set) while InMacroArgs is true. Token* ArgMacro; @@ -201,6 +202,9 @@ class Preprocessor { LangOptions::FPEvalMethodKind TUFPEvalMethod = LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; + LangOptions::RoundingMode CurrentRoundingMode = + LangOptions::RoundingMode::Dynamic; + // Next __COUNTER__ value, starts at 0. unsigned CounterValue = 0; @@ -2356,6 +2360,14 @@ class Preprocessor { TUFPEvalMethod = Val; } + LangOptions::RoundingMode getCurrentRoundingMode() const { + return CurrentRoundingMode; + } + + void setCurrentRoundingMode(LangOptions::RoundingMode RM) { + CurrentRoundingMode = RM; + } + /// Retrieves the module that we're currently building, if any. Module *getCurrentModule(); diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 8af4a97d00cb8..519fbfd666375 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -344,6 +344,7 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__"); Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma"); Ident__FLT_EVAL_METHOD__ = RegisterBuiltinMacro(*this, "__FLT_EVAL_METHOD__"); + Ident__ROUNDING_MODE__ = RegisterBuiltinMacro(*this, "__ROUNDING_MODE__"); // C++ Standing Document Extensions. if (getLangOpts().CPlusPlus) @@ -1654,6 +1655,30 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Diag(Tok, diag::err_illegal_use_of_flt_eval_macro); Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here); } + } else if (II == Ident__ROUNDING_MODE__) { + switch (getCurrentRoundingMode()) { + case LangOptions::RoundingMode::TowardZero: + OS << "_rtz"; + break; + case LangOptions::RoundingMode::NearestTiesToEven: + OS << "_rte"; + break; + case LangOptions::RoundingMode::TowardPositive: + OS << "_rtp"; + break; + case LangOptions::RoundingMode::TowardNegative: + OS << "_rtn"; + break; + case LangOptions::RoundingMode::NearestTiesToAway: + OS << "_rta"; + break; + case LangOptions::RoundingMode::Dynamic: + OS << ""; + break; + default: + llvm_unreachable("unknown rounding mode"); + } + Tok.setKind(tok::string_literal); } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index f847c49920cf3..928a7953859c9 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2725,6 +2725,7 @@ Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() { S.CurFPFeatures = OldFPFeaturesState; S.FpPragmaStack.CurrentValue = OldOverrides; S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod); + S.PP.setCurrentRoundingMode(S.CurFPFeatures.getConstRoundingMode()); } bool Sema::isDeclaratorFunctionLike(Declarator &D) { diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index bb44531495a56..1faa5a879f030 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -1322,6 +1322,7 @@ void Sema::ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode FPR) { NewFPFeatures.setConstRoundingModeOverride(FPR); FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + PP.setCurrentRoundingMode(FPR); } void Sema::setExceptionMode(SourceLocation Loc, diff --git a/clang/test/Preprocessor/macro_rounding_mode.c b/clang/test/Preprocessor/macro_rounding_mode.c new file mode 100644 index 0000000000000..a18c72db9bed2 --- /dev/null +++ b/clang/test/Preprocessor/macro_rounding_mode.c @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -emit-llvm -triple i386-linux -Wno-unknown-pragmas %s -o - | FileCheck %s + +double sin(double); +double sin_rte(double); +double sin_rtz(double); +double sin_rtp(double); +double sin_rtn(double); +double sin_rta(double); + +#define CONCAT(a, b) CONCAT_(a, b) +#define CONCAT_(a, b) a##b +#define ADD_ROUNDING_MODE_SUFFIX(func) CONCAT(func, __ROUNDING_MODE__) + +#define sin(x) ADD_ROUNDING_MODE_SUFFIX(sin)(x) + +double call_dyn(double x) { + return sin(x); +} +// CHECK-LABEL: define {{.*}} double @call_dyn( +// CHECK: call double @llvm.sin.f64( + +#pragma STDC FENV_ROUND FE_TOWARDZERO +double call_tz(double x) { + return sin(x); +} +// CHECK-LABEL: define {{.*}} double @call_tz( +// CHECK: call double @sin_rtz( + +#pragma STDC FENV_ROUND FE_TONEAREST +double call_te(double x) { + return sin(x); +} +// CHECK-LABEL: define {{.*}} double @call_te( +// CHECK: call double @sin_rte( + +#pragma STDC FENV_ROUND FE_DOWNWARD +double call_tn(double x) { + return sin(x); +} +// CHECK-LABEL: define {{.*}} double @call_tn( +// CHECK: call double @sin_rtn( + +#pragma STDC FENV_ROUND FE_UPWARD +double call_tp(double x) { + return sin(x); +} +// CHECK-LABEL: define {{.*}} double @call_tp( +// CHECK: call double @sin_rtp( + +#pragma STDC FENV_ROUND FE_TONEARESTFROMZERO +double call_tea(double x) { + return sin(x); +} +// CHECK-LABEL: define {{.*}} double @call_tea( +// CHECK: call double @sin_rta( >From 937b4d756126a3dff4491f57730df96a7a0a1c98 Mon Sep 17 00:00:00 2001 From: Serge Pavlov <sepavl...@gmail.com> Date: Thu, 23 May 2024 13:06:32 +0700 Subject: [PATCH 2/2] Move handling pragma FENV_ROUND to Preprocessor As the macro __ROUNDING_MODE__ depends on the current static rounding mode, which is managed by pragma FENV_ROUND, handling this pragma in Parser is not possible anymore. Running clang with the option -E should produce usable source code, where __ROUNDIND_MODE__ is substituted and Parser is not called in this case. So the handler of pragma FENV_ROUND is moved from Parser to Preprocessor. Maintaining the rounding mode in Preprocessor also requires to keep track of curly brace nesting level, because the pragma can be specified inside a block, in this case its effect ends as the block is finished and the previous static rounding mode must be established. --- .../include/clang/Basic/DiagnosticLexKinds.td | 2 + .../clang/Basic/DiagnosticParseKinds.td | 3 - clang/include/clang/Lex/Preprocessor.h | 22 ++-- clang/include/clang/Parse/Parser.h | 1 - .../lib/Frontend/PrintPreprocessedOutput.cpp | 6 + clang/lib/Lex/Pragma.cpp | 48 ++++++++ clang/lib/Lex/Preprocessor.cpp | 27 +++++ clang/lib/Parse/ParsePragma.cpp | 81 ++----------- clang/lib/Sema/Sema.cpp | 1 - clang/lib/Sema/SemaAttr.cpp | 1 - clang/test/Parser/pragma-fenv_round.c | 5 +- clang/test/Preprocessor/macro_rounding_mode.c | 107 ++++++++++++------ 12 files changed, 179 insertions(+), 125 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index ad6bacfb118d4..d5fb602278561 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -709,6 +709,8 @@ def note_pp_module_begin_here : Note< "entering module '%0' due to this pragma">; def err_pp_module_build_missing_end : Error< "no matching '#pragma clang module endbuild' for this '#pragma clang module build'">; +def err_pragma_round_expected_mode : Error<"expected rounding mode">; +def err_pragma_round_unknown_mode : Error<"invalid or unsupported rounding mode">; def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">; def err_paste_at_start : Error< diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 8316845844cb2..c8d88fba298e9 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1269,9 +1269,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, def warn_stdc_fenv_round_not_supported : Warning<"pragma STDC FENV_ROUND is not supported">, InGroup<UnknownPragmas>; -def warn_stdc_unknown_rounding_mode : Warning< - "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">, - InGroup<IgnoredPragmas>; def warn_pragma_fp_ignored : Warning< "'#pragma %0' is not supported on this target - ignored">, InGroup<IgnoredPragmas>; diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 295633b2e3c73..f350206dbdf5d 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -202,9 +202,6 @@ class Preprocessor { LangOptions::FPEvalMethodKind TUFPEvalMethod = LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; - LangOptions::RoundingMode CurrentRoundingMode = - LangOptions::RoundingMode::Dynamic; - // Next __COUNTER__ value, starts at 0. unsigned CounterValue = 0; @@ -1166,6 +1163,17 @@ class Preprocessor { /// skipped. llvm::DenseMap<const char *, unsigned> RecordedSkippedRanges; + /// Nesting level of curly braces. + unsigned CurlyBraceLevel = 0; + + /// Information about an instance of pragma FENV_ROUND. + struct RoundingPragmaRecord { + unsigned Level; + LangOptions::RoundingMode RM; + }; + + SmallVector<RoundingPragmaRecord, 8> RoundingPragmas; + void updateOutOfDateIdentifier(const IdentifierInfo &II) const; public: @@ -2360,13 +2368,9 @@ class Preprocessor { TUFPEvalMethod = Val; } - LangOptions::RoundingMode getCurrentRoundingMode() const { - return CurrentRoundingMode; - } + void setRoundingMode(LangOptions::RoundingMode RM); - void setCurrentRoundingMode(LangOptions::RoundingMode RM) { - CurrentRoundingMode = RM; - } + LangOptions::RoundingMode getCurrentRoundingMode() const; /// Retrieves the module that we're currently building, if any. Module *getCurrentModule(); diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 1e796e828b10a..a130c7efe577c 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -211,7 +211,6 @@ class Parser : public CodeCompletionHandler { std::unique_ptr<PragmaHandler> NoUnrollAndJamHintHandler; std::unique_ptr<PragmaHandler> FPHandler; std::unique_ptr<PragmaHandler> STDCFenvAccessHandler; - std::unique_ptr<PragmaHandler> STDCFenvRoundHandler; std::unique_ptr<PragmaHandler> STDCCXLIMITHandler; std::unique_ptr<PragmaHandler> STDCUnknownHandler; std::unique_ptr<PragmaHandler> AttributePragmaHandler; diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index a26d2c3ab8582..7628cfdfbe78c 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -1001,9 +1001,14 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, "#pragma clang", Callbacks, /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + std::unique_ptr<UnknownPragmaHandler> STDCHandler(new UnknownPragmaHandler( + "#pragma STDC", Callbacks, + /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + PP.AddPragmaHandler(MicrosoftExtHandler.get()); PP.AddPragmaHandler("GCC", GCCHandler.get()); PP.AddPragmaHandler("clang", ClangHandler.get()); + PP.AddPragmaHandler("STDC", STDCHandler.get()); // The tokens after pragma omp need to be expanded. // @@ -1050,4 +1055,5 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, PP.RemovePragmaHandler("GCC", GCCHandler.get()); PP.RemovePragmaHandler("clang", ClangHandler.get()); PP.RemovePragmaHandler("omp", OpenMPHandler.get()); + PP.RemovePragmaHandler("STDC", STDCHandler.get()); } diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 10f0ab7180e62..e7c6ebbca6277 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -2125,6 +2125,51 @@ struct PragmaFinalHandler : public PragmaHandler { } }; +struct FenvRoundHandler : public PragmaHandler { + FenvRoundHandler() : PragmaHandler("FENV_ROUND") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &Tok) override { + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_round_expected_mode); + return; + } + IdentifierInfo *II = Tok.getIdentifierInfo(); + + auto RM = + llvm::StringSwitch<llvm::RoundingMode>(II->getName()) + .Case("FE_TOWARDZERO", llvm::RoundingMode::TowardZero) + .Case("FE_TONEAREST", llvm::RoundingMode::NearestTiesToEven) + .Case("FE_UPWARD", llvm::RoundingMode::TowardPositive) + .Case("FE_DOWNWARD", llvm::RoundingMode::TowardNegative) + .Case("FE_TONEARESTFROMZERO", llvm::RoundingMode::NearestTiesToAway) + .Case("FE_DYNAMIC", llvm::RoundingMode::Dynamic) + .Default(llvm::RoundingMode::Invalid); + if (RM == llvm::RoundingMode::Invalid) { + PP.Diag(Tok.getLocation(), diag::err_pragma_round_unknown_mode); + return; + } + PP.Lex(Tok); + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) + << "pragma STDC FENV_ROUND"; + return; + } + + PP.setRoundingMode(RM); + + Token PragmaFenvRound; + PragmaFenvRound.startToken(); + PragmaFenvRound.setKind(tok::annot_pragma_fenv_round); + PragmaFenvRound.setAnnotationRange(SourceRange(Tok.getLocation())); + PragmaFenvRound.setAnnotationValue( + reinterpret_cast<void *>(static_cast<uintptr_t>(RM))); + PP.EnterToken(PragmaFenvRound, /*IsReinject*/ false); + } +}; + } // namespace /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: @@ -2184,6 +2229,9 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler(new PragmaManagedHandler("unmanaged")); } + // #pragma STDC FENV_ROUND + AddPragmaHandler("STDC", new FenvRoundHandler()); + // Pragmas added by plugins for (const PragmaHandlerRegistry::entry &handler : PragmaHandlerRegistry::entries()) { diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 0b70192743a39..4f3b9163dfe53 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -965,6 +965,16 @@ void Preprocessor::Lex(Token &Result) { LastTokenWasAt = Result.is(tok::at); --LexLevel; + if (Result.is(tok::l_brace)) { + CurlyBraceLevel++; + } else if (Result.is(tok::r_brace)) { + if (!RoundingPragmas.empty() && + RoundingPragmas.back().Level >= CurlyBraceLevel) + RoundingPragmas.pop_back(); + if (CurlyBraceLevel > 0) + CurlyBraceLevel--; + } + if ((LexLevel == 0 || PreprocessToken) && !Result.getFlag(Token::IsReinjected)) { if (LexLevel == 0) @@ -1582,3 +1592,20 @@ const char *Preprocessor::getCheckPoint(FileID FID, const char *Start) const { return nullptr; } + +void Preprocessor::setRoundingMode(LangOptions::RoundingMode RM) { + if (!RoundingPragmas.empty()) { + RoundingPragmaRecord &LastRecord = RoundingPragmas.back(); + if (LastRecord.Level == CurlyBraceLevel) { + LastRecord.RM = RM; + return; + } + } + RoundingPragmas.push_back({CurlyBraceLevel, RM}); +} + +LangOptions::RoundingMode Preprocessor::getCurrentRoundingMode() const { + if (RoundingPragmas.empty()) + return LangOptions::RoundingMode::Dynamic; + return RoundingPragmas.back().RM; +} diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 643fdac287d18..1a2bf2ffc3dd3 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -156,14 +156,6 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { } }; -/// Handler for "\#pragma STDC FENV_ROUND ...". -struct PragmaSTDC_FENV_ROUNDHandler : public PragmaHandler { - PragmaSTDC_FENV_ROUNDHandler() : PragmaHandler("FENV_ROUND") {} - - void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, - Token &Tok) override; -}; - /// PragmaSTDC_UnknownHandler - "\#pragma STDC ...". struct PragmaSTDC_UnknownHandler : public PragmaHandler { PragmaSTDC_UnknownHandler() = default; @@ -447,9 +439,6 @@ void Parser::initializePragmaHandlers() { STDCFenvAccessHandler = std::make_unique<PragmaSTDC_FENV_ACCESSHandler>(); PP.AddPragmaHandler("STDC", STDCFenvAccessHandler.get()); - STDCFenvRoundHandler = std::make_unique<PragmaSTDC_FENV_ROUNDHandler>(); - PP.AddPragmaHandler("STDC", STDCFenvRoundHandler.get()); - STDCCXLIMITHandler = std::make_unique<PragmaSTDC_CX_LIMITED_RANGEHandler>(); PP.AddPragmaHandler("STDC", STDCCXLIMITHandler.get()); @@ -656,9 +645,6 @@ void Parser::resetPragmaHandlers() { PP.RemovePragmaHandler("STDC", STDCFenvAccessHandler.get()); STDCFenvAccessHandler.reset(); - PP.RemovePragmaHandler("STDC", STDCFenvRoundHandler.get()); - STDCFenvRoundHandler.reset(); - PP.RemovePragmaHandler("STDC", STDCCXLIMITHandler.get()); STDCCXLIMITHandler.reset(); @@ -903,9 +889,17 @@ void Parser::HandlePragmaFEnvRound() { assert(Tok.is(tok::annot_pragma_fenv_round)); auto RM = static_cast<llvm::RoundingMode>( reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); + SourceLocation Loc = ConsumeAnnotationToken(); - SourceLocation PragmaLoc = ConsumeAnnotationToken(); - Actions.ActOnPragmaFEnvRound(PragmaLoc, RM); + if (!getTargetInfo().hasStrictFP() && !getLangOpts().ExpStrictFP) { + PP.Diag(Loc, diag::warn_pragma_fp_ignored) << "FENV_ROUND"; + return; + } + + // Until the pragma is fully implemented, issue a warning. + PP.Diag(Loc, diag::warn_stdc_fenv_round_not_supported); + + Actions.ActOnPragmaFEnvRound(Loc, RM); } void Parser::HandlePragmaCXLimitedRange() { @@ -3425,61 +3419,6 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, /*DisableMacroExpansion=*/false, /*IsReinject=*/false); } -void PragmaSTDC_FENV_ROUNDHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducer Introducer, - Token &Tok) { - Token PragmaName = Tok; - SmallVector<Token, 1> TokenList; - if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_fp_ignored) - << PragmaName.getIdentifierInfo()->getName(); - return; - } - - PP.Lex(Tok); - if (Tok.isNot(tok::identifier)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) - << PragmaName.getIdentifierInfo()->getName(); - return; - } - IdentifierInfo *II = Tok.getIdentifierInfo(); - - auto RM = - llvm::StringSwitch<llvm::RoundingMode>(II->getName()) - .Case("FE_TOWARDZERO", llvm::RoundingMode::TowardZero) - .Case("FE_TONEAREST", llvm::RoundingMode::NearestTiesToEven) - .Case("FE_UPWARD", llvm::RoundingMode::TowardPositive) - .Case("FE_DOWNWARD", llvm::RoundingMode::TowardNegative) - .Case("FE_TONEARESTFROMZERO", llvm::RoundingMode::NearestTiesToAway) - .Case("FE_DYNAMIC", llvm::RoundingMode::Dynamic) - .Default(llvm::RoundingMode::Invalid); - if (RM == llvm::RoundingMode::Invalid) { - PP.Diag(Tok.getLocation(), diag::warn_stdc_unknown_rounding_mode); - return; - } - PP.Lex(Tok); - - if (Tok.isNot(tok::eod)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) - << "STDC FENV_ROUND"; - return; - } - - // Until the pragma is fully implemented, issue a warning. - PP.Diag(Tok.getLocation(), diag::warn_stdc_fenv_round_not_supported); - - MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), - 1); - Toks[0].startToken(); - Toks[0].setKind(tok::annot_pragma_fenv_round); - Toks[0].setLocation(Tok.getLocation()); - Toks[0].setAnnotationEndLoc(Tok.getLocation()); - Toks[0].setAnnotationValue( - reinterpret_cast<void *>(static_cast<uintptr_t>(RM))); - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, - /*IsReinject=*/false); -} - void Parser::HandlePragmaFP() { assert(Tok.is(tok::annot_pragma_fp)); auto *AnnotValue = diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 928a7953859c9..f847c49920cf3 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2725,7 +2725,6 @@ Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() { S.CurFPFeatures = OldFPFeaturesState; S.FpPragmaStack.CurrentValue = OldOverrides; S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod); - S.PP.setCurrentRoundingMode(S.CurFPFeatures.getConstRoundingMode()); } bool Sema::isDeclaratorFunctionLike(Declarator &D) { diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 1faa5a879f030..bb44531495a56 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -1322,7 +1322,6 @@ void Sema::ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode FPR) { NewFPFeatures.setConstRoundingModeOverride(FPR); FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); - PP.setCurrentRoundingMode(FPR); } void Sema::setExceptionMode(SourceLocation Loc, diff --git a/clang/test/Parser/pragma-fenv_round.c b/clang/test/Parser/pragma-fenv_round.c index b2f6f7ed41a4a..76e268442dc83 100644 --- a/clang/test/Parser/pragma-fenv_round.c +++ b/clang/test/Parser/pragma-fenv_round.c @@ -1,11 +1,12 @@ // RUN: %clang_cc1 -fexperimental-strict-floating-point -fsyntax-only -Wignored-pragmas -verify %s -#pragma STDC FENV_ROUND ON // expected-warning {{invalid or unsupported rounding mode}} +#pragma STDC FENV_ROUND // expected-error{{expected rounding mode}} +#pragma STDC FENV_ROUND ON // expected-error{{invalid or unsupported rounding mode}} +#pragma STDC FENV_ROUND FE_DYNAMIC 0 // expected-warning{{extra tokens at end of #pragma STDC FENV_ROUND directive}} float func_01(int x, float y) { if (x) return y + 2; #pragma STDC FENV_ROUND FE_DOWNWARD // expected-error{{'#pragma STDC FENV_ROUND' can only appear at file scope or at the start of a compound statement}} - // expected-warning@-1{{pragma STDC FENV_ROUND is not supported}} return x + y; } diff --git a/clang/test/Preprocessor/macro_rounding_mode.c b/clang/test/Preprocessor/macro_rounding_mode.c index a18c72db9bed2..b02ed03e66622 100644 --- a/clang/test/Preprocessor/macro_rounding_mode.c +++ b/clang/test/Preprocessor/macro_rounding_mode.c @@ -1,11 +1,62 @@ -// RUN: %clang_cc1 -emit-llvm -triple i386-linux -Wno-unknown-pragmas %s -o - | FileCheck %s +// RUN: %clang_cc1 -E -triple i386-linux -Wno-unknown-pragmas %s -o - | FileCheck %s + +v1 = __ROUNDING_MODE__; +// CHECK: v1 = ; + +#pragma STDC FENV_ROUND FE_TONEAREST +v2 = __ROUNDING_MODE__; +// CHECK: v2 = _rte; + +#pragma STDC FENV_ROUND FE_TOWARDZERO +v3 = __ROUNDING_MODE__; +// CHECK: v3 = _rtz; + +#pragma STDC FENV_ROUND FE_DOWNWARD +v4 = __ROUNDING_MODE__; +// CHECK: v4 = _rtn; + +#pragma STDC FENV_ROUND FE_UPWARD +v5 = __ROUNDING_MODE__; +// CHECK: v5 = _rtp; + +#pragma STDC FENV_ROUND FE_TONEARESTFROMZERO +v6 = __ROUNDING_MODE__; +// CHECK: v6 = _rta; + +#pragma STDC FENV_ROUND FE_DYNAMIC +v7 = __ROUNDING_MODE__; +// CHECK: v7 = ; + + +#pragma STDC FENV_ROUND FE_TOWARDZERO +#pragma STDC FENV_ROUND FE_UPWARD +v10 = __ROUNDING_MODE__; +// CHECK: v10 = _rtp; + +#pragma STDC FENV_ROUND FE_DYNAMIC +{ + #pragma STDC FENV_ROUND FE_TOWARDZERO + { + #pragma STDC FENV_ROUND FE_TONEAREST + { + #pragma STDC FENV_ROUND FE_DOWNWARD + { + #pragma STDC FENV_ROUND FE_UPWARD + v11 = __ROUNDING_MODE__; + // CHECK: v11 = _rtp; + } + v12 = __ROUNDING_MODE__; + // CHECK: v12 = _rtn; + } + v13 = __ROUNDING_MODE__; + // CHECK: v13 = _rte; + } + v14 = __ROUNDING_MODE__; + // CHECK: v14 = _rtz; +} +v15 = __ROUNDING_MODE__; +// CHECK: v15 = ; -double sin(double); -double sin_rte(double); -double sin_rtz(double); -double sin_rtp(double); -double sin_rtn(double); -double sin_rta(double); #define CONCAT(a, b) CONCAT_(a, b) #define CONCAT_(a, b) a##b @@ -13,43 +64,25 @@ double sin_rta(double); #define sin(x) ADD_ROUNDING_MODE_SUFFIX(sin)(x) -double call_dyn(double x) { - return sin(x); -} -// CHECK-LABEL: define {{.*}} double @call_dyn( -// CHECK: call double @llvm.sin.f64( +sin(x); +// CHECK: sin(x); #pragma STDC FENV_ROUND FE_TOWARDZERO -double call_tz(double x) { - return sin(x); -} -// CHECK-LABEL: define {{.*}} double @call_tz( -// CHECK: call double @sin_rtz( +sin(x); +// CHECK: sin_rtz(x); #pragma STDC FENV_ROUND FE_TONEAREST -double call_te(double x) { - return sin(x); -} -// CHECK-LABEL: define {{.*}} double @call_te( -// CHECK: call double @sin_rte( +sin(x); +// CHECK: sin_rte(x); #pragma STDC FENV_ROUND FE_DOWNWARD -double call_tn(double x) { - return sin(x); -} -// CHECK-LABEL: define {{.*}} double @call_tn( -// CHECK: call double @sin_rtn( +sin(x); +// CHECK: sin_rtn(x); #pragma STDC FENV_ROUND FE_UPWARD -double call_tp(double x) { - return sin(x); -} -// CHECK-LABEL: define {{.*}} double @call_tp( -// CHECK: call double @sin_rtp( +sin(x); +// CHECK: sin_rtp(x); #pragma STDC FENV_ROUND FE_TONEARESTFROMZERO -double call_tea(double x) { - return sin(x); -} -// CHECK-LABEL: define {{.*}} double @call_tea( -// CHECK: call double @sin_rta( +sin(x); +// CHECK: sin_rta(x); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits