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 30 define internal i32 @test_returning32_arg0(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) { 31 entry: 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 43 define internal i32 @test_returning32_arg1(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) { 44 entry: 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 57 define internal i32 @test_returning32_arg2(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) { 58 entry: 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 72 define internal i32 @test_returning32_arg3(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) { 73 entry: 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 84 define internal i32 @test_returning32_arg4(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) { 85 entry: 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 96 define internal i32 @test_returning32_arg5(i32 %arg0, i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7) { 97 entry: 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 109 define internal i64 @test_returning64_arg0(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3) { 110 entry: 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 124 define internal i64 @test_returning64_arg1(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3) { 125 entry: 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 140 define internal i64 @test_returning64_arg2(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3) { 141 entry: 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 154 define internal i64 @test_returning64_arg3(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3) { 155 entry: 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 170 define internal i64 @test_returning64_even_arg1(i32 %arg0, i64 %arg1, i64 %arg2) { 171 entry: 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 184 define internal i64 @test_returning64_even_arg1b(i32 %arg0, i32 %arg0b, i64 %arg1, i64 %arg2) { 185 entry: 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 197 define internal i64 @test_returning64_even_arg2(i64 %arg0, i32 %arg1, i64 %arg2) { 198 entry: 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 211 define internal i64 @test_returning64_even_arg2b(i64 %arg0, i32 %arg1, i32 %arg1b, i64 %arg2) { 212 entry: 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 224 define internal i32 @test_returning32_even_arg2(i64 %arg0, i32 %arg1, i32 %arg2) { 225 entry: 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 235 define internal i32 @test_returning32_even_arg2b(i32 %arg0, i32 %arg1, i32 %arg2, i64 %arg3) { 236 entry: 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. 248 define internal i32 @test_returning32_even_arg4(i32 %arg0, i32 %arg1, i32 %arg2, i64 %arg3, i32 %arg4) { 249 entry: 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 264 declare void @IntArgs(i32, i32, i32, i32, i32, i32) 265 266 declare void @killRegisters() 267 268 define 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