Skip to content

Commit 1f1fd07

Browse files
bababuckRyan Buchnerdtcxzyw
authored
[InstCombine] Optimize (select %x, op(%x), 0) to op(%x) for operations where op(0) == 0 (#147605)
Currently this optimization only occurs for `mul`, but this generalizes that for any operation that has a fixed point of `0`. There is similar logic within `EarlyCSE` pass, but that is stricter in terms of `poison` propagation so will not optimize for many operations. Alive2 Proofs: `and`: https://alive2.llvm.org/ce/z/RraasX ; base-case https://alive2.llvm.org/ce/z/gzfFTX ; commuted-case https://alive2.llvm.org/ce/z/63XaoX ; compare against undef https://alive2.llvm.org/ce/z/MVRVNd ; select undef https://alive2.llvm.org/ce/z/2bsoYG ; vector https://alive2.llvm.org/ce/z/xByeX- ; vector compare against undef https://alive2.llvm.org/ce/z/zNdzmZ ; vector select undef `fshl`: https://alive2.llvm.org/ce/z/U3_PG3 ; base-case https://alive2.llvm.org/ce/z/BWCnxT ; compare against undef https://alive2.llvm.org/ce/z/8HGAE_ ; select undef ; vector times out `fshr`: https://alive2.llvm.org/ce/z/o6F47G ; base-case https://alive2.llvm.org/ce/z/fVnBXy ; compare against undef https://alive2.llvm.org/ce/z/suymYJ ; select undef ; vector times out `umin`: https://alive2.llvm.org/ce/z/GGMqf6 ; base-case https://alive2.llvm.org/ce/z/6cx5-k ; commuted-case https://alive2.llvm.org/ce/z/W5d9tz ; compare against undef https://alive2.llvm.org/ce/z/nKbaUn ; select undef https://alive2.llvm.org/ce/z/gxEGqc ; vector https://alive2.llvm.org/ce/z/_SDpi_ ; vector compare against undef `sdiv`: https://alive2.llvm.org/ce/z/5XGs3q `srem`: https://alive2.llvm.org/ce/z/vXAnQM `udiv`: https://alive2.llvm.org/ce/z/e6_8Ug `urem`: https://alive2.llvm.org/ce/z/VmM2SL `shl`: https://alive2.llvm.org/ce/z/aCZr3u ; Argument with range https://alive2.llvm.org/ce/z/YgDy8C ; Instruction with known bits https://alive2.llvm.org/ce/z/6pIxR6 ; Constant `lshr`: https://alive2.llvm.org/ce/z/WCCBej `ashr: https://alive2.llvm.org/ce/z/egV4TR --------- Co-authored-by: Ryan Buchner <[email protected]> Co-authored-by: Yingwei Zheng <[email protected]>
1 parent 34b3ea3 commit 1f1fd07

File tree

4 files changed

+258
-16
lines changed

4 files changed

+258
-16
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,11 @@ static Instruction *foldSetClearBits(SelectInst &Sel,
878878
// is a vector consisting of 0 and undefs. If a constant compared with x
879879
// is a scalar undefined value or undefined vector then an expression
880880
// should be already folded into a constant.
881-
static Instruction *foldSelectZeroOrMul(SelectInst &SI, InstCombinerImpl &IC) {
881+
//
882+
// This also holds all operations such that Op(0) == 0
883+
// e.g. Shl, Umin, etc
884+
static Instruction *foldSelectZeroOrFixedOp(SelectInst &SI,
885+
InstCombinerImpl &IC) {
882886
auto *CondVal = SI.getCondition();
883887
auto *TrueVal = SI.getTrueValue();
884888
auto *FalseVal = SI.getFalseValue();
@@ -900,10 +904,23 @@ static Instruction *foldSelectZeroOrMul(SelectInst &SI, InstCombinerImpl &IC) {
900904
// non-zero elements that are masked by undef elements in the compare
901905
// constant.
902906
auto *TrueValC = dyn_cast<Constant>(TrueVal);
903-
if (TrueValC == nullptr ||
904-
!match(FalseVal, m_c_Mul(m_Specific(X), m_Value(Y))) ||
905-
!isa<Instruction>(FalseVal))
907+
if (TrueValC == nullptr || !isa<Instruction>(FalseVal))
908+
return nullptr;
909+
910+
bool FreezeY;
911+
if (match(FalseVal, m_c_Mul(m_Specific(X), m_Value(Y))) ||
912+
match(FalseVal, m_c_And(m_Specific(X), m_Value(Y))) ||
913+
match(FalseVal, m_FShl(m_Specific(X), m_Specific(X), m_Value(Y))) ||
914+
match(FalseVal, m_FShr(m_Specific(X), m_Specific(X), m_Value(Y))) ||
915+
match(FalseVal,
916+
m_c_Intrinsic<Intrinsic::umin>(m_Specific(X), m_Value(Y)))) {
917+
FreezeY = true;
918+
} else if (match(FalseVal, m_IDiv(m_Specific(X), m_Value(Y))) ||
919+
match(FalseVal, m_IRem(m_Specific(X), m_Value(Y)))) {
920+
FreezeY = false;
921+
} else {
906922
return nullptr;
923+
}
907924

908925
auto *ZeroC = cast<Constant>(cast<Instruction>(CondVal)->getOperand(1));
909926
auto *MergedC = Constant::mergeUndefsWith(TrueValC, ZeroC);
@@ -914,9 +931,15 @@ static Instruction *foldSelectZeroOrMul(SelectInst &SI, InstCombinerImpl &IC) {
914931
return nullptr;
915932

916933
auto *FalseValI = cast<Instruction>(FalseVal);
917-
auto *FrY = IC.InsertNewInstBefore(new FreezeInst(Y, Y->getName() + ".fr"),
918-
FalseValI->getIterator());
919-
IC.replaceOperand(*FalseValI, FalseValI->getOperand(0) == Y ? 0 : 1, FrY);
934+
if (FreezeY) {
935+
auto *FrY = IC.InsertNewInstBefore(new FreezeInst(Y, Y->getName() + ".fr"),
936+
FalseValI->getIterator());
937+
IC.replaceOperand(*FalseValI,
938+
FalseValI->getOperand(0) == Y
939+
? 0
940+
: (FalseValI->getOperand(1) == Y ? 1 : 2),
941+
FrY);
942+
}
920943
return IC.replaceInstUsesWith(SI, FalseValI);
921944
}
922945

@@ -4104,7 +4127,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
41044127
return Add;
41054128
if (Instruction *Or = foldSetClearBits(SI, Builder))
41064129
return Or;
4107-
if (Instruction *Mul = foldSelectZeroOrMul(SI, *this))
4130+
if (Instruction *Mul = foldSelectZeroOrFixedOp(SI, *this))
41084131
return Mul;
41094132

41104133
// Turn (select C, (op X, Y), (op X, Z)) -> (op X, (select C, Y, Z))

llvm/test/Transforms/InstCombine/icmp-select.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,9 @@ define i1 @icmp_select_implied_cond_relational_off_by_one(i8 %x, i8 %y) {
248248

249249
define i1 @umin_seq_comparison(i8 %x, i8 %y) {
250250
; CHECK-LABEL: @umin_seq_comparison(
251-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
252-
; CHECK-NEXT: [[CMP21:%.*]] = icmp ule i8 [[X]], [[Y:%.*]]
253-
; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
254-
; CHECK-NEXT: ret i1 [[CMP2]]
251+
; CHECK-NEXT: [[Y:%.*]] = freeze i8 [[Y1:%.*]]
252+
; CHECK-NEXT: [[CMP21:%.*]] = icmp ule i8 [[X:%.*]], [[Y]]
253+
; CHECK-NEXT: ret i1 [[CMP21]]
255254
;
256255
%min = call i8 @llvm.umin.i8(i8 %x, i8 %y)
257256
%cmp1 = icmp eq i8 %x, 0
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
3+
4+
; (select (icmp x, 0, eq), 0, (umin x, y)) -> (umin x, y)
5+
define i64 @umin_select(i64 %a, i64 %b) {
6+
; CHECK-LABEL: @umin_select(
7+
; CHECK-NEXT: [[B_FR:%.*]] = freeze i64 [[B:%.*]]
8+
; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[A:%.*]], i64 [[B_FR]])
9+
; CHECK-NEXT: ret i64 [[UMIN]]
10+
;
11+
%cond = icmp eq i64 %a, 0
12+
%umin = call i64 @llvm.umin.i64(i64 %a, i64 %b)
13+
%select = select i1 %cond, i64 0, i64 %umin
14+
ret i64 %select
15+
}
16+
17+
; (select (icmp x, 0, eq), 0, (mul x, y)) -> (mul x, y)
18+
define i64 @mul_select(i64 %a, i64 %b) {
19+
; CHECK-LABEL: @mul_select(
20+
; CHECK-NEXT: [[B_FR:%.*]] = freeze i64 [[B:%.*]]
21+
; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B_FR]]
22+
; CHECK-NEXT: ret i64 [[MUL]]
23+
;
24+
%cond = icmp eq i64 %a, 0
25+
%mul = mul i64 %a, %b
26+
%select = select i1 %cond, i64 0, i64 %mul
27+
ret i64 %select
28+
}
29+
30+
; (select (icmp x, 0, eq), 0, (mul x, y)) -> (mul x, y)
31+
define i64 @mul_select_comm(i64 %a, i64 %b) {
32+
; CHECK-LABEL: @mul_select_comm(
33+
; CHECK-NEXT: [[B_FR:%.*]] = freeze i64 [[B:%.*]]
34+
; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[B_FR]], [[A:%.*]]
35+
; CHECK-NEXT: ret i64 [[MUL]]
36+
;
37+
%cond = icmp eq i64 %a, 0
38+
%mul = mul i64 %b, %a
39+
%select = select i1 %cond, i64 0, i64 %mul
40+
ret i64 %select
41+
}
42+
43+
; (select (icmp x, 0, eq), 0, (shl x, y)) -> (shl x, y)
44+
define i64 @shl_select(i64 %a, i64 %b) {
45+
; CHECK-LABEL: @shl_select(
46+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[A:%.*]], 0
47+
; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[A]], [[B_FR:%.*]]
48+
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i64 0, i64 [[SHL]]
49+
; CHECK-NEXT: ret i64 [[SELECT]]
50+
;
51+
%cond = icmp eq i64 %a, 0
52+
%shl = shl i64 %a, %b
53+
%select = select i1 %cond, i64 0, i64 %shl
54+
ret i64 %select
55+
}
56+
57+
; (select (icmp x, 0, eq), 0, (and x, y)) -> (and x, y)
58+
define i64 @and_select(i64 %a, i64 %b) {
59+
; CHECK-LABEL: @and_select(
60+
; CHECK-NEXT: [[B_FR:%.*]] = freeze i64 [[B:%.*]]
61+
; CHECK-NEXT: [[AND:%.*]] = and i64 [[A:%.*]], [[B_FR]]
62+
; CHECK-NEXT: ret i64 [[AND]]
63+
;
64+
%cond = icmp eq i64 %a, 0
65+
%and = and i64 %a, %b
66+
%select = select i1 %cond, i64 0, i64 %and
67+
ret i64 %select
68+
}
69+
70+
; (select (icmp x, 0, eq), 0, (and x, y)) -> (and x, y)
71+
define i64 @and_select_comm(i64 %a, i64 %b) {
72+
; CHECK-LABEL: @and_select_comm(
73+
; CHECK-NEXT: [[B_FR:%.*]] = freeze i64 [[B:%.*]]
74+
; CHECK-NEXT: [[AND:%.*]] = and i64 [[B_FR]], [[A:%.*]]
75+
; CHECK-NEXT: ret i64 [[AND]]
76+
;
77+
%cond = icmp eq i64 %a, 0
78+
%and = and i64 %b, %a
79+
%select = select i1 %cond, i64 0, i64 %and
80+
ret i64 %select
81+
}
82+
83+
; (select (icmp x, 0, ne), (ashr x, y), 0) -> (ashr x, y)
84+
define i64 @ashr_select(i64 %a, i64 %b) {
85+
; CHECK-LABEL: @ashr_select(
86+
; CHECK-NEXT: [[COND_NOT:%.*]] = icmp eq i64 [[A:%.*]], 0
87+
; CHECK-NEXT: [[ASHR:%.*]] = ashr i64 [[A]], [[B_FR:%.*]]
88+
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND_NOT]], i64 0, i64 [[ASHR]]
89+
; CHECK-NEXT: ret i64 [[SELECT]]
90+
;
91+
%cond = icmp ne i64 0, %a
92+
%ashr = ashr i64 %a, %b
93+
%select = select i1 %cond, i64 %ashr, i64 0
94+
ret i64 %select
95+
}
96+
97+
; (select (icmp x, 0, ne), (lshr x, y), 0) -> (lshr x, y)
98+
define i64 @lshr_select(i64 %a, i64 %b) {
99+
; CHECK-LABEL: @lshr_select(
100+
; CHECK-NEXT: [[COND_NOT:%.*]] = icmp eq i64 [[A:%.*]], 0
101+
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[A]], [[B_FR:%.*]]
102+
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND_NOT]], i64 0, i64 [[LSHR]]
103+
; CHECK-NEXT: ret i64 [[SELECT]]
104+
;
105+
%cond = icmp ne i64 0, %a
106+
%lshr = lshr i64 %a, %b
107+
%select = select i1 %cond, i64 %lshr, i64 0
108+
ret i64 %select
109+
}
110+
111+
; (select (icmp x, 0, eq), 0, fshr(x, x, y)) -> fshr(x, x, y)
112+
define i64 @fshr_select(i64 %a, i64 %b) {
113+
; CHECK-LABEL: @fshr_select(
114+
; CHECK-NEXT: [[B_FR:%.*]] = freeze i64 [[B:%.*]]
115+
; CHECK-NEXT: [[FSHR:%.*]] = call i64 @llvm.fshr.i64(i64 [[A:%.*]], i64 [[A]], i64 [[B_FR]])
116+
; CHECK-NEXT: ret i64 [[FSHR]]
117+
;
118+
%cond = icmp eq i64 %a, 0
119+
%fshr = call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 %b)
120+
%select = select i1 %cond, i64 0, i64 %fshr
121+
ret i64 %select
122+
}
123+
124+
; (select (icmp x, 0, eq), 0, (fshl x, x, y)) -> (fshl x, x, y)
125+
define i64 @fshl_select(i64 %a, i64 %b) {
126+
; CHECK-LABEL: @fshl_select(
127+
; CHECK-NEXT: [[B_FR:%.*]] = freeze i64 [[B:%.*]]
128+
; CHECK-NEXT: [[FSHL:%.*]] = call i64 @llvm.fshl.i64(i64 [[A:%.*]], i64 [[A]], i64 [[B_FR]])
129+
; CHECK-NEXT: ret i64 [[FSHL]]
130+
;
131+
%cond = icmp eq i64 %a, 0
132+
%fshl = call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 %b)
133+
%select = select i1 %cond, i64 0, i64 %fshl
134+
ret i64 %select
135+
}
136+
137+
; (select (icmp x, 0, eq), 0, (fshr x, z, y)) -> leave as is
138+
define i64 @fshr_select_no_combine(i64 %a, i64 %b, i64 %c) {
139+
; CHECK-LABEL: @fshr_select_no_combine(
140+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[A:%.*]], 0
141+
; CHECK-NEXT: [[FSHR:%.*]] = call i64 @llvm.fshr.i64(i64 [[A]], i64 [[B:%.*]], i64 [[C:%.*]])
142+
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i64 0, i64 [[FSHR]]
143+
; CHECK-NEXT: ret i64 [[SELECT]]
144+
;
145+
%cond = icmp eq i64 %a, 0
146+
%fshr = call i64 @llvm.fshr.i64(i64 %a, i64 %b, i64 %c)
147+
%select = select i1 %cond, i64 0, i64 %fshr
148+
ret i64 %select
149+
}
150+
151+
; (select (icmp x, 0, eq), 0, (sdiv x, y)) -> (sdiv x, y)
152+
define i64 @sdiv_select(i64 %a, i64 %b) {
153+
; CHECK-LABEL: @sdiv_select(
154+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 [[A:%.*]], [[B_FR:%.*]]
155+
; CHECK-NEXT: ret i64 [[DIV]]
156+
;
157+
%cond = icmp eq i64 %a, 0
158+
%div = sdiv i64 %a, %b
159+
%select = select i1 %cond, i64 0, i64 %div
160+
ret i64 %select
161+
}
162+
163+
; (select (icmp x, 0, eq), 0, (udiv x, y)) -> (udiv x, y)
164+
define i64 @udiv_select(i64 %a, i64 %b) {
165+
; CHECK-LABEL: @udiv_select(
166+
; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A:%.*]], [[B_FR:%.*]]
167+
; CHECK-NEXT: ret i64 [[DIV]]
168+
;
169+
%cond = icmp eq i64 %a, 0
170+
%div = udiv i64 %a, %b
171+
%select = select i1 %cond, i64 0, i64 %div
172+
ret i64 %select
173+
}
174+
175+
; (select (icmp x, 0, eq), 0, (srem x, y)) -> (srem x, y)
176+
define i64 @srem_select(i64 %a, i64 %b) {
177+
; CHECK-LABEL: @srem_select(
178+
; CHECK-NEXT: [[REM:%.*]] = srem i64 [[A:%.*]], [[B:%.*]]
179+
; CHECK-NEXT: ret i64 [[REM]]
180+
;
181+
%cond = icmp eq i64 %a, 0
182+
%rem = srem i64 %a, %b
183+
%select = select i1 %cond, i64 0, i64 %rem
184+
ret i64 %select
185+
}
186+
187+
; (select (icmp x, 0, eq), 0, (urem x, y)) -> (urem x, y)
188+
define i64 @urem_select(i64 %a, i64 %b) {
189+
; CHECK-LABEL: @urem_select(
190+
; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]]
191+
; CHECK-NEXT: ret i64 [[REM]]
192+
;
193+
%cond = icmp eq i64 %a, 0
194+
%rem = urem i64 %a, %b
195+
%select = select i1 %cond, i64 0, i64 %rem
196+
ret i64 %select
197+
}
198+
199+
; (select (icmp x, 0, eq), 0, (icmp x, 0, slt)) -> (icmp x, 0, slt)
200+
define i1 @icmp_slt_select(i64 %a) {
201+
; CHECK-LABEL: @icmp_slt_select(
202+
; CHECK-NEXT: [[ICMP:%.*]] = icmp slt i64 [[A:%.*]], 0
203+
; CHECK-NEXT: ret i1 [[ICMP]]
204+
;
205+
%cond = icmp eq i64 %a, 0
206+
%icmp = icmp slt i64 %a, 0
207+
%select = select i1 %cond, i1 0, i1 %icmp
208+
ret i1 %select
209+
}
210+
211+
; (select (icmp x, 0, eq), 0, (sub 0, x)) -> (sub 0, x)
212+
define i64 @sub_select(i64 %a) {
213+
; CHECK-LABEL: @sub_select(
214+
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[A:%.*]]
215+
; CHECK-NEXT: ret i64 [[SUB]]
216+
;
217+
%cond = icmp eq i64 %a, 0
218+
%sub = sub i64 0, %a
219+
%select = select i1 %cond, i64 0, i64 %sub
220+
ret i64 %select
221+
}

llvm/test/Transforms/InstCombine/select.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -893,10 +893,9 @@ define i32 @test56(i16 %x) {
893893

894894
define i32 @test57(i32 %x, i32 %y) {
895895
; CHECK-LABEL: @test57(
896-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
897-
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X]], 0
898-
; CHECK-NEXT: [[DOTAND:%.*]] = select i1 [[TOBOOL]], i32 0, i32 [[AND]]
899-
; CHECK-NEXT: ret i32 [[DOTAND]]
896+
; CHECK-NEXT: [[Y:%.*]] = freeze i32 [[Y1:%.*]]
897+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y]]
898+
; CHECK-NEXT: ret i32 [[AND]]
900899
;
901900
%and = and i32 %x, %y
902901
%tobool = icmp eq i32 %x, 0

0 commit comments

Comments
 (0)