https://github.com/spavloff created https://github.com/llvm/llvm-project/pull/92699
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. >From 15b6edbcc8fe4559e9a9d8930f88dbbb6ed38b8c Mon Sep 17 00:00:00 2001 From: Serge Pavlov <sepavl...@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..932b201750118 --- /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 @sin( + +#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( _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits