Skip to content

Commit 6944648

Browse files
committed
[InstCombine] Transform (fcmp + fadd + sel) into (fcmp + sel + fadd)
Transform `fcmp + fadd + sel` into `fcmp + sel + fadd` which enables the possibility of lowering `fcmp + sel` into `fmax/fmin`.
1 parent 95361cf commit 6944648

File tree

2 files changed

+294
-0
lines changed

2 files changed

+294
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3668,6 +3668,51 @@ static bool hasAffectedValue(Value *V, SmallPtrSetImpl<Value *> &Affected,
36683668
return false;
36693669
}
36703670

3671+
static Value *foldSelectAddConstant(SelectInst &SI,
3672+
InstCombiner::BuilderTy &Builder) {
3673+
Value *Cmp;
3674+
Instruction *FAdd;
3675+
ConstantFP *C;
3676+
3677+
// select((fcmp OGT/OLT, X, 0), (fadd X, C), C) => fadd((select (fcmp OGT/OLT,
3678+
// X, 0), X, 0), C)
3679+
3680+
// This transformation enables the possibility of transforming fcmp + sel into
3681+
// a fmax/fmin.
3682+
3683+
// OneUse check for `Cmp` is necessary because it makes sure that other
3684+
// InstCombine folds don't undo this transformation and cause an infinite
3685+
// loop.
3686+
if (match(&SI, m_Select(m_OneUse(m_Value(Cmp)), m_OneUse(m_Instruction(FAdd)),
3687+
m_ConstantFP(C))) ||
3688+
match(&SI, m_Select(m_OneUse(m_Value(Cmp)), m_ConstantFP(C),
3689+
m_OneUse(m_Instruction(FAdd))))) {
3690+
Value *X;
3691+
CmpInst::Predicate Pred;
3692+
if (!match(Cmp, m_FCmp(Pred, m_Value(X), m_AnyZeroFP())))
3693+
return nullptr;
3694+
3695+
if (Pred != CmpInst::FCMP_OGT && Pred != CmpInst::FCMP_OLT)
3696+
return nullptr;
3697+
3698+
if (!match(FAdd, m_FAdd(m_Specific(X), m_Specific(C))))
3699+
return nullptr;
3700+
3701+
FastMathFlags FMF = FAdd->getFastMathFlags();
3702+
FMF |= SI.getFastMathFlags();
3703+
3704+
Value *NewSelect = Builder.CreateSelect(
3705+
Cmp, X, ConstantFP::getZero(C->getType()), SI.getName() + ".new", &SI);
3706+
cast<Instruction>(NewSelect)->setFastMathFlags(FMF);
3707+
3708+
Value *NewFAdd =
3709+
Builder.CreateFAddFMF(NewSelect, C, FAdd, FAdd->getName() + ".new");
3710+
return NewFAdd;
3711+
}
3712+
3713+
return nullptr;
3714+
}
3715+
36713716
Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
36723717
Value *CondVal = SI.getCondition();
36733718
Value *TrueVal = SI.getTrueValue();
@@ -4067,6 +4112,10 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
40674112
if (Value *V = foldRoundUpIntegerWithPow2Alignment(SI, Builder))
40684113
return replaceInstUsesWith(SI, V);
40694114

