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:    xorl %ecx, %ecx
112; CHECK-NEXT:    testb $1, %dil
113; CHECK-NEXT:    movl $-1, %eax
114; CHECK-NEXT:    cmovel %ecx, %eax
115; CHECK-NEXT:    retq
116  %sel = select i1 %cond, i32 -1, i32 0
117  ret i32 %sel
118}
119
120define i32 @select_neg1_or_0_zeroext(i1 zeroext %cond) {
121; CHECK-LABEL: select_neg1_or_0_zeroext:
122; CHECK:       # BB#0:
123; CHECK-NEXT:    xorl %ecx, %ecx
124; CHECK-NEXT:    testb %dil, %dil
125; CHECK-NEXT:    movl $-1, %eax
126; CHECK-NEXT:    cmovel %ecx, %eax
127; CHECK-NEXT:    retq
128  %sel = select i1 %cond, i32 -1, i32 0
129  ret i32 %sel
130}
131
132define i32 @select_neg1_or_0_signext(i1 signext %cond) {
133; CHECK-LABEL: select_neg1_or_0_signext:
134; CHECK:       # BB#0:
135; CHECK-NEXT:    xorl %ecx, %ecx
136; CHECK-NEXT:    testb $1, %dil
137; CHECK-NEXT:    movl $-1, %eax
138; CHECK-NEXT:    cmovel %ecx, %eax
139; CHECK-NEXT:    retq
140  %sel = select i1 %cond, i32 -1, i32 0
141  ret i32 %sel
142}
143
144; select Cond, C+1, C --> add (zext Cond), C
145
146define i32 @select_Cplus1_C(i1 %cond) {
147; CHECK-LABEL: select_Cplus1_C:
148; CHECK:       # BB#0:
149; CHECK-NEXT:    # kill: %EDI<def> %EDI<kill> %RDI<def>
150; CHECK-NEXT:    andl $1, %edi
151; CHECK-NEXT:    leal 41(%rdi), %eax
152; CHECK-NEXT:    retq
153  %sel = select i1 %cond, i32 42, i32 41
154  ret i32 %sel
155}
156
157define i32 @select_Cplus1_C_zeroext(i1 zeroext %cond) {
158; CHECK-LABEL: select_Cplus1_C_zeroext:
159; CHECK:       # BB#0:
160; CHECK-NEXT:    movzbl %dil, %eax
161; CHECK-NEXT:    addl $41, %eax
162; CHECK-NEXT:    retq
163  %sel = select i1 %cond, i32 42, i32 41
164  ret i32 %sel
165}
166
167define i32 @select_Cplus1_C_signext(i1 signext %cond) {
168; CHECK-LABEL: select_Cplus1_C_signext:
169; CHECK:       # BB#0:
170; CHECK-NEXT:    andb $1, %dil
171; CHECK-NEXT:    movzbl %dil, %eax
172; CHECK-NEXT:    addl $41, %eax
173; CHECK-NEXT:    retq
174  %sel = select i1 %cond, i32 42, i32 41
175  ret i32 %sel
176}
177
178; select Cond, C, C+1 --> add (sext Cond), C
179
180define i32 @select_C_Cplus1(i1 %cond) {
181; CHECK-LABEL: select_C_Cplus1:
182; CHECK:       # BB#0:
183; CHECK-NEXT:    andb $1, %dil
184; CHECK-NEXT:    cmpb $1, %dil
185; CHECK-NEXT:    movl $41, %eax
186; CHECK-NEXT:    adcl $0, %eax
187; CHECK-NEXT:    retq
188  %sel = select i1 %cond, i32 41, i32 42
189  ret i32 %sel
190}
191
192define i32 @select_C_Cplus1_zeroext(i1 zeroext %cond) {
193; CHECK-LABEL: select_C_Cplus1_zeroext:
194; CHECK:       # BB#0:
195; CHECK-NEXT:    cmpb $1, %dil
196; CHECK-NEXT:    movl $41, %eax
197; CHECK-NEXT:    adcl $0, %eax
198; CHECK-NEXT:    retq
199  %sel = select i1 %cond, i32 41, i32 42
200  ret i32 %sel
201}
202
203define i32 @select_C_Cplus1_signext(i1 signext %cond) {
204; CHECK-LABEL: select_C_Cplus1_signext:
205; CHECK:       # BB#0:
206; CHECK-NEXT:    andb $1, %dil
207; CHECK-NEXT:    cmpb $1, %dil
208; CHECK-NEXT:    movl $41, %eax
209; CHECK-NEXT:    adcl $0, %eax
210; CHECK-NEXT:    retq
211  %sel = select i1 %cond, i32 41, i32 42
212  ret i32 %sel
213}
214
215; In general, select of 2 constants could be:
216; select Cond, C1, C2 --> add (mul (zext Cond), C1-C2), C2 --> add (and (sext Cond), C1-C2), C2
217
218define i32 @select_C1_C2(i1 %cond) {
219; CHECK-LABEL: select_C1_C2:
220; CHECK:       # BB#0:
221; CHECK-NEXT:    testb $1, %dil
222; CHECK-NEXT:    movl $421, %ecx # imm = 0x1A5
223; CHECK-NEXT:    movl $42, %eax
224; CHECK-NEXT:    cmovnel %ecx, %eax
225; CHECK-NEXT:    retq
226  %sel = select i1 %cond, i32 421, i32 42
227  ret i32 %sel
228}
229
230define i32 @select_C1_C2_zeroext(i1 zeroext %cond) {
231; CHECK-LABEL: select_C1_C2_zeroext:
232; CHECK:       # BB#0:
233; CHECK-NEXT:    testb %dil, %dil
234; CHECK-NEXT:    movl $421, %ecx # imm = 0x1A5
235; CHECK-NEXT:    movl $42, %eax
236; CHECK-NEXT:    cmovnel %ecx, %eax
237; CHECK-NEXT:    retq
238  %sel = select i1 %cond, i32 421, i32 42
239  ret i32 %sel
240}
241
242define i32 @select_C1_C2_signext(i1 signext %cond) {
243; CHECK-LABEL: select_C1_C2_signext:
244; CHECK:       # BB#0:
245; CHECK-NEXT:    testb $1, %dil
246; CHECK-NEXT:    movl $421, %ecx # imm = 0x1A5
247; CHECK-NEXT:    movl $42, %eax
248; CHECK-NEXT:    cmovnel %ecx, %eax
249; CHECK-NEXT:    retq
250  %sel = select i1 %cond, i32 421, i32 42
251  ret i32 %sel
252}
253
254; select (x == 2), 2, (x + 1) --> select (x == 2), x, (x + 1)
255
256define i64 @select_2_or_inc(i64 %x) {
257; CHECK-LABEL: select_2_or_inc:
258; CHECK:       # BB#0:
259; CHECK-NEXT:    leaq 1(%rdi), %rax
260; CHECK-NEXT:    cmpq $2, %rdi
261; CHECK-NEXT:    cmoveq %rdi, %rax
262; CHECK-NEXT:    retq
263  %cmp = icmp eq i64 %x, 2
264  %add = add i64 %x, 1
265  %retval.0 = select i1 %cmp, i64 2, i64 %add
266  ret i64 %retval.0
267}
268
269