Skip to content

Commit fc7aab6

Browse files
committed
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.
1 parent 37b7207 commit fc7aab6

File tree

11 files changed

+313
-35
lines changed

11 files changed

+313
-35
lines changed

clang/include/clang/AST/Stmt.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,6 +1663,15 @@ class CompoundStmt final
16631663
return *getTrailingObjects<FPOptionsOverride>();
16641664
}
16651665

1666+
/// Get FPOptions inside this statement. They may differ from the outer
1667+
/// options due to pragmas.
1668+
/// \param CurFPOptions FPOptions outside this statement.
1669+
FPOptions getNewFPOptions(FPOptions CurFPOptions) const {
1670+
return hasStoredFPFeatures()
1671+
? getStoredFPFeatures().applyOverrides(CurFPOptions)
1672+
: CurFPOptions;
1673+
}
1674+
16661675
using body_iterator = Stmt **;
16671676
using body_range = llvm::iterator_range<body_iterator>;
16681677

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,9 +1255,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
12551255
// The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
12561256
// outside external declarations or preceding all explicit declarations and
12571257
// statements inside a compound statement.
1258-
def warn_stdc_fenv_round_not_supported :
1259-
Warning<"pragma STDC FENV_ROUND is not supported">,
1260-
InGroup<UnknownPragmas>;
12611258
def warn_stdc_unknown_rounding_mode : Warning<
12621259
"invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">,
12631260
InGroup<IgnoredPragmas>;

clang/include/clang/Basic/LangOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,12 @@ class FPOptions {
834834
getAllowFEnvAccess();
835835
}
836836

837+
/// Checks if the rounding mode is unknown at compile-time.
838+
bool isRoundingModeDynamic() const {
839+
return (getConstRoundingMode() == RoundingMode::Dynamic) &&
840+
(getAllowFEnvAccess() || getRoundingMath());
841+
}
842+
837843
RoundingMode getRoundingMode() const {
838844
RoundingMode RM = getConstRoundingMode();
839845
if (RM == RoundingMode::Dynamic) {

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
486486
return true;
487487
}
488488

489+
namespace {
490+
/// Cleanup action that restores floating-point control modes upon leaving
491+
/// a scope.
492+
struct FPControlModesCleanup final : EHScopeStack::Cleanup {
493+
llvm::Value *PreviousModes;
494+
FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {}
495+
void Emit(CodeGenFunction &CGF, Flags flags) override {
496+
CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {},
497+
{PreviousModes});
498+
}
499+
};
500+
} // namespace
501+
502+
void CodeGenFunction::emitSetFPControlModes(FPOptions NewFP) {
503+
if (NewFP == CurFPFeatures)
504+
return;
505+
506+
// For now only rounding mode is handled.
507+
508+
// If the new rounding mode is unknown in compile-time, it means that the
509+
// compound statement contains `#pragma STDC FENV_ACCESS ON`. In this case all
510+
// manipulations on FP environment, including setting and restoring control
511+
// modes are made by the user.
512+
if (NewFP.isRoundingModeDynamic())
513+
return;
514+
515+
llvm::RoundingMode OldConstRM = CurFPFeatures.getConstRoundingMode();
516+
llvm::RoundingMode NewConstRM = NewFP.getConstRoundingMode();
517+
if (OldConstRM == NewConstRM)
518+
return;
519+
520+
llvm::RoundingMode OldRM = CurFPFeatures.getRoundingMode();
521+
if (OldRM == NewConstRM)
522+
return;
523+
524+
llvm::Value *PreviousRM = nullptr;
525+
if (CurFPFeatures.isRoundingModeDynamic()) {
526+
llvm::Function *FGetRound = CGM.getIntrinsic(llvm::Intrinsic::get_rounding);
527+
PreviousRM = Builder.CreateCall(FGetRound);
528+
} else {
529+
PreviousRM = llvm::ConstantInt::get(Int32Ty, static_cast<uint64_t>(OldRM));
530+
}
531+
532+
llvm::RoundingMode NewRM = NewFP.getRoundingMode();
533+
Builder.CreateIntrinsic(
534+
llvm::Intrinsic::set_rounding, {},
535+
llvm::ConstantInt::get(Int32Ty, static_cast<uint64_t>(NewRM)));
536+
EHStack.pushCleanup<FPControlModesCleanup>(NormalAndEHCleanup, PreviousRM);
537+
}
538+
489539
/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
490540
/// this captures the expression result of the last sub-statement and returns it
491541
/// (for use by the statement expression extension).
@@ -509,6 +559,12 @@ CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
509559
assert((!GetLast || (GetLast && ExprResult)) &&
510560
"If GetLast is true then the CompoundStmt must have a StmtExprResult");
511561

