Skip to content

Commit 99dc396

Browse files
[InstCombine] Make fptrunc combine use intersection of fast math flags (#118808)
These combines involve swapping the fptrunc with its operand, and using the intersection of fast math flags is the safest option as e.g. if we have (fptrunc (fneg ninf x)) then (fneg ninf (fptrunc x)) will not be correct as if x is a not within the range of the destination type the result of (fptrunc x) will be inf.
1 parent 76db473 commit 99dc396

File tree

3 files changed

+118
-5
lines changed

3 files changed

+118
-5
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,15 +1847,16 @@ Instruction *InstCombinerImpl::visitFPTrunc(FPTruncInst &FPT) {
18471847
Value *X;
18481848
Instruction *Op = dyn_cast<Instruction>(FPT.getOperand(0));
18491849
if (Op && Op->hasOneUse()) {
1850-
// FIXME: The FMF should propagate from the fptrunc, not the source op.
18511850
IRBuilder<>::FastMathFlagGuard FMFG(Builder);
1852-
if (isa<FPMathOperator>(Op))
1853-
Builder.setFastMathFlags(Op->getFastMathFlags());
1851+
FastMathFlags FMF = FPT.getFastMathFlags();
1852+
if (auto *FPMO = dyn_cast<FPMathOperator>(Op))
1853+
FMF &= FPMO->getFastMathFlags();
1854+
Builder.setFastMathFlags(FMF);
18541855

18551856
if (match(Op, m_FNeg(m_Value(X)))) {
18561857
Value *InnerTrunc = Builder.CreateFPTrunc(X, Ty);
1857-
1858-
return UnaryOperator::CreateFNegFMF(InnerTrunc, Op);
1858+
Value *Neg = Builder.CreateFNeg(InnerTrunc);
1859+
return replaceInstUsesWith(FPT, Neg);
18591860
}
18601861

18611862
// If we are truncating a select that has an extended operand, we can

llvm/test/Transforms/InstCombine/fpcast.ll

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ define half @test3(float %a) {
2929
ret half %c
3030
}
3131

32+
define half @test3_fast(float %a) {
33+
; CHECK-LABEL: @test3_fast(
34+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
35+
; CHECK-NEXT: [[C:%.*]] = call half @llvm.fabs.f16(half [[TMP1]])
36+
; CHECK-NEXT: ret half [[C]]
37+
;
38+
%b = call float @llvm.fabs.f32(float %a)
39+
%c = fptrunc fast float %b to half
40+
ret half %c
41+
}
42+
3243
define half @fneg_fptrunc(float %a) {
3344
; CHECK-LABEL: @fneg_fptrunc(
3445
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
@@ -78,6 +89,28 @@ define half @test4-fast(float %a) {
7889
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast float [[A:%.*]] to half
7990
; CHECK-NEXT: [[C:%.*]] = fneg fast half [[TMP1]]
8091
; CHECK-NEXT: ret half [[C]]
92+
;
93+
%b = fsub fast float -0.0, %a
94+
%c = fptrunc fast float %b to half
95+
ret half %c
96+
}
97+
98+
define half @test4-mixed-fast-1(float %a) {
99+
; CHECK-LABEL: @test4-mixed-fast-1(
100+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
101+
; CHECK-NEXT: [[C:%.*]] = fneg half [[TMP1]]
102+
; CHECK-NEXT: ret half [[C]]
103+
;
104+
%b = fsub float -0.0, %a
105+
%c = fptrunc fast float %b to half
106+
ret half %c
107+
}
108+
109+
define half @test4-mixed-fast-2(float %a) {
110+
; CHECK-LABEL: @test4-mixed-fast-2(
111+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
112+
; CHECK-NEXT: [[C:%.*]] = fneg half [[TMP1]]
113+
; CHECK-NEXT: ret half [[C]]
81114
;
82115
%b = fsub fast float -0.0, %a
83116
%c = fptrunc float %b to half
@@ -89,12 +122,67 @@ define half @test4_unary_fneg-fast(float %a) {
89122
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast float [[A:%.*]] to half
90123
; CHECK-NEXT: [[C:%.*]] = fneg fast half [[TMP1]]
91124
; CHECK-NEXT: ret half [[C]]
125+
;
126+
%b = fneg fast float %a
127+
%c = fptrunc fast float %b to half
128+
ret half %c
129+
}
130+
131+
define half @test4_unary_fneg-mixed-fast-1(float %a) {
132+
; CHECK-LABEL: @test4_unary_fneg-mixed-fast-1(
133+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
134+
; CHECK-NEXT: [[C:%.*]] = fneg half [[TMP1]]
135+
; CHECK-NEXT: ret half [[C]]
136+
;
137+
%b = fneg float %a
138+
%c = fptrunc fast float %b to half
139+
ret half %c
140+
}
141+
142+
define half @test4_unary_fneg-mixed-fast-2(float %a) {
143+
; CHECK-LABEL: @test4_unary_fneg-mixed-fast-2(
144+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[A:%.*]] to half
145+
; CHECK-NEXT: [[C:%.*]] = fneg half [[TMP1]]
146+
; CHECK-NEXT: ret half [[C]]
92147
;
93148
%b = fneg fast float %a
94149
%c = fptrunc float %b to half
95150
ret half %c
96151
}
97152

153+
define <2 x half> @test4_unary_fneg-vec-fast(<2 x float> %a) {
154+
; CHECK-LABEL: @test4_unary_fneg-vec-fast(
155+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast <2 x float> [[A:%.*]] to <2 x half>
156+
; CHECK-NEXT: [[C:%.*]] = fneg fast <2 x half> [[TMP1]]
157+
; CHECK-NEXT: ret <2 x half> [[C]]
158+
;
159+
%b = fneg fast <2 x float> %a
160+
%c = fptrunc fast <2 x float> %b to <2 x half>
161+
ret <2 x half> %c
162+
}
163+
164+
define <2 x half> @test4_unary_fneg-vec-mixed-fast-1(<2 x float> %a) {
165+
; CHECK-LABEL: @test4_unary_fneg-vec-mixed-fast-1(
166+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x float> [[A:%.*]] to <2 x half>
167+
; CHECK-NEXT: [[C:%.*]] = fneg <2 x half> [[TMP1]]
168+
; CHECK-NEXT: ret <2 x half> [[C]]
169+
;
170+
%b = fneg <2 x float> %a
171+
%c = fptrunc fast <2 x float> %b to <2 x half>
172+
ret <2 x half> %c
173+
}
174+
175+
define <2 x half> @test4_unary_fneg-vec-mixed-fast-2(<2 x float> %a) {
176+
; CHECK-LABEL: @test4_unary_fneg-vec-mixed-fast-2(
177+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x float> [[A:%.*]] to <2 x half>
178+
; CHECK-NEXT: [[C:%.*]] = fneg <2 x half> [[TMP1]]
179+
; CHECK-NEXT: ret <2 x half> [[C]]
180+
;
181+
%b = fneg fast <2 x float> %a
182+
%c = fptrunc <2 x float> %b to <2 x half>
183+
ret <2 x half> %c
184+
}
185+
98186
define half @test5(float %a, float %b, float %c) {
99187
; CHECK-LABEL: @test5(
100188
; CHECK-NEXT: [[D:%.*]] = fcmp ogt float [[A:%.*]], [[B:%.*]]

llvm/test/Transforms/InstCombine/fptrunc.ll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ define float @fptrunc_select_true_val(float %x, double %y, i1 %cond) {
6161
ret float %r
6262
}
6363

64+
define float @fptrunc_fast_select_true_val(float %x, double %y, i1 %cond) {
65+
; CHECK-LABEL: @fptrunc_fast_select_true_val(
66+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast double [[Y:%.*]] to float
67+
; CHECK-NEXT: [[NARROW_SEL:%.*]] = select i1 [[COND:%.*]], float [[TMP1]], float [[X:%.*]]
68+
; CHECK-NEXT: ret float [[NARROW_SEL]]
69+
;
70+
%e = fpext float %x to double
71+
%sel = select fast i1 %cond, double %y, double %e
72+
%r = fptrunc fast double %sel to float
73+
ret float %r
74+
}
75+
6476
define <2 x float> @fptrunc_select_false_val(<2 x float> %x, <2 x double> %y, <2 x i1> %cond) {
6577
; CHECK-LABEL: @fptrunc_select_false_val(
6678
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[Y:%.*]] to <2 x float>
@@ -73,6 +85,18 @@ define <2 x float> @fptrunc_select_false_val(<2 x float> %x, <2 x double> %y, <2
7385
ret <2 x float> %r
7486
}
7587

88+
define <2 x float> @fptrunc_nnan_select_false_val(<2 x float> %x, <2 x double> %y, <2 x i1> %cond) {
89+
; CHECK-LABEL: @fptrunc_nnan_select_false_val(
90+
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc nnan <2 x double> [[Y:%.*]] to <2 x float>
91+
; CHECK-NEXT: [[NARROW_SEL:%.*]] = select <2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x float> [[TMP1]]
92+
; CHECK-NEXT: ret <2 x float> [[NARROW_SEL]]
93+
;
94+
%e = fpext <2 x float> %x to <2 x double>
95+
%sel = select nnan <2 x i1> %cond, <2 x double> %e, <2 x double> %y
96+
%r = fptrunc nnan <2 x double> %sel to <2 x float>
97+
ret <2 x float> %r
98+
}
99+
76100
declare void @use(float)
77101

78102
define half @fptrunc_select_true_val_extra_use(half %x, float %y, i1 %cond) {

0 commit comments

Comments
 (0)