xref: /llvm-project/llvm/test/CodeGen/X86/fold-masked-merge.ll (revision 55c6bda01ef5a166a69b43956775272d9d67bda5)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -o - %s -mtriple=x86_64-- | FileCheck %s --check-prefixes=CHECK,NOBMI
3; RUN: llc -o - %s -mtriple=x86_64-- -mattr=+bmi | FileCheck %s --check-prefixes=CHECK,BMI
4;
5; test that masked-merge code is generated as "xor;and;xor" sequence or
6; "andn ; and; or" if and-not is available.
7
8define i32 @masked_merge0(i32 %a0, i32 %a1, i32 %a2) {
9; NOBMI-LABEL: masked_merge0:
10; NOBMI:       # %bb.0:
11; NOBMI-NEXT:    movl %esi, %eax
12; NOBMI-NEXT:    xorl %edx, %eax
13; NOBMI-NEXT:    andl %edi, %eax
14; NOBMI-NEXT:    xorl %edx, %eax
15; NOBMI-NEXT:    retq
16;
17; BMI-LABEL: masked_merge0:
18; BMI:       # %bb.0:
19; BMI-NEXT:    andl %edi, %esi
20; BMI-NEXT:    andnl %edx, %edi, %eax
21; BMI-NEXT:    orl %esi, %eax
22; BMI-NEXT:    retq
23  %and0 = and i32 %a0, %a1
24  %not = xor i32 %a0, -1
25  %and1 = and i32 %not, %a2
26  %or = or i32 %and0, %and1
27  ret i32 %or
28}
29
30define i16 @masked_merge1(i16 %a0, i16 %a1, i16 %a2) {
31; NOBMI-LABEL: masked_merge1:
32; NOBMI:       # %bb.0:
33; NOBMI-NEXT:    movl %edi, %eax
34; NOBMI-NEXT:    andl %edi, %esi
35; NOBMI-NEXT:    notl %eax
36; NOBMI-NEXT:    andl %edx, %eax
37; NOBMI-NEXT:    orl %esi, %eax
38; NOBMI-NEXT:    # kill: def $ax killed $ax killed $eax
39; NOBMI-NEXT:    retq
40;
41; BMI-LABEL: masked_merge1:
42; BMI:       # %bb.0:
43; BMI-NEXT:    andl %edi, %esi
44; BMI-NEXT:    andnl %edx, %edi, %eax
45; BMI-NEXT:    orl %esi, %eax
46; BMI-NEXT:    # kill: def $ax killed $ax killed $eax
47; BMI-NEXT:    retq
48  %and0 = and i16 %a0, %a1
49  %not = xor i16 %a0, -1
50  %and1 = and i16 %a2, %not
51  %or = or i16 %and0, %and1
52  ret i16 %or
53}
54
55define i8 @masked_merge2(i8 %a0, i8 %a1, i8 %a2) {
56; NOBMI-LABEL: masked_merge2:
57; NOBMI:       # %bb.0:
58; NOBMI-NEXT:    movl %esi, %eax
59; NOBMI-NEXT:    # kill: def $al killed $al killed $eax
60; NOBMI-NEXT:    retq
61;
62; BMI-LABEL: masked_merge2:
63; BMI:       # %bb.0:
64; BMI-NEXT:    movl %edi, %eax
65; BMI-NEXT:    notb %al
66; BMI-NEXT:    andb %sil, %al
67; BMI-NEXT:    andb %dil, %sil
68; BMI-NEXT:    orb %sil, %al
69; BMI-NEXT:    retq
70  %not = xor i8 %a0, -1
71  %and0 = and i8 %not, %a1
72  %and1 = and i8 %a1, %a0
73  %or = or i8 %and0, %and1
74  ret i8 %or
75}
76
77define i64 @masked_merge3(i64 %a0, i64 %a1, i64 %a2) {
78; NOBMI-LABEL: masked_merge3:
79; NOBMI:       # %bb.0:
80; NOBMI-NEXT:    movq %rsi, %rax
81; NOBMI-NEXT:    notq %rdx
82; NOBMI-NEXT:    xorq %rdx, %rax
83; NOBMI-NEXT:    notq %rax
84; NOBMI-NEXT:    andq %rdi, %rax
85; NOBMI-NEXT:    xorq %rdx, %rax
86; NOBMI-NEXT:    retq
87;
88; BMI-LABEL: masked_merge3:
89; BMI:       # %bb.0:
90; BMI-NEXT:    notq %rdx
91; BMI-NEXT:    andnq %rdx, %rdi, %rcx
92; BMI-NEXT:    andnq %rdi, %rsi, %rax
93; BMI-NEXT:    orq %rcx, %rax
94; BMI-NEXT:    retq
95  %v0 = xor i64 %a1, -1
96  %v1 = xor i64 %a2, -1
97  %not = xor i64 %a0, -1
98  %and0 = and i64 %not, %v1
99  %and1 = and i64 %v0, %a0
100  %or = or i64 %and0, %and1
101  ret i64 %or
102}
103
104; not a masked merge: there is no `not` operation.
105define i32 @not_a_masked_merge0(i32 %a0, i32 %a1, i32 %a2) {
106; CHECK-LABEL: not_a_masked_merge0:
107; CHECK:       # %bb.0:
108; CHECK-NEXT:    movl %edi, %eax
109; CHECK-NEXT:    andl %edi, %esi
110; CHECK-NEXT:    negl %eax
111; CHECK-NEXT:    andl %edx, %eax
112; CHECK-NEXT:    orl %esi, %eax
113; CHECK-NEXT:    retq
114  %and0 = and i32 %a0, %a1
115  %not_a_not = sub i32 0, %a0
116  %and1 = and i32 %not_a_not, %a2
117  %or = or i32 %and0, %and1
118  ret i32 %or
119}
120
121; not a masked merge: `not` operand does not match another `and`-operand.
122define i32 @not_a_masked_merge1(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
123; NOBMI-LABEL: not_a_masked_merge1:
124; NOBMI:       # %bb.0:
125; NOBMI-NEXT:    movl %ecx, %eax
126; NOBMI-NEXT:    andl %esi, %edi
127; NOBMI-NEXT:    notl %eax
128; NOBMI-NEXT:    andl %edx, %eax
129; NOBMI-NEXT:    orl %edi, %eax
130; NOBMI-NEXT:    retq
131;
132; BMI-LABEL: not_a_masked_merge1:
133; BMI:       # %bb.0:
134; BMI-NEXT:    andl %esi, %edi
135; BMI-NEXT:    andnl %edx, %ecx, %eax
136; BMI-NEXT:    orl %edi, %eax
137; BMI-NEXT:    retq
138  %and0 = and i32 %a0, %a1
139  %not = xor i32 %a3, -1
140  %and1 = and i32 %not, %a2
141  %or = or i32 %and0, %and1
142  ret i32 %or
143}
144
145; not a masked merge: one of the operands of `or` is not an `and`.
146define i32 @not_a_masked_merge2(i32 %a0, i32 %a1, i32 %a2) {
147; NOBMI-LABEL: not_a_masked_merge2:
148; NOBMI:       # %bb.0:
149; NOBMI-NEXT:    movl %edi, %eax
150; NOBMI-NEXT:    orl %edi, %esi
151; NOBMI-NEXT:    notl %eax
152; NOBMI-NEXT:    andl %edx, %eax
153; NOBMI-NEXT:    orl %esi, %eax
154; NOBMI-NEXT:    retq
155;
156; BMI-LABEL: not_a_masked_merge2:
157; BMI:       # %bb.0:
158; BMI-NEXT:    orl %edi, %esi
159; BMI-NEXT:    andnl %edx, %edi, %eax
160; BMI-NEXT:    orl %esi, %eax
161; BMI-NEXT:    retq
162  %not_an_and0 = or i32 %a0, %a1
163  %not = xor i32 %a0, -1
164  %and1 = and i32 %not, %a2
165  %or = or i32 %not_an_and0, %and1
166  ret i32 %or
167}
168
169; not a masked merge: one of the operands of `or` is not an `and`.
170define i32 @not_a_masked_merge3(i32 %a0, i32 %a1, i32 %a2) {
171; CHECK-LABEL: not_a_masked_merge3:
172; CHECK:       # %bb.0:
173; CHECK-NEXT:    movl %edx, %eax
174; CHECK-NEXT:    andl %edi, %esi
175; CHECK-NEXT:    xorl %edi, %eax
176; CHECK-NEXT:    notl %eax
177; CHECK-NEXT:    orl %esi, %eax
178; CHECK-NEXT:    retq
179  %and0 = and i32 %a0, %a1
180  %not = xor i32 %a0, -1
181  %not_an_and1 = xor i32 %not, %a2
182  %or = or i32 %and0, %not_an_and1
183  ret i32 %or
184}
185
186; not a masked merge: `not` operand must not be on same `and`.
187define i32 @not_a_masked_merge4(i32 %a0, i32 %a1, i32 %a2) {
188; CHECK-LABEL: not_a_masked_merge4:
189; CHECK:       # %bb.0:
190; CHECK-NEXT:    movl %edi, %eax
191; CHECK-NEXT:    andl %esi, %eax
192; CHECK-NEXT:    retq
193  %and0 = and i32 %a0, %a1
194  %not = xor i32 %a2, -1
195  %and1 = and i32 %not, %a2
196  %or = or i32 %and0, %and1
197  ret i32 %or
198}
199
200; should not transform when operands have multiple users.
201define i32 @masked_merge_no_transform0(i32 %a0, i32 %a1, i32 %a2, ptr %p1) {
202; NOBMI-LABEL: masked_merge_no_transform0:
203; NOBMI:       # %bb.0:
204; NOBMI-NEXT:    movl %edi, %eax
205; NOBMI-NEXT:    andl %edi, %esi
206; NOBMI-NEXT:    notl %eax
207; NOBMI-NEXT:    andl %edx, %eax
208; NOBMI-NEXT:    orl %esi, %eax
209; NOBMI-NEXT:    movl %esi, (%rcx)
210; NOBMI-NEXT:    retq
211;
212; BMI-LABEL: masked_merge_no_transform0:
213; BMI:       # %bb.0:
214; BMI-NEXT:    andl %edi, %esi
215; BMI-NEXT:    andnl %edx, %edi, %eax
216; BMI-NEXT:    orl %esi, %eax
217; BMI-NEXT:    movl %esi, (%rcx)
218; BMI-NEXT:    retq
219  %and0 = and i32 %a0, %a1
220  %not = xor i32 %a0, -1
221  %and1 = and i32 %not, %a2
222  %or = or i32 %and0, %and1
223  store i32 %and0, ptr %p1
224  ret i32 %or
225}
226
227; should not transform when operands have multiple users.
228define i32 @masked_merge_no_transform1(i32 %a0, i32 %a1, i32 %a2, ptr %p1) {
229; NOBMI-LABEL: masked_merge_no_transform1:
230; NOBMI:       # %bb.0:
231; NOBMI-NEXT:    movl %edx, %eax
232; NOBMI-NEXT:    andl %edi, %esi
233; NOBMI-NEXT:    notl %edi
234; NOBMI-NEXT:    andl %edi, %eax
235; NOBMI-NEXT:    orl %esi, %eax
236; NOBMI-NEXT:    movl %edi, (%rcx)
237; NOBMI-NEXT:    retq
238;
239; BMI-LABEL: masked_merge_no_transform1:
240; BMI:       # %bb.0:
241; BMI-NEXT:    andl %edi, %esi
242; BMI-NEXT:    andnl %edx, %edi, %eax
243; BMI-NEXT:    notl %edi
244; BMI-NEXT:    orl %esi, %eax
245; BMI-NEXT:    movl %edi, (%rcx)
246; BMI-NEXT:    retq
247  %and0 = and i32 %a0, %a1
248  %not = xor i32 %a0, -1
249  %and1 = and i32 %not, %a2
250  %or = or i32 %and0, %and1
251  store i32 %not, ptr %p1
252  ret i32 %or
253}
254
255; should not transform when operands have multiple users.
256define i32 @masked_merge_no_transform2(i32 %a0, i32 %a1, i32 %a2, ptr %p1) {
257; NOBMI-LABEL: masked_merge_no_transform2:
258; NOBMI:       # %bb.0:
259; NOBMI-NEXT:    movl %esi, %eax
260; NOBMI-NEXT:    andl %edi, %eax
261; NOBMI-NEXT:    notl %edi
262; NOBMI-NEXT:    andl %edx, %edi
263; NOBMI-NEXT:    orl %edi, %eax
264; NOBMI-NEXT:    movl %edi, (%rcx)
265; NOBMI-NEXT:    retq
266;
267; BMI-LABEL: masked_merge_no_transform2:
268; BMI:       # %bb.0:
269; BMI-NEXT:    movl %esi, %eax
270; BMI-NEXT:    andl %edi, %eax
271; BMI-NEXT:    andnl %edx, %edi, %edx
272; BMI-NEXT:    orl %edx, %eax
273; BMI-NEXT:    movl %edx, (%rcx)
274; BMI-NEXT:    retq
275  %and0 = and i32 %a0, %a1
276  %not = xor i32 %a0, -1
277  %and1 = and i32 %not, %a2
278  %or = or i32 %and0, %and1
279  store i32 %and1, ptr %p1
280  ret i32 %or
281}
282