xref: /llvm-project/llvm/test/Transforms/InstCombine/select-divrem.ll (revision 231d113c7e172a59ec02d33a248d7b44109245d6)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4; It is a miscompile in most of these tests if we
5; execute div/rem without freezing the potentially
6; poison condition value.
7
8define i5 @sdiv_common_divisor(i1 %b, i5 %x, i5 %y, i5 %z) {
9; CHECK-LABEL: @sdiv_common_divisor(
10; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[B:%.*]]
11; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
12; CHECK-NEXT:    [[SEL:%.*]] = sdiv i5 [[SEL_V]], [[X:%.*]]
13; CHECK-NEXT:    ret i5 [[SEL]]
14;
15  %r1 = sdiv i5 %y, %x
16  %r2 = sdiv i5 %z, %x
17  %sel = select i1 %b, i5 %r2, i5 %r1
18  ret i5 %sel
19}
20
21define i5 @srem_common_divisor(i1 %b, i5 %x, i5 %y, i5 %z) {
22; CHECK-LABEL: @srem_common_divisor(
23; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[B:%.*]]
24; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
25; CHECK-NEXT:    [[SEL:%.*]] = srem i5 [[SEL_V]], [[X:%.*]]
26; CHECK-NEXT:    ret i5 [[SEL]]
27;
28  %r1 = srem i5 %y, %x
29  %r2 = srem i5 %z, %x
30  %sel = select i1 %b, i5 %r2, i5 %r1
31  ret i5 %sel
32}
33
34; This is ok without freeze because UB can only happen with x==0,
35; and that occurs in the original code.
36
37define i5 @udiv_common_divisor(i1 %b, i5 %x, i5 %y, i5 %z) {
38; CHECK-LABEL: @udiv_common_divisor(
39; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
40; CHECK-NEXT:    [[SEL:%.*]] = udiv i5 [[SEL_V]], [[X:%.*]]
41; CHECK-NEXT:    ret i5 [[SEL]]
42;
43  %r1 = udiv i5 %y, %x
44  %r2 = udiv i5 %z, %x
45  %sel = select i1 %b, i5 %r2, i5 %r1
46  ret i5 %sel
47}
48
49; This is ok without freeze because UB can only happen with x==0,
50; and that occurs in the original code.
51
52define i5 @urem_common_divisor(i1 %b, i5 %x, i5 %y, i5 %z) {
53; CHECK-LABEL: @urem_common_divisor(
54; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
55; CHECK-NEXT:    [[SEL:%.*]] = urem i5 [[SEL_V]], [[X:%.*]]
56; CHECK-NEXT:    ret i5 [[SEL]]
57;
58  %r1 = urem i5 %y, %x
59  %r2 = urem i5 %z, %x
60  %sel = select i1 %b, i5 %r2, i5 %r1
61  ret i5 %sel
62}
63
64define i5 @sdiv_common_dividend(i1 %b, i5 %x, i5 %y, i5 %z) {
65; CHECK-LABEL: @sdiv_common_dividend(
66; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[B:%.*]]
67; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
68; CHECK-NEXT:    [[SEL:%.*]] = sdiv i5 [[X:%.*]], [[SEL_V]]
69; CHECK-NEXT:    ret i5 [[SEL]]
70;
71  %r1 = sdiv i5 %x, %y
72  %r2 = sdiv i5 %x, %z
73  %sel = select i1 %b, i5 %r2, i5 %r1
74  ret i5 %sel
75}
76
77define i5 @srem_common_dividend(i1 %b, i5 %x, i5 %y, i5 %z) {
78; CHECK-LABEL: @srem_common_dividend(
79; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[B:%.*]]
80; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
81; CHECK-NEXT:    [[SEL:%.*]] = srem i5 [[X:%.*]], [[SEL_V]]
82; CHECK-NEXT:    ret i5 [[SEL]]
83;
84  %r1 = srem i5 %x, %y
85  %r2 = srem i5 %x, %z
86  %sel = select i1 %b, i5 %r2, i5 %r1
87  ret i5 %sel
88}
89
90define i5 @udiv_common_dividend(i1 %b, i5 %x, i5 %y, i5 %z) {
91; CHECK-LABEL: @udiv_common_dividend(
92; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[B:%.*]]
93; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
94; CHECK-NEXT:    [[SEL:%.*]] = udiv i5 [[X:%.*]], [[SEL_V]]
95; CHECK-NEXT:    ret i5 [[SEL]]
96;
97  %r1 = udiv i5 %x, %y
98  %r2 = udiv i5 %x, %z
99  %sel = select i1 %b, i5 %r2, i5 %r1
100  ret i5 %sel
101}
102
103define i5 @urem_common_dividend(i1 %b, i5 %x, i5 %y, i5 %z) {
104; CHECK-LABEL: @urem_common_dividend(
105; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[B:%.*]]
106; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
107; CHECK-NEXT:    [[SEL:%.*]] = urem i5 [[X:%.*]], [[SEL_V]]
108; CHECK-NEXT:    ret i5 [[SEL]]
109;
110  %r1 = urem i5 %x, %y
111  %r2 = urem i5 %x, %z
112  %sel = select i1 %b, i5 %r2, i5 %r1
113  ret i5 %sel
114}
115
116; Repeat the above tests, but guarantee that the select
117; condition is not poison via argument attribute. That
118; makes it safe to execute the select before div/rem
119; without needing to freeze the condition.
120
121define i5 @sdiv_common_divisor_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
122; CHECK-LABEL: @sdiv_common_divisor_defined_cond(
123; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
124; CHECK-NEXT:    [[SEL:%.*]] = sdiv i5 [[SEL_V]], [[X:%.*]]
125; CHECK-NEXT:    ret i5 [[SEL]]
126;
127  %r1 = sdiv i5 %y, %x
128  %r2 = sdiv i5 %z, %x
129  %sel = select i1 %b, i5 %r2, i5 %r1
130  ret i5 %sel
131}
132
133define i5 @srem_common_divisor_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
134; CHECK-LABEL: @srem_common_divisor_defined_cond(
135; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
136; CHECK-NEXT:    [[SEL:%.*]] = srem i5 [[SEL_V]], [[X:%.*]]
137; CHECK-NEXT:    ret i5 [[SEL]]
138;
139  %r1 = srem i5 %y, %x
140  %r2 = srem i5 %z, %x
141  %sel = select i1 %b, i5 %r2, i5 %r1
142  ret i5 %sel
143}
144
145define i5 @udiv_common_divisor_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
146; CHECK-LABEL: @udiv_common_divisor_defined_cond(
147; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
148; CHECK-NEXT:    [[SEL:%.*]] = udiv i5 [[SEL_V]], [[X:%.*]]
149; CHECK-NEXT:    ret i5 [[SEL]]
150;
151  %r1 = udiv i5 %y, %x
152  %r2 = udiv i5 %z, %x
153  %sel = select i1 %b, i5 %r2, i5 %r1
154  ret i5 %sel
155}
156
157define i5 @urem_common_divisor_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
158; CHECK-LABEL: @urem_common_divisor_defined_cond(
159; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
160; CHECK-NEXT:    [[SEL:%.*]] = urem i5 [[SEL_V]], [[X:%.*]]
161; CHECK-NEXT:    ret i5 [[SEL]]
162;
163  %r1 = urem i5 %y, %x
164  %r2 = urem i5 %z, %x
165  %sel = select i1 %b, i5 %r2, i5 %r1
166  ret i5 %sel
167}
168
169define i5 @sdiv_common_dividend_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
170; CHECK-LABEL: @sdiv_common_dividend_defined_cond(
171; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
172; CHECK-NEXT:    [[SEL:%.*]] = sdiv i5 [[X:%.*]], [[SEL_V]]
173; CHECK-NEXT:    ret i5 [[SEL]]
174;
175  %r1 = sdiv i5 %x, %y
176  %r2 = sdiv i5 %x, %z
177  %sel = select i1 %b, i5 %r2, i5 %r1
178  ret i5 %sel
179}
180
181define i5 @srem_common_dividend_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
182; CHECK-LABEL: @srem_common_dividend_defined_cond(
183; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
184; CHECK-NEXT:    [[SEL:%.*]] = srem i5 [[X:%.*]], [[SEL_V]]
185; CHECK-NEXT:    ret i5 [[SEL]]
186;
187  %r1 = srem i5 %x, %y
188  %r2 = srem i5 %x, %z
189  %sel = select i1 %b, i5 %r2, i5 %r1
190  ret i5 %sel
191}
192
193define i5 @udiv_common_dividend_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
194; CHECK-LABEL: @udiv_common_dividend_defined_cond(
195; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
196; CHECK-NEXT:    [[SEL:%.*]] = udiv i5 [[X:%.*]], [[SEL_V]]
197; CHECK-NEXT:    ret i5 [[SEL]]
198;
199  %r1 = udiv i5 %x, %y
200  %r2 = udiv i5 %x, %z
201  %sel = select i1 %b, i5 %r2, i5 %r1
202  ret i5 %sel
203}
204
205define i5 @urem_common_dividend_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
206; CHECK-LABEL: @urem_common_dividend_defined_cond(
207; CHECK-NEXT:    [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
208; CHECK-NEXT:    [[SEL:%.*]] = urem i5 [[X:%.*]], [[SEL_V]]
209; CHECK-NEXT:    ret i5 [[SEL]]
210;
211  %r1 = urem i5 %x, %y
212  %r2 = urem i5 %x, %z
213  %sel = select i1 %b, i5 %r2, i5 %r1
214  ret i5 %sel
215}
216
217define i32 @rem_euclid_1(i32 %0) {
218; CHECK-LABEL: @rem_euclid_1(
219; CHECK-NEXT:    [[SEL:%.*]] = and i32 [[TMP0:%.*]], 7
220; CHECK-NEXT:    ret i32 [[SEL]]
221;
222  %rem = srem i32 %0, 8
223  %cond = icmp slt i32 %rem, 0
224  %add = add i32 %rem, 8
225  %sel = select i1 %cond, i32 %add, i32 %rem
226  ret i32 %sel
227}
228
229define i32 @rem_euclid_2(i32 %0) {
230; CHECK-LABEL: @rem_euclid_2(
231; CHECK-NEXT:    [[SEL:%.*]] = and i32 [[TMP0:%.*]], 7
232; CHECK-NEXT:    ret i32 [[SEL]]
233;
234  %rem = srem i32 %0, 8
235  %cond = icmp sgt i32 %rem, -1
236  %add = add i32 %rem, 8
237  %sel = select i1 %cond, i32 %rem, i32 %add
238  ret i32 %sel
239}
240
241define i32 @rem_euclid_wrong_sign_test(i32 %0) {
242; CHECK-LABEL: @rem_euclid_wrong_sign_test(
243; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[TMP0:%.*]], 8
244; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i32 [[REM]], 0
245; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[REM]], 8
246; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 [[ADD]], i32 [[REM]]
247; CHECK-NEXT:    ret i32 [[SEL]]
248;
249  %rem = srem i32 %0, 8
250  %cond = icmp sgt i32 %rem, 0
251  %add = add i32 %rem, 8
252  %sel = select i1 %cond, i32 %add, i32 %rem
253  ret i32 %sel
254}
255
256define i32 @rem_euclid_add_different_const(i32 %0) {
257; CHECK-LABEL: @rem_euclid_add_different_const(
258; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[TMP0:%.*]], 8
259; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[REM]], 0
260; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[REM]], 9
261; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 [[ADD]], i32 [[REM]]
262; CHECK-NEXT:    ret i32 [[SEL]]
263;
264  %rem = srem i32 %0, 8
265  %cond = icmp slt i32 %rem, 0
266  %add = add i32 %rem, 9
267  %sel = select i1 %cond, i32 %add, i32 %rem
268  ret i32 %sel
269}
270
271define i32 @rem_euclid_wrong_operands_select(i32 %0) {
272; CHECK-LABEL: @rem_euclid_wrong_operands_select(
273; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[TMP0:%.*]], 8
274; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[REM]], 0
275; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[REM]], 8
276; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 [[REM]], i32 [[ADD]]
277; CHECK-NEXT:    ret i32 [[SEL]]
278;
279  %rem = srem i32 %0, 8
280  %cond = icmp slt i32 %rem, 0
281  %add = add i32 %rem, 8
282  %sel = select i1 %cond, i32 %rem, i32 %add
283  ret i32 %sel
284}
285
286define <2 x i32> @rem_euclid_vec(<2 x i32> %0) {
287; CHECK-LABEL: @rem_euclid_vec(
288; CHECK-NEXT:    [[SEL:%.*]] = and <2 x i32> [[TMP0:%.*]], splat (i32 7)
289; CHECK-NEXT:    ret <2 x i32> [[SEL]]
290;
291  %rem = srem <2 x i32> %0, <i32 8, i32 8>
292  %cond = icmp slt <2 x i32> %rem, <i32 0, i32 0>
293  %add = add <2 x i32> %rem, <i32 8, i32 8>
294  %sel = select <2 x i1> %cond, <2 x i32> %add, <2 x i32> %rem
295  ret <2 x i32> %sel
296}
297
298define i128 @rem_euclid_i128(i128 %0) {
299; CHECK-LABEL: @rem_euclid_i128(
300; CHECK-NEXT:    [[SEL:%.*]] = and i128 [[TMP0:%.*]], 7
301; CHECK-NEXT:    ret i128 [[SEL]]
302;
303  %rem = srem i128 %0, 8
304  %cond = icmp slt i128 %rem, 0
305  %add = add i128 %rem, 8
306  %sel = select i1 %cond, i128 %add, i128 %rem
307  ret i128 %sel
308}
309
310define i8 @rem_euclid_non_const_pow2(i8 %0, i8 %1) {
311; CHECK-LABEL: @rem_euclid_non_const_pow2(
312; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i8 -1, [[TMP0:%.*]]
313; CHECK-NEXT:    [[TMP3:%.*]] = xor i8 [[NOTMASK]], -1
314; CHECK-NEXT:    [[SEL:%.*]] = and i8 [[TMP1:%.*]], [[TMP3]]
315; CHECK-NEXT:    ret i8 [[SEL]]
316;
317  %pow2 = shl i8 1, %0
318  %rem = srem i8 %1, %pow2
319  %cond = icmp slt i8 %rem, 0
320  %add = add i8 %rem, %pow2
321  %sel = select i1 %cond, i8 %add, i8 %rem
322  ret i8 %sel
323}
324
325define i8 @rem_euclid_non_const_pow2_commuted(i8 %0, i8 %1) {
326; CHECK-LABEL: @rem_euclid_non_const_pow2_commuted(
327; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i8 -1, [[TMP0:%.*]]
328; CHECK-NEXT:    [[TMP3:%.*]] = xor i8 [[NOTMASK]], -1
329; CHECK-NEXT:    [[SEL:%.*]] = and i8 [[TMP1:%.*]], [[TMP3]]
330; CHECK-NEXT:    ret i8 [[SEL]]
331;
332  %pow2 = shl i8 1, %0
333  %rem = srem i8 %1, %pow2
334  %cond = icmp slt i8 %rem, 0
335  %add = add i8 %pow2, %rem
336  %sel = select i1 %cond, i8 %add, i8 %rem
337  ret i8 %sel
338}
339
340define i32 @rem_euclid_pow2_true_arm_folded(i32 %n) {
341; CHECK-LABEL: @rem_euclid_pow2_true_arm_folded(
342; CHECK-NEXT:    [[RES:%.*]] = and i32 [[N:%.*]], 1
343; CHECK-NEXT:    ret i32 [[RES]]
344;
345  %rem = srem i32 %n, 2
346  %neg = icmp slt i32 %rem, 0
347  %res = select i1 %neg, i32 1, i32 %rem
348  ret i32 %res
349}
350
351define i32 @rem_euclid_pow2_false_arm_folded(i32 %n) {
352; CHECK-LABEL: @rem_euclid_pow2_false_arm_folded(
353; CHECK-NEXT:    [[RES:%.*]] = and i32 [[N:%.*]], 1
354; CHECK-NEXT:    ret i32 [[RES]]
355;
356  %rem = srem i32 %n, 2
357  %nonneg = icmp sge i32 %rem, 0
358  %res = select i1 %nonneg, i32 %rem, i32 1
359  ret i32 %res
360}
361
362define i8 @pr89516(i8 %n, i8 %x) {
363; CHECK-LABEL: @pr89516(
364; CHECK-NEXT:    [[COND:%.*]] = icmp slt i8 [[X:%.*]], 0
365; CHECK-NEXT:    [[POW2:%.*]] = shl nuw i8 1, [[N:%.*]]
366; CHECK-NEXT:    [[SREM:%.*]] = srem i8 1, [[POW2]]
367; CHECK-NEXT:    [[ADD:%.*]] = select i1 [[COND]], i8 [[POW2]], i8 0
368; CHECK-NEXT:    [[RES:%.*]] = add nuw i8 [[SREM]], [[ADD]]
369; CHECK-NEXT:    ret i8 [[RES]]
370;
371  %cond = icmp slt i8 %x, 0
372  %pow2 = shl nuw i8 1, %n
373  %srem = srem i8 1, %pow2
374  %add = add nuw i8 %srem, %pow2
375  %res = select i1 %cond, i8 %add, i8 %srem
376  ret i8 %res
377}
378