1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=i686-unknown-linux-gnu             < %s | FileCheck %s   --check-prefixes=X86,NOBMI-X86
3; RUN: llc -mtriple=i686-unknown-linux-gnu -mattr=+bmi < %s | FileCheck %s   --check-prefixes=X86,BMI-X86
4; RUN: llc -mtriple=x86_64-unknown-linux-gnu             < %s | FileCheck %s --check-prefixes=X64,NOBMI-X64
5; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=+bmi < %s | FileCheck %s --check-prefixes=X64,BMI-X64
6
7; Fold
8;   ptr - (ptr & mask)
9; To
10;   ptr & (~mask)
11;
12; This needs to be a backend-level fold because only by now pointers
13; are just registers; in middle-end IR this can only be done via @llvm.ptrmask()
14; intrinsic which is not sufficiently widely-spread yet.
15;
16; https://bugs.llvm.org/show_bug.cgi?id=44448
17
18; The basic positive tests
19
20define i32 @t0_32(i32 %ptr, i32 %mask) nounwind {
21; NOBMI-X86-LABEL: t0_32:
22; NOBMI-X86:       # %bb.0:
23; NOBMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
24; NOBMI-X86-NEXT:    notl %eax
25; NOBMI-X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
26; NOBMI-X86-NEXT:    retl
27;
28; BMI-X86-LABEL: t0_32:
29; BMI-X86:       # %bb.0:
30; BMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
31; BMI-X86-NEXT:    andnl {{[0-9]+}}(%esp), %eax, %eax
32; BMI-X86-NEXT:    retl
33;
34; NOBMI-X64-LABEL: t0_32:
35; NOBMI-X64:       # %bb.0:
36; NOBMI-X64-NEXT:    movl %esi, %eax
37; NOBMI-X64-NEXT:    notl %eax
38; NOBMI-X64-NEXT:    andl %edi, %eax
39; NOBMI-X64-NEXT:    retq
40;
41; BMI-X64-LABEL: t0_32:
42; BMI-X64:       # %bb.0:
43; BMI-X64-NEXT:    andnl %edi, %esi, %eax
44; BMI-X64-NEXT:    retq
45  %bias = and i32 %ptr, %mask
46  %r = sub i32 %ptr, %bias
47  ret i32 %r
48}
49define i64 @t1_64(i64 %ptr, i64 %mask) nounwind {
50; NOBMI-X86-LABEL: t1_64:
51; NOBMI-X86:       # %bb.0:
52; NOBMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
53; NOBMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
54; NOBMI-X86-NEXT:    notl %eax
55; NOBMI-X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
56; NOBMI-X86-NEXT:    notl %edx
57; NOBMI-X86-NEXT:    andl {{[0-9]+}}(%esp), %edx
58; NOBMI-X86-NEXT:    retl
59;
60; BMI-X86-LABEL: t1_64:
61; BMI-X86:       # %bb.0:
62; BMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
63; BMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
64; BMI-X86-NEXT:    andnl {{[0-9]+}}(%esp), %eax, %eax
65; BMI-X86-NEXT:    andnl {{[0-9]+}}(%esp), %ecx, %edx
66; BMI-X86-NEXT:    retl
67;
68; NOBMI-X64-LABEL: t1_64:
69; NOBMI-X64:       # %bb.0:
70; NOBMI-X64-NEXT:    movq %rsi, %rax
71; NOBMI-X64-NEXT:    notq %rax
72; NOBMI-X64-NEXT:    andq %rdi, %rax
73; NOBMI-X64-NEXT:    retq
74;
75; BMI-X64-LABEL: t1_64:
76; BMI-X64:       # %bb.0:
77; BMI-X64-NEXT:    andnq %rdi, %rsi, %rax
78; BMI-X64-NEXT:    retq
79  %bias = and i64 %ptr, %mask
80  %r = sub i64 %ptr, %bias
81  ret i64 %r
82}
83
84define i32 @t2_commutative(i32 %ptr, i32 %mask) nounwind {
85; NOBMI-X86-LABEL: t2_commutative:
86; NOBMI-X86:       # %bb.0:
87; NOBMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
88; NOBMI-X86-NEXT:    notl %eax
89; NOBMI-X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
90; NOBMI-X86-NEXT:    retl
91;
92; BMI-X86-LABEL: t2_commutative:
93; BMI-X86:       # %bb.0:
94; BMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
95; BMI-X86-NEXT:    andnl {{[0-9]+}}(%esp), %eax, %eax
96; BMI-X86-NEXT:    retl
97;
98; NOBMI-X64-LABEL: t2_commutative:
99; NOBMI-X64:       # %bb.0:
100; NOBMI-X64-NEXT:    movl %esi, %eax
101; NOBMI-X64-NEXT:    notl %eax
102; NOBMI-X64-NEXT:    andl %edi, %eax
103; NOBMI-X64-NEXT:    retq
104;
105; BMI-X64-LABEL: t2_commutative:
106; BMI-X64:       # %bb.0:
107; BMI-X64-NEXT:    andnl %edi, %esi, %eax
108; BMI-X64-NEXT:    retq
109  %bias = and i32 %mask, %ptr ; swapped
110  %r = sub i32 %ptr, %bias
111  ret i32 %r
112}
113
114; Extra use tests
115
116define i32 @n3_extrause1(i32 %ptr, i32 %mask, i32* %bias_storage) nounwind {
117; X86-LABEL: n3_extrause1:
118; X86:       # %bb.0:
119; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
120; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
121; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
122; X86-NEXT:    andl %eax, %edx
123; X86-NEXT:    movl %edx, (%ecx)
124; X86-NEXT:    subl %edx, %eax
125; X86-NEXT:    retl
126;
127; X64-LABEL: n3_extrause1:
128; X64:       # %bb.0:
129; X64-NEXT:    movl %edi, %eax
130; X64-NEXT:    andl %edi, %esi
131; X64-NEXT:    movl %esi, (%rdx)
132; X64-NEXT:    subl %esi, %eax
133; X64-NEXT:    retq
134  %bias = and i32 %ptr, %mask ; has extra uses, can't fold
135  store i32 %bias, i32* %bias_storage
136  %r = sub i32 %ptr, %bias
137  ret i32 %r
138}
139
140; Negative tests
141
142define i32 @n4_different_ptrs(i32 %ptr0, i32 %ptr1, i32 %mask) nounwind {
143; X86-LABEL: n4_different_ptrs:
144; X86:       # %bb.0:
145; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
146; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
147; X86-NEXT:    andl {{[0-9]+}}(%esp), %ecx
148; X86-NEXT:    subl %ecx, %eax
149; X86-NEXT:    retl
150;
151; X64-LABEL: n4_different_ptrs:
152; X64:       # %bb.0:
153; X64-NEXT:    movl %edi, %eax
154; X64-NEXT:    andl %edx, %esi
155; X64-NEXT:    subl %esi, %eax
156; X64-NEXT:    retq
157  %bias = and i32 %ptr1, %mask ; not %ptr0
158  %r = sub i32 %ptr0, %bias ; not %ptr1
159  ret i32 %r
160}
161define i32 @n5_different_ptrs_commutative(i32 %ptr0, i32 %ptr1, i32 %mask) nounwind {
162; X86-LABEL: n5_different_ptrs_commutative:
163; X86:       # %bb.0:
164; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
165; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
166; X86-NEXT:    andl {{[0-9]+}}(%esp), %ecx
167; X86-NEXT:    subl %ecx, %eax
168; X86-NEXT:    retl
169;
170; X64-LABEL: n5_different_ptrs_commutative:
171; X64:       # %bb.0:
172; X64-NEXT:    movl %edi, %eax
173; X64-NEXT:    andl %edx, %esi
174; X64-NEXT:    subl %esi, %eax
175; X64-NEXT:    retq
176  %bias = and i32 %mask, %ptr1 ; swapped, not %ptr0
177  %r = sub i32 %ptr0, %bias ; not %ptr1
178  ret i32 %r
179}
180
181define i32 @n6_not_lowbit_mask(i32 %ptr, i32 %mask) nounwind {
182; NOBMI-X86-LABEL: n6_not_lowbit_mask:
183; NOBMI-X86:       # %bb.0:
184; NOBMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
185; NOBMI-X86-NEXT:    notl %eax
186; NOBMI-X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
187; NOBMI-X86-NEXT:    retl
188;
189; BMI-X86-LABEL: n6_not_lowbit_mask:
190; BMI-X86:       # %bb.0:
191; BMI-X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
192; BMI-X86-NEXT:    andnl {{[0-9]+}}(%esp), %eax, %eax
193; BMI-X86-NEXT:    retl
194;
195; NOBMI-X64-LABEL: n6_not_lowbit_mask:
196; NOBMI-X64:       # %bb.0:
197; NOBMI-X64-NEXT:    movl %esi, %eax
198; NOBMI-X64-NEXT:    notl %eax
199; NOBMI-X64-NEXT:    andl %edi, %eax
200; NOBMI-X64-NEXT:    retq
201;
202; BMI-X64-LABEL: n6_not_lowbit_mask:
203; BMI-X64:       # %bb.0:
204; BMI-X64-NEXT:    andnl %edi, %esi, %eax
205; BMI-X64-NEXT:    retq
206  %bias = and i32 %ptr, %mask
207  %r = sub i32 %ptr, %bias
208  ret i32 %r
209}
210
211define i32 @n7_sub_is_not_commutative(i32 %ptr, i32 %mask) nounwind {
212; X86-LABEL: n7_sub_is_not_commutative:
213; X86:       # %bb.0:
214; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
215; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
216; X86-NEXT:    andl %ecx, %eax
217; X86-NEXT:    subl %ecx, %eax
218; X86-NEXT:    retl
219;
220; X64-LABEL: n7_sub_is_not_commutative:
221; X64:       # %bb.0:
222; X64-NEXT:    movl %esi, %eax
223; X64-NEXT:    andl %edi, %eax
224; X64-NEXT:    subl %edi, %eax
225; X64-NEXT:    retq
226  %bias = and i32 %ptr, %mask
227  %r = sub i32 %bias, %ptr ; wrong order
228  ret i32 %r
229}
230