Use Align for TFL::TransientStackAlignment
[llvm-core.git] / test / CodeGen / X86 / arg-copy-elide.ll
blob603e50ff30a35b6dcec7bff0a96e60fe03734d67
1 ; RUN: llc -mtriple=i686-windows < %s | FileCheck %s
3 declare void @addrof_i1(i1*)
4 declare void @addrof_i32(i32*)
5 declare void @addrof_i64(i64*)
6 declare void @addrof_i128(i128*)
7 declare void @addrof_i32_x3(i32*, i32*, i32*)
9 define void @simple(i32 %x) {
10 entry:
11   %x.addr = alloca i32
12   store i32 %x, i32* %x.addr
13   call void @addrof_i32(i32* %x.addr)
14   ret void
17 ; CHECK-LABEL: _simple:
18 ; CHECK: leal 4(%esp), %[[reg:[^ ]*]]
19 ; CHECK: pushl %[[reg]]
20 ; CHECK: calll _addrof_i32
21 ; CHECK: retl
24 ; We need to load %x before calling addrof_i32 now because it could mutate %x in
25 ; place.
27 define i32 @use_arg(i32 %x) {
28 entry:
29   %x.addr = alloca i32
30   store i32 %x, i32* %x.addr
31   call void @addrof_i32(i32* %x.addr)
32   ret i32 %x
35 ; CHECK-LABEL: _use_arg:
36 ; CHECK: pushl %[[csr:[^ ]*]]
37 ; CHECK-DAG: movl 8(%esp), %[[csr]]
38 ; CHECK-DAG: leal 8(%esp), %[[reg:[^ ]*]]
39 ; CHECK: pushl %[[reg]]
40 ; CHECK: calll _addrof_i32
41 ; CHECK: movl %[[csr]], %eax
42 ; CHECK: popl %[[csr]]
43 ; CHECK: retl
45 ; We won't copy elide for types needing legalization such as i64 or i1.
47 define i64 @split_i64(i64 %x) {
48 entry:
49   %x.addr = alloca i64, align 4
50   store i64 %x, i64* %x.addr, align 4
51   call void @addrof_i64(i64* %x.addr)
52   ret i64 %x
55 ; CHECK-LABEL: _split_i64:
56 ; CHECK: pushl %ebp
57 ; CHECK: movl %esp, %ebp
58 ; CHECK: pushl %[[csr2:[^ ]*]]
59 ; CHECK: pushl %[[csr1:[^ ]*]]
60 ; CHECK: andl $-8, %esp
61 ; CHECK-DAG: movl 8(%ebp), %[[csr1]]
62 ; CHECK-DAG: movl 12(%ebp), %[[csr2]]
63 ; CHECK-DAG: leal 8(%ebp), %[[reg:[^ ]*]]
64 ; CHECK: pushl %[[reg]]
65 ; CHECK: calll _addrof_i64
66 ; CHECK-DAG: movl %[[csr1]], %eax
67 ; CHECK-DAG: movl %[[csr2]], %edx
68 ; CHECK: leal -8(%ebp), %esp
69 ; CHECK: popl %[[csr1]]
70 ; CHECK: popl %[[csr2]]
71 ; CHECK: popl %ebp
72 ; CHECK: retl
74 define i1 @i1_arg(i1 %x) {
75   %x.addr = alloca i1
76   store i1 %x, i1* %x.addr
77   call void @addrof_i1(i1* %x.addr)
78   ret i1 %x
81 ; CHECK-LABEL: _i1_arg:
82 ; CHECK: pushl   %ebx
83 ; CHECK: movb 8(%esp), %bl
84 ; CHECK: leal 8(%esp), %eax
85 ; CHECK: pushl %eax
86 ; CHECK: calll _addrof_i1
87 ; CHECK: addl $4, %esp
88 ; CHECK: movl %ebx, %eax
89 ; CHECK: popl %ebx
90 ; CHECK: retl
92 ; We can't copy elide when an i64 is split between registers and memory in a
93 ; fastcc function.
95 define fastcc i64 @fastcc_split_i64(i64* %p, i64 %x) {
96 entry:
97   %x.addr = alloca i64, align 4
98   store i64 %x, i64* %x.addr, align 4
99   call void @addrof_i64(i64* %x.addr)
100   ret i64 %x
103 ; CHECK-LABEL: _fastcc_split_i64:
104 ; CHECK: pushl %ebp
105 ; CHECK: movl %esp, %ebp
106 ; CHECK-DAG: movl %edx, %[[r1:[^ ]*]]
107 ; CHECK-DAG: movl 8(%ebp), %[[r2:[^ ]*]]
108 ; CHECK-DAG: movl %[[r2]], 4(%esp)
109 ; CHECK-DAG: movl %edx, (%esp)
110 ; CHECK: movl %esp, %[[reg:[^ ]*]]
111 ; CHECK: pushl %[[reg]]
112 ; CHECK: calll _addrof_i64
113 ; CHECK: popl %ebp
114 ; CHECK: retl
117 ; We can't copy elide when it would reduce the user requested alignment.
119 define void @high_alignment(i32 %x) {
120 entry:
121   %x.p = alloca i32, align 128
122   store i32 %x, i32* %x.p
123   call void @addrof_i32(i32* %x.p)
124   ret void
127 ; CHECK-LABEL: _high_alignment:
128 ; CHECK: andl $-128, %esp
129 ; CHECK: movl 8(%ebp), %[[reg:[^ ]*]]
130 ; CHECK: movl %[[reg]], (%esp)
131 ; CHECK: movl %esp, %[[reg:[^ ]*]]
132 ; CHECK: pushl %[[reg]]
133 ; CHECK: calll _addrof_i32
134 ; CHECK: retl
137 ; We can't copy elide when it would reduce the ABI required alignment.
138 ; FIXME: We should lower the ABI alignment of i64 on Windows, since MSVC
139 ; doesn't guarantee it.
141 define void @abi_alignment(i64 %x) {
142 entry:
143   %x.p = alloca i64
144   store i64 %x, i64* %x.p
145   call void @addrof_i64(i64* %x.p)
146   ret void
149 ; CHECK-LABEL: _abi_alignment:
150 ; CHECK: andl $-8, %esp
151 ; CHECK: movl 8(%ebp), %[[reg:[^ ]*]]
152 ; CHECK: movl %[[reg]], (%esp)
153 ; CHECK: movl %esp, %[[reg:[^ ]*]]
154 ; CHECK: pushl %[[reg]]
155 ; CHECK: calll _addrof_i64
156 ; CHECK: retl
159 ; The code we generate for this is unimportant. This is mostly a crash test.
161 define void @split_i128(i128* %sret, i128 %x) {
162 entry:
163   %x.addr = alloca i128
164   store i128 %x, i128* %x.addr
165   call void @addrof_i128(i128* %x.addr)
166   store i128 %x, i128* %sret
167   ret void
170 ; CHECK-LABEL: _split_i128:
171 ; CHECK: pushl %ebp
172 ; CHECK: calll _addrof_i128
173 ; CHECK: retl
176 ; Check that we load all of x, y, and z before the call.
178 define i32 @three_args(i32 %x, i32 %y, i32 %z) {
179 entry:
180   %z.addr = alloca i32, align 4
181   %y.addr = alloca i32, align 4
182   %x.addr = alloca i32, align 4
183   store i32 %z, i32* %z.addr, align 4
184   store i32 %y, i32* %y.addr, align 4
185   store i32 %x, i32* %x.addr, align 4
186   call void @addrof_i32_x3(i32* %x.addr, i32* %y.addr, i32* %z.addr)
187   %s1 = add i32 %x, %y
188   %sum = add i32 %s1, %z
189   ret i32 %sum
192 ; CHECK-LABEL: _three_args:
193 ; CHECK: pushl %[[csr:[^ ]*]]
194 ; CHECK-DAG: movl {{[0-9]+}}(%esp), %[[csr]]
195 ; CHECK-DAG: addl {{[0-9]+}}(%esp), %[[csr]]
196 ; CHECK-DAG: addl {{[0-9]+}}(%esp), %[[csr]]
197 ; CHECK-DAG: leal 8(%esp), %[[x:[^ ]*]]
198 ; CHECK-DAG: leal 12(%esp), %[[y:[^ ]*]]
199 ; CHECK-DAG: leal 16(%esp), %[[z:[^ ]*]]
200 ; CHECK: pushl %[[z]]
201 ; CHECK: pushl %[[y]]
202 ; CHECK: pushl %[[x]]
203 ; CHECK: calll _addrof_i32_x3
204 ; CHECK: movl %[[csr]], %eax
205 ; CHECK: popl %[[csr]]
206 ; CHECK: retl
209 define void @two_args_same_alloca(i32 %x, i32 %y) {
210 entry:
211   %x.addr = alloca i32
212   store i32 %x, i32* %x.addr
213   store i32 %y, i32* %x.addr
214   call void @addrof_i32(i32* %x.addr)
215   ret void
218 ; CHECK-LABEL: _two_args_same_alloca:
219 ; CHECK: movl 8(%esp), {{.*}}
220 ; CHECK: movl {{.*}}, 4(%esp)
221 ; CHECK: leal 4(%esp), %[[reg:[^ ]*]]
222 ; CHECK: pushl %[[reg]]
223 ; CHECK: calll _addrof_i32
224 ; CHECK: retl
227 define void @avoid_byval(i32* byval %x) {
228 entry:
229   %x.p.p = alloca i32*
230   store i32* %x, i32** %x.p.p
231   call void @addrof_i32(i32* %x)
232   ret void
235 ; CHECK-LABEL: _avoid_byval:
236 ; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
237 ; CHECK: pushl %[[reg]]
238 ; CHECK: calll _addrof_i32
239 ; CHECK: retl
242 define void @avoid_inalloca(i32* inalloca %x) {
243 entry:
244   %x.p.p = alloca i32*
245   store i32* %x, i32** %x.p.p
246   call void @addrof_i32(i32* %x)
247   ret void
250 ; CHECK-LABEL: _avoid_inalloca:
251 ; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
252 ; CHECK: pushl %[[reg]]
253 ; CHECK: calll _addrof_i32
254 ; CHECK: retl
256 ; Don't elide the copy when the alloca is escaped with a store.
257 define void @escape_with_store(i32 %x) {
258   %x1 = alloca i32
259   %x2 = alloca i32*
260   store i32* %x1, i32** %x2
261   %x3 = load i32*, i32** %x2
262   store i32 0, i32* %x3
263   store i32 %x, i32* %x1
264   call void @addrof_i32(i32* %x1)
265   ret void
268 ; CHECK-LABEL: _escape_with_store:
269 ; CHECK: movl {{.*}}(%esp), %[[reg:[^ ]*]]
270 ; CHECK: movl %[[reg]], [[offs:[0-9]*]](%esp)
271 ; CHECK: calll _addrof_i32
274 ; This test case exposed issues with the use of TokenFactor.
276 define void @sret_and_elide(i32* sret %sret, i32 %v) {
277   %v.p = alloca i32
278   store i32 %v, i32* %v.p
279   call void @addrof_i32(i32* %v.p)
280   store i32 %v, i32* %sret
281   ret void
284 ; CHECK-LABEL: _sret_and_elide:
285 ; CHECK: pushl
286 ; CHECK: pushl
287 ; CHECK: movl 12(%esp), %[[sret:[^ ]*]]
288 ; CHECK: movl 16(%esp), %[[v:[^ ]*]]
289 ; CHECK: leal 16(%esp), %[[reg:[^ ]*]]
290 ; CHECK: pushl %[[reg]]
291 ; CHECK: calll _addrof_i32
292 ; CHECK: movl %[[v]], (%[[sret]])
293 ; CHECK: movl %[[sret]], %eax
294 ; CHECK: popl
295 ; CHECK: popl
296 ; CHECK: retl