[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / InstCombine / select-and-or.ll
blob8cd473525aeb3be9b85edf250ad8c93df11e5c9d
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -instcombine < %s | FileCheck %s
4 declare void @use(i1)
6 ; Should not be converted to "and", which has different poison semantics.
7 define i1 @logical_and(i1 %a, i1 %b) {
8 ; CHECK-LABEL: @logical_and(
9 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
10 ; CHECK-NEXT:    ret i1 [[RES]]
12   %res = select i1 %a, i1 %b, i1 false
13   ret i1 %res
16 ; Should not be converted to "or", which has different poison semantics.
17 define i1 @logical_or(i1 %a, i1 %b) {
18 ; CHECK-LABEL: @logical_or(
19 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
20 ; CHECK-NEXT:    ret i1 [[RES]]
22   %res = select i1 %a, i1 true, i1 %b
23   ret i1 %res
25 ; Canonicalize to logical and form, even if that requires adding a "not".
26 define i1 @logical_and_not(i1 %a, i1 %b) {
27 ; CHECK-LABEL: @logical_and_not(
28 ; CHECK-NEXT:    [[NOT_A:%.*]] = xor i1 [[A:%.*]], true
29 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[NOT_A]], i1 [[B:%.*]], i1 false
30 ; CHECK-NEXT:    ret i1 [[RES]]
32   %res = select i1 %a, i1 false, i1 %b
33   ret i1 %res
36 ; Canonicalize to logical or form, even if that requires adding a "not".
37 define i1 @logical_or_not(i1 %a, i1 %b) {
38 ; CHECK-LABEL: @logical_or_not(
39 ; CHECK-NEXT:    [[NOT_A:%.*]] = xor i1 [[A:%.*]], true
40 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[NOT_A]], i1 true, i1 [[B:%.*]]
41 ; CHECK-NEXT:    ret i1 [[RES]]
43   %res = select i1 %a, i1 %b, i1 true
44   ret i1 %res
47 ; These are variants where condition or !condition is used to represent true
48 ; or false in one of the select arms. It should be canonicalized to the
49 ; constants.
51 define i1 @logical_and_cond_reuse(i1 %a, i1 %b) {
52 ; CHECK-LABEL: @logical_and_cond_reuse(
53 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
54 ; CHECK-NEXT:    ret i1 [[RES]]
56   %res = select i1 %a, i1 %b, i1 %a
57   ret i1 %res
60 define i1 @logical_or_cond_reuse(i1 %a, i1 %b) {
61 ; CHECK-LABEL: @logical_or_cond_reuse(
62 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
63 ; CHECK-NEXT:    ret i1 [[RES]]
65   %res = select i1 %a, i1 %a, i1 %b
66   ret i1 %res
69 define i1 @logical_and_not_cond_reuse(i1 %a, i1 %b) {
70 ; CHECK-LABEL: @logical_and_not_cond_reuse(
71 ; CHECK-NEXT:    [[A_NOT:%.*]] = xor i1 [[A:%.*]], true
72 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A_NOT]], i1 true, i1 [[B:%.*]]
73 ; CHECK-NEXT:    ret i1 [[RES]]
75   %a.not = xor i1 %a, true
76   %res = select i1 %a, i1 %b, i1 %a.not
77   ret i1 %res
80 define i1 @logical_or_not_cond_reuse(i1 %a, i1 %b) {
81 ; CHECK-LABEL: @logical_or_not_cond_reuse(
82 ; CHECK-NEXT:    [[A_NOT:%.*]] = xor i1 [[A:%.*]], true
83 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A_NOT]], i1 [[B:%.*]], i1 false
84 ; CHECK-NEXT:    ret i1 [[RES]]
86   %a.not = xor i1 %a, true
87   %res = select i1 %a, i1 %a.not, i1 %b
88   ret i1 %res
91 ; Safe to convert to or due to poison implication.
92 define i1 @logical_or_implies(i32 %x) {
93 ; CHECK-LABEL: @logical_or_implies(
94 ; CHECK-NEXT:    [[C1:%.*]] = icmp eq i32 [[X:%.*]], 0
95 ; CHECK-NEXT:    [[C2:%.*]] = icmp eq i32 [[X]], 42
96 ; CHECK-NEXT:    [[RES:%.*]] = or i1 [[C1]], [[C2]]
97 ; CHECK-NEXT:    ret i1 [[RES]]
99   %c1 = icmp eq i32 %x, 0
100   %c2 = icmp eq i32 %x, 42
101   %res = select i1 %c1, i1 true, i1 %c2
102   ret i1 %res
105 ; Will fold after conversion to or.
106 define i1 @logical_or_implies_folds(i32 %x) {
107 ; CHECK-LABEL: @logical_or_implies_folds(
108 ; CHECK-NEXT:    ret i1 true
110   %c1 = icmp slt i32 %x, 0
111   %c2 = icmp sge i32 %x, 0
112   %res = select i1 %c1, i1 true, i1 %c2
113   ret i1 %res
116 ; Safe to convert to and due to poison implication.
117 define i1 @logical_and_implies(i32 %x) {
118 ; CHECK-LABEL: @logical_and_implies(
119 ; CHECK-NEXT:    [[C1:%.*]] = icmp ne i32 [[X:%.*]], 0
120 ; CHECK-NEXT:    [[C2:%.*]] = icmp ne i32 [[X]], 42
121 ; CHECK-NEXT:    [[RES:%.*]] = and i1 [[C1]], [[C2]]
122 ; CHECK-NEXT:    ret i1 [[RES]]
124   %c1 = icmp ne i32 %x, 0
125   %c2 = icmp ne i32 %x, 42
126   %res = select i1 %c1, i1 %c2, i1 false
127   ret i1 %res
130 ; Will fold after conversion to and.
131 define i1 @logical_and_implies_folds(i32 %x) {
132 ; CHECK-LABEL: @logical_and_implies_folds(
133 ; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i32 [[X:%.*]], 42
134 ; CHECK-NEXT:    ret i1 [[C1]]
136   %c1 = icmp ugt i32 %x, 42
137   %c2 = icmp ne i32 %x, 0
138   %res = select i1 %c1, i1 %c2, i1 false
139   ret i1 %res
142 ; Noundef on condition has no effect.
143 define i1 @logical_or_noundef_a(i1 noundef %a, i1 %b) {
144 ; CHECK-LABEL: @logical_or_noundef_a(
145 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
146 ; CHECK-NEXT:    ret i1 [[RES]]
148   %res = select i1 %a, i1 true, i1 %b
149   ret i1 %res
152 ; Noundef on false value allows conversion to or.
153 define i1 @logical_or_noundef_b(i1 %a, i1 noundef %b) {
154 ; CHECK-LABEL: @logical_or_noundef_b(
155 ; CHECK-NEXT:    [[RES:%.*]] = or i1 [[A:%.*]], [[B:%.*]]
156 ; CHECK-NEXT:    ret i1 [[RES]]
158   %res = select i1 %a, i1 true, i1 %b
159   ret i1 %res
162 ; Noundef on condition has no effect.
163 define i1 @logical_and_noundef_a(i1 noundef %a, i1 %b) {
164 ; CHECK-LABEL: @logical_and_noundef_a(
165 ; CHECK-NEXT:    [[RES:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
166 ; CHECK-NEXT:    ret i1 [[RES]]
168   %res = select i1 %a, i1 %b, i1 false
169   ret i1 %res
172 ; Noundef on false value allows conversion to and.
173 define i1 @logical_and_noundef_b(i1 %a, i1 noundef %b) {
174 ; CHECK-LABEL: @logical_and_noundef_b(
175 ; CHECK-NEXT:    [[RES:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
176 ; CHECK-NEXT:    ret i1 [[RES]]
178   %res = select i1 %a, i1 %b, i1 false
179   ret i1 %res
182 ; (!x && !y) || x --> x || !y
184 define i1 @not_not_true(i1 %x, i1 %y) {
185 ; CHECK-LABEL: @not_not_true(
186 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
187 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[NOTY]]
188 ; CHECK-NEXT:    ret i1 [[R]]
190   %notx = xor i1 %x, true
191   %noty = xor i1 %y, true
192   %r = select i1 %notx, i1 %noty, i1 true
193   ret i1 %r
196 ; (!x && !y) --> !(x || y)
198 define i1 @not_not_false(i1 %x, i1 %y) {
199 ; CHECK-LABEL: @not_not_false(
200 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]]
201 ; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
202 ; CHECK-NEXT:    ret i1 [[R]]
204   %notx = xor i1 %x, true
205   %noty = xor i1 %y, true
206   %r = select i1 %notx, i1 %noty, i1 false
207   ret i1 %r
210 ; (!x || !y) --> !(x && y)
212 define i1 @not_true_not(i1 %x, i1 %y) {
213 ; CHECK-LABEL: @not_true_not(
214 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
215 ; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
216 ; CHECK-NEXT:    ret i1 [[R]]
218   %notx = xor i1 %x, true
219   %noty = xor i1 %y, true
220   %r = select i1 %notx, i1 true, i1 %noty
221   ret i1 %r
224 ; (!!x && !y) --> x && !y
226 define i1 @not_false_not(i1 %x, i1 %y) {
227 ; CHECK-LABEL: @not_false_not(
228 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
229 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[X:%.*]], i1 [[NOTY]], i1 false
230 ; CHECK-NEXT:    ret i1 [[R]]
232   %notx = xor i1 %x, true
233   %noty = xor i1 %y, true
234   %r = select i1 %notx, i1 false, i1 %noty
235   ret i1 %r
238 define i1 @not_not_true_use1(i1 %x, i1 %y) {
239 ; CHECK-LABEL: @not_not_true_use1(
240 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
241 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
242 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
243 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[X]], i1 true, i1 [[NOTY]]
244 ; CHECK-NEXT:    ret i1 [[R]]
246   %notx = xor i1 %x, true
247   call void @use(i1 %notx)
248   %noty = xor i1 %y, true
249   %r = select i1 %notx, i1 %noty, i1 true
250   ret i1 %r
253 define i1 @not_not_false_use1(i1 %x, i1 %y) {
254 ; CHECK-LABEL: @not_not_false_use1(
255 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
256 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
257 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X]], i1 true, i1 [[Y:%.*]]
258 ; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
259 ; CHECK-NEXT:    ret i1 [[R]]
261   %notx = xor i1 %x, true
262   call void @use(i1 %notx)
263   %noty = xor i1 %y, true
264   %r = select i1 %notx, i1 %noty, i1 false
265   ret i1 %r
268 define i1 @not_true_not_use1(i1 %x, i1 %y) {
269 ; CHECK-LABEL: @not_true_not_use1(
270 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
271 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
272 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X]], i1 [[Y:%.*]], i1 false
273 ; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
274 ; CHECK-NEXT:    ret i1 [[R]]
276   %notx = xor i1 %x, true
277   call void @use(i1 %notx)
278   %noty = xor i1 %y, true
279   %r = select i1 %notx, i1 true, i1 %noty
280   ret i1 %r
283 define i1 @not_false_not_use1(i1 %x, i1 %y) {
284 ; CHECK-LABEL: @not_false_not_use1(
285 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
286 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
287 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
288 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[X]], i1 [[NOTY]], i1 false
289 ; CHECK-NEXT:    ret i1 [[R]]
291   %notx = xor i1 %x, true
292   call void @use(i1 %notx)
293   %noty = xor i1 %y, true
294   %r = select i1 %notx, i1 false, i1 %noty
295   ret i1 %r
298 define i1 @not_not_true_use2(i1 %x, i1 %y) {
299 ; CHECK-LABEL: @not_not_true_use2(
300 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
301 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
302 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[NOTY]]
303 ; CHECK-NEXT:    ret i1 [[R]]
305   %notx = xor i1 %x, true
306   %noty = xor i1 %y, true
307   call void @use(i1 %noty)
308   %r = select i1 %notx, i1 %noty, i1 true
309   ret i1 %r
312 define i1 @not_not_false_use2(i1 %x, i1 %y) {
313 ; CHECK-LABEL: @not_not_false_use2(
314 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
315 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
316 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y]]
317 ; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
318 ; CHECK-NEXT:    ret i1 [[R]]
320   %notx = xor i1 %x, true
321   %noty = xor i1 %y, true
322   call void @use(i1 %noty)
323   %r = select i1 %notx, i1 %noty, i1 false
324   ret i1 %r
327 define i1 @not_true_not_use2(i1 %x, i1 %y) {
328 ; CHECK-LABEL: @not_true_not_use2(
329 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
330 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
331 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y]], i1 false
332 ; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
333 ; CHECK-NEXT:    ret i1 [[R]]
335   %notx = xor i1 %x, true
336   %noty = xor i1 %y, true
337   call void @use(i1 %noty)
338   %r = select i1 %notx, i1 true, i1 %noty
339   ret i1 %r
342 define i1 @not_false_not_use2(i1 %x, i1 %y) {
343 ; CHECK-LABEL: @not_false_not_use2(
344 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
345 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
346 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[X:%.*]], i1 [[NOTY]], i1 false
347 ; CHECK-NEXT:    ret i1 [[R]]
349   %notx = xor i1 %x, true
350   %noty = xor i1 %y, true
351   call void @use(i1 %noty)
352   %r = select i1 %notx, i1 false, i1 %noty
353   ret i1 %r
356 define i1 @not_not_true_use3(i1 %x, i1 %y) {
357 ; CHECK-LABEL: @not_not_true_use3(
358 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
359 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
360 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
361 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
362 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[X]], i1 true, i1 [[NOTY]]
363 ; CHECK-NEXT:    ret i1 [[R]]
365   %notx = xor i1 %x, true
366   call void @use(i1 %notx)
367   %noty = xor i1 %y, true
368   call void @use(i1 %noty)
369   %r = select i1 %notx, i1 %noty, i1 true
370   ret i1 %r
373 define i1 @not_not_false_use3(i1 %x, i1 %y) {
374 ; CHECK-LABEL: @not_not_false_use3(
375 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
376 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
377 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
378 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
379 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOTX]], i1 [[NOTY]], i1 false
380 ; CHECK-NEXT:    ret i1 [[R]]
382   %notx = xor i1 %x, true
383   call void @use(i1 %notx)
384   %noty = xor i1 %y, true
385   call void @use(i1 %noty)
386   %r = select i1 %notx, i1 %noty, i1 false
387   ret i1 %r
390 define i1 @not_true_not_use3(i1 %x, i1 %y) {
391 ; CHECK-LABEL: @not_true_not_use3(
392 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
393 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
394 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
395 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
396 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOTX]], i1 true, i1 [[NOTY]]
397 ; CHECK-NEXT:    ret i1 [[R]]
399   %notx = xor i1 %x, true
400   call void @use(i1 %notx)
401   %noty = xor i1 %y, true
402   call void @use(i1 %noty)
403   %r = select i1 %notx, i1 true, i1 %noty
404   ret i1 %r
407 define i1 @not_false_not_use3(i1 %x, i1 %y) {
408 ; CHECK-LABEL: @not_false_not_use3(
409 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
410 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
411 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
412 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
413 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[X]], i1 [[NOTY]], i1 false
414 ; CHECK-NEXT:    ret i1 [[R]]
416   %notx = xor i1 %x, true
417   call void @use(i1 %notx)
418   %noty = xor i1 %y, true
419   call void @use(i1 %noty)
420   %r = select i1 %notx, i1 false, i1 %noty
421   ret i1 %r
424 ; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=35399
426 @g1 = external global i16
427 @g2 = external global i16
429 define i1 @demorgan_select_infloop1(i1 %L) {
430 ; CHECK-LABEL: @demorgan_select_infloop1(
431 ; CHECK-NEXT:    [[NOT_L:%.*]] = xor i1 [[L:%.*]], true
432 ; CHECK-NEXT:    [[C15:%.*]] = select i1 [[NOT_L]], i1 xor (i1 and (i1 icmp eq (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1), i1 icmp ne (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1)), i1 true), i1 false
433 ; CHECK-NEXT:    ret i1 [[C15]]
435   %not.L = xor i1 %L, true
436   %C15 = select i1 %not.L, i1 xor (i1 and (i1 icmp eq (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1), i1 icmp ne (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1)), i1 true), i1 false
437   ret i1 %C15
441 define i1 @demorgan_select_infloop2(i1 %L) {
442 ; CHECK-LABEL: @demorgan_select_infloop2(
443 ; CHECK-NEXT:    [[NOT_L:%.*]] = xor i1 [[L:%.*]], true
444 ; CHECK-NEXT:    [[C15:%.*]] = select i1 [[NOT_L]], i1 true, i1 xor (i1 and (i1 icmp eq (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1), i1 icmp ne (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1)), i1 true)
445 ; CHECK-NEXT:    ret i1 [[C15]]
447   %not.L = xor i1 %L, true
448   %C15 = select i1 %not.L, i1 true, i1 xor (i1 and (i1 icmp eq (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1), i1 icmp ne (i16* getelementptr inbounds (i16, i16* @g2, i64 1), i16* @g1)), i1 true)
449   ret i1 %C15