[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 22 08:58:26 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Serge Pavlov (spavloff)
<details>
<summary>Changes</summary>
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<FPOptionsOverride>();
}
+ /// 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<body_iterator>;
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<UnknownPragmas>;
def warn_stdc_unknown_rounding_mode : Warning<
"invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">,
InGroup<IgnoredPragmas>;
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 mode is handled.
+
+ // If the new rounding mode is unknown in compile-time, it means that the
+ // compound statement contains `#pragma STDC FENV_ACCESS ON`. In this case all
+ // manipulations on FP environment, including setting and restoring control
+ // modes are made by the user.
+ if (NewFP.isRoundingModeDynamic())
+ return;
+
+ llvm::RoundingMode OldConstRM = CurFPFeatures.getConstRoundingMode();
+ llvm::RoundingMode NewConstRM = NewFP.getConstRoundingMode();
+ if (OldConstRM == NewConstRM)
+ return;
+
+ llvm::RoundingMode OldRM = CurFPFeatures.getRoundingMode();
+ if (OldRM == NewConstRM)
+ return;
+
+ llvm::Value *PreviousRM = nullptr;
+ if (CurFPFeatures.isRoundingModeDynamic()) {
+ llvm::Function *FGetRound = CGM.getIntrinsic(llvm::Intrinsic::get_rounding);
+ PreviousRM = Builder.CreateCall(FGetRound);
+ } else {
+ PreviousRM = llvm::ConstantInt::get(Int32Ty, static_cast<uint64_t>(OldRM));
+ }
+
+ llvm::RoundingMode NewRM = NewFP.getRoundingMode();
+ Builder.CreateIntrinsic(
+ llvm::Intrinsic::set_rounding, {},
+ llvm::ConstantInt::get(Int32Ty, static_cast<uint64_t>(NewRM)));
+ EHStack.pushCleanup<FPControlModesCleanup>(NormalAndEHCleanup, PreviousRM);
+}
+
/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
/// this captures the expression result of the last sub-statement and returns it
/// (for use by the statement expression extension).
@@ -509,6 +559,12 @@ CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
assert((!GetLast || (GetLast && ExprResult)) &&
"If GetLast is true then the CompoundStmt must have a StmtExprResult");
+ // Optionally set up the new FP environment, if the compound statement
+ // contains a pragma that modifies it.
+ FPOptions NewFP = S.getNewFPOptions(CurFPFeatures);
+ emitSetFPControlModes(NewFP);
+ CGFPOptionsRAII SavedFPFeatues(*this, NewFP);
+
Address RetAlloca = Address::invalid();
for (auto *CurStmt : S.body()) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index c49e9fd00c8d3e..4964a1c6c0c5fb 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3323,6 +3323,9 @@ class CodeGenFunction : public CodeGenTypeCache {
/// Get the record field index as represented in debug info.
unsigned getDebugInfoFIndex(const RecordDecl *Rec, unsigned FieldIndex);
+ /// Optionally emit code that sets required floating-point control modes and
+ /// creates corresponding cleanup action.
+ void emitSetFPControlModes(FPOptions NewFP);
//===--------------------------------------------------------------------===//
// Declaration Emission
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 3979f75b6020db..56b15bda975a9a 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -3461,9 +3461,6 @@ void PragmaSTDC_FENV_ROUNDHandler::HandlePragma(Preprocessor &PP,
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();
diff --git a/clang/test/CodeGen/complex-strictfp.c b/clang/test/CodeGen/complex-strictfp.c
index b0c84d5eebe725..e1f5405b921978 100644
--- a/clang/test/CodeGen/complex-strictfp.c
+++ b/clang/test/CodeGen/complex-strictfp.c
@@ -17,16 +17,18 @@ double D;
// CHECK-LABEL: @test3a(
// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3:[0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8
// CHECK-NEXT: [[CF_REAL:%.*]] = load float, ptr @cf, align 4
// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
-// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2:[0-9]+]]
-// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR2]]
-// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[CONV]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
-// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[ADD_R]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
-// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[CONV1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR3]]
+// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR3]]
+// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[CONV]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
+// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[ADD_R]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
+// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[CONV1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: store float [[CONV2]], ptr @cf, align 4
// CHECK-NEXT: store float [[CONV3]], ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void test3a(void) {
@@ -35,13 +37,15 @@ void test3a(void) {
// CHECK-LABEL: @test3b(
// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
// CHECK-NEXT: [[CF_REAL:%.*]] = load float, ptr @cf, align 4
// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
-// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2]]
-// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR3]]
+// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8
-// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[CONV]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[CONV]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: store double [[ADD_R]], ptr @D, align 8
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void test3b(void) {
@@ -50,19 +54,21 @@ void test3b(void) {
// CHECK-LABEL: @test3c(
// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
// CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8
// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
// CHECK-NEXT: [[CF_REAL:%.*]] = load float, ptr @cf, align 4
// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
-// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2]]
-// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR2]]
-// CHECK-NEXT: [[CALL:%.*]] = call { double, double } @__divdc3(double noundef [[CONV]], double noundef [[CONV1]], double noundef [[G1_REAL]], double noundef [[G1_IMAG]]) #[[ATTR3:[0-9]+]]
+// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR3]]
+// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR3]]
+// CHECK-NEXT: [[CALL:%.*]] = call { double, double } @__divdc3(double noundef [[CONV]], double noundef [[CONV1]], double noundef [[G1_REAL]], double noundef [[G1_IMAG]]) #[[ATTR4:[0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = extractvalue { double, double } [[CALL]], 0
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[CALL]], 1
-// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
-// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
+// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: store float [[CONV2]], ptr @cf, align 4
// CHECK-NEXT: store float [[CONV3]], ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void test3c(void) {
@@ -71,12 +77,14 @@ void test3c(void) {
// CHECK-LABEL: @test3d(
// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
// CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8
// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8
-// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[G1_REAL]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[G1_REAL]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: store double [[ADD_R]], ptr @g1, align 8
// CHECK-NEXT: store double [[G1_IMAG]], ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void test3d(void) {
@@ -85,12 +93,14 @@ void test3d(void) {
// CHECK-LABEL: @test3e(
// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8
// CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8
// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
-// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[G1_REAL]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[G1_REAL]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: store double [[ADD_R]], ptr @g1, align 8
// CHECK-NEXT: store double [[G1_IMAG]], ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void test3e(void) {
@@ -99,8 +109,10 @@ void test3e(void) {
// CHECK-LABEL: @t1(
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
+// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: store float [[CONV]], ptr @cf, align 4
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void t1(void) {
@@ -109,8 +121,10 @@ void t1(void) {
// CHECK-LABEL: @t2(
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
+// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: store float [[CONV]], ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void t2(void) {
@@ -120,16 +134,18 @@ void t2(void) {
// CHECK-LABEL: @t91(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[C:%.*]] = alloca [0 x i8], align 1
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
// CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
// CHECK: cond.true:
-// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: br label [[COND_END:%.*]]
// CHECK: cond.false:
-// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: br label [[COND_END]]
// CHECK: cond.end:
// CHECK-NEXT: [[COND_R:%.*]] = phi double [ [[CONV]], [[COND_TRUE]] ], [ [[CONV1]], [[COND_FALSE]] ]
// CHECK-NEXT: [[COND_I:%.*]] = phi double [ 0.000000e+00, [[COND_TRUE]] ], [ 0.000000e+00, [[COND_FALSE]] ]
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void t91(void) {
@@ -142,16 +158,18 @@ void t91(void) {
// CHECK-LABEL: @t92(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[C:%.*]] = alloca [0 x i8], align 1
+// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
// CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
// CHECK: cond.true:
-// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: br label [[COND_END:%.*]]
// CHECK: cond.false:
-// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR3]]
// CHECK-NEXT: br label [[COND_END]]
// CHECK: cond.end:
// CHECK-NEXT: [[COND_R:%.*]] = phi double [ [[CONV]], [[COND_TRUE]] ], [ [[CONV1]], [[COND_FALSE]] ]
// CHECK-NEXT: [[COND_I:%.*]] = phi double [ 0.000000e+00, [[COND_TRUE]] ], [ 0.000000e+00, [[COND_FALSE]] ]
+// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
// CHECK-NEXT: ret void
//
void t92(void) {
diff --git a/clang/test/CodeGen/math-errno.c b/clang/test/CodeGen/math-errno.c
index b5354e47e26b77..b8da81b585fa53 100644
--- a/clang/test/CodeGen/math-errno.c
+++ b/clang/test/CodeGen/math-errno.c
@@ -27,7 +27,7 @@ float f1(float x) {
// CHECK: tail call float @sqrtf(float noundef {{.*}}) #[[ATTR4_O2:[0-9]+]]
// FAST-LABEL: define {{.*}} nofpclass(nan inf) float @f1
-// FAST: call fast nofpclass(nan inf) float @sqrtf(float noundef nofpclass(nan inf) {{.*}}) #[[ATTR3_FAST:[0-9]+]]
+// FAST: call nofpclass(nan inf) float @sqrtf(float noundef nofpclass(nan inf) {{.*}}) #[[ATTR3_FAST:[0-9]+]]
// NOOPT-LABEL: define {{.*}} float @f1
// NOOPT...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/89617
More information about the cfe-commits
mailing list