[clang] [clang] Macro for constant rounding mode (PR #92699)
Serge Pavlov via cfe-commits
cfe-commits at lists.llvm.org
Sun May 19 10:25:11 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] [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(
More information about the cfe-commits
mailing list