[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-05-17 Thread Joshua Cranmer via cfe-commits


@@ -5980,6 +5987,64 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo 
&CallInfo,
   return Ret;
 }
 
+static bool endsWithRoundingModeSuffix(StringRef FuncName) {
+  size_t Underscore = FuncName.find_last_of("_");
+  if (Underscore == StringRef::npos || Underscore < 2)
+return false;
+  StringRef Suffix = FuncName.substr(Underscore + 1);
+  static const StringRef RMSuffixes[] = {"rtz", "rte", "rtp", "rtn", "rhaz",
+ "rz",  "rn",  "ru",  "rd"};
+  for (auto RM : RMSuffixes) {
+if (Suffix == RM)
+  return true;
+  }
+  return false;
+}
+
+bool CodeGenFunction::requiresDynamicRounding(const CGCallee &Callee) {
+  if (Callee.isOrdinary()) {
+const Decl *CalleeDecl = 
Callee.getAbstractInfo().getCalleeDecl().getDecl();
+if (const FunctionDecl *FD = dyn_cast_or_null(CalleeDecl)) {
+  IdentifierInfo *FuncNameII = FD->getDeclName().getAsIdentifierInfo();
+  if (FuncNameII) {
+StringRef FuncName = FuncNameII->getName();
+// If a reserved identifier ends with rounding mode suffix preceded by
+// underscore, this function does not need the previous dynamic 
rounding
+// mode to be set.
+if (isReservedInAllContexts(
+FuncNameII->isReserved(getContext().getLangOpts( {
+  if (endsWithRoundingModeSuffix(FuncName))
+return false;
+}
+  }
+}
+  }
+  return true;
+}
+
+/// Sets dynamic rounding mode for the function called in the region where
+/// pragma FENV_ROUND is in effect.
+void CodeGenFunction::setRoundingModeForCall(const CGCallee &Callee) {
+  if (Target.hasStaticRounding() || Callee.isBuiltin() ||
+  !requiresDynamicRounding(Callee))
+return;
+  if (!CurrentRoundingIsStatic || !DynamicRoundingMode)
+return;
+  Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::set_rounding),
+ DynamicRoundingMode);
+  CurrentRoundingIsStatic = false;

jcranmer-intel wrote:

I'm not seeing logic here to effect the proper handling of, e.g., `sqrt`. Is 
this planned in a future patch? If so, add in a TODO note.

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-05-17 Thread Joshua Cranmer via cfe-commits


@@ -5980,6 +5987,64 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo 
&CallInfo,
   return Ret;
 }
 
+static bool endsWithRoundingModeSuffix(StringRef FuncName) {
+  size_t Underscore = FuncName.find_last_of("_");
+  if (Underscore == StringRef::npos || Underscore < 2)
+return false;
+  StringRef Suffix = FuncName.substr(Underscore + 1);
+  static const StringRef RMSuffixes[] = {"rtz", "rte", "rtp", "rtn", "rhaz",
+ "rz",  "rn",  "ru",  "rd"};
+  for (auto RM : RMSuffixes) {
+if (Suffix == RM)
+  return true;
+  }
+  return false;
+}
+
+bool CodeGenFunction::requiresDynamicRounding(const CGCallee &Callee) {
+  if (Callee.isOrdinary()) {
+const Decl *CalleeDecl = 
Callee.getAbstractInfo().getCalleeDecl().getDecl();
+if (const FunctionDecl *FD = dyn_cast_or_null(CalleeDecl)) {
+  IdentifierInfo *FuncNameII = FD->getDeclName().getAsIdentifierInfo();
+  if (FuncNameII) {
+StringRef FuncName = FuncNameII->getName();
+// If a reserved identifier ends with rounding mode suffix preceded by
+// underscore, this function does not need the previous dynamic 
rounding
+// mode to be set.

jcranmer-intel wrote:

Where is this rule coming from?

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-05-17 Thread Joshua Cranmer via cfe-commits


@@ -1232,6 +1232,14 @@ class TargetInfo : public TransferrableTargetInfo,
 return true;
   }
 
+  /// Returns true, if an operations that depends on rounding mode can be
+  /// implemented without changing FP environment. In this case the rounding
+  /// mode is encoded in the bits of implementing instruction.

jcranmer-intel wrote:

I'm not sure we actually have any (non-target-specific) IR constructs at the 
moment that actually implement static rounding mode. The documentation for 
constrained intrinsics says:

> For values other than “round.dynamic” optimization passes may assume that the 
> actual runtime rounding mode (as defined in a target-specific manner) matches 
> the specified rounding mode, but this is not guaranteed.

It's also the case that static rounding mode may be a less-than-global 
decision. X86 AVX512/AVX10 has static rounding mode, which is a subtarget 
consideration, but even then, it's not entirely clear that they would be 
absolutely preferred.

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-05-17 Thread Joshua Cranmer via cfe-commits

https://github.com/jcranmer-intel commented:

Sorry for just thinking of this now, but we should also have tests for some of 
the builtins like `__builtin_fma` or `__builtin_sqrt`.

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-05-17 Thread Joshua Cranmer via cfe-commits

https://github.com/jcranmer-intel edited 
https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-05-13 Thread Serge Pavlov via cfe-commits

spavloff wrote:

> 7.6.2p4 does clearly state that floating constants need to be evaluated 
> according to the standard rounding mode, so that the constant 0.1 evaluates 
> to a different value in FE_DOWNWARD versus FE_UPWARD.

Treatment of floating-point constants is fixed in 
https://github.com/llvm/llvm-project/pull/90877.

> I'm not seeing from the tests how the code is handling calls to functions. 
> Calls to all functions outside of a finite list (see same paragraph) need to 
> restore the saved dynamic rounding mode for the duration of the call.

The latest update to this PR fixes this.

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-05-13 Thread Serge Pavlov via cfe-commits

https://github.com/spavloff edited 
https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-05-13 Thread Serge Pavlov via cfe-commits

https://github.com/spavloff updated 
https://github.com/llvm/llvm-project/pull/89617

>From ec8838685fb7af618445c3ff1bae953778996c37 Mon Sep 17 00:00:00 2001
From: Serge Pavlov 
Date: Thu, 14 Apr 2022 18:00:14 +0700
Subject: [PATCH 1/3] Implementation of '#pragma STDC FENV_ROUND'

This pragma is introduced by forthcoming C2x standard and can be used to
set particular rounding mode without need to call 'fesetmode' or accessing
control mode registers directly. Previously this pragma was implemented in
clang partially, only for the purpose of using in constant expressions and
making tests.

This change implements the pragma according to the standard draft. It sets
up dynamic rounding mode in the compound statement where the pragma acts.
This is inevitable for targets that set rounding mode by changing some
control register. Targets that support static rounding mode encoded in
instructions can have more efficient implementation, it is not
implemented in this change.

The implementation uses intrinsic functions 'get_rounding' and
'set_rounding' to save/restore dynamic rounding mode. In some cases
using functions that operate entire set of control modes or even FP
environment may give more efficient implementation. This optimization is
not a part of this change.
---
 clang/include/clang/AST/Stmt.h|   9 +
 .../clang/Basic/DiagnosticParseKinds.td   |   3 -
 clang/include/clang/Basic/LangOptions.h   |   6 +
 clang/lib/CodeGen/CGStmt.cpp  |  56 ++
 clang/lib/CodeGen/CodeGenFunction.h   |   3 +
 clang/lib/Parse/ParsePragma.cpp   |   3 -
 clang/test/CodeGen/complex-strictfp.c |  60 ---
 clang/test/CodeGen/math-errno.c   |   6 +-
 clang/test/CodeGen/pragma-fenv_access.c   |  45 -
 clang/test/CodeGen/pragma-fenv_round.c| 160 ++
 clang/test/Parser/pragma-fenv_round.c |   1 -
 11 files changed, 315 insertions(+), 37 deletions(-)
 create mode 100644 clang/test/CodeGen/pragma-fenv_round.c

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 9cd7a364cd3f1..6eceecd93e59c 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1658,6 +1658,15 @@ class CompoundStmt final
 return *getTrailingObjects();
   }
 
+  /// Get FPOptions inside this statement. They may differ from the outer
+  /// options due to pragmas.
+  /// \param CurFPOptions FPOptions outside this statement.
+  FPOptions getNewFPOptions(FPOptions CurFPOptions) const {
+return hasStoredFPFeatures()
+   ? getStoredFPFeatures().applyOverrides(CurFPOptions)
+   : CurFPOptions;
+  }
+
   using body_iterator = Stmt **;
   using body_range = llvm::iterator_range;
 
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 44bc4e0e130de..c9b0c0e616c71 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1266,9 +1266,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in 
STDC namespace">,
 // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
 // outside external declarations or preceding all explicit declarations and
 // statements inside a compound statement.
-def warn_stdc_fenv_round_not_supported :
-   Warning<"pragma STDC FENV_ROUND is not supported">,
-   InGroup;
 def warn_stdc_unknown_rounding_mode : Warning<
   "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - 
ignored">,
   InGroup;
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index e2a2aa71b880b..53c498f1c4017 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -846,6 +846,12 @@ class FPOptions {
getAllowFEnvAccess();
   }
 
+  /// Checks if the rounding mode is unknown at compile-time.
+  bool isRoundingModeDynamic() const {
+return (getConstRoundingMode() == RoundingMode::Dynamic) &&
+   (getAllowFEnvAccess() || getRoundingMath());
+  }
+
   RoundingMode getRoundingMode() const {
 RoundingMode RM = getConstRoundingMode();
 if (RM == RoundingMode::Dynamic) {
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 576fe2f7a2d46..4fbc906afaeed 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
   return true;
 }
 
+namespace {
+/// Cleanup action that restores floating-point control modes upon leaving
+/// a scope.
+struct FPControlModesCleanup final : EHScopeStack::Cleanup {
+  llvm::Value *PreviousModes;
+  FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {}
+  void Emit(CodeGenFunction &CGF, Flags flags) override {
+CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {},
+{PreviousModes});
+  }
+};
+} // namespace

[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-26 Thread Joshua Cranmer via cfe-commits

https://github.com/jcranmer-intel requested changes to this pull request.

I haven't fully tested the changes yet, so right now I'm looking at the test to 
figure out how much is supported. Nevertheless, I can already tell that this is 
not complete support.

7.6.2p4 does clearly state that floating constants need to be evaluated 
according to the standard rounding mode, so that the constant `0.1` evaluates 
to a different value in `FE_DOWNWARD` versus `FE_UPWARD`.

I'm not seeing from the tests how the code is handling calls to functions. 
Calls to all functions outside of a finite list (see same paragraph) need to 
restore the saved dynamic rounding mode for the duration of the call.

I'd like to see tests covering casts and conversions better.

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-25 Thread Serge Pavlov via cfe-commits

https://github.com/spavloff updated 
https://github.com/llvm/llvm-project/pull/89617

>From 0fc5c57264ecf51f8b9fe8303520a51cb1fee40e Mon Sep 17 00:00:00 2001
From: Serge Pavlov 
Date: Thu, 14 Apr 2022 18:00:14 +0700
Subject: [PATCH 1/2] Implementation of '#pragma STDC FENV_ROUND'

This pragma is introduced by forthcoming C2x standard and can be used to
set particular rounding mode without need to call 'fesetmode' or accessing
control mode registers directly. Previously this pragma was implemented in
clang partially, only for the purpose of using in constant expressions and
making tests.

This change implements the pragma according to the standard draft. It sets
up dynamic rounding mode in the compound statement where the pragma acts.
This is inevitable for targets that set rounding mode by changing some
control register. Targets that support static rounding mode encoded in
instructions can have more efficient implementation, it is not
implemented in this change.

The implementation uses intrinsic functions 'get_rounding' and
'set_rounding' to save/restore dynamic rounding mode. In some cases
using functions that operate entire set of control modes or even FP
environment may give more efficient implementation. This optimization is
not a part of this change.
---
 clang/include/clang/AST/Stmt.h|   9 +
 .../clang/Basic/DiagnosticParseKinds.td   |   3 -
 clang/include/clang/Basic/LangOptions.h   |   6 +
 clang/lib/CodeGen/CGStmt.cpp  |  56 ++
 clang/lib/CodeGen/CodeGenFunction.h   |   3 +
 clang/lib/Parse/ParsePragma.cpp   |   3 -
 clang/test/CodeGen/complex-strictfp.c |  60 ---
 clang/test/CodeGen/math-errno.c   |   6 +-
 clang/test/CodeGen/pragma-fenv_access.c   |  45 -
 clang/test/CodeGen/pragma-fenv_round.c| 160 ++
 clang/test/Parser/pragma-fenv_round.c |   1 -
 11 files changed, 315 insertions(+), 37 deletions(-)
 create mode 100644 clang/test/CodeGen/pragma-fenv_round.c

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 9cd7a364cd3f1d..6eceecd93e59c2 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1658,6 +1658,15 @@ class CompoundStmt final
 return *getTrailingObjects();
   }
 
+  /// Get FPOptions inside this statement. They may differ from the outer
+  /// options due to pragmas.
+  /// \param CurFPOptions FPOptions outside this statement.
+  FPOptions getNewFPOptions(FPOptions CurFPOptions) const {
+return hasStoredFPFeatures()
+   ? getStoredFPFeatures().applyOverrides(CurFPOptions)
+   : CurFPOptions;
+  }
+
   using body_iterator = Stmt **;
   using body_range = llvm::iterator_range;
 
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 38174cf3549f14..329af794405998 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1257,9 +1257,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in 
STDC namespace">,
 // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
 // outside external declarations or preceding all explicit declarations and
 // statements inside a compound statement.
-def warn_stdc_fenv_round_not_supported :
-   Warning<"pragma STDC FENV_ROUND is not supported">,
-   InGroup;
 def warn_stdc_unknown_rounding_mode : Warning<
   "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - 
ignored">,
   InGroup;
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index ae4715921d1665..28164f564e907d 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -839,6 +839,12 @@ class FPOptions {
getAllowFEnvAccess();
   }
 
+  /// Checks if the rounding mode is unknown at compile-time.
+  bool isRoundingModeDynamic() const {
+return (getConstRoundingMode() == RoundingMode::Dynamic) &&
+   (getAllowFEnvAccess() || getRoundingMath());
+  }
+
   RoundingMode getRoundingMode() const {
 RoundingMode RM = getConstRoundingMode();
 if (RM == RoundingMode::Dynamic) {
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 576fe2f7a2d46f..4fbc906afaeed5 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
   return true;
 }
 
+namespace {
+/// Cleanup action that restores floating-point control modes upon leaving
+/// a scope.
+struct FPControlModesCleanup final : EHScopeStack::Cleanup {
+  llvm::Value *PreviousModes;
+  FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {}
+  void Emit(CodeGenFunction &CGF, Flags flags) override {
+CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {},
+{PreviousModes});
+  }
+};
+} // n

[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-24 Thread Joshua Cranmer via cfe-commits


@@ -0,0 +1,160 @@
+// RUN: %clang_cc1 -S -triple x86_64-linux-gnu -emit-llvm %s -o - | \
+// RUN:   FileCheck %s --implicit-check-not "call void @llvm.set.rounding" 
--implicit-check-not "call i32 @llvm.get.rounding"
+
+float func_rz_ru(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+#pragma STDC FENV_ROUND FE_UPWARD
+result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_rz_ru
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 2)
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata 
!"round.upward", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+float func_rz_rz(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+#pragma STDC FENV_ROUND FE_TOWARDZERO
+result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_rz_rz
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+float func_rne_rne(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TONEAREST
+  float result = x * y;
+  {
+#pragma STDC FENV_ROUND FE_TONEAREST
+result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_rne_rne
+// CHECK:  fmul
+// CHECK:  fadd
+// CHECK:  fsub
+
+float func_rz_dyn_noacc(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+#pragma STDC FENV_ROUND FE_DYNAMIC
+result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_rz_dyn_noacc
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata 
!"round.tonearest", metadata !"fpexcept.ignore")

jcranmer-intel wrote:

7.6.2p3:
> If the FE_DYNAMIC mode is specified and FENV_ACCESS is "off", the translator 
> may assume that the default rounding mode is in effect.

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-24 Thread Zahira Ammarguellat via cfe-commits


@@ -1257,9 +1257,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in 
STDC namespace">,
 // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either

zahiraam wrote:

This comment can be removed I think.

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-24 Thread Zahira Ammarguellat via cfe-commits


@@ -0,0 +1,160 @@
+// RUN: %clang_cc1 -S -triple x86_64-linux-gnu -emit-llvm %s -o - | \
+// RUN:   FileCheck %s --implicit-check-not "call void @llvm.set.rounding" 
--implicit-check-not "call i32 @llvm.get.rounding"
+
+float func_rz_ru(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+#pragma STDC FENV_ROUND FE_UPWARD
+result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_rz_ru
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 2)
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata 
!"round.upward", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+float func_rz_rz(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+#pragma STDC FENV_ROUND FE_TOWARDZERO
+result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_rz_rz
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+float func_rne_rne(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TONEAREST
+  float result = x * y;
+  {
+#pragma STDC FENV_ROUND FE_TONEAREST
+result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_rne_rne
+// CHECK:  fmul
+// CHECK:  fadd
+// CHECK:  fsub
+
+float func_rz_dyn_noacc(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+#pragma STDC FENV_ROUND FE_DYNAMIC
+result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_rz_dyn_noacc
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata 
!"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata 
!"round.tonearest", metadata !"fpexcept.ignore")

zahiraam wrote:

Shouldn't the `result += z` be dynamic here?

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-24 Thread Zahira Ammarguellat via cfe-commits

zahiraam wrote:

How about adding `pragma STDC FENV_ROUND` at file scope and some C++ tests 
(with default argument in functions).

https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-23 Thread Serge Pavlov via cfe-commits

https://github.com/spavloff updated 
https://github.com/llvm/llvm-project/pull/89617

>From 0fc5c57264ecf51f8b9fe8303520a51cb1fee40e Mon Sep 17 00:00:00 2001
From: Serge Pavlov 
Date: Thu, 14 Apr 2022 18:00:14 +0700
Subject: [PATCH] Implementation of '#pragma STDC FENV_ROUND'

This pragma is introduced by forthcoming C2x standard and can be used to
set particular rounding mode without need to call 'fesetmode' or accessing
control mode registers directly. Previously this pragma was implemented in
clang partially, only for the purpose of using in constant expressions and
making tests.

This change implements the pragma according to the standard draft. It sets
up dynamic rounding mode in the compound statement where the pragma acts.
This is inevitable for targets that set rounding mode by changing some
control register. Targets that support static rounding mode encoded in
instructions can have more efficient implementation, it is not
implemented in this change.

The implementation uses intrinsic functions 'get_rounding' and
'set_rounding' to save/restore dynamic rounding mode. In some cases
using functions that operate entire set of control modes or even FP
environment may give more efficient implementation. This optimization is
not a part of this change.
---
 clang/include/clang/AST/Stmt.h|   9 +
 .../clang/Basic/DiagnosticParseKinds.td   |   3 -
 clang/include/clang/Basic/LangOptions.h   |   6 +
 clang/lib/CodeGen/CGStmt.cpp  |  56 ++
 clang/lib/CodeGen/CodeGenFunction.h   |   3 +
 clang/lib/Parse/ParsePragma.cpp   |   3 -
 clang/test/CodeGen/complex-strictfp.c |  60 ---
 clang/test/CodeGen/math-errno.c   |   6 +-
 clang/test/CodeGen/pragma-fenv_access.c   |  45 -
 clang/test/CodeGen/pragma-fenv_round.c| 160 ++
 clang/test/Parser/pragma-fenv_round.c |   1 -
 11 files changed, 315 insertions(+), 37 deletions(-)
 create mode 100644 clang/test/CodeGen/pragma-fenv_round.c

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 9cd7a364cd3f1d..6eceecd93e59c2 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1658,6 +1658,15 @@ class CompoundStmt final
 return *getTrailingObjects();
   }
 
+  /// Get FPOptions inside this statement. They may differ from the outer
+  /// options due to pragmas.
+  /// \param CurFPOptions FPOptions outside this statement.
+  FPOptions getNewFPOptions(FPOptions CurFPOptions) const {
+return hasStoredFPFeatures()
+   ? getStoredFPFeatures().applyOverrides(CurFPOptions)
+   : CurFPOptions;
+  }
+
   using body_iterator = Stmt **;
   using body_range = llvm::iterator_range;
 
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 38174cf3549f14..329af794405998 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1257,9 +1257,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in 
STDC namespace">,
 // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
 // outside external declarations or preceding all explicit declarations and
 // statements inside a compound statement.
-def warn_stdc_fenv_round_not_supported :
-   Warning<"pragma STDC FENV_ROUND is not supported">,
-   InGroup;
 def warn_stdc_unknown_rounding_mode : Warning<
   "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - 
ignored">,
   InGroup;
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index ae4715921d1665..28164f564e907d 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -839,6 +839,12 @@ class FPOptions {
getAllowFEnvAccess();
   }
 
+  /// Checks if the rounding mode is unknown at compile-time.
+  bool isRoundingModeDynamic() const {
+return (getConstRoundingMode() == RoundingMode::Dynamic) &&
+   (getAllowFEnvAccess() || getRoundingMath());
+  }
+
   RoundingMode getRoundingMode() const {
 RoundingMode RM = getConstRoundingMode();
 if (RM == RoundingMode::Dynamic) {
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 576fe2f7a2d46f..4fbc906afaeed5 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
   return true;
 }
 
+namespace {
+/// Cleanup action that restores floating-point control modes upon leaving
+/// a scope.
+struct FPControlModesCleanup final : EHScopeStack::Cleanup {
+  llvm::Value *PreviousModes;
+  FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {}
+  void Emit(CodeGenFunction &CGF, Flags flags) override {
+CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {},
+{PreviousModes});
+  }
+};
+} // names

[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-22 Thread Serge Pavlov via cfe-commits

https://github.com/spavloff updated 
https://github.com/llvm/llvm-project/pull/89617

>From fc7aab600c25b39b2df039c0cbcf517719736311 Mon Sep 17 00:00:00 2001
From: Serge Pavlov 
Date: Thu, 14 Apr 2022 18:00:14 +0700
Subject: [PATCH] Implementation of '#pragma STDC FENV_ROUND'

This pragma is introduced by forthcoming C2x standard and can be used to
set particular rounding mode without need to call 'fesetmode' or accessing
control mode registers directly. Previously this pragma was implemented in
clang partially, only for the purpose of using in constant expressions and
making tests.

This change implements the pragma according to the standard draft. It sets
up dynamic rounding mode in the compound statement where the pragma acts.
This is inevitable for targets that set rounding mode by changing some
control register. Targets that support static rounding mode encoded in
instructions can have more efficient implementation, it is not
implemented in this change.

The implementation uses intrinsic functions 'get_rounding' and
'set_rounding' to save/restore dynamic rounding mode. In some cases
using functions that operate entire set of control modes or even FP
environment may give more efficient implementation. This optimization is
not a part of this change.
---
 clang/include/clang/AST/Stmt.h|   9 +
 .../clang/Basic/DiagnosticParseKinds.td   |   3 -
 clang/include/clang/Basic/LangOptions.h   |   6 +
 clang/lib/CodeGen/CGStmt.cpp  |  56 ++
 clang/lib/CodeGen/CodeGenFunction.h   |   3 +
 clang/lib/Parse/ParsePragma.cpp   |   3 -
 clang/test/CodeGen/complex-strictfp.c |  60 ---
 clang/test/CodeGen/math-errno.c   |   2 +-
 clang/test/CodeGen/pragma-fenv_access.c   |  45 -
 clang/test/CodeGen/pragma-fenv_round.c| 160 ++
 clang/test/Parser/pragma-fenv_round.c |   1 -
 11 files changed, 313 insertions(+), 35 deletions(-)
 create mode 100644 clang/test/CodeGen/pragma-fenv_round.c

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 1b9c9231047717..0ee9c13df75e41 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1663,6 +1663,15 @@ class CompoundStmt final
 return *getTrailingObjects();
   }
 
+  /// Get FPOptions inside this statement. They may differ from the outer
+  /// options due to pragmas.
+  /// \param CurFPOptions FPOptions outside this statement.
+  FPOptions getNewFPOptions(FPOptions CurFPOptions) const {
+return hasStoredFPFeatures()
+   ? getStoredFPFeatures().applyOverrides(CurFPOptions)
+   : CurFPOptions;
+  }
+
   using body_iterator = Stmt **;
   using body_range = llvm::iterator_range;
 
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index bb9ca2a50cc06c..cbda8975717d2e 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1255,9 +1255,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in 
STDC namespace">,
 // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
 // outside external declarations or preceding all explicit declarations and
 // statements inside a compound statement.
-def warn_stdc_fenv_round_not_supported :
-   Warning<"pragma STDC FENV_ROUND is not supported">,
-   InGroup;
 def warn_stdc_unknown_rounding_mode : Warning<
   "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - 
ignored">,
   InGroup;
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index 24b109e32cdd3e..ae8c7b2ead8ee2 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -834,6 +834,12 @@ class FPOptions {
getAllowFEnvAccess();
   }
 
+  /// Checks if the rounding mode is unknown at compile-time.
+  bool isRoundingModeDynamic() const {
+return (getConstRoundingMode() == RoundingMode::Dynamic) &&
+   (getAllowFEnvAccess() || getRoundingMath());
+  }
+
   RoundingMode getRoundingMode() const {
 RoundingMode RM = getConstRoundingMode();
 if (RM == RoundingMode::Dynamic) {
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 576fe2f7a2d46f..4fbc906afaeed5 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
   return true;
 }
 
+namespace {
+/// Cleanup action that restores floating-point control modes upon leaving
+/// a scope.
+struct FPControlModesCleanup final : EHScopeStack::Cleanup {
+  llvm::Value *PreviousModes;
+  FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {}
+  void Emit(CodeGenFunction &CGF, Flags flags) override {
+CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {},
+{PreviousModes});
+  }
+};
+} // names

[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-22 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff 37b7207651b44743909a427b5509bed5e6c21b59 
58adf3643828272d071fd49195cfcf0b2164eb70 -- 
clang/test/CodeGen/pragma-fenv_round.c clang/include/clang/AST/Stmt.h 
clang/include/clang/Basic/LangOptions.h clang/lib/CodeGen/CGStmt.cpp 
clang/lib/CodeGen/CodeGenFunction.h clang/lib/Parse/ParsePragma.cpp 
clang/test/CodeGen/complex-strictfp.c clang/test/CodeGen/math-errno.c 
clang/test/CodeGen/pragma-fenv_access.c clang/test/Parser/pragma-fenv_round.c
``





View the diff from clang-format here.


``diff
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index 2ec642e25d..ae8c7b2ead 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -837,7 +837,7 @@ public:
   /// Checks if the rounding mode is unknown at compile-time.
   bool isRoundingModeDynamic() const {
 return (getConstRoundingMode() == RoundingMode::Dynamic) &&
-  (getAllowFEnvAccess() || getRoundingMath());
+   (getAllowFEnvAccess() || getRoundingMath());
   }
 
   RoundingMode getRoundingMode() const {

``




https://github.com/llvm/llvm-project/pull/89617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-22 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-codegen

Author: Serge Pavlov (spavloff)


Changes

This pragma is introduced by forthcoming C2x standard and can be used to set 
particular rounding mode without need to call 'fesetmode' or accessing control 
mode registers directly. Previously this pragma was implemented in clang 
partially, only for the purpose of using in constant expressions and making 
tests.

This change implements the pragma according to the standard draft. It sets up 
dynamic rounding mode in the compound statement where the pragma acts. This is 
inevitable for targets that set rounding mode by changing some control 
register. Targets that support static rounding mode encoded in instructions can 
have more efficient implementation, it is not implemented in this change.

The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' 
to save/restore dynamic rounding mode. In some cases using functions that 
operate entire set of control modes or even FP environment may give more 
efficient implementation. This optimization is not a part of this change.

---

Patch is 33.34 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/89617.diff


11 Files Affected:

- (modified) clang/include/clang/AST/Stmt.h (+9) 
- (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (-3) 
- (modified) clang/include/clang/Basic/LangOptions.h (+6) 
- (modified) clang/lib/CodeGen/CGStmt.cpp (+56) 
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+3) 
- (modified) clang/lib/Parse/ParsePragma.cpp (-3) 
- (modified) clang/test/CodeGen/complex-strictfp.c (+39-21) 
- (modified) clang/test/CodeGen/math-errno.c (+1-1) 
- (modified) clang/test/CodeGen/pragma-fenv_access.c (+39-6) 
- (added) clang/test/CodeGen/pragma-fenv_round.c (+160) 
- (modified) clang/test/Parser/pragma-fenv_round.c (-1) 


``diff
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 1b9c9231047717..0ee9c13df75e41 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1663,6 +1663,15 @@ class CompoundStmt final
 return *getTrailingObjects();
   }
 
+  /// Get FPOptions inside this statement. They may differ from the outer
+  /// options due to pragmas.
+  /// \param CurFPOptions FPOptions outside this statement.
+  FPOptions getNewFPOptions(FPOptions CurFPOptions) const {
+return hasStoredFPFeatures()
+   ? getStoredFPFeatures().applyOverrides(CurFPOptions)
+   : CurFPOptions;
+  }
+
   using body_iterator = Stmt **;
   using body_range = llvm::iterator_range;
 
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index bb9ca2a50cc06c..cbda8975717d2e 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1255,9 +1255,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in 
STDC namespace">,
 // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
 // outside external declarations or preceding all explicit declarations and
 // statements inside a compound statement.
-def warn_stdc_fenv_round_not_supported :
-   Warning<"pragma STDC FENV_ROUND is not supported">,
-   InGroup;
 def warn_stdc_unknown_rounding_mode : Warning<
   "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - 
ignored">,
   InGroup;
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index 24b109e32cdd3e..2ec642e25ddcc6 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -834,6 +834,12 @@ class FPOptions {
getAllowFEnvAccess();
   }
 
+  /// Checks if the rounding mode is unknown at compile-time.
+  bool isRoundingModeDynamic() const {
+return (getConstRoundingMode() == RoundingMode::Dynamic) &&
+  (getAllowFEnvAccess() || getRoundingMath());
+  }
+
   RoundingMode getRoundingMode() const {
 RoundingMode RM = getConstRoundingMode();
 if (RM == RoundingMode::Dynamic) {
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 576fe2f7a2d46f..4fbc906afaeed5 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
   return true;
 }
 
+namespace {
+/// Cleanup action that restores floating-point control modes upon leaving
+/// a scope.
+struct FPControlModesCleanup final : EHScopeStack::Cleanup {
+  llvm::Value *PreviousModes;
+  FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {}
+  void Emit(CodeGenFunction &CGF, Flags flags) override {
+CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {},
+{PreviousModes});
+  }
+};
+} // namespace
+
+void CodeGenFunction::emitSetFPControlModes(FPOptions NewFP) {
+  if (NewFP == CurFPFeatures)
+return;
+
+  // For now only rounding

[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)

2024-04-22 Thread Serge Pavlov via cfe-commits

https://github.com/spavloff created 
https://github.com/llvm/llvm-project/pull/89617

This pragma is introduced by forthcoming C2x standard and can be used to set 
particular rounding mode without need to call 'fesetmode' or accessing control 
mode registers directly. Previously this pragma was implemented in clang 
partially, only for the purpose of using in constant expressions and making 
tests.

This change implements the pragma according to the standard draft. It sets up 
dynamic rounding mode in the compound statement where the pragma acts. This is 
inevitable for targets that set rounding mode by changing some control 
register. Targets that support static rounding mode encoded in instructions can 
have more efficient implementation, it is not implemented in this change.

The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' 
to save/restore dynamic rounding mode. In some cases using functions that 
operate entire set of control modes or even FP environment may give more 
efficient implementation. This optimization is not a part of this change.

>From 58adf3643828272d071fd49195cfcf0b2164eb70 Mon Sep 17 00:00:00 2001
From: Serge Pavlov 
Date: Thu, 14 Apr 2022 18:00:14 +0700
Subject: [PATCH] Implementation of '#pragma STDC FENV_ROUND'

This pragma is introduced by forthcoming C2x standard and can be used to
set particular rounding mode without need to call 'fesetmode' or accessing
control mode registers directly. Previously this pragma was implemented in
clang partially, only for the purpose of using in constant expressions and
making tests.

This change implements the pragma according to the standard draft. It sets
up dynamic rounding mode in the compound statement where the pragma acts.
This is inevitable for targets that set rounding mode by changing some
control register. Targets that support static rounding mode encoded in
instructions can have more efficient implementation, it is not
implemented in this change.

The implementation uses intrinsic functions 'get_rounding' and
'set_rounding' to save/restore dynamic rounding mode. In some cases
using functions that operate entire set of control modes or even FP
environment may give more efficient implementation. This optimization is
not a part of this change.
---
 clang/include/clang/AST/Stmt.h|   9 +
 .../clang/Basic/DiagnosticParseKinds.td   |   3 -
 clang/include/clang/Basic/LangOptions.h   |   6 +
 clang/lib/CodeGen/CGStmt.cpp  |  56 ++
 clang/lib/CodeGen/CodeGenFunction.h   |   3 +
 clang/lib/Parse/ParsePragma.cpp   |   3 -
 clang/test/CodeGen/complex-strictfp.c |  60 ---
 clang/test/CodeGen/math-errno.c   |   2 +-
 clang/test/CodeGen/pragma-fenv_access.c   |  45 -
 clang/test/CodeGen/pragma-fenv_round.c| 160 ++
 clang/test/Parser/pragma-fenv_round.c |   1 -
 11 files changed, 313 insertions(+), 35 deletions(-)
 create mode 100644 clang/test/CodeGen/pragma-fenv_round.c

diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 1b9c9231047717..0ee9c13df75e41 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1663,6 +1663,15 @@ class CompoundStmt final
 return *getTrailingObjects();
   }
 
+  /// Get FPOptions inside this statement. They may differ from the outer
+  /// options due to pragmas.
+  /// \param CurFPOptions FPOptions outside this statement.
+  FPOptions getNewFPOptions(FPOptions CurFPOptions) const {
+return hasStoredFPFeatures()
+   ? getStoredFPFeatures().applyOverrides(CurFPOptions)
+   : CurFPOptions;
+  }
+
   using body_iterator = Stmt **;
   using body_range = llvm::iterator_range;
 
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index bb9ca2a50cc06c..cbda8975717d2e 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1255,9 +1255,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in 
STDC namespace">,
 // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
 // outside external declarations or preceding all explicit declarations and
 // statements inside a compound statement.
-def warn_stdc_fenv_round_not_supported :
-   Warning<"pragma STDC FENV_ROUND is not supported">,
-   InGroup;
 def warn_stdc_unknown_rounding_mode : Warning<
   "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - 
ignored">,
   InGroup;
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index 24b109e32cdd3e..2ec642e25ddcc6 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -834,6 +834,12 @@ class FPOptions {
getAllowFEnvAccess();
   }
 
+  /// Checks if the rounding mode is unknown at compile-time.
+  bool isRoundingModeDynamic