[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