1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4define i32 @test1(i32 %A) {
5; CHECK-LABEL: @test1(
6; CHECK-NEXT:    ret i32 [[A:%.*]]
7;
8  %B = xor i32 %A, -1
9  %C = xor i32 %B, -1
10  ret i32 %C
11}
12
13define i1 @invert_icmp(i32 %A, i32 %B) {
14; CHECK-LABEL: @invert_icmp(
15; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], [[B:%.*]]
16; CHECK-NEXT:    ret i1 [[CMP]]
17;
18  %cmp = icmp sle i32 %A, %B
19  %not = xor i1 %cmp, true
20  ret i1 %not
21}
22
23; PR1570
24
25define i1 @invert_fcmp(float %X, float %Y) {
26; CHECK-LABEL: @invert_fcmp(
27; CHECK-NEXT:    [[CMP:%.*]] = fcmp uge float [[X:%.*]], [[Y:%.*]]
28; CHECK-NEXT:    ret i1 [[CMP]]
29;
30  %cmp = fcmp olt float %X, %Y
31  %not = xor i1 %cmp, true
32  ret i1 %not
33}
34
35; PR2298
36
37define i1 @not_not_cmp(i32 %a, i32 %b) {
38; CHECK-LABEL: @not_not_cmp(
39; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[B:%.*]], [[A:%.*]]
40; CHECK-NEXT:    ret i1 [[CMP]]
41;
42  %nota = xor i32 %a, -1
43  %notb = xor i32 %b, -1
44  %cmp = icmp slt i32 %nota, %notb
45  ret i1 %cmp
46}
47
48define <2 x i1> @not_not_cmp_vector(<2 x i32> %a, <2 x i32> %b) {
49; CHECK-LABEL: @not_not_cmp_vector(
50; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i32> [[B:%.*]], [[A:%.*]]
51; CHECK-NEXT:    ret <2 x i1> [[CMP]]
52;
53  %nota = xor <2 x i32> %a, <i32 -1, i32 -1>
54  %notb = xor <2 x i32> %b, <i32 -1, i32 -1>
55  %cmp = icmp ugt <2 x i32> %nota, %notb
56  ret <2 x i1> %cmp
57}
58
59define i1 @not_cmp_constant(i32 %a) {
60; CHECK-LABEL: @not_cmp_constant(
61; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], -43
62; CHECK-NEXT:    ret i1 [[CMP]]
63;
64  %nota = xor i32 %a, -1
65  %cmp = icmp ugt i32 %nota, 42
66  ret i1 %cmp
67}
68
69define <2 x i1> @not_cmp_constant_vector(<2 x i32> %a) {
70; CHECK-LABEL: @not_cmp_constant_vector(
71; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i32> [[A:%.*]], <i32 -43, i32 -43>
72; CHECK-NEXT:    ret <2 x i1> [[CMP]]
73;
74  %nota = xor <2 x i32> %a, <i32 -1, i32 -1>
75  %cmp = icmp slt <2 x i32> %nota, <i32 42, i32 42>
76  ret <2 x i1> %cmp
77}
78
79define <2 x i1> @test7(<2 x i32> %A, <2 x i32> %B) {
80; CHECK-LABEL: @test7(
81; CHECK-NEXT:    [[COND:%.*]] = icmp sgt <2 x i32> [[A:%.*]], [[B:%.*]]
82; CHECK-NEXT:    ret <2 x i1> [[COND]]
83;
84  %cond = icmp sle <2 x i32> %A, %B
85  %Ret = xor <2 x i1> %cond, <i1 true, i1 true>
86  ret <2 x i1> %Ret
87}
88
89define i32 @not_ashr_not(i32 %A, i32 %B) {
90; CHECK-LABEL: @not_ashr_not(
91; CHECK-NEXT:    [[NOT2:%.*]] = ashr i32 [[A:%.*]], [[B:%.*]]
92; CHECK-NEXT:    ret i32 [[NOT2]]
93;
94  %not1 = xor i32 %A, -1
95  %ashr = ashr i32 %not1, %B
96  %not2 = xor i32 %ashr, -1
97  ret i32 %not2
98}
99
100define i8 @not_ashr_const(i8 %x) {
101; CHECK-LABEL: @not_ashr_const(
102; CHECK-NEXT:    [[NOT:%.*]] = lshr i8 41, [[X:%.*]]
103; CHECK-NEXT:    ret i8 [[NOT]]
104;
105  %shr = ashr i8 -42, %x
106  %not = xor i8 %shr, -1
107  ret i8 %not
108}
109
110define <2 x i8> @not_ashr_const_splat(<2 x i8> %x) {
111; CHECK-LABEL: @not_ashr_const_splat(
112; CHECK-NEXT:    [[NOT:%.*]] = lshr <2 x i8> <i8 41, i8 41>, [[X:%.*]]
113; CHECK-NEXT:    ret <2 x i8> [[NOT]]
114;
115  %shr = ashr <2 x i8> <i8 -42, i8 -42>, %x
116  %not = xor <2 x i8> %shr, <i8 -1, i8 -1>
117  ret <2 x i8> %not
118}
119
120; We can't get rid of the 'not' on a logical shift of a negative constant.
121
122define i8 @not_lshr_const_negative(i8 %x) {
123; CHECK-LABEL: @not_lshr_const_negative(
124; CHECK-NEXT:    [[SHR:%.*]] = lshr i8 -42, [[X:%.*]]
125; CHECK-NEXT:    [[NOT:%.*]] = xor i8 [[SHR]], -1
126; CHECK-NEXT:    ret i8 [[NOT]]
127;
128  %shr = lshr i8 -42, %x
129  %not = xor i8 %shr, -1
130  ret i8 %not
131}
132
133define i8 @not_lshr_const(i8 %x) {
134; CHECK-LABEL: @not_lshr_const(
135; CHECK-NEXT:    [[NOT:%.*]] = ashr i8 -43, [[X:%.*]]
136; CHECK-NEXT:    ret i8 [[NOT]]
137;
138  %shr = lshr i8 42, %x
139  %not = xor i8 %shr, -1
140  ret i8 %not
141}
142
143define <2 x i8> @not_lshr_const_splat(<2 x i8> %x) {
144; CHECK-LABEL: @not_lshr_const_splat(
145; CHECK-NEXT:    [[NOT:%.*]] = ashr <2 x i8> <i8 -43, i8 -43>, [[X:%.*]]
146; CHECK-NEXT:    ret <2 x i8> [[NOT]]
147;
148  %shr = lshr <2 x i8> <i8 42, i8 42>, %x
149  %not = xor <2 x i8> %shr, <i8 -1, i8 -1>
150  ret <2 x i8> %not
151}
152
153define i32 @not_sub(i32 %y) {
154; CHECK-LABEL: @not_sub(
155; CHECK-NEXT:    [[R:%.*]] = add i32 [[Y:%.*]], -124
156; CHECK-NEXT:    ret i32 [[R]]
157;
158  %s = sub i32 123, %y
159  %r = xor i32 %s, -1
160  ret i32 %r
161}
162
163define i32 @not_sub_extra_use(i32 %y, i32* %p) {
164; CHECK-LABEL: @not_sub_extra_use(
165; CHECK-NEXT:    [[S:%.*]] = sub i32 123, [[Y:%.*]]
166; CHECK-NEXT:    store i32 [[S]], i32* [[P:%.*]], align 4
167; CHECK-NEXT:    [[R:%.*]] = add i32 [[Y]], -124
168; CHECK-NEXT:    ret i32 [[R]]
169;
170  %s = sub i32 123, %y
171  store i32 %s, i32* %p
172  %r = xor i32 %s, -1
173  ret i32 %r
174}
175
176define <2 x i32> @not_sub_splat(<2 x i32> %y) {
177; CHECK-LABEL: @not_sub_splat(
178; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], <i32 -124, i32 -124>
179; CHECK-NEXT:    ret <2 x i32> [[R]]
180;
181  %s = sub <2 x i32> <i32 123, i32 123>, %y
182  %r = xor <2 x i32> %s, <i32 -1, i32 -1>
183  ret <2 x i32> %r
184}
185
186define <2 x i32> @not_sub_extra_use_splat(<2 x i32> %y, <2 x i32>* %p) {
187; CHECK-LABEL: @not_sub_extra_use_splat(
188; CHECK-NEXT:    [[S:%.*]] = sub <2 x i32> <i32 123, i32 123>, [[Y:%.*]]
189; CHECK-NEXT:    store <2 x i32> [[S]], <2 x i32>* [[P:%.*]], align 8
190; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y]], <i32 -124, i32 -124>
191; CHECK-NEXT:    ret <2 x i32> [[R]]
192;
193  %s = sub <2 x i32> <i32 123, i32 123>, %y
194  store <2 x i32> %s, <2 x i32>* %p
195  %r = xor <2 x i32> %s, <i32 -1, i32 -1>
196  ret <2 x i32> %r
197}
198
199define <2 x i32> @not_sub_vec(<2 x i32> %y) {
200; CHECK-LABEL: @not_sub_vec(
201; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y:%.*]], <i32 -43, i32 -124>
202; CHECK-NEXT:    ret <2 x i32> [[R]]
203;
204  %s = sub <2 x i32> <i32 42, i32 123>, %y
205  %r = xor <2 x i32> %s, <i32 -1, i32 -1>
206  ret <2 x i32> %r
207}
208
209define <2 x i32> @not_sub_extra_use_vec(<2 x i32> %y, <2 x i32>* %p) {
210; CHECK-LABEL: @not_sub_extra_use_vec(
211; CHECK-NEXT:    [[S:%.*]] = sub <2 x i32> <i32 123, i32 42>, [[Y:%.*]]
212; CHECK-NEXT:    store <2 x i32> [[S]], <2 x i32>* [[P:%.*]], align 8
213; CHECK-NEXT:    [[R:%.*]] = add <2 x i32> [[Y]], <i32 -124, i32 -43>
214; CHECK-NEXT:    ret <2 x i32> [[R]]
215;
216  %s = sub <2 x i32> <i32 123, i32 42>, %y
217  store <2 x i32> %s, <2 x i32>* %p
218  %r = xor <2 x i32> %s, <i32 -1, i32 -1>
219  ret <2 x i32> %r
220}
221
222; ~(X + C) --> -X - C - 1 --> -(C + 1) - X
223
224define i32 @not_add(i32 %x) {
225; CHECK-LABEL: @not_add(
226; CHECK-NEXT:    [[R:%.*]] = sub i32 -124, [[X:%.*]]
227; CHECK-NEXT:    ret i32 [[R]]
228;
229  %a = add i32 %x, 123
230  %r = xor i32 %a, -1
231  ret i32 %r
232}
233
234define <2 x i32> @not_add_splat(<2 x i32> %x) {
235; CHECK-LABEL: @not_add_splat(
236; CHECK-NEXT:    [[R:%.*]] = sub <2 x i32> <i32 -124, i32 -124>, [[X:%.*]]
237; CHECK-NEXT:    ret <2 x i32> [[R]]
238;
239  %a = add <2 x i32> %x, <i32 123, i32 123>
240  %r = xor <2 x i32> %a, <i32 -1, i32 -1>
241  ret <2 x i32> %r
242}
243
244define <2 x i32> @not_add_vec(<2 x i32> %x) {
245; CHECK-LABEL: @not_add_vec(
246; CHECK-NEXT:    [[R:%.*]] = sub <2 x i32> <i32 -43, i32 -124>, [[X:%.*]]
247; CHECK-NEXT:    ret <2 x i32> [[R]]
248;
249  %a = add <2 x i32> %x, <i32 42, i32 123>
250  %r = xor <2 x i32> %a, <i32 -1, i32 -1>
251  ret <2 x i32> %r
252}
253
254define i1 @not_select_cmp_cmp(i32 %x, i32 %y, float %z, float %w, i1 %cond) {
255; CHECK-LABEL: @not_select_cmp_cmp(
256; CHECK-NEXT:    [[CMPT:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
257; CHECK-NEXT:    [[CMPF:%.*]] = fcmp ole float [[Z:%.*]], [[W:%.*]]
258; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[CMPT]], i1 [[CMPF]]
259; CHECK-NEXT:    ret i1 [[SEL]]
260;
261  %cmpt = icmp sle i32 %x, %y
262  %cmpf = fcmp ugt float %z, %w
263  %sel = select i1 %cond, i1 %cmpt, i1 %cmpf
264  %not = xor i1 %sel, true
265  ret i1 %not
266}
267
268declare void @use1(i1)
269
270; TODO: Missed canonicalization - hoist 'not'?
271
272define i1 @not_select_cmp_cmp_extra_use1(i32 %x, i32 %y, float %z, float %w, i1 %cond) {
273; CHECK-LABEL: @not_select_cmp_cmp_extra_use1(
274; CHECK-NEXT:    [[CMPT:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]
275; CHECK-NEXT:    call void @use1(i1 [[CMPT]])
276; CHECK-NEXT:    [[CMPF:%.*]] = fcmp ugt float [[Z:%.*]], [[W:%.*]]
277; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[CMPT]], i1 [[CMPF]]
278; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[SEL]], true
279; CHECK-NEXT:    ret i1 [[NOT]]
280;
281  %cmpt = icmp sle i32 %x, %y
282  call void @use1(i1 %cmpt)
283  %cmpf = fcmp ugt float %z, %w
284  %sel = select i1 %cond, i1 %cmpt, i1 %cmpf
285  %not = xor i1 %sel, true
286  ret i1 %not
287}
288
289; TODO: Missed canonicalization - hoist 'not'?
290
291define i1 @not_select_cmp_cmp_extra_use2(i32 %x, i32 %y, float %z, float %w, i1 %cond) {
292; CHECK-LABEL: @not_select_cmp_cmp_extra_use2(
293; CHECK-NEXT:    [[CMPT:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]
294; CHECK-NEXT:    [[CMPF:%.*]] = fcmp ugt float [[Z:%.*]], [[W:%.*]]
295; CHECK-NEXT:    call void @use1(i1 [[CMPF]])
296; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[CMPT]], i1 [[CMPF]]
297; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[SEL]], true
298; CHECK-NEXT:    ret i1 [[NOT]]
299;
300  %cmpt = icmp sle i32 %x, %y
301  %cmpf = fcmp ugt float %z, %w
302  call void @use1(i1 %cmpf)
303  %sel = select i1 %cond, i1 %cmpt, i1 %cmpf
304  %not = xor i1 %sel, true
305  ret i1 %not
306}
307
308; Negative test - extra uses would require more instructions.
309
310define i1 @not_select_cmp_cmp_extra_use3(i32 %x, i32 %y, float %z, float %w, i1 %cond) {
311; CHECK-LABEL: @not_select_cmp_cmp_extra_use3(
312; CHECK-NEXT:    [[CMPT:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]
313; CHECK-NEXT:    call void @use1(i1 [[CMPT]])
314; CHECK-NEXT:    [[CMPF:%.*]] = fcmp ugt float [[Z:%.*]], [[W:%.*]]
315; CHECK-NEXT:    call void @use1(i1 [[CMPF]])
316; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[CMPT]], i1 [[CMPF]]
317; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[SEL]], true
318; CHECK-NEXT:    ret i1 [[NOT]]
319;
320  %cmpt = icmp sle i32 %x, %y
321  call void @use1(i1 %cmpt)
322  %cmpf = fcmp ugt float %z, %w
323  call void @use1(i1 %cmpf)
324  %sel = select i1 %cond, i1 %cmpt, i1 %cmpf
325  %not = xor i1 %sel, true
326  ret i1 %not
327}
328
329; Negative test - extra uses would require more instructions.
330
331define i1 @not_select_cmp_cmp_extra_use4(i32 %x, i32 %y, float %z, float %w, i1 %cond) {
332; CHECK-LABEL: @not_select_cmp_cmp_extra_use4(
333; CHECK-NEXT:    [[CMPT:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]
334; CHECK-NEXT:    [[CMPF:%.*]] = fcmp ugt float [[Z:%.*]], [[W:%.*]]
335; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[CMPT]], i1 [[CMPF]]
336; CHECK-NEXT:    call void @use1(i1 [[SEL]])
337; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[SEL]], true
338; CHECK-NEXT:    ret i1 [[NOT]]
339;
340  %cmpt = icmp sle i32 %x, %y
341  %cmpf = fcmp ugt float %z, %w
342  %sel = select i1 %cond, i1 %cmpt, i1 %cmpf
343  call void @use1(i1 %sel)
344  %not = xor i1 %sel, true
345  ret i1 %not
346}
347
348; TODO: Missed canonicalization - hoist 'not'?
349
350define i1 @not_select_cmpt(double %x, double %y, i1 %z, i1 %cond) {
351; CHECK-LABEL: @not_select_cmpt(
352; CHECK-NEXT:    [[CMPT:%.*]] = fcmp oeq double [[X:%.*]], [[Y:%.*]]
353; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[CMPT]], i1 [[Z:%.*]]
354; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[SEL]], true
355; CHECK-NEXT:    ret i1 [[NOT]]
356;
357  %cmpt = fcmp oeq double %x, %y
358  %sel = select i1 %cond, i1 %cmpt, i1 %z
359  %not = xor i1 %sel, true
360  ret i1 %not
361}
362
363; TODO: Missed canonicalization - hoist 'not'?
364
365define i1 @not_select_cmpf(i1 %x, i32 %z, i32 %w, i1 %cond) {
366; CHECK-LABEL: @not_select_cmpf(
367; CHECK-NEXT:    [[CMPF:%.*]] = icmp ugt i32 [[Z:%.*]], [[W:%.*]]
368; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[X:%.*]], i1 [[CMPF]]
369; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[SEL]], true
370; CHECK-NEXT:    ret i1 [[NOT]]
371;
372  %cmpf = icmp ugt i32 %z, %w
373  %sel = select i1 %cond, i1 %x, i1 %cmpf
374  %not = xor i1 %sel, true
375  ret i1 %not
376}
377
378define i1 @not_select_cmpt_extra_use(double %x, double %y, i1 %z, i1 %cond) {
379; CHECK-LABEL: @not_select_cmpt_extra_use(
380; CHECK-NEXT:    [[CMPT:%.*]] = fcmp oeq double [[X:%.*]], [[Y:%.*]]
381; CHECK-NEXT:    call void @use1(i1 [[CMPT]])
382; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[CMPT]], i1 [[Z:%.*]]
383; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[SEL]], true
384; CHECK-NEXT:    ret i1 [[NOT]]
385;
386  %cmpt = fcmp oeq double %x, %y
387  call void @use1(i1 %cmpt)
388  %sel = select i1 %cond, i1 %cmpt, i1 %z
389  %not = xor i1 %sel, true
390  ret i1 %not
391}
392
393define i1 @not_select_cmpf_extra_use(i1 %x, i32 %z, i32 %w, i1 %cond) {
394; CHECK-LABEL: @not_select_cmpf_extra_use(
395; CHECK-NEXT:    [[CMPF:%.*]] = icmp ugt i32 [[Z:%.*]], [[W:%.*]]
396; CHECK-NEXT:    call void @use1(i1 [[CMPF]])
397; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND:%.*]], i1 [[X:%.*]], i1 [[CMPF]]
398; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[SEL]], true
399; CHECK-NEXT:    ret i1 [[NOT]]
400;
401  %cmpf = icmp ugt i32 %z, %w
402  call void @use1(i1 %cmpf)
403  %sel = select i1 %cond, i1 %x, i1 %cmpf
404  %not = xor i1 %sel, true
405  ret i1 %not
406}
407