1; This file checks that Subzero generates code in accordance with the
2; calling convention for integers.
3
4; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \
5; RUN:   --target x8632 -i %s --args -O2 -allow-externally-defined-symbols \
6; RUN:   | %if --need=target_X8632 --command FileCheck %s
7
8; RUN: %if --need=target_ARM32 \
9; RUN:   --command %p2i --filetype=obj \
10; RUN:   --disassemble --target arm32 -i %s --args -O2 \
11; RUN:   -allow-externally-defined-symbols \
12; RUN:   | %if --need=target_ARM32 \
13; RUN:   --command FileCheck --check-prefix ARM32 %s
14
15; TODO: Switch to --filetype=obj when possible.
16; RUN: %if --need=target_MIPS32 --need=allow_dump \
17; RUN:   --command %p2i --filetype=asm --assemble \
18; RUN:   --disassemble --target mips32 -i %s --args -O2 \
19; RUN:   -allow-externally-defined-symbols \
20; RUN:   | %if --need=target_MIPS32 --need=allow_dump \
21; RUN:   --command FileCheck --check-prefix MIPS32 %s
22
23; For x86-32, integer arguments use the stack.
24; For ARM32, integer arguments can be r0-r3. i64 arguments occupy two
25; adjacent 32-bit registers, and require the first to be an even register.
26
27
28; i32
29
30define internal i32 @test_returning32_arg0(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) {
31entry:
32  ret i32 %arg0
33}
34; CHECK-LABEL: test_returning32_arg0
35; CHECK-NEXT: mov eax,{{.*}} [esp+0x4]
36; CHECK-NEXT: ret
37; ARM32-LABEL: test_returning32_arg0
38; ARM32-NEXT: bx lr
39; MIPS32-LABEL: test_returning32_arg0
40; MIPS32: move v0,a0
41; MIPS32-NEXT: jr       ra
42
43define internal i32 @test_returning32_arg1(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) {
44entry:
45  ret i32 %arg1
46}
47; CHECK-LABEL: test_returning32_arg1
48; CHECK-NEXT: mov eax,{{.*}} [esp+0x8]
49; CHECK-NEXT: ret
50; ARM32-LABEL: test_returning32_arg1
51; ARM32-NEXT: mov r0, r1
52; ARM32-NEXT: bx lr
53; MIPS32-LABEL: test_returning32_arg1
54; MIPS32: move v0,a1
55; MIPS32-NEXT: jr       ra
56
57define internal i32 @test_returning32_arg2(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) {
58entry:
59  ret i32 %arg2
60}
61; CHECK-LABEL: test_returning32_arg2
62; CHECK-NEXT: mov eax,{{.*}} [esp+0xc]
63; CHECK-NEXT: ret
64; ARM32-LABEL: test_returning32_arg2
65; ARM32-NEXT: mov r0, r2
66; ARM32-NEXT: bx lr
67; MIPS32-LABEL: test_returning32_arg2
68; MIPS32: move v0,a2
69; MIPS32-NEXT: jr       ra
70
71
72define internal i32 @test_returning32_arg3(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) {
73entry:
74  ret i32 %arg3
75}
76; CHECK-LABEL: test_returning32_arg3
77; CHECK-NEXT: mov eax,{{.*}} [esp+0x10]
78; CHECK-NEXT: ret
79; ARM32-LABEL: test_returning32_arg3
80; ARM32-NEXT: mov r0, r3
81; ARM32-NEXT: bx lr
82
83
84define internal i32 @test_returning32_arg4(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) {
85entry:
86  ret i32 %arg4
87}
88; CHECK-LABEL: test_returning32_arg4
89; CHECK-NEXT: mov eax,{{.*}} [esp+0x14]
90; CHECK-NEXT: ret
91; ARM32-LABEL: test_returning32_arg4
92; ARM32-NEXT: ldr r0, [sp]
93; ARM32-NEXT: bx lr
94
95
96define internal i32 @test_returning32_arg5(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) {
97entry:
98  ret i32 %arg5
99}
100; CHECK-LABEL: test_returning32_arg5
101; CHECK-NEXT: mov eax,{{.*}} [esp+0x18]
102; CHECK-NEXT: ret
103; ARM32-LABEL: test_returning32_arg5
104; ARM32-NEXT: ldr r0, [sp, #4]
105; ARM32-NEXT: bx lr
106
107; i64
108
109define internal i64 @test_returning64_arg0(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3) {
110entry:
111  ret i64 %arg0
112}
113; CHECK-LABEL: test_returning64_arg0
114; CHECK-NEXT: mov {{.*}} [esp+0x4]
115; CHECK-NEXT: mov {{.*}} [esp+0x8]
116; CHECK: ret
117; ARM32-LABEL: test_returning64_arg0
118; ARM32-NEXT: bx lr
119; MIPS32-LABEL: test_returning64_arg0
120; MIPS32-NEXT: move v0,a0
121; MIPS32-NEXT: move v1,a1
122
123
124define internal i64 @test_returning64_arg1(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3) {
125entry:
126  ret i64 %arg1
127}
128; CHECK-LABEL: test_returning64_arg1
129; CHECK-NEXT: mov {{.*}} [esp+0xc]
130; CHECK-NEXT: mov {{.*}} [esp+0x10]
131; CHECK: ret
132; ARM32-LABEL: test_returning64_arg1
133; ARM32-NEXT: mov r0, r2
134; ARM32-NEXT: mov r1, r3
135; ARM32-NEXT: bx lr
136; MIPS32-LABEL: test_returning64_arg1
137; MIPS32-NEXT: move v0,a2
138; MIPS32-NEXT: move v1,a3
139
140define internal i64 @test_returning64_arg2(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3) {
141entry:
142  ret i64 %arg2
143}
144; CHECK-LABEL: test_returning64_arg2
145; CHECK-NEXT: mov {{.*}} [esp+0x14]
146; CHECK-NEXT: mov {{.*}} [esp+0x18]
147; CHECK: ret
148; ARM32-LABEL: test_returning64_arg2
149; This could have been a ldm sp, {r0, r1}, but we don't do the ldm optimization.
150; ARM32-NEXT: ldr r0, [sp]
151; ARM32-NEXT: ldr r1, [sp, #4]
152; ARM32-NEXT: bx lr
153
154define internal i64 @test_returning64_arg3(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3) {
155entry:
156  ret i64 %arg3
157}
158; CHECK-LABEL: test_returning64_arg3
159; CHECK-NEXT: mov {{.*}} [esp+0x1c]
160; CHECK-NEXT: mov {{.*}} [esp+0x20]
161; CHECK: ret
162; ARM32-LABEL: test_returning64_arg3
163; ARM32-NEXT: ldr r0, [sp, #8]
164; ARM32-NEXT: ldr r1, [sp, #12]
165; ARM32-NEXT: bx lr
166
167
168; Test that on ARM, the i64 arguments start with an even register.
169
170define internal i64 @test_returning64_even_arg1(i32 %arg0, i64 %arg1, i64 %arg2) {
171entry:
172  ret i64 %arg1
173}
174; Not padded out x86-32.
175; CHECK-LABEL: test_returning64_even_arg1
176; CHECK-NEXT: mov {{.*}} [esp+0x8]
177; CHECK-NEXT: mov {{.*}} [esp+0xc]
178; CHECK: ret
179; ARM32-LABEL: test_returning64_even_arg1
180; ARM32-NEXT: mov r0, r2
181; ARM32-NEXT: mov r1, r3
182; ARM32-NEXT: bx lr
183
184define internal i64 @test_returning64_even_arg1b(i32 %arg0, i32 %arg0b, i64 %arg1, i64 %arg2) {
185entry:
186  ret i64 %arg1
187}
188; CHECK-LABEL: test_returning64_even_arg1b
189; CHECK-NEXT: mov {{.*}} [esp+0xc]
190; CHECK-NEXT: mov {{.*}} [esp+0x10]
191; CHECK: ret
192; ARM32-LABEL: test_returning64_even_arg1b
193; ARM32-NEXT: mov r0, r2
194; ARM32-NEXT: mov r1, r3
195; ARM32-NEXT: bx lr
196
197define internal i64 @test_returning64_even_arg2(i64 %arg0, i32 %arg1, i64 %arg2) {
198entry:
199  ret i64 %arg2
200}
201; Not padded out on x86-32.
202; CHECK-LABEL: test_returning64_even_arg2
203; CHECK-NEXT: mov {{.*}} [esp+0x10]
204; CHECK-NEXT: mov {{.*}} [esp+0x14]
205; CHECK: ret
206; ARM32-LABEL: test_returning64_even_arg2
207; ARM32-DAG: ldr r0, [sp]
208; ARM32-DAG: ldr r1, [sp, #4]
209; ARM32-NEXT: bx lr
210
211define internal i64 @test_returning64_even_arg2b(i64 %arg0, i32 %arg1, i32 %arg1b, i64 %arg2) {
212entry:
213  ret i64 %arg2
214}
215; CHECK-LABEL: test_returning64_even_arg2b
216; CHECK-NEXT: mov {{.*}} [esp+0x14]
217; CHECK-NEXT: mov {{.*}} [esp+0x18]
218; CHECK: ret
219; ARM32-LABEL: test_returning64_even_arg2b
220; ARM32-NEXT: ldr r0, [sp]
221; ARM32-NEXT: ldr r1, [sp, #4]
222; ARM32-NEXT: bx lr
223
224define internal i32 @test_returning32_even_arg2(i64 %arg0, i32 %arg1, i32 %arg2) {
225entry:
226  ret i32 %arg2
227}
228; CHECK-LABEL: test_returning32_even_arg2
229; CHECK-NEXT: mov {{.*}} [esp+0x10]
230; CHECK-NEXT: ret
231; ARM32-LABEL: test_returning32_even_arg2
232; ARM32-NEXT: mov r0, r3
233; ARM32-NEXT: bx lr
234
235define internal i32 @test_returning32_even_arg2b(i32 %arg0, i32 %arg1, i32 %arg2, i64 %arg3) {
236entry:
237  ret i32 %arg2
238}
239; CHECK-LABEL: test_returning32_even_arg2b
240; CHECK-NEXT: mov {{.*}} [esp+0xc]
241; CHECK-NEXT: ret
242; ARM32-LABEL: test_returning32_even_arg2b
243; ARM32-NEXT: mov r0, r2
244; ARM32-NEXT: bx lr
245
246; The i64 won't fit in a pair of register, and consumes the last register so a
247; following i32 can't use that free register.
248define internal i32 @test_returning32_even_arg4(i32 %arg0, i32 %arg1, i32 %arg2, i64 %arg3, i32 %arg4) {
249entry:
250  ret i32 %arg4
251}
252; CHECK-LABEL: test_returning32_even_arg4
253; CHECK-NEXT: mov {{.*}} [esp+0x18]
254; CHECK-NEXT: ret
255; ARM32-LABEL: test_returning32_even_arg4
256; ARM32-NEXT: ldr r0, [sp, #8]
257; ARM32-NEXT: bx lr
258
259; Test interleaving float/double and integer (different register streams on ARM).
260; TODO(jvoung): Test once the S/D/Q regs are modeled.
261
262; Test that integers are passed correctly as arguments to a function.
263
264declare void @IntArgs(i32, i32, i32, i32, i32, i32)
265
266declare void @killRegisters()
267
268define internal void @test_passing_integers(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6) {
269  call void @killRegisters()
270  call void @IntArgs(i32 %arg6, i32 %arg5, i32 %arg4, i32 %arg3, i32 %arg2, i32 %arg1)
271  ret void
272}
273
274; CHECK-LABEL: test_passing_integers
275; CHECK-DAG: mov [[REG1:e.*]],DWORD PTR [esp+0x44]
276; CHECK-DAG: mov [[REG2:e.*]],DWORD PTR [esp+0x48]
277; CHECK-DAG: mov [[REG3:e.*]],DWORD PTR [esp+0x4c]
278; CHECK-DAG: mov [[REG4:e.*]],DWORD PTR [esp+0x50]
279; CHECK: mov DWORD PTR [esp]
280; CHECK: mov DWORD PTR [esp+0x4]
281; CHECK-DAG: mov DWORD PTR [esp+0x8],[[REG4]]
282; CHECK-DAG: mov DWORD PTR [esp+0xc],[[REG3]]
283; CHECK-DAG: mov DWORD PTR [esp+0x10],[[REG2]]
284; CHECK-DAG: mov DWORD PTR [esp+0x14],[[REG1]]
285; CHECK: call
286
287; ARM32-LABEL: test_passing_integers
288; ARM32-DAG: mov [[REG1:.*]], r1
289; ARM32-DAG: mov [[REG2:.*]], r2
290; ARM32-DAG: mov [[REG3:.*]], r3
291; ARM32: str [[REG2]], [sp]
292; ARM32: str [[REG1]], [sp, #4]
293; ARM32-DAG: mov r0
294; ARM32-DAG: mov r1
295; ARM32-DAG: mov r2
296; ARM32-DAG: mov r3, [[REG3]]
297; ARM32: bl
298