4115+
if (Value *V = foldSelectAddConstant(SI, Builder)) {
4116+
return replaceInstUsesWith(SI, V);
4117+
}
4118+
40704119
// select(mask, mload(,,mask,0), 0) -> mload(,,mask,0)
40714120
// Load inst is intentionally not checked for hasOneUse()
40724121
if (match(FalseVal, m_Zero()) &&
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3+
4+
; Check for fcmp + sel pattern which later lowered into fmax
5+
define float @test_fmax_pos1(float %in) {
6+
; CHECK-LABEL: define float @test_fmax_pos1(
7+
; CHECK-SAME: float [[IN:%.*]]) {
8+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
9+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
10+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
11+
; CHECK-NEXT: ret float [[ADD_NEW]]
12+
;
13+
%cmp1 = fcmp ogt float %in, 0.000000e+00
14+
%add = fadd float %in, 1.000000e+00
15+
%sel = select i1 %cmp1, float %add, float 1.000000e+00
16+
ret float %sel
17+
}
18+
19+
define float @test_fmax_pos2(float %in) {
20+
; CHECK-LABEL: define float @test_fmax_pos2(
21+
; CHECK-SAME: float [[IN:%.*]]) {
22+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
23+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
24+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
25+
; CHECK-NEXT: ret float [[ADD_NEW]]
26+
;
27+
%cmp1 = fcmp ogt float %in, 0.000000e+00
28+
%add = fadd float %in, 1.000000e+00
29+
%sel = select i1 %cmp1, float 1.000000e+00, float %add
30+
ret float %sel
31+
}
32+
33+
define float @test_fmax_pos3(float %in) {
34+
; CHECK-LABEL: define float @test_fmax_pos3(
35+
; CHECK-SAME: float [[IN:%.*]]) {
36+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
37+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
38+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
39+
; CHECK-NEXT: ret float [[ADD_NEW]]
40+
;
41+
%cmp1 = fcmp ogt float %in, 0.000000e+00
42+
%add = fadd float 1.000000e+00, %in
43+
%sel = select i1 %cmp1, float %add, float 1.000000e+00
44+
ret float %sel
45+
}
46+
47+
define float @test_fmax_pos4(float %in) {
48+
; CHECK-LABEL: define float @test_fmax_pos4(
49+
; CHECK-SAME: float [[IN:%.*]]) {
50+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
51+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
52+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
53+
; CHECK-NEXT: ret float [[ADD_NEW]]
54+
;
55+
%cmp1 = fcmp ogt float %in, 0.000000e+00
56+
%add = fadd float 1.000000e+00, %in
57+
%sel = select i1 %cmp1, float 1.000000e+00, float %add
58+
ret float %sel
59+
}
60+
61+
define float @test_fmax_pos5(float %in) {
62+
; CHECK-LABEL: define float @test_fmax_pos5(
63+
; CHECK-SAME: float [[IN:%.*]]) {
64+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
65+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
66+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 2.000000e+00
67+
; CHECK-NEXT: ret float [[ADD_NEW]]
68+
;
69+
%cmp1 = fcmp ogt float %in, 0.000000e+00
70+
%add = fadd float 2.000000e+00, %in
71+
%sel = select i1 %cmp1, float 2.000000e+00, float %add
72+
ret float %sel
73+
}
74+
75+
76+
; Check for fcmp + sel pattern which later lowered into fmin
77+
define float @test_fmin_pos1(float %in) {
78+
; CHECK-LABEL: define float @test_fmin_pos1(
79+
; CHECK-SAME: float [[IN:%.*]]) {
80+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
81+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
82+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
83+
; CHECK-NEXT: ret float [[ADD_NEW]]
84+
;
85+
%cmp1 = fcmp olt float %in, 0.000000e+00
86+
%add = fadd float %in, 1.000000e+00
87+
%sel = select i1 %cmp1, float %add, float 1.000000e+00
88+
ret float %sel
89+
}
90+
91+
define float @test_fmin_pos2(float %in) {
92+
; CHECK-LABEL: define float @test_fmin_pos2(
93+
; CHECK-SAME: float [[IN:%.*]]) {
94+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
95+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
96+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
97+
; CHECK-NEXT: ret float [[ADD_NEW]]
98+
;
99+
%cmp1 = fcmp olt float %in, 0.000000e+00
100+
%add = fadd float %in, 1.000000e+00
101+
%sel = select i1 %cmp1, float 1.000000e+00, float %add
102+
ret float %sel
103+
}
104+
105+
define float @test_fmin_pos3(float %in) {
106+
; CHECK-LABEL: define float @test_fmin_pos3(
107+
; CHECK-SAME: float [[IN:%.*]]) {
108+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
109+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
110+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
111+
; CHECK-NEXT: ret float [[ADD_NEW]]
112+
;
113+
%cmp1 = fcmp olt float %in, 0.000000e+00
114+
%add = fadd float 1.000000e+00, %in
115+
%sel = select i1 %cmp1, float %add, float 1.000000e+00
116+
ret float %sel
117+
}
118+
119+
define float @test_fmin_pos4(float %in) {
120+
; CHECK-LABEL: define float @test_fmin_pos4(
121+
; CHECK-SAME: float [[IN:%.*]]) {
122+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
123+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
124+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
125+
; CHECK-NEXT: ret float [[ADD_NEW]]
126+
;
127+
%cmp1 = fcmp olt float %in, 0.000000e+00
128+
%add = fadd float 1.000000e+00, %in
129+
%sel = select i1 %cmp1, float 1.000000e+00, float %add
130+
ret float %sel
131+
}
132+
133+
define float @test_fmin_pos5(float %in) {
134+
; CHECK-LABEL: define float @test_fmin_pos5(
135+
; CHECK-SAME: float [[IN:%.*]]) {
136+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
137+
; CHECK-NEXT: [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
138+
; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 2.000000e+00
139+
; CHECK-NEXT: ret float [[ADD_NEW]]
140+
;
141+
%cmp1 = fcmp olt float %in, 0.000000e+00
142+
%add = fadd float 2.000000e+00, %in
143+
%sel = select i1 %cmp1, float 2.000000e+00, float %add
144+
ret float %sel
145+
}
146+
147+
148+
; Check for fmax scenarios that shouldn't be transformed.
149+
define float @test_fmax_neg1(float %in, float %in2) {
150+
; CHECK-LABEL: define float @test_fmax_neg1(
151+
; CHECK-SAME: float [[IN:%.*]], float [[IN2:%.*]]) {
152+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[IN2]], 0.000000e+00
153+
; CHECK-NEXT: [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
154+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
155+
; CHECK-NEXT: ret float [[SEL]]
156+
;
157+
%cmp1 = fcmp ogt float %in2, 0.000000e+00
158+
%add = fadd float %in, 1.000000e+00
159+
%sel = select i1 %cmp1, float %add, float 1.000000e+00
160+
ret float %sel
161+
}
162+
163+
define float @test_fmax_neg2(float %in) {
164+
; CHECK-LABEL: define float @test_fmax_neg2(
165+
; CHECK-SAME: float [[IN:%.*]]) {
166+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[IN]], 1.000000e+00
167+
; CHECK-NEXT: [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
168+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
169+
; CHECK-NEXT: ret float [[SEL]]
170+
;
171+
%cmp1 = fcmp ogt float %in, 1.000000e+00
172+
%add = fadd float %in, 1.000000e+00
173+
%sel = select i1 %cmp1, float %add, float 1.000000e+00
174+
ret float %sel
175+
}
176+
177+
define float @test_fmax_neg3(float %in) {
178+
; CHECK-LABEL: define float @test_fmax_neg3(
179+
; CHECK-SAME: float [[IN:%.*]]) {
180+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
181+
; CHECK-NEXT: [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
182+
; CHECK-NEXT: [[ADD_2:%.*]] = fadd float [[IN]], 1.000000e+00
183+
; CHECK-NEXT: [[SEL_1:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
184+
; CHECK-NEXT: [[SEL_2:%.*]] = select i1 [[CMP1]], float 2.000000e+00, float [[ADD_2]]
185+
; CHECK-NEXT: [[RES:%.*]] = fadd float [[SEL_1]], [[SEL_2]]
186+
; CHECK-NEXT: ret float [[RES]]
187+
;
188+
%cmp1 = fcmp ogt float %in, 0.000000e+00
189+
%add = fadd float %in, 1.000000e+00
190+
%add.2 = fadd float %in, 1.000000e+00
191+
%sel.1 = select i1 %cmp1, float %add, float 1.000000e+00
192+
%sel.2 = select i1 %cmp1, float 2.000000e+00, float %add.2
193+
%res = fadd float %sel.1, %sel.2
194+
ret float %res
195+
}
196+
197+
198+
; Check for fmin scenarios that shouldn't be transformed.
199+
define float @test_fmin_neg1(float %in, float %in2) {
200+
; CHECK-LABEL: define float @test_fmin_neg1(
201+
; CHECK-SAME: float [[IN:%.*]], float [[IN2:%.*]]) {
202+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[IN2]], 0.000000e+00
203+
; CHECK-NEXT: [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
204+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
205+
; CHECK-NEXT: ret float [[SEL]]
206+
;
207+
%cmp1 = fcmp olt float %in2, 0.000000e+00
208+
%add = fadd float %in, 1.000000e+00
209+
%sel = select i1 %cmp1, float %add, float 1.000000e+00
210+
ret float %sel
211+
}
212+
213+
define float @test_fmin_neg2(float %in) {
214+
; CHECK-LABEL: define float @test_fmin_neg2(
215+
; CHECK-SAME: float [[IN:%.*]]) {
216+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[IN]], 1.000000e+00
217+
; CHECK-NEXT: [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
218+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
219+
; CHECK-NEXT: ret float [[SEL]]
220+
;
221+
%cmp1 = fcmp olt float %in, 1.000000e+00
222+
%add = fadd float %in, 1.000000e+00
223+
%sel = select i1 %cmp1, float %add, float 1.000000e+00
224+
ret float %sel
225+
}
226+
227+
define float @test_fmin_neg3(float %in) {
228+
; CHECK-LABEL: define float @test_fmin_neg3(
229+
; CHECK-SAME: float [[IN:%.*]]) {
230+
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
231+
; CHECK-NEXT: [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
232+
; CHECK-NEXT: [[ADD_2:%.*]] = fadd float [[IN]], 1.000000e+00
233+
; CHECK-NEXT: [[SEL_1:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
234+
; CHECK-NEXT: [[SEL_2:%.*]] = select i1 [[CMP1]], float 2.000000e+00, float [[ADD_2]]
235+
; CHECK-NEXT: [[RES:%.*]] = fadd float [[SEL_1]], [[SEL_2]]
236+
; CHECK-NEXT: ret float [[RES]]
237+
;
238+
%cmp1 = fcmp olt float %in, 0.000000e+00
239+
%add = fadd float %in, 1.000000e+00
240+
%add.2 = fadd float %in, 1.000000e+00
241+
%sel.1 = select i1 %cmp1, float %add, float 1.000000e+00
242+
%sel.2 = select i1 %cmp1, float 2.000000e+00, float %add.2
243+
%res = fadd float %sel.1, %sel.2
244+
ret float %res
245+
}

0 commit comments

Comments
 (0)