blob: 15afb56ed691b178a1887bc45e5284e782316954 [file] [log] [blame]
Reid Klecknerf7c09802017-03-01 21:42:00 +00001; RUN: llc -mtriple=i686-windows < %s | FileCheck %s
2
3declare void @addrof_i32(i32*)
4declare void @addrof_i64(i64*)
5declare void @addrof_i128(i128*)
6declare void @addrof_i32_x3(i32*, i32*, i32*)
7
8define void @simple(i32 %x) {
9entry:
10 %x.addr = alloca i32
11 store i32 %x, i32* %x.addr
12 call void @addrof_i32(i32* %x.addr)
13 ret void
14}
15
16; CHECK-LABEL: _simple:
17; CHECK: leal 4(%esp), %[[reg:[^ ]*]]
18; CHECK: pushl %[[reg]]
19; CHECK: calll _addrof_i32
20; CHECK: retl
21
22
23; We need to load %x before calling addrof_i32 now because it could mutate %x in
24; place.
25
26define i32 @use_arg(i32 %x) {
27entry:
28 %x.addr = alloca i32
29 store i32 %x, i32* %x.addr
30 call void @addrof_i32(i32* %x.addr)
31 ret i32 %x
32}
33
34; CHECK-LABEL: _use_arg:
35; CHECK: pushl %[[csr:[^ ]*]]
36; CHECK-DAG: movl 8(%esp), %[[csr]]
37; CHECK-DAG: leal 8(%esp), %[[reg:[^ ]*]]
38; CHECK: pushl %[[reg]]
39; CHECK: calll _addrof_i32
40; CHECK: movl %[[csr]], %eax
41; CHECK: popl %[[csr]]
42; CHECK: retl
43
44
45define i64 @split_i64(i64 %x) {
46entry:
47 %x.addr = alloca i64, align 4
48 store i64 %x, i64* %x.addr, align 4
49 call void @addrof_i64(i64* %x.addr)
50 ret i64 %x
51}
52
53; CHECK-LABEL: _split_i64:
54; CHECK: pushl %ebp
55; CHECK: movl %esp, %ebp
56; CHECK: pushl %[[csr2:[^ ]*]]
57; CHECK: pushl %[[csr1:[^ ]*]]
58; CHECK: andl $-8, %esp
59; CHECK-DAG: movl 8(%ebp), %[[csr1]]
60; CHECK-DAG: movl 12(%ebp), %[[csr2]]
61; CHECK-DAG: leal 8(%ebp), %[[reg:[^ ]*]]
62; CHECK: pushl %[[reg]]
63; CHECK: calll _addrof_i64
64; CHECK-DAG: movl %[[csr1]], %eax
65; CHECK-DAG: movl %[[csr2]], %edx
66; CHECK: leal -8(%ebp), %esp
67; CHECK: popl %[[csr1]]
68; CHECK: popl %[[csr2]]
69; CHECK: popl %ebp
70; CHECK: retl
71
72
73; We can't copy elide when an i64 is split between registers and memory in a
74; fastcc function.
75
76define fastcc i64 @fastcc_split_i64(i64* %p, i64 %x) {
77entry:
78 %x.addr = alloca i64, align 4
79 store i64 %x, i64* %x.addr, align 4
80 call void @addrof_i64(i64* %x.addr)
81 ret i64 %x
82}
83
84; CHECK-LABEL: _fastcc_split_i64:
85; CHECK: pushl %ebp
86; CHECK: movl %esp, %ebp
87; CHECK-DAG: movl %edx, %[[r1:[^ ]*]]
88; CHECK-DAG: movl 8(%ebp), %[[r2:[^ ]*]]
89; CHECK-DAG: movl %[[r2]], 4(%esp)
90; CHECK-DAG: movl %[[r1]], (%esp)
91; CHECK: movl %esp, %[[reg:[^ ]*]]
92; CHECK: pushl %[[reg]]
93; CHECK: calll _addrof_i64
94; CHECK: popl %ebp
95; CHECK: retl
96
97
98; We can't copy elide when it would reduce the user requested alignment.
99
100define void @high_alignment(i32 %x) {
101entry:
102 %x.p = alloca i32, align 128
103 store i32 %x, i32* %x.p
104 call void @addrof_i32(i32* %x.p)
105 ret void
106}
107
108; CHECK-LABEL: _high_alignment:
109; CHECK: andl $-128, %esp
110; CHECK: movl 8(%ebp), %[[reg:[^ ]*]]
111; CHECK: movl %[[reg]], (%esp)
112; CHECK: movl %esp, %[[reg:[^ ]*]]
113; CHECK: pushl %[[reg]]
114; CHECK: calll _addrof_i32
115; CHECK: retl
116
117
118; We can't copy elide when it would reduce the ABI required alignment.
119; FIXME: We should lower the ABI alignment of i64 on Windows, since MSVC
120; doesn't guarantee it.
121
122define void @abi_alignment(i64 %x) {
123entry:
124 %x.p = alloca i64
125 store i64 %x, i64* %x.p
126 call void @addrof_i64(i64* %x.p)
127 ret void
128}
129
130; CHECK-LABEL: _abi_alignment:
131; CHECK: andl $-8, %esp
132; CHECK: movl 8(%ebp), %[[reg:[^ ]*]]
133; CHECK: movl %[[reg]], (%esp)
134; CHECK: movl %esp, %[[reg:[^ ]*]]
135; CHECK: pushl %[[reg]]
136; CHECK: calll _addrof_i64
137; CHECK: retl
138
139
140; The code we generate for this is unimportant. This is mostly a crash test.
141
142define void @split_i128(i128* %sret, i128 %x) {
143entry:
144 %x.addr = alloca i128
145 store i128 %x, i128* %x.addr
146 call void @addrof_i128(i128* %x.addr)
147 store i128 %x, i128* %sret
148 ret void
149}
150
151; CHECK-LABEL: _split_i128:
152; CHECK: pushl %ebp
153; CHECK: calll _addrof_i128
154; CHECK: retl
155
156
157; Check that we load all of x, y, and z before the call.
158
159define i32 @three_args(i32 %x, i32 %y, i32 %z) {
160entry:
161 %z.addr = alloca i32, align 4
162 %y.addr = alloca i32, align 4
163 %x.addr = alloca i32, align 4
164 store i32 %z, i32* %z.addr, align 4
165 store i32 %y, i32* %y.addr, align 4
166 store i32 %x, i32* %x.addr, align 4
167 call void @addrof_i32_x3(i32* %x.addr, i32* %y.addr, i32* %z.addr)
168 %s1 = add i32 %x, %y
169 %sum = add i32 %s1, %z
170 ret i32 %sum
171}
172
173; CHECK-LABEL: _three_args:
174; CHECK: pushl %[[csr:[^ ]*]]
175; CHECK-DAG: movl {{[0-9]+}}(%esp), %[[csr]]
176; CHECK-DAG: addl {{[0-9]+}}(%esp), %[[csr]]
177; CHECK-DAG: addl {{[0-9]+}}(%esp), %[[csr]]
178; CHECK-DAG: leal 8(%esp), %[[x:[^ ]*]]
179; CHECK-DAG: leal 12(%esp), %[[y:[^ ]*]]
180; CHECK-DAG: leal 16(%esp), %[[z:[^ ]*]]
181; CHECK: pushl %[[z]]
182; CHECK: pushl %[[y]]
183; CHECK: pushl %[[x]]
184; CHECK: calll _addrof_i32_x3
185; CHECK: movl %[[csr]], %eax
186; CHECK: popl %[[csr]]
187; CHECK: retl
188
189
190define void @two_args_same_alloca(i32 %x, i32 %y) {
191entry:
192 %x.addr = alloca i32
193 store i32 %x, i32* %x.addr
194 store i32 %y, i32* %x.addr
195 call void @addrof_i32(i32* %x.addr)
196 ret void
197}
198
199; CHECK-LABEL: _two_args_same_alloca:
200; CHECK: movl 8(%esp), {{.*}}
201; CHECK: movl {{.*}}, 4(%esp)
202; CHECK: leal 4(%esp), %[[reg:[^ ]*]]
203; CHECK: pushl %[[reg]]
204; CHECK: calll _addrof_i32
205; CHECK: retl
206
207
208define void @avoid_byval(i32* byval %x) {
209entry:
210 %x.p.p = alloca i32*
211 store i32* %x, i32** %x.p.p
212 call void @addrof_i32(i32* %x)
213 ret void
214}
215
216; CHECK-LABEL: _avoid_byval:
217; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
218; CHECK: pushl %[[reg]]
219; CHECK: calll _addrof_i32
220; CHECK: retl
221
222
223define void @avoid_inalloca(i32* inalloca %x) {
224entry:
225 %x.p.p = alloca i32*
226 store i32* %x, i32** %x.p.p
227 call void @addrof_i32(i32* %x)
228 ret void
229}
230
231; CHECK-LABEL: _avoid_inalloca:
232; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]]
233; CHECK: pushl %[[reg]]
234; CHECK: calll _addrof_i32
235; CHECK: retl
236
237
238; Don't elide the copy when the alloca is escaped with a store.
239
240define void @escape_with_store(i32 %x) {
241 %x1 = alloca i32
242 %x2 = alloca i32*
243 store i32* %x1, i32** %x2
244 %x3 = load i32*, i32** %x2
245 store i32 0, i32* %x3
246 store i32 %x, i32* %x1
247 call void @addrof_i32(i32* %x1)
248 ret void
249}
250
251; CHECK-LABEL: _escape_with_store:
252; CHECK-DAG: movl {{.*}}(%esp), %[[reg:[^ ]*]]
253; CHECK-DAG: movl $0, [[offs:[0-9]*]](%esp)
254; CHECK: movl %[[reg]], [[offs]](%esp)
255; CHECK: calll _addrof_i32
256
257
258; This test case exposed issues with the use of TokenFactor.
259
260define void @sret_and_elide(i32* sret %sret, i32 %v) {
261 %v.p = alloca i32
262 store i32 %v, i32* %v.p
263 call void @addrof_i32(i32* %v.p)
264 store i32 %v, i32* %sret
265 ret void
266}
267
268; CHECK-LABEL: _sret_and_elide:
269; CHECK: pushl
270; CHECK: pushl
271; CHECK: movl 12(%esp), %[[sret:[^ ]*]]
272; CHECK: movl 16(%esp), %[[v:[^ ]*]]
273; CHECK: leal 16(%esp), %[[reg:[^ ]*]]
274; CHECK: pushl %[[reg]]
275; CHECK: calll _addrof_i32
276; CHECK: movl %[[v]], (%[[sret]])
277; CHECK: movl %[[sret]], %eax
278; CHECK: popl
279; CHECK: popl
280; CHECK: retl