xref: /llvm-project/llvm/test/Transforms/InstCombine/unfold-masked-merge-with-const-mask-scalar.ll (revision 7ec4f6094e54911794c142b5d88496a220d807d6)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=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(
11; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X:%.*]], 1
12; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y:%.*]], -2
13; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
14; 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(
24; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X:%.*]], -2
25; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y:%.*]], 1
26; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
27; 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:    [[R1:%.*]] = or i4 [[Y:%.*]], 1
64; CHECK-NEXT:    ret i4 [[R1]]
65;
66  %n0 = xor i4 %y, -1 ; %x
67  %n1 = and i4 %n0, 1
68  %r = xor i4 %n1, %y
69  ret i4 %r
70}
71
72define i4 @in_constant_14_vary(i4 %y, i4 %mask) {
73; CHECK-LABEL: @in_constant_14_vary(
74; CHECK-NEXT:    [[R:%.*]] = and i4 [[Y:%.*]], -2
75; CHECK-NEXT:    ret i4 [[R]]
76;
77  %n0 = xor i4 %y, 14 ; %x
78  %n1 = and i4 %n0, 1
79  %r = xor i4 %n1, %y
80  ret i4 %r
81}
82
83; ============================================================================ ;
84; Commutativity
85; ============================================================================ ;
86
87; Used to make sure that the IR complexity sorting does not interfere.
88declare i4 @gen4()
89
90define i4 @c_1_0_0 (i4 %x, i4 %y) {
91; CHECK-LABEL: @c_1_0_0(
92; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X:%.*]], -2
93; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y:%.*]], 1
94; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
95; CHECK-NEXT:    ret i4 [[R]]
96;
97  %n0 = xor i4 %y, %x ; swapped order
98  %n1 = and i4 %n0, -2
99  %r  = xor i4 %n1, %y
100  ret i4 %r
101}
102
103define i4 @c_0_1_0 (i4 %x, i4 %y) {
104; CHECK-LABEL: @c_0_1_0(
105; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
106; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[X:%.*]], 1
107; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
108; CHECK-NEXT:    ret i4 [[R]]
109;
110  %n0 = xor i4 %x, %y
111  %n1 = and i4 %n0, -2
112  %r  = xor i4 %n1, %x ; %x instead of %y
113  ret i4 %r
114}
115
116define i4 @c_0_0_1 () {
117; CHECK-LABEL: @c_0_0_1(
118; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
119; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
120; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X]], -2
121; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y]], 1
122; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
123; CHECK-NEXT:    ret i4 [[R]]
124;
125  %x  = call i4 @gen4()
126  %y  = call i4 @gen4()
127  %n0 = xor i4 %x, %y
128  %n1 = and i4 %n0, -2
129  %r  = xor i4 %y, %n1 ; swapped order
130  ret i4 %r
131}
132
133define i4 @c_1_1_0 (i4 %x, i4 %y) {
134; CHECK-LABEL: @c_1_1_0(
135; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
136; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[X:%.*]], 1
137; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
138; CHECK-NEXT:    ret i4 [[R]]
139;
140  %n0 = xor i4 %y, %x ; swapped order
141  %n1 = and i4 %n0, -2
142  %r  = xor i4 %n1, %x ; %x instead of %y
143  ret i4 %r
144}
145
146define i4 @c_1_0_1 (i4 %x) {
147; CHECK-LABEL: @c_1_0_1(
148; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
149; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[X:%.*]], -2
150; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[Y]], 1
151; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
152; CHECK-NEXT:    ret i4 [[R]]
153;
154  %y  = call i4 @gen4()
155  %n0 = xor i4 %y, %x ; swapped order
156  %n1 = and i4 %n0, -2
157  %r  = xor i4 %y, %n1 ; swapped order
158  ret i4 %r
159}
160
161define i4 @c_0_1_1 (i4 %y) {
162; CHECK-LABEL: @c_0_1_1(
163; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
164; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[Y:%.*]], -2
165; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[X]], 1
166; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
167; CHECK-NEXT:    ret i4 [[R]]
168;
169  %x  = call i4 @gen4()
170  %n0 = xor i4 %x, %y
171  %n1 = and i4 %n0, -2
172  %r  = xor i4 %x, %n1 ; swapped order, %x instead of %y
173  ret i4 %r
174}
175
176define i4 @c_1_1_1 () {
177; CHECK-LABEL: @c_1_1_1(
178; CHECK-NEXT:    [[X:%.*]] = call i4 @gen4()
179; CHECK-NEXT:    [[Y:%.*]] = call i4 @gen4()
180; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[Y]], -2
181; CHECK-NEXT:    [[TMP2:%.*]] = and i4 [[X]], 1
182; CHECK-NEXT:    [[R:%.*]] = or disjoint i4 [[TMP1]], [[TMP2]]
183; CHECK-NEXT:    ret i4 [[R]]
184;
185  %x  = call i4 @gen4()
186  %y  = call i4 @gen4()
187  %n0 = xor i4 %y, %x ; swapped order
188  %n1 = and i4 %n0, -2
189  %r  = xor i4 %x, %n1 ; swapped order, %x instead of %y
190  ret i4 %r
191}
192
193define i4 @commutativity_constant_14_vary(i4 %y, i4 %mask) {
194; CHECK-LABEL: @commutativity_constant_14_vary(
195; CHECK-NEXT:    [[R:%.*]] = and i4 [[Y:%.*]], -2
196; CHECK-NEXT:    ret i4 [[R]]
197;
198  %n0 = xor i4 %y, 14 ; %x
199  %n1 = and i4 %n0, 1
200  %r = xor i4 %y, %n1 ; swapped
201  ret i4 %r
202}
203
204; ============================================================================ ;
205; Negative tests. Should not be folded.
206; ============================================================================ ;
207
208; One use only.
209
210declare void @use4(i4)
211
212define i4 @n_oneuse_D (i4 %x, i4 %y) {
213; CHECK-LABEL: @n_oneuse_D(
214; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
215; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], -2
216; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
217; CHECK-NEXT:    call void @use4(i4 [[N0]])
218; CHECK-NEXT:    ret i4 [[R]]
219;
220  %n0 = xor i4 %x, %y ; two uses of %n0, which is going to be replaced
221  %n1 = and i4 %n0, -2
222  %r  = xor i4 %n1, %y
223  call void @use4(i4 %n0)
224  ret i4 %r
225}
226
227define i4 @n_oneuse_A (i4 %x, i4 %y) {
228; CHECK-LABEL: @n_oneuse_A(
229; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
230; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], -2
231; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
232; CHECK-NEXT:    call void @use4(i4 [[N1]])
233; CHECK-NEXT:    ret i4 [[R]]
234;
235  %n0 = xor i4 %x, %y
236  %n1 = and i4 %n0, -2 ; two uses of %n1, which is going to be replaced
237  %r  = xor i4 %n1, %y
238  call void @use4(i4 %n1)
239  ret i4 %r
240}
241
242define i4 @n_oneuse_AD (i4 %x, i4 %y) {
243; CHECK-LABEL: @n_oneuse_AD(
244; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
245; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], -2
246; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
247; CHECK-NEXT:    call void @use4(i4 [[N0]])
248; CHECK-NEXT:    call void @use4(i4 [[N1]])
249; CHECK-NEXT:    ret i4 [[R]]
250;
251  %n0 = xor i4 %x, %y
252  %n1 = and i4 %n0, -2 ; two uses of %n1, which is going to be replaced
253  %r  = xor i4 %n1, %y
254  call void @use4(i4 %n0)
255  call void @use4(i4 %n1)
256  ret i4 %r
257}
258
259; Mask is not constant
260
261define i4 @n_var_mask (i4 %x, i4 %y, i4 %m) {
262; CHECK-LABEL: @n_var_mask(
263; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
264; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], [[M:%.*]]
265; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Y]]
266; CHECK-NEXT:    ret i4 [[R]]
267;
268  %n0 = xor i4 %x, %y
269  %n1 = and i4 %n0, %m
270  %r  = xor i4 %n1, %y
271  ret i4 %r
272}
273
274; Some third variable is used
275
276define i4 @n_third_var (i4 %x, i4 %y, i4 %z) {
277; CHECK-LABEL: @n_third_var(
278; CHECK-NEXT:    [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]
279; CHECK-NEXT:    [[N1:%.*]] = and i4 [[N0]], -2
280; CHECK-NEXT:    [[R:%.*]] = xor i4 [[N1]], [[Z:%.*]]
281; CHECK-NEXT:    ret i4 [[R]]
282;
283  %n0 = xor i4 %x, %y
284  %n1 = and i4 %n0, -2
285  %r  = xor i4 %n1, %z ; not %x or %y
286  ret i4 %r
287}
288