1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=-bmi < %s | FileCheck %s --check-prefix=CHECK-NOBMI
3; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=+bmi < %s | FileCheck %s --check-prefix=CHECK-BMI
4
5; https://bugs.llvm.org/show_bug.cgi?id=37104
6
7; X:               [byte1][byte0]
8; Y: [byte3][byte2]
9
10define i8 @out8_constmask(i8 %x, i8 %y) {
11; CHECK-NOBMI-LABEL: out8_constmask:
12; CHECK-NOBMI:       # %bb.0:
13; CHECK-NOBMI-NEXT:    # kill: def $esi killed $esi def $rsi
14; CHECK-NOBMI-NEXT:    # kill: def $edi killed $edi def $rdi
15; CHECK-NOBMI-NEXT:    andb $15, %dil
16; CHECK-NOBMI-NEXT:    andb $-16, %sil
17; CHECK-NOBMI-NEXT:    leal (%rsi,%rdi), %eax
18; CHECK-NOBMI-NEXT:    # kill: def $al killed $al killed $eax
19; CHECK-NOBMI-NEXT:    retq
20;
21; CHECK-BMI-LABEL: out8_constmask:
22; CHECK-BMI:       # %bb.0:
23; CHECK-BMI-NEXT:    # kill: def $esi killed $esi def $rsi
24; CHECK-BMI-NEXT:    # kill: def $edi killed $edi def $rdi
25; CHECK-BMI-NEXT:    andb $15, %dil
26; CHECK-BMI-NEXT:    andb $-16, %sil
27; CHECK-BMI-NEXT:    leal (%rsi,%rdi), %eax
28; CHECK-BMI-NEXT:    # kill: def $al killed $al killed $eax
29; CHECK-BMI-NEXT:    retq
30  %mx = and i8 %x, 15
31  %my = and i8 %y, -16
32  %r = or i8 %mx, %my
33  ret i8 %r
34}
35
36define i16 @out16_constmask(i16 %x, i16 %y) {
37; CHECK-NOBMI-LABEL: out16_constmask:
38; CHECK-NOBMI:       # %bb.0:
39; CHECK-NOBMI-NEXT:    movzbl %dil, %eax
40; CHECK-NOBMI-NEXT:    andl $-256, %esi
41; CHECK-NOBMI-NEXT:    orl %esi, %eax
42; CHECK-NOBMI-NEXT:    # kill: def $ax killed $ax killed $eax
43; CHECK-NOBMI-NEXT:    retq
44;
45; CHECK-BMI-LABEL: out16_constmask:
46; CHECK-BMI:       # %bb.0:
47; CHECK-BMI-NEXT:    movzbl %dil, %eax
48; CHECK-BMI-NEXT:    andl $-256, %esi
49; CHECK-BMI-NEXT:    orl %esi, %eax
50; CHECK-BMI-NEXT:    # kill: def $ax killed $ax killed $eax
51; CHECK-BMI-NEXT:    retq
52  %mx = and i16 %x, 255
53  %my = and i16 %y, -256
54  %r = or i16 %mx, %my
55  ret i16 %r
56}
57
58define i32 @out32_constmask(i32 %x, i32 %y) {
59; CHECK-NOBMI-LABEL: out32_constmask:
60; CHECK-NOBMI:       # %bb.0:
61; CHECK-NOBMI-NEXT:    movzwl %di, %eax
62; CHECK-NOBMI-NEXT:    andl $-65536, %esi # imm = 0xFFFF0000
63; CHECK-NOBMI-NEXT:    orl %esi, %eax
64; CHECK-NOBMI-NEXT:    retq
65;
66; CHECK-BMI-LABEL: out32_constmask:
67; CHECK-BMI:       # %bb.0:
68; CHECK-BMI-NEXT:    movzwl %di, %eax
69; CHECK-BMI-NEXT:    andl $-65536, %esi # imm = 0xFFFF0000
70; CHECK-BMI-NEXT:    orl %esi, %eax
71; CHECK-BMI-NEXT:    retq
72  %mx = and i32 %x, 65535
73  %my = and i32 %y, -65536
74  %r = or i32 %mx, %my
75  ret i32 %r
76}
77
78define i64 @out64_constmask(i64 %x, i64 %y) {
79; CHECK-NOBMI-LABEL: out64_constmask:
80; CHECK-NOBMI:       # %bb.0:
81; CHECK-NOBMI-NEXT:    movl %edi, %ecx
82; CHECK-NOBMI-NEXT:    movabsq $-4294967296, %rax # imm = 0xFFFFFFFF00000000
83; CHECK-NOBMI-NEXT:    andq %rsi, %rax
84; CHECK-NOBMI-NEXT:    orq %rcx, %rax
85; CHECK-NOBMI-NEXT:    retq
86;
87; CHECK-BMI-LABEL: out64_constmask:
88; CHECK-BMI:       # %bb.0:
89; CHECK-BMI-NEXT:    movl %edi, %ecx
90; CHECK-BMI-NEXT:    movabsq $-4294967296, %rax # imm = 0xFFFFFFFF00000000
91; CHECK-BMI-NEXT:    andq %rsi, %rax
92; CHECK-BMI-NEXT:    orq %rcx, %rax
93; CHECK-BMI-NEXT:    retq
94  %mx = and i64 %x, 4294967295
95  %my = and i64 %y, -4294967296
96  %r = or i64 %mx, %my
97  ret i64 %r
98}
99
100;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
101; Should be the same as the previous one.
102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
103
104define i8 @in8_constmask(i8 %x, i8 %y) {
105; CHECK-NOBMI-LABEL: in8_constmask:
106; CHECK-NOBMI:       # %bb.0:
107; CHECK-NOBMI-NEXT:    movl %esi, %eax
108; CHECK-NOBMI-NEXT:    xorl %esi, %edi
109; CHECK-NOBMI-NEXT:    andb $15, %dil
110; CHECK-NOBMI-NEXT:    xorb %dil, %al
111; CHECK-NOBMI-NEXT:    # kill: def $al killed $al killed $eax
112; CHECK-NOBMI-NEXT:    retq
113;
114; CHECK-BMI-LABEL: in8_constmask:
115; CHECK-BMI:       # %bb.0:
116; CHECK-BMI-NEXT:    movl %esi, %eax
117; CHECK-BMI-NEXT:    xorl %esi, %edi
118; CHECK-BMI-NEXT:    andb $15, %dil
119; CHECK-BMI-NEXT:    xorb %dil, %al
120; CHECK-BMI-NEXT:    # kill: def $al killed $al killed $eax
121; CHECK-BMI-NEXT:    retq
122  %n0 = xor i8 %x, %y
123  %n1 = and i8 %n0, 15
124  %r = xor i8 %n1, %y
125  ret i8 %r
126}
127
128define i16 @in16_constmask(i16 %x, i16 %y) {
129; CHECK-NOBMI-LABEL: in16_constmask:
130; CHECK-NOBMI:       # %bb.0:
131; CHECK-NOBMI-NEXT:    xorl %esi, %edi
132; CHECK-NOBMI-NEXT:    movzbl %dil, %eax
133; CHECK-NOBMI-NEXT:    xorl %esi, %eax
134; CHECK-NOBMI-NEXT:    # kill: def $ax killed $ax killed $eax
135; CHECK-NOBMI-NEXT:    retq
136;
137; CHECK-BMI-LABEL: in16_constmask:
138; CHECK-BMI:       # %bb.0:
139; CHECK-BMI-NEXT:    xorl %esi, %edi
140; CHECK-BMI-NEXT:    movzbl %dil, %eax
141; CHECK-BMI-NEXT:    xorl %esi, %eax
142; CHECK-BMI-NEXT:    # kill: def $ax killed $ax killed $eax
143; CHECK-BMI-NEXT:    retq
144  %n0 = xor i16 %x, %y
145  %n1 = and i16 %n0, 255
146  %r = xor i16 %n1, %y
147  ret i16 %r
148}
149
150define i32 @in32_constmask(i32 %x, i32 %y) {
151; CHECK-NOBMI-LABEL: in32_constmask:
152; CHECK-NOBMI:       # %bb.0:
153; CHECK-NOBMI-NEXT:    xorl %esi, %edi
154; CHECK-NOBMI-NEXT:    movzwl %di, %eax
155; CHECK-NOBMI-NEXT:    xorl %esi, %eax
156; CHECK-NOBMI-NEXT:    retq
157;
158; CHECK-BMI-LABEL: in32_constmask:
159; CHECK-BMI:       # %bb.0:
160; CHECK-BMI-NEXT:    xorl %esi, %edi
161; CHECK-BMI-NEXT:    movzwl %di, %eax
162; CHECK-BMI-NEXT:    xorl %esi, %eax
163; CHECK-BMI-NEXT:    retq
164  %n0 = xor i32 %x, %y
165  %n1 = and i32 %n0, 65535
166  %r = xor i32 %n1, %y
167  ret i32 %r
168}
169
170define i64 @in64_constmask(i64 %x, i64 %y) {
171; CHECK-NOBMI-LABEL: in64_constmask:
172; CHECK-NOBMI:       # %bb.0:
173; CHECK-NOBMI-NEXT:    movl %esi, %eax
174; CHECK-NOBMI-NEXT:    xorl %edi, %eax
175; CHECK-NOBMI-NEXT:    xorq %rsi, %rax
176; CHECK-NOBMI-NEXT:    retq
177;
178; CHECK-BMI-LABEL: in64_constmask:
179; CHECK-BMI:       # %bb.0:
180; CHECK-BMI-NEXT:    movl %esi, %eax
181; CHECK-BMI-NEXT:    xorl %edi, %eax
182; CHECK-BMI-NEXT:    xorq %rsi, %rax
183; CHECK-BMI-NEXT:    retq
184  %n0 = xor i64 %x, %y
185  %n1 = and i64 %n0, 4294967295
186  %r = xor i64 %n1, %y
187  ret i64 %r
188}
189
190; ============================================================================ ;
191; Constant Commutativity tests.
192; ============================================================================ ;
193
194define i32 @in_constmask_commutativity_0_1(i32 %x, i32 %y) {
195; CHECK-NOBMI-LABEL: in_constmask_commutativity_0_1:
196; CHECK-NOBMI:       # %bb.0:
197; CHECK-NOBMI-NEXT:    xorl %esi, %edi
198; CHECK-NOBMI-NEXT:    movzwl %di, %eax
199; CHECK-NOBMI-NEXT:    xorl %esi, %eax
200; CHECK-NOBMI-NEXT:    retq
201;
202; CHECK-BMI-LABEL: in_constmask_commutativity_0_1:
203; CHECK-BMI:       # %bb.0:
204; CHECK-BMI-NEXT:    xorl %esi, %edi
205; CHECK-BMI-NEXT:    movzwl %di, %eax
206; CHECK-BMI-NEXT:    xorl %esi, %eax
207; CHECK-BMI-NEXT:    retq
208  %n0 = xor i32 %x, %y
209  %n1 = and i32 %n0, 65535
210  %r = xor i32 %y, %n1 ; swapped
211  ret i32 %r
212}
213
214define i32 @in_constmask_commutativity_1_0(i32 %x, i32 %y) {
215; CHECK-NOBMI-LABEL: in_constmask_commutativity_1_0:
216; CHECK-NOBMI:       # %bb.0:
217; CHECK-NOBMI-NEXT:    xorl %edi, %esi
218; CHECK-NOBMI-NEXT:    movzwl %si, %eax
219; CHECK-NOBMI-NEXT:    xorl %edi, %eax
220; CHECK-NOBMI-NEXT:    retq
221;
222; CHECK-BMI-LABEL: in_constmask_commutativity_1_0:
223; CHECK-BMI:       # %bb.0:
224; CHECK-BMI-NEXT:    xorl %edi, %esi
225; CHECK-BMI-NEXT:    movzwl %si, %eax
226; CHECK-BMI-NEXT:    xorl %edi, %eax
227; CHECK-BMI-NEXT:    retq
228  %n0 = xor i32 %x, %y
229  %n1 = and i32 %n0, 65535
230  %r = xor i32 %n1, %x ; %x instead of %y
231  ret i32 %r
232}
233
234define i32 @in_constmask_commutativity_1_1(i32 %x, i32 %y) {
235; CHECK-NOBMI-LABEL: in_constmask_commutativity_1_1:
236; CHECK-NOBMI:       # %bb.0:
237; CHECK-NOBMI-NEXT:    xorl %edi, %esi
238; CHECK-NOBMI-NEXT:    movzwl %si, %eax
239; CHECK-NOBMI-NEXT:    xorl %edi, %eax
240; CHECK-NOBMI-NEXT:    retq
241;
242; CHECK-BMI-LABEL: in_constmask_commutativity_1_1:
243; CHECK-BMI:       # %bb.0:
244; CHECK-BMI-NEXT:    xorl %edi, %esi
245; CHECK-BMI-NEXT:    movzwl %si, %eax
246; CHECK-BMI-NEXT:    xorl %edi, %eax
247; CHECK-BMI-NEXT:    retq
248  %n0 = xor i32 %x, %y
249  %n1 = and i32 %n0, 65535
250  %r = xor i32 %x, %n1 ; swapped, %x instead of %y
251  ret i32 %r
252}
253
254; ============================================================================ ;
255; Y is an 'and' too.
256; ============================================================================ ;
257
258define i32 @in_complex_y0_constmask(i32 %x, i32 %y_hi, i32 %y_low) {
259; CHECK-NOBMI-LABEL: in_complex_y0_constmask:
260; CHECK-NOBMI:       # %bb.0:
261; CHECK-NOBMI-NEXT:    andl %edx, %esi
262; CHECK-NOBMI-NEXT:    xorl %esi, %edi
263; CHECK-NOBMI-NEXT:    movzwl %di, %eax
264; CHECK-NOBMI-NEXT:    xorl %esi, %eax
265; CHECK-NOBMI-NEXT:    retq
266;
267; CHECK-BMI-LABEL: in_complex_y0_constmask:
268; CHECK-BMI:       # %bb.0:
269; CHECK-BMI-NEXT:    andl %edx, %esi
270; CHECK-BMI-NEXT:    xorl %esi, %edi
271; CHECK-BMI-NEXT:    movzwl %di, %eax
272; CHECK-BMI-NEXT:    xorl %esi, %eax
273; CHECK-BMI-NEXT:    retq
274  %y = and i32 %y_hi, %y_low
275  %n0 = xor i32 %x, %y
276  %n1 = and i32 %n0, 65535
277  %r = xor i32 %n1, %y
278  ret i32 %r
279}
280
281define i32 @in_complex_y1_constmask(i32 %x, i32 %y_hi, i32 %y_low) {
282; CHECK-NOBMI-LABEL: in_complex_y1_constmask:
283; CHECK-NOBMI:       # %bb.0:
284; CHECK-NOBMI-NEXT:    andl %edx, %esi
285; CHECK-NOBMI-NEXT:    xorl %esi, %edi
286; CHECK-NOBMI-NEXT:    movzwl %di, %eax
287; CHECK-NOBMI-NEXT:    xorl %esi, %eax
288; CHECK-NOBMI-NEXT:    retq
289;
290; CHECK-BMI-LABEL: in_complex_y1_constmask:
291; CHECK-BMI:       # %bb.0:
292; CHECK-BMI-NEXT:    andl %edx, %esi
293; CHECK-BMI-NEXT:    xorl %esi, %edi
294; CHECK-BMI-NEXT:    movzwl %di, %eax
295; CHECK-BMI-NEXT:    xorl %esi, %eax
296; CHECK-BMI-NEXT:    retq
297  %y = and i32 %y_hi, %y_low
298  %n0 = xor i32 %x, %y
299  %n1 = and i32 %n0, 65535
300  %r = xor i32 %y, %n1
301  ret i32 %r
302}
303
304; ============================================================================ ;
305; Negative tests. Should not be folded.
306; ============================================================================ ;
307
308; Multi-use tests.
309
310declare void @use32(i32) nounwind
311
312define i32 @in_multiuse_A_constmask(i32 %x, i32 %y, i32 %z) nounwind {
313; CHECK-NOBMI-LABEL: in_multiuse_A_constmask:
314; CHECK-NOBMI:       # %bb.0:
315; CHECK-NOBMI-NEXT:    pushq %rbp
316; CHECK-NOBMI-NEXT:    pushq %rbx
317; CHECK-NOBMI-NEXT:    pushq %rax
318; CHECK-NOBMI-NEXT:    movl %esi, %ebx
319; CHECK-NOBMI-NEXT:    xorl %esi, %edi
320; CHECK-NOBMI-NEXT:    movzwl %di, %ebp
321; CHECK-NOBMI-NEXT:    movl %ebp, %edi
322; CHECK-NOBMI-NEXT:    callq use32
323; CHECK-NOBMI-NEXT:    xorl %ebx, %ebp
324; CHECK-NOBMI-NEXT:    movl %ebp, %eax
325; CHECK-NOBMI-NEXT:    addq $8, %rsp
326; CHECK-NOBMI-NEXT:    popq %rbx
327; CHECK-NOBMI-NEXT:    popq %rbp
328; CHECK-NOBMI-NEXT:    retq
329;
330; CHECK-BMI-LABEL: in_multiuse_A_constmask:
331; CHECK-BMI:       # %bb.0:
332; CHECK-BMI-NEXT:    pushq %rbp
333; CHECK-BMI-NEXT:    pushq %rbx
334; CHECK-BMI-NEXT:    pushq %rax
335; CHECK-BMI-NEXT:    movl %esi, %ebx
336; CHECK-BMI-NEXT:    xorl %esi, %edi
337; CHECK-BMI-NEXT:    movzwl %di, %ebp
338; CHECK-BMI-NEXT:    movl %ebp, %edi
339; CHECK-BMI-NEXT:    callq use32
340; CHECK-BMI-NEXT:    xorl %ebx, %ebp
341; CHECK-BMI-NEXT:    movl %ebp, %eax
342; CHECK-BMI-NEXT:    addq $8, %rsp
343; CHECK-BMI-NEXT:    popq %rbx
344; CHECK-BMI-NEXT:    popq %rbp
345; CHECK-BMI-NEXT:    retq
346  %n0 = xor i32 %x, %y
347  %n1 = and i32 %n0, 65535
348  call void @use32(i32 %n1)
349  %r = xor i32 %n1, %y
350  ret i32 %r
351}
352
353define i32 @in_multiuse_B_constmask(i32 %x, i32 %y, i32 %z) nounwind {
354; CHECK-NOBMI-LABEL: in_multiuse_B_constmask:
355; CHECK-NOBMI:       # %bb.0:
356; CHECK-NOBMI-NEXT:    pushq %rbp
357; CHECK-NOBMI-NEXT:    pushq %rbx
358; CHECK-NOBMI-NEXT:    pushq %rax
359; CHECK-NOBMI-NEXT:    movl %esi, %ebx
360; CHECK-NOBMI-NEXT:    xorl %esi, %edi
361; CHECK-NOBMI-NEXT:    movzwl %di, %ebp
362; CHECK-NOBMI-NEXT:    callq use32
363; CHECK-NOBMI-NEXT:    xorl %ebx, %ebp
364; CHECK-NOBMI-NEXT:    movl %ebp, %eax
365; CHECK-NOBMI-NEXT:    addq $8, %rsp
366; CHECK-NOBMI-NEXT:    popq %rbx
367; CHECK-NOBMI-NEXT:    popq %rbp
368; CHECK-NOBMI-NEXT:    retq
369;
370; CHECK-BMI-LABEL: in_multiuse_B_constmask:
371; CHECK-BMI:       # %bb.0:
372; CHECK-BMI-NEXT:    pushq %rbp
373; CHECK-BMI-NEXT:    pushq %rbx
374; CHECK-BMI-NEXT:    pushq %rax
375; CHECK-BMI-NEXT:    movl %esi, %ebx
376; CHECK-BMI-NEXT:    xorl %esi, %edi
377; CHECK-BMI-NEXT:    movzwl %di, %ebp
378; CHECK-BMI-NEXT:    callq use32
379; CHECK-BMI-NEXT:    xorl %ebx, %ebp
380; CHECK-BMI-NEXT:    movl %ebp, %eax
381; CHECK-BMI-NEXT:    addq $8, %rsp
382; CHECK-BMI-NEXT:    popq %rbx
383; CHECK-BMI-NEXT:    popq %rbp
384; CHECK-BMI-NEXT:    retq
385  %n0 = xor i32 %x, %y
386  %n1 = and i32 %n0, 65535
387  call void @use32(i32 %n0)
388  %r = xor i32 %n1, %y
389  ret i32 %r
390}
391
392; Various bad variants
393
394define i32 @n0_badconstmask(i32 %x, i32 %y) {
395; CHECK-NOBMI-LABEL: n0_badconstmask:
396; CHECK-NOBMI:       # %bb.0:
397; CHECK-NOBMI-NEXT:    movzwl %di, %eax
398; CHECK-NOBMI-NEXT:    andl $-65535, %esi # imm = 0xFFFF0001
399; CHECK-NOBMI-NEXT:    orl %esi, %eax
400; CHECK-NOBMI-NEXT:    retq
401;
402; CHECK-BMI-LABEL: n0_badconstmask:
403; CHECK-BMI:       # %bb.0:
404; CHECK-BMI-NEXT:    movzwl %di, %eax
405; CHECK-BMI-NEXT:    andl $-65535, %esi # imm = 0xFFFF0001
406; CHECK-BMI-NEXT:    orl %esi, %eax
407; CHECK-BMI-NEXT:    retq
408  %mx = and i32 %x, 65535
409  %my = and i32 %y, -65535 ; instead of -65536
410  %r = or i32 %mx, %my
411  ret i32 %r
412}
413
414define i32 @n1_thirdvar_constmask(i32 %x, i32 %y, i32 %z) {
415; CHECK-NOBMI-LABEL: n1_thirdvar_constmask:
416; CHECK-NOBMI:       # %bb.0:
417; CHECK-NOBMI-NEXT:    xorl %esi, %edi
418; CHECK-NOBMI-NEXT:    movzwl %di, %eax
419; CHECK-NOBMI-NEXT:    xorl %edx, %eax
420; CHECK-NOBMI-NEXT:    retq
421;
422; CHECK-BMI-LABEL: n1_thirdvar_constmask:
423; CHECK-BMI:       # %bb.0:
424; CHECK-BMI-NEXT:    xorl %esi, %edi
425; CHECK-BMI-NEXT:    movzwl %di, %eax
426; CHECK-BMI-NEXT:    xorl %edx, %eax
427; CHECK-BMI-NEXT:    retq
428  %n0 = xor i32 %x, %y
429  %n1 = and i32 %n0, 65535
430  %r = xor i32 %n1, %z ; instead of %y
431  ret i32 %r
432}
433