1; RUN: llc -mtriple=i686-unknown-linux-gnu -mattr=+cmov %s -o - | FileCheck %s --check-prefix=CHECK32
2; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=+cmov %s -o - | FileCheck %s --check-prefix=CHECK64
3; RUN: llc -mtriple=x86_64-pc-win32 -mattr=+cmov %s -o - | FileCheck %s --check-prefix=CHECKWIN64
4
5define i32 @one32_nooptsize() {
6entry:
7  ret i32 1
8
9; When not optimizing for size, use mov.
10; CHECK32-LABEL: one32_nooptsize:
11; CHECK32:       movl $1, %eax
12; CHECK32-NEXT:  retl
13; CHECK64-LABEL: one32_nooptsize:
14; CHECK64:       movl $1, %eax
15; CHECK64-NEXT:  retq
16}
17
18define i32 @one32() optsize {
19entry:
20  ret i32 1
21
22; CHECK32-LABEL: one32:
23; CHECK32:       xorl %eax, %eax
24; CHECK32-NEXT:  incl %eax
25; CHECK32-NEXT:  retl
26
27; FIXME: Figure out the best approach in 64-bit mode.
28; CHECK64-LABEL: one32:
29; CHECK64:       movl $1, %eax
30; CHECK64-NEXT:  retq
31}
32
33define i32 @one32_minsize() minsize {
34entry:
35  ret i32 1
36
37; On 32-bit, xor-inc is preferred over push-pop.
38; CHECK32-LABEL: one32_minsize:
39; CHECK32:       xorl %eax, %eax
40; CHECK32-NEXT:  incl %eax
41; CHECK32-NEXT:  retl
42
43; On 64-bit we don't do xor-inc yet, so push-pop it is. Note that we have to
44; pop into a 64-bit register even when we just need 32 bits.
45; CHECK64-LABEL: one32_minsize:
46; CHECK64:       pushq $1
47; CHECK64:       .cfi_adjust_cfa_offset 8
48; CHECK64:       popq %rax
49; CHECK64:       .cfi_adjust_cfa_offset -8
50; CHECK64-NEXT:  retq
51
52; On Win64 we can't adjust the stack unless there's a frame pointer.
53; CHECKWIN64-LABEL: one32_minsize:
54; CHECKWIN64:       movl $1, %eax
55; CHECKWIN64-NEXT:  retq
56}
57
58define i32 @pr26023() minsize {
59entry:
60  %x = alloca [120 x i8]
61  %0 = getelementptr inbounds [120 x i8], [120 x i8]* %x, i64 0, i64 0
62  call void asm sideeffect "", "imr,~{memory},~{dirflag},~{fpsr},~{flags}"(i8* %0)
63  %arrayidx = getelementptr inbounds [120 x i8], [120 x i8]* %x, i64 0, i64 119
64  store volatile i8 -2, i8* %arrayidx
65  call void asm sideeffect "", "r,~{dirflag},~{fpsr},~{flags}"(i32 5)
66  %1 = load volatile i8, i8* %arrayidx
67  %conv = sext i8 %1 to i32
68  ret i32 %conv
69
70; The function writes to the redzone, so push/pop cannot be used.
71; CHECK64-LABEL: pr26023:
72; CHECK64:       movl $5, %ecx
73; CHECK64:       retq
74
75; 32-bit X86 doesn't have a redzone.
76; CHECK32-LABEL: pr26023:
77; CHECK32:       pushl $5
78; CHECK32:       popl %ecx
79; CHECK32:       retl
80}
81
82
83define i64 @one64_minsize() minsize {
84entry:
85  ret i64 1
86; On 64-bit we don't do xor-inc yet, so push-pop it is.
87; CHECK64-LABEL: one64_minsize:
88; CHECK64:       pushq $1
89; CHECK64:       .cfi_adjust_cfa_offset 8
90; CHECK64:       popq %rax
91; CHECK64:       .cfi_adjust_cfa_offset -8
92; CHECK64-NEXT:  retq
93
94; On Win64 we can't adjust the stack unless there's a frame pointer.
95; CHECKWIN64-LABEL: one64_minsize:
96; CHECKWIN64:       movl $1, %eax
97; CHECKWIN64-NEXT:  retq
98}
99
100define i32 @minus_one32() optsize {
101entry:
102  ret i32 -1
103
104; CHECK32-LABEL: minus_one32:
105; CHECK32:       xorl %eax, %eax
106; CHECK32-NEXT:  decl %eax
107; CHECK32-NEXT:  retl
108}
109
110define i32 @minus_one32_minsize() minsize {
111entry:
112  ret i32 -1
113
114; xor-dec is preferred over push-pop.
115; CHECK32-LABEL: minus_one32_minsize:
116; CHECK32:       xorl %eax, %eax
117; CHECK32-NEXT:  decl %eax
118; CHECK32-NEXT:  retl
119}
120
121define i16 @one16() optsize {
122entry:
123  ret i16 1
124
125; CHECK32-LABEL: one16:
126; CHECK32:       xorl %eax, %eax
127; CHECK32-NEXT:  incl %eax
128; CHECK32-NEXT:  retl
129}
130
131define i16 @minus_one16() optsize {
132entry:
133  ret i16 -1
134
135; CHECK32-LABEL: minus_one16:
136; CHECK32:       xorl %eax, %eax
137; CHECK32-NEXT:  decl %eax
138; CHECK32-NEXT:  retl
139}
140
141define i32 @minus_five32() minsize {
142entry:
143  ret i32 -5
144
145; CHECK32-LABEL: minus_five32:
146; CHECK32: pushl $-5
147; CHECK32: popl %eax
148; CHECK32: retl
149}
150
151define i64 @minus_five64() minsize {
152entry:
153  ret i64 -5
154
155; CHECK64-LABEL: minus_five64:
156; CHECK64: pushq $-5
157; CHECK64:       .cfi_adjust_cfa_offset 8
158; CHECK64: popq %rax
159; CHECK64:       .cfi_adjust_cfa_offset -8
160; CHECK64: retq
161}
162
163define i32 @rematerialize_minus_one() optsize {
164entry:
165  ; Materialize -1 (thiscall forces it into %ecx).
166  tail call x86_thiscallcc void @f(i32 -1)
167
168  ; Clobber all registers except %esp, leaving nowhere to store the -1 besides
169  ; spilling it to the stack.
170  tail call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{edx},~{edi},~{esi},~{ebp},~{dirflag},~{fpsr},~{flags}"()
171
172  ; -1 should be re-materialized here instead of getting spilled above.
173  ret i32 -1
174
175; CHECK32-LABEL: rematerialize_minus_one
176; CHECK32:       xorl %ecx, %ecx
177; CHECK32-NEXT:  decl %ecx
178; CHECK32:       calll
179; CHECK32:       xorl %eax, %eax
180; CHECK32-NEXT:  decl %eax
181; CHECK32-NOT:   %eax
182; CHECK32:       retl
183}
184
185define i32 @rematerialize_minus_one_eflags(i32 %x) optsize {
186entry:
187  ; Materialize -1 (thiscall forces it into %ecx).
188  tail call x86_thiscallcc void @f(i32 -1)
189
190  ; Clobber all registers except %esp, leaving nowhere to store the -1 besides
191  ; spilling it to the stack.
192  tail call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{edx},~{edi},~{esi},~{ebp},~{dirflag},~{fpsr},~{flags}"()
193
194  ; Define eflags.
195  %a = icmp ne i32 %x, 123
196  %b = zext i1 %a to i32
197  ; Cause -1 to be rematerialized right in front of the cmov, which needs eflags.
198  ; It must therefore not use the xor-dec lowering.
199  %c = select i1 %a, i32 %b, i32 -1
200  ret i32 %c
201
202; CHECK32-LABEL: rematerialize_minus_one_eflags
203; CHECK32:       xorl %ecx, %ecx
204; CHECK32-NEXT:  decl %ecx
205; CHECK32:       calll
206; CHECK32:       cmpl
207; CHECK32:       setne
208; CHECK32-NOT:   xorl
209; CHECK32:       movl $-1
210; CHECK32:       cmov
211; CHECK32:       retl
212}
213
214declare x86_thiscallcc void @f(i32)
215