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] [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(

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to