• 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 %[[csr2:[^ ]*]]
57; CHECK: pushl %[[csr1:[^ ]*]]
58; CHECK-DAG: movl 12(%esp), %[[csr1]]
59; CHECK-DAG: movl 16(%esp), %[[csr2]]
60; CHECK-DAG: leal 12(%esp), %[[reg:[^ ]*]]
61; CHECK: pushl %[[reg]]
62; CHECK: calll _addrof_i64
63; CHECK: addl $4, %esp
64; CHECK-DAG: movl %[[csr1]], %eax
65; CHECK-DAG: movl %[[csr2]], %edx
66; CHECK: popl %[[csr1]]
67; CHECK: popl %[[csr2]]
68; CHECK: retl
69
70define i1 @i1_arg(i1 %x) {
71  %x.addr = alloca i1
72  store i1 %x, i1* %x.addr
73  call void @addrof_i1(i1* %x.addr)
74  ret i1 %x
75}
76
77; CHECK-LABEL: _i1_arg:
78; CHECK: pushl   %ebx
79; CHECK: movb 8(%esp), %bl
80; CHECK: leal 8(%esp), %eax
81; CHECK: pushl %eax
82; CHECK: calll _addrof_i1
83; CHECK: addl $4, %esp
84; CHECK: movl %ebx, %eax
85; CHECK: popl %ebx
86; CHECK: retl
87
88; We can't copy elide when an i64 is split between registers and memory in a
89; fastcc function.
90
91define fastcc i64 @fastcc_split_i64(i64* %p, i64 %x) {
92entry:
93  %x.addr = alloca i64, align 4
94  store i64 %x, i64* %x.addr, align 4
95  call void @addrof_i64(i64* %x.addr)
96  ret i64 %x
97}
98
99; CHECK-LABEL: _fastcc_split_i64:
100; CHECK-DAG: movl %edx, %[[r1:[^ ]*]]
101; CHECK-DAG: movl 20(%esp), %[[r2:[^ ]*]]
102; CHECK-DAG: movl %[[r2]], 4(%esp)
103; CHECK-DAG: movl %edx, (%esp)
104; CHECK: movl %esp, %[[reg:[^ ]*]]
105; CHECK: pushl %[[reg]]
106; CHECK: calll _addrof_i64
107; CHECK: retl
108
109
110; We can't copy elide when it would reduce the user requested alignment.
111
112define void @high_alignment(i32 %x) {
113entry:
114  %x.p = alloca i32, align 128
115  store i32 %x, i32* %x.p
116  call void @addrof_i32(i32* %x.p)
117  ret void
118}
119
120; CHECK-LABEL: _high_alignment:
121; CHECK: andl $-128, %esp
122; CHECK: movl 8(%ebp), %[[reg:[^ ]*]]
123; CHECK: movl %[[reg]], (%esp)
124; CHECK: movl %esp, %[[reg:[^ ]*]]
125; CHECK: pushl %[[reg]]
126; CHECK: calll _addrof_i32
127; CHECK: retl
128
129
130; We can't copy elide when it would reduce the ABI required alignment.
131; FIXME: We should lower the ABI alignment of i64 on Windows, since MSVC
132; doesn't guarantee it.
133
134define void @abi_alignment(i64 %x) {
135entry:
136  %x.p = alloca i64
137  store i64 %x, i64* %x.p
138  call void @addrof_i64(i64* %x.p)
139  ret void
140}
141
142; CHECK-LABEL: _abi_alignment:
143; CHECK: andl $-8, %esp
144; CHECK: movl 8(%ebp), %[[reg:[^ ]*]]
145; CHECK: movl %[[reg]], (%esp)
146; CHECK: movl %esp, %[[reg:[^ ]*]]
147; CHECK: pushl %[[reg]]
148; CHECK: calll _addrof_i64
149; CHECK: retl
150
151
152; The code we generate for this is unimportant. This is mostly a crash test.
153
154define void @split_i128(i128* %sret, i128 %x) {
155entry:
156  %x.addr = alloca i128
157  store i128 %x, i128* %x.addr
158  call void @addrof_i128(i128* %x.addr)
159  store i128 %x, i128* %sret
160  ret void
161}
162
163; CHECK-LABEL: _split_i128:
164; CHECK: pushl %ebp
165; CHECK: calll _addrof_i128
166; CHECK: retl
167
168
169; Check that we load all of x, y, and z before the call.
170
171define i32 @three_args(i32 %x, i32 %y, i32 %z) {
172entry:
173  %z.addr = alloca i32, align 4
174  %y.addr = alloca i32, align 4
175  %x.addr = alloca i32, align 4
176  store i32 %z, i32* %z.addr, align 4
177  store i32 %y, i32* %y.addr, align 4
178  store i32 %x, i32* %x.addr, align 4
179  call void @addrof_i32_x3(i32* %x.addr, i32* %y.addr, i32* %z.addr)
180  %s1 = add i32 %x, %y
181  %sum = add i32 %s1, %z
182  ret i32 %sum
183}
184
185; CHECK-LABEL: _three_args:
186; CHECK: pushl %[[csr:[^ ]*]]
187; CHECK-DAG: movl {{[0-9]+}}(%esp), %[[csr]]
188; CHECK-DAG: addl {{[0-9]+}}(%esp), %[[csr]]
189; CHECK-DAG: addl {{[0-9]+}}(%esp), %[[csr]]
190; CHECK-DAG: leal 8(%esp), %[[x:[^ ]*]]
191; CHECK-DAG: leal 12(%esp), %[[y:[^ ]*]]
192; CHECK-DAG: leal 16(%esp), %[[z:[^ ]*]]
193; CHECK: pushl %[[z]]
194; CHECK: pushl %[[y]]
195; CHECK: pushl %[[x]]
196; CHECK: calll _addrof_i32_x3
197; CHECK: movl %[[csr]], %eax
198; CHECK: popl %[[csr]]
199; CHECK: retl
200
201
202define void @two_args_same_alloca(i32 %x, i32 %y) {
203entry:
204  %x.addr = alloca i32
205  store i32 %x, i32* %x.addr
206  store i32 %y, i32* %x.addr
207  call void @addrof_i32(i32* %x.addr)
208  ret void
209}
210
211; CHECK-LABEL: _two_args_same_alloca:
212; CHECK: movl 8(%esp), {{.*}}
213; CHECK: movl {{.*}}, 4(%esp)
214; CHECK: leal 4(%esp), %[[reg:[^ ]*]]
215; CHECK: pushl %[[reg]]
216; CHECK: calll _addrof_i32
217; CHECK: retl
218
219
220define void @avoid_byval(i32* byval(i32) %x) {
221entry:
222  %x.p.p = alloca i32*
223  store i32* %x, i32** %x.p.p
224  call void @addrof_i32(i32* %x)
225  ret void
226}
227
228; CHECK-LABEL: _avoid_byval:
229; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
230; CHECK: pushl %[[reg]]
231; CHECK: calll _addrof_i32
232; CHECK: retl
233
234
235define void @avoid_inalloca(i32* inalloca %x) {
236entry:
237  %x.p.p = alloca i32*
238  store i32* %x, i32** %x.p.p
239  call void @addrof_i32(i32* %x)
240  ret void
241}
242
243; CHECK-LABEL: _avoid_inalloca:
244; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
245; CHECK: pushl %[[reg]]
246; CHECK: calll _addrof_i32
247; CHECK: retl
248
249define void @avoid_preallocated(i32* preallocated(i32) %x) {
250entry:
251  %x.p.p = alloca i32*
252  store i32* %x, i32** %x.p.p
253  call void @addrof_i32(i32* %x)
254  ret void
255}
256
257; CHECK-LABEL: _avoid_preallocated:
258; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
259; CHECK: pushl %[[reg]]
260; CHECK: calll _addrof_i32
261; CHECK: retl
262
263; Don't elide the copy when the alloca is escaped with a store.
264define void @escape_with_store(i32 %x) {
265  %x1 = alloca i32
266  %x2 = alloca i32*
267  store i32* %x1, i32** %x2
268  %x3 = load i32*, i32** %x2
269  store i32 0, i32* %x3
270  store i32 %x, i32* %x1
271  call void @addrof_i32(i32* %x1)
272  ret void
273}
274
275; CHECK-LABEL: _escape_with_store:
276; CHECK: movl {{.*}}(%esp), %[[reg:[^ ]*]]
277; CHECK: movl %[[reg]], [[offs:[0-9]*]](%esp)
278; CHECK: calll _addrof_i32
279
280
281; This test case exposed issues with the use of TokenFactor.
282
283define void @sret_and_elide(i32* sret(i32) %sret, i32 %v) {
284  %v.p = alloca i32
285  store i32 %v, i32* %v.p
286  call void @addrof_i32(i32* %v.p)
287  store i32 %v, i32* %sret
288  ret void
289}
290
291; CHECK-LABEL: _sret_and_elide:
292; CHECK: pushl
293; CHECK: pushl
294; CHECK: movl 12(%esp), %[[sret:[^ ]*]]
295; CHECK: movl 16(%esp), %[[v:[^ ]*]]
296; CHECK: leal 16(%esp), %[[reg:[^ ]*]]
297; CHECK: pushl %[[reg]]
298; CHECK: calll _addrof_i32
299; CHECK: movl %[[v]], (%[[sret]])
300; CHECK: movl %[[sret]], %eax
301; CHECK: popl
302; CHECK: popl
303; CHECK: retl
304