562+
// Optionally set up the new FP environment, if the compound statement
563+
// contains a pragma that modifies it.
564+
FPOptions NewFP = S.getNewFPOptions(CurFPFeatures);
565+
emitSetFPControlModes(NewFP);
566+
CGFPOptionsRAII SavedFPFeatues(*this, NewFP);
567+
512568
Address RetAlloca = Address::invalid();
513569

514570
for (auto *CurStmt : S.body()) {

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3323,6 +3323,9 @@ class CodeGenFunction : public CodeGenTypeCache {
33233323
/// Get the record field index as represented in debug info.
33243324
unsigned getDebugInfoFIndex(const RecordDecl *Rec, unsigned FieldIndex);
33253325

3326+
/// Optionally emit code that sets required floating-point control modes and
3327+
/// creates corresponding cleanup action.
3328+
void emitSetFPControlModes(FPOptions NewFP);
33263329

33273330
//===--------------------------------------------------------------------===//
33283331
// Declaration Emission

clang/lib/Parse/ParsePragma.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3461,9 +3461,6 @@ void PragmaSTDC_FENV_ROUNDHandler::HandlePragma(Preprocessor &PP,
34613461
return;
34623462
}
34633463

3464-
// Until the pragma is fully implemented, issue a warning.
3465-
PP.Diag(Tok.getLocation(), diag::warn_stdc_fenv_round_not_supported);
3466-
34673464
MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1),
34683465
1);
34693466
Toks[0].startToken();

clang/test/CodeGen/complex-strictfp.c

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@ double D;
1717

