blob: b3bc74d3cfe08cff898cd2f55d2e07f9b9882a0e [file] [log] [blame]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +00001; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4; If we have a masked merge, in the form of: (M is constant)
5; ((x ^ y) & M) ^ y
6; Unfold it to
7; (x & M) | (y & ~M)
8
9define i4 @scalar0 (i4 %x, i4 %y) {
10; CHECK-LABEL: @scalar0(
Roman Lebedevaa4faec2018-04-30 17:59:33 +000011; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X:%.*]], 1
12; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y:%.*]], -2
13; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +000014; CHECK-NEXT: ret i4 [[R]]
15;
16 %n0 = xor i4 %x, %y
17 %n1 = and i4 %n0, 1
18 %r = xor i4 %n1, %y
19 ret i4 %r
20}
21
22define i4 @scalar1 (i4 %x, i4 %y) {
23; CHECK-LABEL: @scalar1(
Roman Lebedevaa4faec2018-04-30 17:59:33 +000024; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X:%.*]], -2
25; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y:%.*]], 1
26; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +000027; CHECK-NEXT: ret i4 [[R]]
28;
29 %n0 = xor i4 %x, %y
30 %n1 = and i4 %n0, -2
31 %r = xor i4 %n1, %y
32 ret i4 %r
33}
34
35; ============================================================================ ;
36; Various cases with %x and/or %y being a constant
37; ============================================================================ ;
38
39define i4 @in_constant_varx_mone(i4 %x, i4 %mask) {
40; CHECK-LABEL: @in_constant_varx_mone(
41; CHECK-NEXT: [[R1:%.*]] = or i4 [[X:%.*]], -2
42; CHECK-NEXT: ret i4 [[R1]]
43;
44 %n0 = xor i4 %x, -1 ; %x
45 %n1 = and i4 %n0, 1
46 %r = xor i4 %n1, -1
47 ret i4 %r
48}
49
50define i4 @in_constant_varx_14(i4 %x, i4 %mask) {
51; CHECK-LABEL: @in_constant_varx_14(
52; CHECK-NEXT: [[R1:%.*]] = or i4 [[X:%.*]], -2
53; CHECK-NEXT: ret i4 [[R1]]
54;
55 %n0 = xor i4 %x, 14 ; %x
56 %n1 = and i4 %n0, 1
57 %r = xor i4 %n1, 14
58 ret i4 %r
59}
60
61define i4 @in_constant_mone_vary(i4 %y, i4 %mask) {
62; CHECK-LABEL: @in_constant_mone_vary(
63; CHECK-NEXT: [[N0:%.*]] = and i4 [[Y:%.*]], 1
64; CHECK-NEXT: [[N1:%.*]] = xor i4 [[N0]], 1
65; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]
66; CHECK-NEXT: ret i4 [[R]]
67;
68 %n0 = xor i4 %y, -1 ; %x
69 %n1 = and i4 %n0, 1
70 %r = xor i4 %n1, %y
71 ret i4 %r
72}
73
74define i4 @in_constant_14_vary(i4 %y, i4 %mask) {
75; CHECK-LABEL: @in_constant_14_vary(
76; CHECK-NEXT: [[R:%.*]] = and i4 [[Y:%.*]], -2
77; CHECK-NEXT: ret i4 [[R]]
78;
79 %n0 = xor i4 %y, 14 ; %x
80 %n1 = and i4 %n0, 1
81 %r = xor i4 %n1, %y
82 ret i4 %r
83}
84
85; ============================================================================ ;
86; Commutativity
87; ============================================================================ ;
88
89; Used to make sure that the IR complexity sorting does not interfere.
90declare i4 @gen4()
91
92define i4 @c_1_0_0 (i4 %x, i4 %y) {
93; CHECK-LABEL: @c_1_0_0(
Roman Lebedevaa4faec2018-04-30 17:59:33 +000094; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X:%.*]], -2
95; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y:%.*]], 1
96; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +000097; CHECK-NEXT: ret i4 [[R]]
98;
99 %n0 = xor i4 %y, %x ; swapped order
100 %n1 = and i4 %n0, -2
101 %r = xor i4 %n1, %y
102 ret i4 %r
103}
104
105define i4 @c_0_1_0 (i4 %x, i4 %y) {
106; CHECK-LABEL: @c_0_1_0(
Roman Lebedevaa4faec2018-04-30 17:59:33 +0000107; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
108; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[X:%.*]], 1
109; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +0000110; CHECK-NEXT: ret i4 [[R]]
111;
112 %n0 = xor i4 %x, %y
113 %n1 = and i4 %n0, -2
114 %r = xor i4 %n1, %x ; %x instead of %y
115 ret i4 %r
116}
117
118define i4 @c_0_0_1 () {
119; CHECK-LABEL: @c_0_0_1(
120; CHECK-NEXT: [[X:%.*]] = call i4 @gen4()
121; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4()
Roman Lebedevaa4faec2018-04-30 17:59:33 +0000122; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X]], -2
123; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y]], 1
124; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +0000125; CHECK-NEXT: ret i4 [[R]]
126;
127 %x = call i4 @gen4()
128 %y = call i4 @gen4()
129 %n0 = xor i4 %x, %y
130 %n1 = and i4 %n0, -2
131 %r = xor i4 %y, %n1 ; swapped order
132 ret i4 %r
133}
134
135define i4 @c_1_1_0 (i4 %x, i4 %y) {
136; CHECK-LABEL: @c_1_1_0(
Roman Lebedevaa4faec2018-04-30 17:59:33 +0000137; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
138; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[X:%.*]], 1
139; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +0000140; CHECK-NEXT: ret i4 [[R]]
141;
142 %n0 = xor i4 %y, %x ; swapped order
143 %n1 = and i4 %n0, -2
144 %r = xor i4 %n1, %x ; %x instead of %y
145 ret i4 %r
146}
147
148define i4 @c_1_0_1 (i4 %x) {
149; CHECK-LABEL: @c_1_0_1(
150; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4()
Roman Lebedevaa4faec2018-04-30 17:59:33 +0000151; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X:%.*]], -2
152; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y]], 1
153; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +0000154; CHECK-NEXT: ret i4 [[R]]
155;
156 %y = call i4 @gen4()
157 %n0 = xor i4 %y, %x ; swapped order
158 %n1 = and i4 %n0, -2
159 %r = xor i4 %y, %n1 ; swapped order
160 ret i4 %r
161}
162
163define i4 @c_0_1_1 (i4 %y) {
164; CHECK-LABEL: @c_0_1_1(
165; CHECK-NEXT: [[X:%.*]] = call i4 @gen4()
Roman Lebedevaa4faec2018-04-30 17:59:33 +0000166; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
167; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[X]], 1
168; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +0000169; CHECK-NEXT: ret i4 [[R]]
170;
171 %x = call i4 @gen4()
172 %n0 = xor i4 %x, %y
173 %n1 = and i4 %n0, -2
174 %r = xor i4 %x, %n1 ; swapped order, %x instead of %y
175 ret i4 %r
176}
177
178define i4 @c_1_1_1 () {
179; CHECK-LABEL: @c_1_1_1(
180; CHECK-NEXT: [[X:%.*]] = call i4 @gen4()
181; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4()
Roman Lebedevaa4faec2018-04-30 17:59:33 +0000182; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[Y]], -2
183; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[X]], 1
184; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]]
Roman Lebedevb7ae4ef2018-04-30 17:59:26 +0000185; CHECK-NEXT: ret i4 [[R]]
186;
187 %x = call i4 @gen4()
188 %y = call i4 @gen4()
189 %n0 = xor i4 %y, %x ; swapped order
190 %n1 = and i4 %n0, -2
191 %r = xor i4 %x, %n1 ; swapped order, %x instead of %y
192 ret i4 %r
193}
194
195define i4 @commutativity_constant_14_vary(i4 %y, i4 %mask) {
196; CHECK-LABEL: @commutativity_constant_14_vary(
197; CHECK-NEXT: [[R:%.*]] = and i4 [[Y:%.*]], -2
198; CHECK-NEXT: ret i4 [[R]]
199;
200 %n0 = xor i4 %y, 14 ; %x
201 %n1 = and i4 %n0, 1
202 %r = xor i4 %y, %n1 ; swapped
203 ret i4 %r
204}
205
206; ============================================================================ ;
207; Negative tests. Should not be folded.
208; ============================================================================ ;
209
210; One use only.
211
212declare void @use4(i4)
213
214define i4 @n_oneuse_D (i4 %x, i4 %y) {
215; CHECK-LABEL: @n_oneuse_D(
216; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
217; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], -2
218; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]
219; CHECK-NEXT: call void @use4(i4 [[N0]])
220; CHECK-NEXT: ret i4 [[R]]
221;
222 %n0 = xor i4 %x, %y ; two uses of %n0, which is going to be replaced
223 %n1 = and i4 %n0, -2
224 %r = xor i4 %n1, %y
225 call void @use4(i4 %n0)
226 ret i4 %r
227}
228
229define i4 @n_oneuse_A (i4 %x, i4 %y) {
230; CHECK-LABEL: @n_oneuse_A(
231; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
232; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], -2
233; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]
234; CHECK-NEXT: call void @use4(i4 [[N1]])
235; CHECK-NEXT: ret i4 [[R]]
236;
237 %n0 = xor i4 %x, %y
238 %n1 = and i4 %n0, -2 ; two uses of %n1, which is going to be replaced
239 %r = xor i4 %n1, %y
240 call void @use4(i4 %n1)
241 ret i4 %r
242}
243
244define i4 @n_oneuse_AD (i4 %x, i4 %y) {
245; CHECK-LABEL: @n_oneuse_AD(
246; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
247; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], -2
248; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]
249; CHECK-NEXT: call void @use4(i4 [[N0]])
250; CHECK-NEXT: call void @use4(i4 [[N1]])
251; CHECK-NEXT: ret i4 [[R]]
252;
253 %n0 = xor i4 %x, %y
254 %n1 = and i4 %n0, -2 ; two uses of %n1, which is going to be replaced
255 %r = xor i4 %n1, %y
256 call void @use4(i4 %n0)
257 call void @use4(i4 %n1)
258 ret i4 %r
259}
260
261; Mask is not constant
262
263define i4 @n_var_mask (i4 %x, i4 %y, i4 %m) {
264; CHECK-LABEL: @n_var_mask(
265; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
266; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[M:%.*]]
267; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]
268; CHECK-NEXT: ret i4 [[R]]
269;
270 %n0 = xor i4 %x, %y
271 %n1 = and i4 %n0, %m
272 %r = xor i4 %n1, %y
273 ret i4 %r
274}
275
276; Some third variable is used
277
278define i4 @n_third_var (i4 %x, i4 %y, i4 %z) {
279; CHECK-LABEL: @n_third_var(
280; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
281; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], -2
282; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Z:%.*]]
283; CHECK-NEXT: ret i4 [[R]]
284;
285 %n0 = xor i4 %x, %y
286 %n1 = and i4 %n0, -2
287 %r = xor i4 %n1, %z ; not %x or %y
288 ret i4 %r
289}