1; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD 2; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc -mattr=soft-float | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT 3 4; CHECK-LABEL: intarg: 5; The save/restore frame is not strictly necessary here, but we would need to 6; refer to %o registers instead. 7; CHECK: save %sp, -128, %sp 8; CHECK: ldx [%fp+2231], [[R2:%[gilo][0-7]]] 9; CHECK: ld [%fp+2227], [[R1:%[gilo][0-7]]] 10; CHECK: stb %i0, [%i4] 11; CHECK: stb %i1, [%i4] 12; CHECK: sth %i2, [%i4] 13; CHECK: st %i3, [%i4] 14; CHECK: stx %i4, [%i4] 15; CHECK: st %i5, [%i4] 16; CHECK: st [[R1]], [%i4] 17; CHECK: stx [[R2]], [%i4] 18; CHECK: restore 19define void @intarg(i8 %a0, ; %i0 20 i8 %a1, ; %i1 21 i16 %a2, ; %i2 22 i32 %a3, ; %i3 23 i8* %a4, ; %i4 24 i32 %a5, ; %i5 25 i32 signext %a6, ; [%fp+BIAS+176] 26 i8* %a7) { ; [%fp+BIAS+184] 27 store volatile i8 %a0, i8* %a4 28 store volatile i8 %a1, i8* %a4 29 %p16 = bitcast i8* %a4 to i16* 30 store volatile i16 %a2, i16* %p16 31 %p32 = bitcast i8* %a4 to i32* 32 store volatile i32 %a3, i32* %p32 33 %pp = bitcast i8* %a4 to i8** 34 store volatile i8* %a4, i8** %pp 35 store volatile i32 %a5, i32* %p32 36 store volatile i32 %a6, i32* %p32 37 store volatile i8* %a7, i8** %pp 38 ret void 39} 40 41; CHECK-LABEL: call_intarg: 42; 16 saved + 8 args. 43; CHECK: save %sp, -192, %sp 44; Sign-extend and store the full 64 bits. 45; CHECK: sra %i0, 0, [[R:%[gilo][0-7]]] 46; Use %o0-%o5 for outgoing arguments 47; CHECK: mov 5, %o5 48; CHECK: stx [[R]], [%sp+2223] 49; CHECK: call intarg 50; CHECK-NOT: add %sp 51; CHECK: restore 52define void @call_intarg(i32 %i0, i8* %i1) { 53 call void @intarg(i8 0, i8 1, i16 2, i32 3, i8* undef, i32 5, i32 %i0, i8* %i1) 54 ret void 55} 56 57; CHECK-LABEL: floatarg: 58; HARD: save %sp, -128, %sp 59; HARD: ld [%fp+2307], [[F:%f[0-9]+]] 60; HARD: fstod %f1, 61; HARD: faddd %f2, 62; HARD: faddd %f4, 63; HARD: faddd %f6, 64; HARD: fadds %f31, [[F]] 65; SOFT: save %sp, -176, %sp 66; SOFT: ld [%fp+2299], %i4 67; SOFT: ld [%fp+2307], %i5 68; SOFT: srl %i0, 0, %o0 69; SOFT-NEXT: call __extendsfdf2 70; SOFT: mov %o0, %o1 71; SOFT: mov %i1, %o0 72; SOFT: mov %i2, %o0 73; SOFT: mov %i3, %o0 74define double @floatarg(float %a0, ; %f1 75 double %a1, ; %d2 76 double %a2, ; %d4 77 double %a3, ; %d6 78 float %a4, ; %f9 79 float %a5, ; %f11 80 float %a6, ; %f13 81 float %a7, ; %f15 82 float %a8, ; %f17 83 float %a9, ; %f19 84 float %a10, ; %f21 85 float %a11, ; %f23 86 float %a12, ; %f25 87 float %a13, ; %f27 88 float %a14, ; %f29 89 float %a15, ; %f31 90 float %a16, ; [%fp+BIAS+256] (using 8 bytes) 91 double %a17) { ; [%fp+BIAS+264] (using 8 bytes) 92 %d0 = fpext float %a0 to double 93 %s1 = fadd double %a1, %d0 94 %s2 = fadd double %a2, %s1 95 %s3 = fadd double %a3, %s2 96 %s16 = fadd float %a15, %a16 97 %d16 = fpext float %s16 to double 98 %s17 = fadd double %d16, %s3 99 ret double %s17 100} 101 102; CHECK-LABEL: call_floatarg: 103; CHECK: save %sp, -272, %sp 104; Store 8 bytes in full slot. 105; HARD: std %f2, [%sp+2311] 106; Store 4 bytes, right-aligned in slot. 107; HARD: st %f1, [%sp+2307] 108; HARD: fmovd %f2, %f4 109; SOFT: stx %i1, [%sp+2311] 110; SOFT: stx %i0, [%sp+2303] 111; SOFT: stx %i2, [%sp+2295] 112; SOFT: stx %i2, [%sp+2287] 113; SOFT: stx %i2, [%sp+2279] 114; SOFT: stx %i2, [%sp+2271] 115; SOFT: stx %i2, [%sp+2263] 116; SOFT: stx %i2, [%sp+2255] 117; SOFT: stx %i2, [%sp+2247] 118; SOFT: stx %i2, [%sp+2239] 119; SOFT: stx %i2, [%sp+2231] 120; SOFT: stx %i2, [%sp+2223] 121; SOFT: mov %i2, %o0 122; SOFT: mov %i1, %o1 123; SOFT: mov %i1, %o2 124; SOFT: mov %i1, %o3 125; SOFT: mov %i2, %o4 126; SOFT: mov %i2, %o5 127; CHECK: call floatarg 128; CHECK-NOT: add %sp 129; CHECK: restore 130 131define void @call_floatarg(float %f1, double %d2, float %f5, double *%p) { 132 %r = call double @floatarg(float %f5, double %d2, double %d2, double %d2, 133 float %f5, float %f5, float %f5, float %f5, 134 float %f5, float %f5, float %f5, float %f5, 135 float %f5, float %f5, float %f5, float %f5, 136 float %f1, double %d2) 137 store double %r, double* %p 138 ret void 139} 140 141; CHECK-LABEL: mixedarg: 142; CHECK: ldx [%fp+2247] 143; CHECK: ldx [%fp+2231] 144; SOFT: ldx [%fp+2239], %i0 145; HARD: fstod %f3 146; HARD: faddd %f6 147; HARD: faddd %f16 148; SOFT: mov %o0, %o1 149; SOFT-NEXT: mov %i3, %o0 150; SOFT-NEXT: call __adddf3 151; SOFT: mov %o0, %o1 152; SOFT-NEXT: mov %i0, %o0 153; SOFT-NEXT: call __adddf3 154; HARD: std %f0, [%i1] 155; SOFT: stx %o0, [%i5] 156 157define void @mixedarg(i8 %a0, ; %i0 158 float %a1, ; %f3 159 i16 %a2, ; %i2 160 double %a3, ; %d6 161 i13 %a4, ; %i4 162 float %a5, ; %f11 163 i64 %a6, ; [%fp+BIAS+176] 164 double *%a7, ; [%fp+BIAS+184] 165 double %a8, ; %d16 166 i16* %a9) { ; [%fp+BIAS+200] 167 %d1 = fpext float %a1 to double 168 %s3 = fadd double %a3, %d1 169 %s8 = fadd double %a8, %s3 170 store double %s8, double* %a7 171 store i16 %a2, i16* %a9 172 ret void 173} 174 175; CHECK-LABEL: call_mixedarg: 176; CHECK: stx %i2, [%sp+2247] 177; SOFT: stx %i1, [%sp+2239] 178; CHECK: stx %i0, [%sp+2223] 179; HARD: fmovd %f2, %f6 180; HARD: fmovd %f2, %f16 181; SOFT: mov %i1, %o3 182; CHECK: call mixedarg 183; CHECK-NOT: add %sp 184; CHECK: restore 185 186define void @call_mixedarg(i64 %i0, double %f2, i16* %i2) { 187 call void @mixedarg(i8 undef, 188 float undef, 189 i16 undef, 190 double %f2, 191 i13 undef, 192 float undef, 193 i64 %i0, 194 double* undef, 195 double %f2, 196 i16* %i2) 197 ret void 198} 199 200; The inreg attribute is used to indicate 32-bit sized struct elements that 201; share an 8-byte slot. 202; CHECK-LABEL: inreg_fi: 203; SOFT: srlx %i0, 32, [[R:%[gilo][0-7]]] 204; HARD: fstoi %f1 205; SOFT: call __fixsfsi 206; HARD: srlx %i0, 32, [[R:%[gilo][0-7]]] 207; CHECK: sub [[R]], 208define i32 @inreg_fi(i32 inreg %a0, ; high bits of %i0 209 float inreg %a1) { ; %f1 210 %b1 = fptosi float %a1 to i32 211 %rv = sub i32 %a0, %b1 212 ret i32 %rv 213} 214 215; CHECK-LABEL: call_inreg_fi: 216; Allocate space for 6 arguments, even when only 2 are used. 217; CHECK: save %sp, -176, %sp 218; HARD-DAG: sllx %i1, 32, %o0 219; HARD-DAG: fmovs %f5, %f1 220; SOFT: srl %i2, 0, %i0 221; SOFT: sllx %i1, 32, %i1 222; SOFT: or %i1, %i0, %o0 223; CHECK: call inreg_fi 224define void @call_inreg_fi(i32* %p, i32 %i1, float %f5) { 225 %x = call i32 @inreg_fi(i32 %i1, float %f5) 226 ret void 227} 228 229; CHECK-LABEL: inreg_ff: 230; HARD: fsubs %f0, %f1, %f0 231; SOFT: srlx %i0, 32, %o0 232; SOFT: srl %i0, 0, %o1 233; SOFT: call __subsf3 234define float @inreg_ff(float inreg %a0, ; %f0 235 float inreg %a1) { ; %f1 236 %rv = fsub float %a0, %a1 237 ret float %rv 238} 239 240; CHECK-LABEL: call_inreg_ff: 241; HARD-DAG: fmovs %f3, %f0 242; HARD-DAG: fmovs %f5, %f1 243; SOFT: srl %i2, 0, %i0 244; SOFT: sllx %i1, 32, %i1 245; SOFT: or %i1, %i0, %o0 246; CHECK: call inreg_ff 247define void @call_inreg_ff(i32* %p, float %f3, float %f5) { 248 %x = call float @inreg_ff(float %f3, float %f5) 249 ret void 250} 251 252; CHECK-LABEL: inreg_if: 253; HARD: fstoi %f0 254; SOFT: srlx %i0, 32, %o0 255; SOFT: call __fixsfsi 256; CHECK: sub %i0 257define i32 @inreg_if(float inreg %a0, ; %f0 258 i32 inreg %a1) { ; low bits of %i0 259 %b0 = fptosi float %a0 to i32 260 %rv = sub i32 %a1, %b0 261 ret i32 %rv 262} 263 264; CHECK-LABEL: call_inreg_if: 265; HARD: fmovs %f3, %f0 266; HARD: mov %i2, %o0 267; SOFT: srl %i2, 0, %i0 268; SOFT: sllx %i1, 32, %i1 269; SOFT: or %i1, %i0, %o0 270; CHECK: call inreg_if 271define void @call_inreg_if(i32* %p, float %f3, i32 %i2) { 272 %x = call i32 @inreg_if(float %f3, i32 %i2) 273 ret void 274} 275 276; The frontend shouldn't do this. Just pass i64 instead. 277; CHECK-LABEL: inreg_ii: 278; CHECK: srlx %i0, 32, [[R:%[gilo][0-7]]] 279; CHECK: sub %i0, [[R]], %i0 280define i32 @inreg_ii(i32 inreg %a0, ; high bits of %i0 281 i32 inreg %a1) { ; low bits of %i0 282 %rv = sub i32 %a1, %a0 283 ret i32 %rv 284} 285 286; CHECK-LABEL: call_inreg_ii: 287; CHECK: srl %i2, 0, [[R2:%[gilo][0-7]]] 288; CHECK: sllx %i1, 32, [[R1:%[gilo][0-7]]] 289; CHECK: or [[R1]], [[R2]], %o0 290; CHECK: call inreg_ii 291define void @call_inreg_ii(i32* %p, i32 %i1, i32 %i2) { 292 %x = call i32 @inreg_ii(i32 %i1, i32 %i2) 293 ret void 294} 295 296; Structs up to 32 bytes in size can be returned in registers. 297; CHECK-LABEL: ret_i64_pair: 298; CHECK: ldx [%i2], %i0 299; CHECK: ldx [%i3], %i1 300define { i64, i64 } @ret_i64_pair(i32 %a0, i32 %a1, i64* %p, i64* %q) { 301 %r1 = load i64, i64* %p 302 %rv1 = insertvalue { i64, i64 } undef, i64 %r1, 0 303 store i64 0, i64* %p 304 %r2 = load i64, i64* %q 305 %rv2 = insertvalue { i64, i64 } %rv1, i64 %r2, 1 306 ret { i64, i64 } %rv2 307} 308 309; CHECK-LABEL: call_ret_i64_pair: 310; CHECK: call ret_i64_pair 311; CHECK: stx %o0, [%i0] 312; CHECK: stx %o1, [%i0] 313define void @call_ret_i64_pair(i64* %i0) { 314 %rv = call { i64, i64 } @ret_i64_pair(i32 undef, i32 undef, 315 i64* undef, i64* undef) 316 %e0 = extractvalue { i64, i64 } %rv, 0 317 store volatile i64 %e0, i64* %i0 318 %e1 = extractvalue { i64, i64 } %rv, 1 319 store i64 %e1, i64* %i0 320 ret void 321} 322 323; This is not a C struct, the i32 member uses 8 bytes, but the float only 4. 324; CHECK-LABEL: ret_i32_float_pair: 325; CHECK: ld [%i2], %i0 326; HARD: ld [%i3], %f2 327; SOFT: ld [%i3], %i1 328define { i32, float } @ret_i32_float_pair(i32 %a0, i32 %a1, 329 i32* %p, float* %q) { 330 %r1 = load i32, i32* %p 331 %rv1 = insertvalue { i32, float } undef, i32 %r1, 0 332 store i32 0, i32* %p 333 %r2 = load float, float* %q 334 %rv2 = insertvalue { i32, float } %rv1, float %r2, 1 335 ret { i32, float } %rv2 336} 337 338; CHECK-LABEL: call_ret_i32_float_pair: 339; CHECK: call ret_i32_float_pair 340; CHECK: st %o0, [%i0] 341; HARD: st %f2, [%i1] 342; SOFT: st %o1, [%i1] 343define void @call_ret_i32_float_pair(i32* %i0, float* %i1) { 344 %rv = call { i32, float } @ret_i32_float_pair(i32 undef, i32 undef, 345 i32* undef, float* undef) 346 %e0 = extractvalue { i32, float } %rv, 0 347 store i32 %e0, i32* %i0 348 %e1 = extractvalue { i32, float } %rv, 1 349 store float %e1, float* %i1 350 ret void 351} 352 353; This is a C struct, each member uses 4 bytes. 354; CHECK-LABEL: ret_i32_float_packed: 355; CHECK: ld [%i2], [[R:%[gilo][0-7]]] 356; HARD: ld [%i3], %f1 357; SOFT: ld [%i3], %i1 358; CHECK: sllx [[R]], 32, %i0 359define inreg { i32, float } @ret_i32_float_packed(i32 %a0, i32 %a1, 360 i32* %p, float* %q) { 361 %r1 = load i32, i32* %p 362 %rv1 = insertvalue { i32, float } undef, i32 %r1, 0 363 store i32 0, i32* %p 364 %r2 = load float, float* %q 365 %rv2 = insertvalue { i32, float } %rv1, float %r2, 1 366 ret { i32, float } %rv2 367} 368 369; CHECK-LABEL: call_ret_i32_float_packed: 370; CHECK: call ret_i32_float_packed 371; CHECK: srlx %o0, 32, [[R:%[gilo][0-7]]] 372; CHECK: st [[R]], [%i0] 373; HARD: st %f1, [%i1] 374; SOFT: st %o0, [%i1] 375define void @call_ret_i32_float_packed(i32* %i0, float* %i1) { 376 %rv = call { i32, float } @ret_i32_float_packed(i32 undef, i32 undef, 377 i32* undef, float* undef) 378 %e0 = extractvalue { i32, float } %rv, 0 379 store i32 %e0, i32* %i0 380 %e1 = extractvalue { i32, float } %rv, 1 381 store float %e1, float* %i1 382 ret void 383} 384 385; The C frontend should use i64 to return { i32, i32 } structs, but verify that 386; we don't miscompile thi case where both struct elements are placed in %i0. 387; CHECK-LABEL: ret_i32_packed: 388; CHECK: ld [%i2], [[R1:%[gilo][0-7]]] 389; CHECK: ld [%i3], [[R2:%[gilo][0-7]]] 390; CHECK: sllx [[R2]], 32, [[R3:%[gilo][0-7]]] 391; CHECK: or [[R3]], [[R1]], %i0 392define inreg { i32, i32 } @ret_i32_packed(i32 %a0, i32 %a1, 393 i32* %p, i32* %q) { 394 %r1 = load i32, i32* %p 395 %rv1 = insertvalue { i32, i32 } undef, i32 %r1, 1 396 store i32 0, i32* %p 397 %r2 = load i32, i32* %q 398 %rv2 = insertvalue { i32, i32 } %rv1, i32 %r2, 0 399 ret { i32, i32 } %rv2 400} 401 402; CHECK-LABEL: call_ret_i32_packed: 403; CHECK: call ret_i32_packed 404; CHECK: srlx %o0, 32, [[R:%[gilo][0-7]]] 405; CHECK: st [[R]], [%i0] 406; CHECK: st %o0, [%i1] 407define void @call_ret_i32_packed(i32* %i0, i32* %i1) { 408 %rv = call { i32, i32 } @ret_i32_packed(i32 undef, i32 undef, 409 i32* undef, i32* undef) 410 %e0 = extractvalue { i32, i32 } %rv, 0 411 store i32 %e0, i32* %i0 412 %e1 = extractvalue { i32, i32 } %rv, 1 413 store i32 %e1, i32* %i1 414 ret void 415} 416 417; The return value must be sign-extended to 64 bits. 418; CHECK-LABEL: ret_sext: 419; CHECK: sra %i0, 0, %i0 420define signext i32 @ret_sext(i32 %a0) { 421 ret i32 %a0 422} 423 424; CHECK-LABEL: ret_zext: 425; CHECK: srl %i0, 0, %i0 426define zeroext i32 @ret_zext(i32 %a0) { 427 ret i32 %a0 428} 429 430; CHECK-LABEL: ret_nosext: 431; CHECK-NOT: sra 432define signext i32 @ret_nosext(i32 signext %a0) { 433 ret i32 %a0 434} 435 436; CHECK-LABEL: ret_nozext: 437; CHECK-NOT: srl 438define signext i32 @ret_nozext(i32 signext %a0) { 439 ret i32 %a0 440} 441 442; CHECK-LABEL: test_register_directive: 443; CHECK: .register %g2, #scratch 444; CHECK: .register %g3, #scratch 445; CHECK: add %i0, 2, %g2 446; CHECK: add %i0, 3, %g3 447define i32 @test_register_directive(i32 %i0) { 448entry: 449 %0 = add nsw i32 %i0, 2 450 %1 = add nsw i32 %i0, 3 451 tail call void asm sideeffect "", "r,r,~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6},~{o7},~{g1},~{g4},~{g5},~{g6},~{g7}"(i32 %0, i32 %1) 452 %2 = add nsw i32 %0, %1 453 ret i32 %2 454} 455 456; CHECK-LABEL: test_large_stack: 457 458; CHECK: sethi 16, %g1 459; CHECK: xor %g1, -176, %g1 460; CHECK: save %sp, %g1, %sp 461 462; CHECK: sethi 14, %g1 463; CHECK: xor %g1, -1, %g1 464; CHECK: add %g1, %fp, %g1 465; CHECK: call use_buf 466 467define i32 @test_large_stack() { 468entry: 469 %buffer1 = alloca [16384 x i8], align 8 470 %buffer1.sub = getelementptr inbounds [16384 x i8], [16384 x i8]* %buffer1, i32 0, i32 0 471 %0 = call i32 @use_buf(i32 16384, i8* %buffer1.sub) 472 ret i32 %0 473} 474 475declare i32 @use_buf(i32, i8*) 476 477; CHECK-LABEL: test_fp128_args: 478; HARD-DAG: std %f0, [%fp+{{.+}}] 479; HARD-DAG: std %f2, [%fp+{{.+}}] 480; HARD-DAG: std %f6, [%fp+{{.+}}] 481; HARD-DAG: std %f4, [%fp+{{.+}}] 482; HARD: add %fp, [[Offset:[0-9]+]], %o0 483; HARD: call _Qp_add 484; HARD: ldd [%fp+[[Offset]]], %f0 485; SOFT-DAG: mov %i0, %o0 486; SOFT-DAG: mov %i1, %o1 487; SOFT-DAG: mov %i2, %o2 488; SOFT-DAG: mov %i3, %o3 489; SOFT: call __addtf3 490; SOFT: mov %o0, %i0 491; SOFT: mov %o1, %i1 492 493define fp128 @test_fp128_args(fp128 %a, fp128 %b) { 494entry: 495 %0 = fadd fp128 %a, %b 496 ret fp128 %0 497} 498 499declare i64 @receive_fp128(i64 %a, ...) 500 501; CHECK-LABEL: test_fp128_variable_args: 502; HARD-DAG: std %f4, [%sp+[[Offset0:[0-9]+]]] 503; HARD-DAG: std %f6, [%sp+[[Offset1:[0-9]+]]] 504; HARD-DAG: ldx [%sp+[[Offset0]]], %o2 505; HARD-DAG: ldx [%sp+[[Offset1]]], %o3 506; SOFT-DAG: mov %i0, %o0 507; SOFT-DAG: mov %i1, %o1 508; SOFT-DAG: mov %i2, %o2 509; CHECK: call receive_fp128 510define i64 @test_fp128_variable_args(i64 %a, fp128 %b) { 511entry: 512 %0 = call i64 (i64, ...) @receive_fp128(i64 %a, fp128 %b) 513 ret i64 %0 514} 515 516; CHECK-LABEL: test_call_libfunc: 517; HARD: st %f1, [%fp+[[Offset0:[0-9]+]]] 518; HARD: fmovs %f3, %f1 519; SOFT: srl %i1, 0, %o0 520; CHECK: call cosf 521; HARD: st %f0, [%fp+[[Offset1:[0-9]+]]] 522; HARD: ld [%fp+[[Offset0]]], %f1 523; SOFT: mov %o0, %i1 524; SOFT: srl %i0, 0, %o0 525; CHECK: call sinf 526; HARD: ld [%fp+[[Offset1]]], %f1 527; HARD: fmuls %f1, %f0, %f0 528; SOFT: mov %o0, %o1 529; SOFT: mov %i1, %o0 530; SOFT: call __mulsf3 531; SOFT: sllx %o0, 32, %i0 532 533define inreg float @test_call_libfunc(float %arg0, float %arg1) { 534entry: 535 %0 = tail call inreg float @cosf(float %arg1) 536 %1 = tail call inreg float @sinf(float %arg0) 537 %2 = fmul float %0, %1 538 ret float %2 539} 540 541declare inreg float @cosf(float %arg) readnone nounwind 542declare inreg float @sinf(float %arg) readnone nounwind 543