1818
// CHECK-LABEL: @test3a(
1919
// CHECK-NEXT: entry:
20+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3:[0-9]+]]
2021
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8
2122
// CHECK-NEXT: [[CF_REAL:%.*]] = load float, ptr @cf, align 4
2223
// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
23-
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2:[0-9]+]]
24-
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR2]]
25-
// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[CONV]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
26-
// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[ADD_R]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
27-
// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[CONV1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
24+
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR3]]
25+
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR3]]
26+
// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[CONV]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
27+
// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[ADD_R]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
28+
// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[CONV1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
2829
// CHECK-NEXT: store float [[CONV2]], ptr @cf, align 4
2930
// CHECK-NEXT: store float [[CONV3]], ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
31+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
3032
// CHECK-NEXT: ret void
3133
//
3234
void test3a(void) {
@@ -35,13 +37,15 @@ void test3a(void) {
3537

3638
// CHECK-LABEL: @test3b(
3739
// CHECK-NEXT: entry:
40+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
3841
// CHECK-NEXT: [[CF_REAL:%.*]] = load float, ptr @cf, align 4
3942
// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
40-
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2]]
41-
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR2]]
43+
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR3]]
44+
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR3]]
4245
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8
43-
// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[CONV]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
46+
// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[CONV]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
4447
// CHECK-NEXT: store double [[ADD_R]], ptr @D, align 8
48+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
4549
// CHECK-NEXT: ret void
4650
//
4751
void test3b(void) {
@@ -50,19 +54,21 @@ void test3b(void) {
5054

5155
// CHECK-LABEL: @test3c(
5256
// CHECK-NEXT: entry:
57+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
5358
// CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8
5459
// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
5560
// CHECK-NEXT: [[CF_REAL:%.*]] = load float, ptr @cf, align 4
5661
// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
57-
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2]]
58-
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR2]]
59-
// CHECK-NEXT: [[CALL:%.*]] = call { double, double } @__divdc3(double noundef [[CONV]], double noundef [[CONV1]], double noundef [[G1_REAL]], double noundef [[G1_IMAG]]) #[[ATTR3:[0-9]+]]
62+
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR3]]
63+
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR3]]
64+
// CHECK-NEXT: [[CALL:%.*]] = call { double, double } @__divdc3(double noundef [[CONV]], double noundef [[CONV1]], double noundef [[G1_REAL]], double noundef [[G1_IMAG]]) #[[ATTR4:[0-9]+]]
6065
// CHECK-NEXT: [[TMP0:%.*]] = extractvalue { double, double } [[CALL]], 0
6166
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[CALL]], 1
62-
// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
63-
// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
67+
// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
68+
// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
6469
// CHECK-NEXT: store float [[CONV2]], ptr @cf, align 4
6570
// CHECK-NEXT: store float [[CONV3]], ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
71+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
6672
// CHECK-NEXT: ret void
6773
//
6874
void test3c(void) {
@@ -71,12 +77,14 @@ void test3c(void) {
7177

7278
// CHECK-LABEL: @test3d(
7379
// CHECK-NEXT: entry:
80+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
7481
// CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8
7582
// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
7683
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8
77-
// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[G1_REAL]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
84+
// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[G1_REAL]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
7885
// CHECK-NEXT: store double [[ADD_R]], ptr @g1, align 8
7986
// CHECK-NEXT: store double [[G1_IMAG]], ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
87+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
8088
// CHECK-NEXT: ret void
8189
//
8290
void test3d(void) {
@@ -85,12 +93,14 @@ void test3d(void) {
8593

8694
// CHECK-LABEL: @test3e(
8795
// CHECK-NEXT: entry:
96+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
8897
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8
8998
// CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8
9099
// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
91-
// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[G1_REAL]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
100+
// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[G1_REAL]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
92101
// CHECK-NEXT: store double [[ADD_R]], ptr @g1, align 8
93102
// CHECK-NEXT: store double [[G1_IMAG]], ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8
103+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
94104
// CHECK-NEXT: ret void
95105
//
96106
void test3e(void) {
@@ -99,8 +109,10 @@ void test3e(void) {
99109

100110
// CHECK-LABEL: @t1(
101111
// CHECK-NEXT: entry:
102-
// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
112+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
113+
// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
103114
// CHECK-NEXT: store float [[CONV]], ptr @cf, align 4
115+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
104116
// CHECK-NEXT: ret void
105117
//
106118
void t1(void) {
@@ -109,8 +121,10 @@ void t1(void) {
109121

110122
// CHECK-LABEL: @t2(
111123
// CHECK-NEXT: entry:
112-
// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
124+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
125+
// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR3]]
113126
// CHECK-NEXT: store float [[CONV]], ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4
127+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
114128
// CHECK-NEXT: ret void
115129
//
116130
void t2(void) {
@@ -120,16 +134,18 @@ void t2(void) {
120134
// CHECK-LABEL: @t91(
121135
// CHECK-NEXT: entry:
122136
// CHECK-NEXT: [[C:%.*]] = alloca [0 x i8], align 1
137+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
123138
// CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
124139
// CHECK: cond.true:
125-
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
140+
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR3]]
126141
// CHECK-NEXT: br label [[COND_END:%.*]]
127142
// CHECK: cond.false:
128-
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
143+
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR3]]
129144
// CHECK-NEXT: br label [[COND_END]]
130145
// CHECK: cond.end:
131146
// CHECK-NEXT: [[COND_R:%.*]] = phi double [ [[CONV]], [[COND_TRUE]] ], [ [[CONV1]], [[COND_FALSE]] ]
132147
// CHECK-NEXT: [[COND_I:%.*]] = phi double [ 0.000000e+00, [[COND_TRUE]] ], [ 0.000000e+00, [[COND_FALSE]] ]
148+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
133149
// CHECK-NEXT: ret void
134150
//
135151
void t91(void) {
@@ -142,16 +158,18 @@ void t91(void) {
142158
// CHECK-LABEL: @t92(
143159
// CHECK-NEXT: entry:
144160
// CHECK-NEXT: [[C:%.*]] = alloca [0 x i8], align 1
161+
// CHECK-NEXT: call void @llvm.set.rounding(i32 2) #[[ATTR3]]
145162
// CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
146163
// CHECK: cond.true:
147-
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
164+
// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR3]]
148165
// CHECK-NEXT: br label [[COND_END:%.*]]
149166
// CHECK: cond.false:
150-
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
167+
// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR3]]
151168
// CHECK-NEXT: br label [[COND_END]]
152169
// CHECK: cond.end:
153170
// CHECK-NEXT: [[COND_R:%.*]] = phi double [ [[CONV]], [[COND_TRUE]] ], [ [[CONV1]], [[COND_FALSE]] ]
154171
// CHECK-NEXT: [[COND_I:%.*]] = phi double [ 0.000000e+00, [[COND_TRUE]] ], [ 0.000000e+00, [[COND_FALSE]] ]
172+
// CHECK-NEXT: call void @llvm.set.rounding(i32 1) #[[ATTR3]]
155173
// CHECK-NEXT: ret void
156174
//
157175
void t92(void) {

clang/test/CodeGen/math-errno.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ float f1(float x) {
2727
// CHECK: tail call float @sqrtf(float noundef {{.*}}) #[[ATTR4_O2:[0-9]+]]
2828

2929
// FAST-LABEL: define {{.*}} nofpclass(nan inf) float @f1
30-
// FAST: call fast nofpclass(nan inf) float @sqrtf(float noundef nofpclass(nan inf) {{.*}}) #[[ATTR3_FAST:[0-9]+]]
30+
// FAST: call nofpclass(nan inf) float @sqrtf(float noundef nofpclass(nan inf) {{.*}}) #[[ATTR3_FAST:[0-9]+]]
3131

3232
// NOOPT-LABEL: define {{.*}} float @f1
3333
// NOOPT: call float @sqrtf(float noundef {{.*}}) #[[ATTR4_NOOPT:[0-9]+]]

0 commit comments

Comments
 (0)