[clang] [clang] Macro for constant rounding mode (PR #92699)
Serge Pavlov via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 4 09:31:40 PDT 2024
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 <sepavloff at gmail.com>
Date: Sun, 19 May 2024 18:43:08 +0700
Subject: [PATCH 1/4] [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 <sepavloff at gmail.com>
Date: Thu, 23 May 2024 13:06:32 +0700
Subject: [PATCH 2/4] 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 at -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);
>From 0cf19f6422ac6addc22ec50dd122a0c473169a72 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Sat, 25 May 2024 01:42:08 +0700
Subject: [PATCH 3/4] Count braces only if pragma FENV_ROUND acts
---
clang/lib/Lex/Preprocessor.cpp | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 4f3b9163dfe53..37392fcecdbdd 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -965,14 +965,15 @@ 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 (!RoundingPragmas.empty()) {
+ if (Result.is(tok::l_brace)) {
+ CurlyBraceLevel++;
+ } else if (Result.is(tok::r_brace)) {
+ if (RoundingPragmas.back().Level >= CurlyBraceLevel)
+ RoundingPragmas.pop_back();
+ if (CurlyBraceLevel > 0)
+ CurlyBraceLevel--;
+ }
}
if ((LexLevel == 0 || PreprocessToken) &&
>From 5e9223bb9a689952879dfe1dd37823544d192d49 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Tue, 4 Jun 2024 23:18:14 +0700
Subject: [PATCH 4/4] Use identifiers for __ROUNDING_MODE__
---
clang/lib/Lex/PPMacroExpansion.cpp | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 519fbfd666375..0380fc4f68086 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1656,29 +1656,31 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here);
}
} else if (II == Ident__ROUNDING_MODE__) {
+ StringRef RoundingModeIdent;
switch (getCurrentRoundingMode()) {
case LangOptions::RoundingMode::TowardZero:
- OS << "_rtz";
+ RoundingModeIdent = "_rtz";
break;
case LangOptions::RoundingMode::NearestTiesToEven:
- OS << "_rte";
+ RoundingModeIdent = "_rte";
break;
case LangOptions::RoundingMode::TowardPositive:
- OS << "_rtp";
+ RoundingModeIdent = "_rtp";
break;
case LangOptions::RoundingMode::TowardNegative:
- OS << "_rtn";
+ RoundingModeIdent = "_rtn";
break;
case LangOptions::RoundingMode::NearestTiesToAway:
- OS << "_rta";
+ RoundingModeIdent = "_rta";
break;
case LangOptions::RoundingMode::Dynamic:
- OS << "";
break;
default:
llvm_unreachable("unknown rounding mode");
}
- Tok.setKind(tok::string_literal);
+ OS << RoundingModeIdent;
+ Tok.setIdentifierInfo(getIdentifierInfo(RoundingModeIdent));
+ Tok.setKind(tok::identifier);
} else if (II == Ident__COUNTER__) {
// __COUNTER__ expands to a simple numeric value.
OS << CounterValue++;
More information about the cfe-commits
mailing list