1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s
3
4; Select of constants: control flow / conditional moves can always be replaced by logic+math (but may not be worth it?).
5; Test the zeroext/signext variants of each pattern to see if that makes a difference.
6
7; select Cond, 0, 1 --> zext (!Cond)
8
9define i32 @select_0_or_1(i1 %cond) {
10; CHECK-LABEL: select_0_or_1:
11; CHECK:       # BB#0:
12; CHECK-NEXT:    notb %dil
13; CHECK-NEXT:    movzbl %dil, %eax
14; CHECK-NEXT:    andl $1, %eax
15; CHECK-NEXT:    retq
16  %sel = select i1 %cond, i32 0, i32 1
17  ret i32 %sel
18}
19
20define i32 @select_0_or_1_zeroext(i1 zeroext %cond) {
21; CHECK-LABEL: select_0_or_1_zeroext:
22; CHECK:       # BB#0:
23; CHECK-NEXT:    xorb $1, %dil
24; CHECK-NEXT:    movzbl %dil, %eax
25; CHECK-NEXT:    retq
26  %sel = select i1 %cond, i32 0, i32 1
27  ret i32 %sel
28}
29
30define i32 @select_0_or_1_signext(i1 signext %cond) {
31; CHECK-LABEL: select_0_or_1_signext:
32; CHECK:       # BB#0:
33; CHECK-NEXT:    notb %dil
34; CHECK-NEXT:    movzbl %dil, %eax
35; CHECK-NEXT:    andl $1, %eax
36; CHECK-NEXT:    retq
37  %sel = select i1 %cond, i32 0, i32 1
38  ret i32 %sel
39}
40
41; select Cond, 1, 0 --> zext (Cond)
42
43define i32 @select_1_or_0(i1 %cond) {
44; CHECK-LABEL: select_1_or_0:
45; CHECK:       # BB#0:
46; CHECK-NEXT:    andl $1, %edi
47; CHECK-NEXT:    movl %edi, %eax
48; CHECK-NEXT:    retq
49  %sel = select i1 %cond, i32 1, i32 0
50  ret i32 %sel
51}
52
53define i32 @select_1_or_0_zeroext(i1 zeroext %cond) {
54; CHECK-LABEL: select_1_or_0_zeroext:
55; CHECK:       # BB#0:
56; CHECK-NEXT:    movzbl %dil, %eax
57; CHECK-NEXT:    retq
58  %sel = select i1 %cond, i32 1, i32 0
59  ret i32 %sel
60}
61
62define i32 @select_1_or_0_signext(i1 signext %cond) {
63; CHECK-LABEL: select_1_or_0_signext:
64; CHECK:       # BB#0:
65; CHECK-NEXT:    andb $1, %dil
66; CHECK-NEXT:    movzbl %dil, %eax
67; CHECK-NEXT:    retq
68  %sel = select i1 %cond, i32 1, i32 0
69  ret i32 %sel
70}
71
72; select Cond, 0, -1 --> sext (!Cond)
73
74define i32 @select_0_or_neg1(i1 %cond) {
75; CHECK-LABEL: select_0_or_neg1:
76; CHECK:       # BB#0:
77; CHECK-NEXT:    # kill: %EDI<def> %EDI<kill> %RDI<def>
78; CHECK-NEXT:    andl $1, %edi
79; CHECK-NEXT:    leal -1(%rdi), %eax
80; CHECK-NEXT:    retq
81  %sel = select i1 %cond, i32 0, i32 -1
82  ret i32 %sel
83}
84
85define i32 @select_0_or_neg1_zeroext(i1 zeroext %cond) {
86; CHECK-LABEL: select_0_or_neg1_zeroext:
87; CHECK:       # BB#0:
88; CHECK-NEXT:    movzbl %dil, %eax
89; CHECK-NEXT:    decl %eax
90; CHECK-NEXT:    retq
91  %sel = select i1 %cond, i32 0, i32 -1
92  ret i32 %sel
93}
94
95define i32 @select_0_or_neg1_signext(i1 signext %cond) {
96; CHECK-LABEL: select_0_or_neg1_signext:
97; CHECK:       # BB#0:
98; CHECK-NEXT:    andb $1, %dil
99; CHECK-NEXT:    movzbl %dil, %eax
100; CHECK-NEXT:    decl %eax
101; CHECK-NEXT:    retq
102  %sel = select i1 %cond, i32 0, i32 -1
103  ret i32 %sel
104}
105
106; select Cond, -1, 0 --> sext (Cond)
107
108define i32 @select_neg1_or_0(i1 %cond) {
109; CHECK-LABEL: select_neg1_or_0:
110; CHECK:       # BB#0:
111; CHECK-NEXT:    andl $1, %edi
112; CHECK-NEXT:    negl %edi
113; CHECK-NEXT:    movl %edi, %eax
114; CHECK-NEXT:    retq
115  %sel = select i1 %cond, i32 -1, i32 0
116  ret i32 %sel
117}
118
119define i32 @select_neg1_or_0_zeroext(i1 zeroext %cond) {
120; CHECK-LABEL: select_neg1_or_0_zeroext:
121; CHECK:       # BB#0:
122; CHECK-NEXT:    movzbl %dil, %eax
123; CHECK-NEXT:    negl %eax
124; CHECK-NEXT:    retq
125  %sel = select i1 %cond, i32 -1, i32 0
126  ret i32 %sel
127}
128
129define i32 @select_neg1_or_0_signext(i1 signext %cond) {
130; CHECK-LABEL: select_neg1_or_0_signext:
131; CHECK:       # BB#0:
132; CHECK-NEXT:    movsbl %dil, %eax
133; CHECK-NEXT:    retq
134  %sel = select i1 %cond, i32 -1, i32 0
135  ret i32 %sel
136}
137
138; select Cond, C+1, C --> add (zext Cond), C
139
140define i32 @select_Cplus1_C(i1 %cond) {
141; CHECK-LABEL: select_Cplus1_C:
142; CHECK:       # BB#0:
143; CHECK-NEXT:    # kill: %EDI<def> %EDI<kill> %RDI<def>
144; CHECK-NEXT:    andl $1, %edi
145; CHECK-NEXT:    leal 41(%rdi), %eax
146; CHECK-NEXT:    retq
147  %sel = select i1 %cond, i32 42, i32 41
148  ret i32 %sel
149}
150
151define i32 @select_Cplus1_C_zeroext(i1 zeroext %cond) {
152; CHECK-LABEL: select_Cplus1_C_zeroext:
153; CHECK:       # BB#0:
154; CHECK-NEXT:    movzbl %dil, %eax
155; CHECK-NEXT:    addl $41, %eax
156; CHECK-NEXT:    retq
157  %sel = select i1 %cond, i32 42, i32 41
158  ret i32 %sel
159}
160
161define i32 @select_Cplus1_C_signext(i1 signext %cond) {
162; CHECK-LABEL: select_Cplus1_C_signext:
163; CHECK:       # BB#0:
164; CHECK-NEXT:    andb $1, %dil
165; CHECK-NEXT:    movzbl %dil, %eax
166; CHECK-NEXT:    addl $41, %eax
167; CHECK-NEXT:    retq
168  %sel = select i1 %cond, i32 42, i32 41
169  ret i32 %sel
170}
171
172; select Cond, C, C+1 --> add (sext Cond), C
173
174define i32 @select_C_Cplus1(i1 %cond) {
175; CHECK-LABEL: select_C_Cplus1:
176; CHECK:       # BB#0:
177; CHECK-NEXT:    andb $1, %dil
178; CHECK-NEXT:    cmpb $1, %dil
179; CHECK-NEXT:    movl $41, %eax
180; CHECK-NEXT:    adcl $0, %eax
181; CHECK-NEXT:    retq
182  %sel = select i1 %cond, i32 41, i32 42
183  ret i32 %sel
184}
185
186define i32 @select_C_Cplus1_zeroext(i1 zeroext %cond) {
187; CHECK-LABEL: select_C_Cplus1_zeroext:
188; CHECK:       # BB#0:
189; CHECK-NEXT:    cmpb $1, %dil
190; CHECK-NEXT:    movl $41, %eax
191; CHECK-NEXT:    adcl $0, %eax
192; CHECK-NEXT:    retq
193  %sel = select i1 %cond, i32 41, i32 42
194  ret i32 %sel
195}
196
197define i32 @select_C_Cplus1_signext(i1 signext %cond) {
198; CHECK-LABEL: select_C_Cplus1_signext:
199; CHECK:       # BB#0:
200; CHECK-NEXT:    andb $1, %dil
201; CHECK-NEXT:    cmpb $1, %dil
202; CHECK-NEXT:    movl $41, %eax
203; CHECK-NEXT:    adcl $0, %eax
204; CHECK-NEXT:    retq
205  %sel = select i1 %cond, i32 41, i32 42
206  ret i32 %sel
207}
208
209; In general, select of 2 constants could be:
210; select Cond, C1, C2 --> add (mul (zext Cond), C1-C2), C2 --> add (and (sext Cond), C1-C2), C2
211
212define i32 @select_C1_C2(i1 %cond) {
213; CHECK-LABEL: select_C1_C2:
214; CHECK:       # BB#0:
215; CHECK-NEXT:    testb $1, %dil
216; CHECK-NEXT:    movl $421, %ecx # imm = 0x1A5
217; CHECK-NEXT:    movl $42, %eax
218; CHECK-NEXT:    cmovnel %ecx, %eax
219; CHECK-NEXT:    retq
220  %sel = select i1 %cond, i32 421, i32 42
221  ret i32 %sel
222}
223
224define i32 @select_C1_C2_zeroext(i1 zeroext %cond) {
225; CHECK-LABEL: select_C1_C2_zeroext:
226; CHECK:       # BB#0:
227; CHECK-NEXT:    testb %dil, %dil
228; CHECK-NEXT:    movl $421, %ecx # imm = 0x1A5
229; CHECK-NEXT:    movl $42, %eax
230; CHECK-NEXT:    cmovnel %ecx, %eax
231; CHECK-NEXT:    retq
232  %sel = select i1 %cond, i32 421, i32 42
233  ret i32 %sel
234}
235
236define i32 @select_C1_C2_signext(i1 signext %cond) {
237; CHECK-LABEL: select_C1_C2_signext:
238; CHECK:       # BB#0:
239; CHECK-NEXT:    testb $1, %dil
240; CHECK-NEXT:    movl $421, %ecx # imm = 0x1A5
241; CHECK-NEXT:    movl $42, %eax
242; CHECK-NEXT:    cmovnel %ecx, %eax
243; CHECK-NEXT:    retq
244  %sel = select i1 %cond, i32 421, i32 42
245  ret i32 %sel
246}
247
248; select (x == 2), 2, (x + 1) --> select (x == 2), x, (x + 1)
249
250define i64 @select_2_or_inc(i64 %x) {
251; CHECK-LABEL: select_2_or_inc:
252; CHECK:       # BB#0:
253; CHECK-NEXT:    leaq 1(%rdi), %rax
254; CHECK-NEXT:    cmpq $2, %rdi
255; CHECK-NEXT:    cmoveq %rdi, %rax
256; CHECK-NEXT:    retq
257  %cmp = icmp eq i64 %x, 2
258  %add = add i64 %x, 1
259  %retval.0 = select i1 %cmp, i64 2, i64 %add
260  ret i64 %retval.0
261}
262
263define <4 x i32> @sel_constants_add_constant_vec(i1 %cond) {
264; CHECK-LABEL: sel_constants_add_constant_vec:
265; CHECK:       # BB#0:
266; CHECK-NEXT:    testb $1, %dil
267; CHECK-NEXT:    jne .LBB22_1
268; CHECK-NEXT:  # BB#2:
269; CHECK-NEXT:    movaps {{.*#+}} xmm0 = [12,13,14,15]
270; CHECK-NEXT:    retq
271; CHECK-NEXT:  .LBB22_1:
272; CHECK-NEXT:    movaps {{.*#+}} xmm0 = [4294967293,14,4,4]
273; CHECK-NEXT:    retq
274  %sel = select i1 %cond, <4 x i32> <i32 -4, i32 12, i32 1, i32 0>, <4 x i32> <i32 11, i32 11, i32 11, i32 11>
275  %bo = add <4 x i32> %sel, <i32 1, i32 2, i32 3, i32 4>
276  ret <4 x i32> %bo
277}
278
279define <2 x double> @sel_constants_fmul_constant_vec(i1 %cond) {
280; CHECK-LABEL: sel_constants_fmul_constant_vec:
281; CHECK:       # BB#0:
282; CHECK-NEXT:    testb $1, %dil
283; CHECK-NEXT:    jne .LBB23_1
284; CHECK-NEXT:  # BB#2:
285; CHECK-NEXT:    movaps {{.*#+}} xmm0 = [1.188300e+02,3.454000e+01]
286; CHECK-NEXT:    retq
287; CHECK-NEXT:  .LBB23_1:
288; CHECK-NEXT:    movaps {{.*#+}} xmm0 = [-2.040000e+01,3.768000e+01]
289; CHECK-NEXT:    retq
290  %sel = select i1 %cond, <2 x double> <double -4.0, double 12.0>, <2 x double> <double 23.3, double 11.0>
291  %bo = fmul <2 x double> %sel, <double 5.1, double 3.14>
292  ret <2 x double> %bo
293}
294
295; 4294967297 = 0x100000001.
296; This becomes an opaque constant via ConstantHoisting, so we don't fold it into the select.
297
298define i64 @opaque_constant(i1 %cond, i64 %x) {
299; CHECK-LABEL: opaque_constant:
300; CHECK:       # BB#0:
301; CHECK-NEXT:    testb $1, %dil
302; CHECK-NEXT:    movl $23, %ecx
303; CHECK-NEXT:    movq $-4, %rax
304; CHECK-NEXT:    cmoveq %rcx, %rax
305; CHECK-NEXT:    movabsq $4294967297, %rcx # imm = 0x100000001
306; CHECK-NEXT:    andq %rcx, %rax
307; CHECK-NEXT:    xorl %edx, %edx
308; CHECK-NEXT:    cmpq %rcx, %rsi
309; CHECK-NEXT:    sete %dl
310; CHECK-NEXT:    subq %rdx, %rax
311; CHECK-NEXT:    retq
312  %sel = select i1 %cond, i64 -4, i64 23
313  %bo = and i64 %sel, 4294967297
314  %cmp = icmp eq i64 %x, 4294967297
315  %sext = sext i1 %cmp to i64
316  %add = add i64 %bo, %sext
317  ret i64 %add
318}
319
320