• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: llc -mtriple=i686-windows < %s | FileCheck %s
2
3declare void @addrof_i1(i1*)
4declare void @addrof_i32(i32*)
5declare void @addrof_i64(i64*)
6declare void @addrof_i128(i128*)
7declare void @addrof_i32_x3(i32*, i32*, i32*)
8
9define void @simple(i32 %x) {
10entry:
11  %x.addr = alloca i32
12  store i32 %x, i32* %x.addr
13  call void @addrof_i32(i32* %x.addr)
14  ret void
15}
16
17; CHECK-LABEL: _simple:
18; CHECK: leal 4(%esp), %[[reg:[^ ]*]]
19; CHECK: pushl %[[reg]]
20; CHECK: calll _addrof_i32
21; CHECK: retl
22
23
24; We need to load %x before calling addrof_i32 now because it could mutate %x in
25; place.
26
27define i32 @use_arg(i32 %x) {
28entry:
29  %x.addr = alloca i32
30  store i32 %x, i32* %x.addr
31  call void @addrof_i32(i32* %x.addr)
32  ret i32 %x
33}
34
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
44
45; We won't copy elide for types needing legalization such as i64 or i1.
46
47define i64 @split_i64(i64 %x) {
48entry:
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
53}
54
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
73
74define 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
79}
80
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
91
92; We can't copy elide when an i64 is split between registers and memory in a
93; fastcc function.
94
95define fastcc i64 @fastcc_split_i64(i64* %p, i64 %x) {
96entry:
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
101}
102
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
115
116
117; We can't copy elide when it would reduce the user requested alignment.
118
119define void @high_alignment(i32 %x) {
120entry:
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
125}
126
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
135
136
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.
140
141define void @abi_alignment(i64 %x) {
142entry:
143  %x.p = alloca i64
144  store i64 %x, i64* %x.p
145  call void @addrof_i64(i64* %x.p)
146  ret void
147}
148
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
157
158
159; The code we generate for this is unimportant. This is mostly a crash test.
160
161define void @split_i128(i128* %sret, i128 %x) {
162entry:
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
168}
169
170; CHECK-LABEL: _split_i128:
171; CHECK: pushl %ebp
172; CHECK: calll _addrof_i128
173; CHECK: retl
174
175
176; Check that we load all of x, y, and z before the call.
177
178define i32 @three_args(i32 %x, i32 %y, i32 %z) {
179entry:
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
190}
191
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
207
208
209define void @two_args_same_alloca(i32 %x, i32 %y) {
210entry:
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
216}
217
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
225
226
227define void @avoid_byval(i32* byval %x) {
228entry:
229  %x.p.p = alloca i32*
230  store i32* %x, i32** %x.p.p
231  call void @addrof_i32(i32* %x)
232  ret void
233}
234
235; CHECK-LABEL: _avoid_byval:
236; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
237; CHECK: pushl %[[reg]]
238; CHECK: calll _addrof_i32
239; CHECK: retl
240
241
242define void @avoid_inalloca(i32* inalloca %x) {
243entry:
244  %x.p.p = alloca i32*
245  store i32* %x, i32** %x.p.p
246  call void @addrof_i32(i32* %x)
247  ret void
248}
249
250; CHECK-LABEL: _avoid_inalloca:
251; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
252; CHECK: pushl %[[reg]]
253; CHECK: calll _addrof_i32
254; CHECK: retl
255
256; Don't elide the copy when the alloca is escaped with a store.
257define 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
266}
267
268; CHECK-LABEL: _escape_with_store:
269; CHECK: movl {{.*}}(%esp), %[[reg:[^ ]*]]
270; CHECK: movl %[[reg]], [[offs:[0-9]*]](%esp)
271; CHECK: calll _addrof_i32
272
273
274; This test case exposed issues with the use of TokenFactor.
275
276define 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
282}
283
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
297