xref: /llvm-project/llvm/test/Transforms/InstCombine/sink-not-into-logical-or.ll (revision b20ccccda22b1465b54bd069bd53a0a96224f3ec)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4; Transform
5;   z = ~(x | y)
6; into:
7;   z = ~(~x & ~y)
8; iff both x and y are free to invert.
9
10declare void @use1(i1)
11
12; Most basic positive test
13define i1 @t0(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
14; CHECK-LABEL: @t0(
15; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
16; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
17; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
18; CHECK-NEXT:    ret i1 [[I3_NOT]]
19;
20  %i1 = icmp eq i32 %v0, %v1
21  %i2 = icmp eq i32 %v2, %v3
22  %i3 = select i1 %i2, i1 true, i1 %i1
23  %i4 = xor i1 %i3, -1
24  ret i1 %i4
25}
26
27; All operands must be invertible
28define i1 @n1(i1 %i1, i32 %v2, i32 %v3) {
29; CHECK-LABEL: @n1(
30; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
31; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1:%.*]]
32; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
33; CHECK-NEXT:    ret i1 [[I4]]
34;
35  %i2 = icmp eq i32 %v2, %v3
36  %i3 = select i1 %i2, i1 true, i1 %i1
37  %i4 = xor i1 %i3, -1
38  ret i1 %i4
39}
40define i1 @n2(i32 %v0, i32 %v1, i1 %i2) {
41; CHECK-LABEL: @n2(
42; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
43; CHECK-NEXT:    [[NOT_I2:%.*]] = xor i1 [[I2:%.*]], true
44; CHECK-NEXT:    [[I3:%.*]] = select i1 [[NOT_I2]], i1 [[I1]], i1 false
45; CHECK-NEXT:    ret i1 [[I3]]
46;
47  %i1 = icmp eq i32 %v0, %v1
48  %i3 = select i1 %i2, i1 true, i1 %i1
49  %i4 = xor i1 %i3, -1
50  ret i1 %i4
51}
52define i1 @n3(i1 %i1, i1 %i2) {
53; CHECK-LABEL: @n3(
54; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2:%.*]], i1 true, i1 [[I1:%.*]]
55; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
56; CHECK-NEXT:    ret i1 [[I4]]
57;
58  %i3 = select i1 %i2, i1 true, i1 %i1
59  %i4 = xor i1 %i3, -1
60  ret i1 %i4
61}
62
63; All other uses of operands must be invertible
64define i1 @n4(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
65; CHECK-LABEL: @n4(
66; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
67; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
68; CHECK-NEXT:    call void @use1(i1 [[I1]])
69; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
70; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
71; CHECK-NEXT:    ret i1 [[I4]]
72;
73  %i1 = icmp eq i32 %v0, %v1
74  %i2 = icmp eq i32 %v2, %v3
75  call void @use1(i1 %i1)
76  %i3 = select i1 %i2, i1 true, i1 %i1
77  %i4 = xor i1 %i3, -1
78  ret i1 %i4
79}
80define i1 @n5(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
81; CHECK-LABEL: @n5(
82; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
83; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
84; CHECK-NEXT:    call void @use1(i1 [[I2]])
85; CHECK-NEXT:    [[NOT_I2:%.*]] = xor i1 [[I2]], true
86; CHECK-NEXT:    [[I3:%.*]] = select i1 [[NOT_I2]], i1 [[I1]], i1 false
87; CHECK-NEXT:    ret i1 [[I3]]
88;
89  %i1 = icmp eq i32 %v0, %v1
90  %i2 = icmp eq i32 %v2, %v3
91  call void @use1(i1 %i2)
92  %i3 = select i1 %i2, i1 true, i1 %i1
93  %i4 = xor i1 %i3, -1
94  ret i1 %i4
95}
96define i1 @n6(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
97; CHECK-LABEL: @n6(
98; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
99; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
100; CHECK-NEXT:    call void @use1(i1 [[I1]])
101; CHECK-NEXT:    call void @use1(i1 [[I2]])
102; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
103; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
104; CHECK-NEXT:    ret i1 [[I4]]
105;
106  %i1 = icmp eq i32 %v0, %v1
107  %i2 = icmp eq i32 %v2, %v3
108  call void @use1(i1 %i1)
109  call void @use1(i1 %i2)
110  %i3 = select i1 %i2, i1 true, i1 %i1
111  %i4 = xor i1 %i3, -1
112  ret i1 %i4
113}
114
115; Hands have invertible uses
116define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
117; CHECK-LABEL: @t7(
118; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
119; CHECK-NEXT:    call void @use1(i1 [[I1]])
120; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
121; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
122; CHECK-NEXT:    ret i1 [[I3_NOT]]
123;
124  %i1 = icmp eq i32 %v0, %v1
125  %i1.not = xor i1 %i1, -1
126  call void @use1(i1 %i1.not)
127  %i2 = icmp eq i32 %v2, %v3
128  %i3 = select i1 %i2, i1 true, i1 %i1
129  %i4 = xor i1 %i3, -1
130  ret i1 %i4
131}
132define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
133; CHECK-LABEL: @t8(
134; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
135; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
136; CHECK-NEXT:    call void @use1(i1 [[I2]])
137; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
138; CHECK-NEXT:    ret i1 [[I3_NOT]]
139;
140  %i1 = icmp eq i32 %v0, %v1
141  %i2 = icmp eq i32 %v2, %v3
142  %i2.not = xor i1 %i2, -1
143  call void @use1(i1 %i2.not)
144  %i3 = select i1 %i2, i1 true, i1 %i1
145  %i4 = xor i1 %i3, -1
146  ret i1 %i4
147}
148define i1 @t9(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
149; CHECK-LABEL: @t9(
150; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
151; CHECK-NEXT:    call void @use1(i1 [[I1]])
152; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
153; CHECK-NEXT:    call void @use1(i1 [[I2]])
154; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
155; CHECK-NEXT:    ret i1 [[I3_NOT]]
156;
157  %i1 = icmp eq i32 %v0, %v1
158  %i1.not = xor i1 %i1, -1
159  call void @use1(i1 %i1.not)
160  %i2 = icmp eq i32 %v2, %v3
161  %i2.not = xor i1 %i2, -1
162  call void @use1(i1 %i2.not)
163  %i3 = select i1 %i2, i1 true, i1 %i1
164  %i4 = xor i1 %i3, -1
165  ret i1 %i4
166}
167
168; Select can have other uses
169
170; Not all uses can be adapted
171define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
172; CHECK-LABEL: @n10(
173; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
174; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
175; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
176; CHECK-NEXT:    call void @use1(i1 [[I3]])
177; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
178; CHECK-NEXT:    ret i1 [[I4]]
179;
180  %i1 = icmp eq i32 %v0, %v1
181  %i2 = icmp eq i32 %v2, %v3
182  %i3 = select i1 %i2, i1 true, i1 %i1
183  call void @use1(i1 %i3)
184  %i4 = xor i1 %i3, -1
185  ret i1 %i4
186}
187
188; All other uses can be adapted.
189define i1 @t11(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i1 %v4, i1 %v5) {
190; CHECK-LABEL: @t11(
191; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
192; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
193; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
194; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3_NOT]], i1 [[V5:%.*]], i1 [[V4:%.*]]
195; CHECK-NEXT:    call void @use1(i1 [[I5]])
196; CHECK-NEXT:    ret i1 [[I3_NOT]]
197;
198  %i1 = icmp eq i32 %v0, %v1
199  %i2 = icmp eq i32 %v2, %v3
200  %i3 = select i1 %i2, i1 true, i1 %i1
201  %i4 = xor i1 %i3, -1
202  %i5 = select i1 %i3, i1 %v4, i1 %v5
203  call void @use1(i1 %i5)
204  ret i1 %i4
205}
206