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