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 i8 %a0, i8* %a4 28 store i8 %a1, i8* %a4 29 %p16 = bitcast i8* %a4 to i16* 30 store i16 %a2, i16* %p16 31 %p32 = bitcast i8* %a4 to i32* 32 store i32 %a3, i32* %p32 33 %pp = bitcast i8* %a4 to i8** 34 store i8* %a4, i8** %pp 35 store i32 %a5, i32* %p32 36 store i32 %a6, i32* %p32 37 store 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: srl %i0, 0, %o0 67; SOFT-NEXT: call __extendsfdf2 68; SOFT: mov %o0, %i0 69; SOFT: mov %i1, %o0 70; SOFT: mov %i2, %o0 71; SOFT: mov %i3, %o0 72; SOFT: ld [%fp+2299], %o0 73; SOFT: ld [%fp+2307], %o1 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, %i1 149; SOFT-NEXT: mov %i3, %o0 150; SOFT-NEXT: mov %i1, %o1 151; SOFT-NEXT: call __adddf3 152; SOFT: mov %o0, %i1 153; SOFT-NEXT: mov %i0, %o0 154; SOFT-NEXT: mov %i1, %o1 155; SOFT-NEXT: call __adddf3 156; HARD: std %f0, [%i1] 157; SOFT: stx %o0, [%i5] 158 159define void @mixedarg(i8 %a0, ; %i0 160 float %a1, ; %f3 161 i16 %a2, ; %i2 162 double %a3, ; %d6 163 i13 %a4, ; %i4 164 float %a5, ; %f11 165 i64 %a6, ; [%fp+BIAS+176] 166 double *%a7, ; [%fp+BIAS+184] 167 double %a8, ; %d16 168 i16* %a9) { ; [%fp+BIAS+200] 169 %d1 = fpext float %a1 to double 170 %s3 = fadd double %a3, %d1 171 %s8 = fadd double %a8, %s3 172 store double %s8, double* %a7 173 store i16 %a2, i16* %a9 174 ret void 175} 176 177; CHECK-LABEL: call_mixedarg: 178; CHECK: stx %i2, [%sp+2247] 179; SOFT: stx %i1, [%sp+2239] 180; CHECK: stx %i0, [%sp+2223] 181; HARD: fmovd %f2, %f6 182; HARD: fmovd %f2, %f16 183; SOFT: mov %i1, %o3 184; CHECK: call mixedarg 185; CHECK-NOT: add %sp 186; CHECK: restore 187 188define void @call_mixedarg(i64 %i0, double %f2, i16* %i2) { 189 call void @mixedarg(i8 undef, 190 float undef, 191 i16 undef, 192 double %f2, 193 i13 undef, 194 float undef, 195 i64 %i0, 196 double* undef, 197 double %f2, 198 i16* %i2) 199 ret void 200} 201 202; The inreg attribute is used to indicate 32-bit sized struct elements that 203; share an 8-byte slot. 204; CHECK-LABEL: inreg_fi: 205; SOFT: srlx %i0, 32, [[R:%[gilo][0-7]]] 206; HARD: fstoi %f1 207; SOFT: call __fixsfsi 208; HARD: srlx %i0, 32, [[R:%[gilo][0-7]]] 209; CHECK: sub [[R]], 210define i32 @inreg_fi(i32 inreg %a0, ; high bits of %i0 211 float inreg %a1) { ; %f1 212 %b1 = fptosi float %a1 to i32 213 %rv = sub i32 %a0, %b1 214 ret i32 %rv 215} 216 217; CHECK-LABEL: call_inreg_fi: 218; Allocate space for 6 arguments, even when only 2 are used. 219; CHECK: save %sp, -176, %sp 220; HARD: sllx %i1, 32, %o0 221; HARD: fmovs %f5, %f1 222; SOFT: srl %i2, 0, %i0 223; SOFT: sllx %i1, 32, %i1 224; SOFT: or %i1, %i0, %o0 225; CHECK: call inreg_fi 226define void @call_inreg_fi(i32* %p, i32 %i1, float %f5) { 227 %x = call i32 @inreg_fi(i32 %i1, float %f5) 228 ret void 229} 230 231; CHECK-LABEL: inreg_ff: 232; HARD: fsubs %f0, %f1, %f0 233; SOFT: srlx %i0, 32, %o0 234; SOFT: srl %i0, 0, %o1 235; SOFT: call __subsf3 236define float @inreg_ff(float inreg %a0, ; %f0 237 float inreg %a1) { ; %f1 238 %rv = fsub float %a0, %a1 239 ret float %rv 240} 241 242; CHECK-LABEL: call_inreg_ff: 243; HARD: fmovs %f3, %f0 244; HARD: fmovs %f5, %f1 245; SOFT: srl %i2, 0, %i0 246; SOFT: sllx %i1, 32, %i1 247; SOFT: or %i1, %i0, %o0 248; CHECK: call inreg_ff 249define void @call_inreg_ff(i32* %p, float %f3, float %f5) { 250 %x = call float @inreg_ff(float %f3, float %f5) 251 ret void 252} 253 254; CHECK-LABEL: inreg_if: 255; HARD: fstoi %f0 256; SOFT: srlx %i0, 32, %o0 257; SOFT: call __fixsfsi 258; CHECK: sub %i0 259define i32 @inreg_if(float inreg %a0, ; %f0 260 i32 inreg %a1) { ; low bits of %i0 261 %b0 = fptosi float %a0 to i32 262 %rv = sub i32 %a1, %b0 263 ret i32 %rv 264} 265 266; CHECK-LABEL: call_inreg_if: 267; HARD: fmovs %f3, %f0 268; HARD: mov %i2, %o0 269; SOFT: srl %i2, 0, %i0 270; SOFT: sllx %i1, 32, %i1 271; SOFT: or %i1, %i0, %o0 272; CHECK: call inreg_if 273define void @call_inreg_if(i32* %p, float %f3, i32 %i2) { 274 %x = call i32 @inreg_if(float %f3, i32 %i2) 275 ret void 276} 277 278; The frontend shouldn't do this. Just pass i64 instead. 279; CHECK-LABEL: inreg_ii: 280; CHECK: srlx %i0, 32, [[R:%[gilo][0-7]]] 281; CHECK: sub %i0, [[R]], %i0 282define i32 @inreg_ii(i32 inreg %a0, ; high bits of %i0 283 i32 inreg %a1) { ; low bits of %i0 284 %rv = sub i32 %a1, %a0 285 ret i32 %rv 286} 287 288; CHECK-LABEL: call_inreg_ii: 289; CHECK: srl %i2, 0, [[R2:%[gilo][0-7]]] 290; CHECK: sllx %i1, 32, [[R1:%[gilo][0-7]]] 291; CHECK: or [[R1]], [[R2]], %o0 292; CHECK: call inreg_ii 293define void @call_inreg_ii(i32* %p, i32 %i1, i32 %i2) { 294 %x = call i32 @inreg_ii(i32 %i1, i32 %i2) 295 ret void 296} 297 298; Structs up to 32 bytes in size can be returned in registers. 299; CHECK-LABEL: ret_i64_pair: 300; CHECK: ldx [%i2], %i0 301; CHECK: ldx [%i3], %i1 302define { i64, i64 } @ret_i64_pair(i32 %a0, i32 %a1, i64* %p, i64* %q) { 303 %r1 = load i64, i64* %p 304 %rv1 = insertvalue { i64, i64 } undef, i64 %r1, 0 305 store i64 0, i64* %p 306 %r2 = load i64, i64* %q 307 %rv2 = insertvalue { i64, i64 } %rv1, i64 %r2, 1 308 ret { i64, i64 } %rv2 309} 310 311; CHECK-LABEL: call_ret_i64_pair: 312; CHECK: call ret_i64_pair 313; CHECK: stx %o0, [%i0] 314; CHECK: stx %o1, [%i0] 315define void @call_ret_i64_pair(i64* %i0) { 316 %rv = call { i64, i64 } @ret_i64_pair(i32 undef, i32 undef, 317 i64* undef, i64* undef) 318 %e0 = extractvalue { i64, i64 } %rv, 0 319 store i64 %e0, i64* %i0 320 %e1 = extractvalue { i64, i64 } %rv, 1 321 store i64 %e1, i64* %i0 322 ret void 323} 324 325; This is not a C struct, the i32 member uses 8 bytes, but the float only 4. 326; CHECK-LABEL: ret_i32_float_pair: 327; CHECK: ld [%i2], %i0 328; HARD: ld [%i3], %f2 329; SOFT: ld [%i3], %i1 330define { i32, float } @ret_i32_float_pair(i32 %a0, i32 %a1, 331 i32* %p, float* %q) { 332 %r1 = load i32, i32* %p 333 %rv1 = insertvalue { i32, float } undef, i32 %r1, 0 334 store i32 0, i32* %p 335 %r2 = load float, float* %q 336 %rv2 = insertvalue { i32, float } %rv1, float %r2, 1 337 ret { i32, float } %rv2 338} 339 340; CHECK-LABEL: call_ret_i32_float_pair: 341; CHECK: call ret_i32_float_pair 342; CHECK: st %o0, [%i0] 343; HARD: st %f2, [%i1] 344; SOFT: st %o1, [%i1] 345define void @call_ret_i32_float_pair(i32* %i0, float* %i1) { 346 %rv = call { i32, float } @ret_i32_float_pair(i32 undef, i32 undef, 347 i32* undef, float* undef) 348 %e0 = extractvalue { i32, float } %rv, 0 349 store i32 %e0, i32* %i0 350 %e1 = extractvalue { i32, float } %rv, 1 351 store float %e1, float* %i1 352 ret void 353} 354 355; This is a C struct, each member uses 4 bytes. 356; CHECK-LABEL: ret_i32_float_packed: 357; CHECK: ld [%i2], [[R:%[gilo][0-7]]] 358; HARD: ld [%i3], %f1 359; SOFT: ld [%i3], %i1 360; CHECK: sllx [[R]], 32, %i0 361define inreg { i32, float } @ret_i32_float_packed(i32 %a0, i32 %a1, 362 i32* %p, float* %q) { 363 %r1 = load i32, i32* %p 364 %rv1 = insertvalue { i32, float } undef, i32 %r1, 0 365 store i32 0, i32* %p 366 %r2 = load float, float* %q 367 %rv2 = insertvalue { i32, float } %rv1, float %r2, 1 368 ret { i32, float } %rv2 369} 370 371; CHECK-LABEL: call_ret_i32_float_packed: 372; CHECK: call ret_i32_float_packed 373; CHECK: srlx %o0, 32, [[R:%[gilo][0-7]]] 374; CHECK: st [[R]], [%i0] 375; HARD: st %f1, [%i1] 376; SOFT: st %o0, [%i1] 377define void @call_ret_i32_float_packed(i32* %i0, float* %i1) { 378 %rv = call { i32, float } @ret_i32_float_packed(i32 undef, i32 undef, 379 i32* undef, float* undef) 380 %e0 = extractvalue { i32, float } %rv, 0 381 store i32 %e0, i32* %i0 382 %e1 = extractvalue { i32, float } %rv, 1 383 store float %e1, float* %i1 384 ret void 385} 386 387; The C frontend should use i64 to return { i32, i32 } structs, but verify that 388; we don't miscompile thi case where both struct elements are placed in %i0. 389; CHECK-LABEL: ret_i32_packed: 390; CHECK: ld [%i2], [[R1:%[gilo][0-7]]] 391; CHECK: ld [%i3], [[R2:%[gilo][0-7]]] 392; CHECK: sllx [[R2]], 32, [[R3:%[gilo][0-7]]] 393; CHECK: or [[R3]], [[R1]], %i0 394define inreg { i32, i32 } @ret_i32_packed(i32 %a0, i32 %a1, 395 i32* %p, i32* %q) { 396 %r1 = load i32, i32* %p 397 %rv1 = insertvalue { i32, i32 } undef, i32 %r1, 1 398 store i32 0, i32* %p 399 %r2 = load i32, i32* %q 400 %rv2 = insertvalue { i32, i32 } %rv1, i32 %r2, 0 401 ret { i32, i32 } %rv2 402} 403 404; CHECK-LABEL: call_ret_i32_packed: 405; CHECK: call ret_i32_packed 406; CHECK: srlx %o0, 32, [[R:%[gilo][0-7]]] 407; CHECK: st [[R]], [%i0] 408; CHECK: st %o0, [%i1] 409define void @call_ret_i32_packed(i32* %i0, i32* %i1) { 410 %rv = call { i32, i32 } @ret_i32_packed(i32 undef, i32 undef, 411 i32* undef, i32* undef) 412 %e0 = extractvalue { i32, i32 } %rv, 0 413 store i32 %e0, i32* %i0 414 %e1 = extractvalue { i32, i32 } %rv, 1 415 store i32 %e1, i32* %i1 416 ret void 417} 418 419; The return value must be sign-extended to 64 bits. 420; CHECK-LABEL: ret_sext: 421; CHECK: sra %i0, 0, %i0 422define signext i32 @ret_sext(i32 %a0) { 423 ret i32 %a0 424} 425 426; CHECK-LABEL: ret_zext: 427; CHECK: srl %i0, 0, %i0 428define zeroext i32 @ret_zext(i32 %a0) { 429 ret i32 %a0 430} 431 432; CHECK-LABEL: ret_nosext: 433; CHECK-NOT: sra 434define signext i32 @ret_nosext(i32 signext %a0) { 435 ret i32 %a0 436} 437 438; CHECK-LABEL: ret_nozext: 439; CHECK-NOT: srl 440define signext i32 @ret_nozext(i32 signext %a0) { 441 ret i32 %a0 442} 443 444; CHECK-LABEL: test_register_directive: 445; CHECK: .register %g2, #scratch 446; CHECK: .register %g3, #scratch 447; CHECK: add %i0, 2, %g2 448; CHECK: add %i0, 3, %g3 449define i32 @test_register_directive(i32 %i0) { 450entry: 451 %0 = add nsw i32 %i0, 2 452 %1 = add nsw i32 %i0, 3 453 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) 454 %2 = add nsw i32 %0, %1 455 ret i32 %2 456} 457 458; CHECK-LABEL: test_large_stack: 459 460; CHECK: sethi 16, %g1 461; CHECK: xor %g1, -176, %g1 462; CHECK: save %sp, %g1, %sp 463 464; CHECK: sethi 14, %g1 465; CHECK: xor %g1, -1, %g1 466; CHECK: add %g1, %fp, %g1 467; CHECK: call use_buf 468 469define i32 @test_large_stack() { 470entry: 471 %buffer1 = alloca [16384 x i8], align 8 472 %buffer1.sub = getelementptr inbounds [16384 x i8], [16384 x i8]* %buffer1, i32 0, i32 0 473 %0 = call i32 @use_buf(i32 16384, i8* %buffer1.sub) 474 ret i32 %0 475} 476 477declare i32 @use_buf(i32, i8*) 478 479; CHECK-LABEL: test_fp128_args: 480; HARD-DAG: std %f0, [%fp+{{.+}}] 481; HARD-DAG: std %f2, [%fp+{{.+}}] 482; HARD-DAG: std %f6, [%fp+{{.+}}] 483; HARD-DAG: std %f4, [%fp+{{.+}}] 484; HARD: add %fp, [[Offset:[0-9]+]], %o0 485; HARD: call _Qp_add 486; HARD: ldd [%fp+[[Offset]]], %f0 487; SOFT-DAG: mov %i0, %o0 488; SOFT-DAG: mov %i1, %o1 489; SOFT-DAG: mov %i2, %o2 490; SOFT-DAG: mov %i3, %o3 491; SOFT: call __addtf3 492; SOFT: mov %o0, %i0 493; SOFT: mov %o1, %i1 494 495define fp128 @test_fp128_args(fp128 %a, fp128 %b) { 496entry: 497 %0 = fadd fp128 %a, %b 498 ret fp128 %0 499} 500 501declare i64 @receive_fp128(i64 %a, ...) 502 503; CHECK-LABEL: test_fp128_variable_args: 504; HARD-DAG: std %f4, [%sp+[[Offset0:[0-9]+]]] 505; HARD-DAG: std %f6, [%sp+[[Offset1:[0-9]+]]] 506; HARD-DAG: ldx [%sp+[[Offset0]]], %o2 507; HARD-DAG: ldx [%sp+[[Offset1]]], %o3 508; SOFT-DAG: mov %i0, %o0 509; SOFT-DAG: mov %i1, %o1 510; SOFT-DAG: mov %i2, %o2 511; CHECK: call receive_fp128 512define i64 @test_fp128_variable_args(i64 %a, fp128 %b) { 513entry: 514 %0 = call i64 (i64, ...) @receive_fp128(i64 %a, fp128 %b) 515 ret i64 %0 516} 517 518; CHECK-LABEL: test_call_libfunc: 519; HARD: st %f1, [%fp+[[Offset0:[0-9]+]]] 520; HARD: fmovs %f3, %f1 521; SOFT: srl %i1, 0, %o0 522; CHECK: call cosf 523; HARD: st %f0, [%fp+[[Offset1:[0-9]+]]] 524; HARD: ld [%fp+[[Offset0]]], %f1 525; SOFT: mov %o0, %i1 526; SOFT: srl %i0, 0, %o0 527; CHECK: call sinf 528; HARD: ld [%fp+[[Offset1]]], %f1 529; HARD: fmuls %f1, %f0, %f0 530; SOFT: mov %o0, %i0 531; SOFT: mov %i1, %o0 532; SOFT: mov %i0, %o1 533; SOFT: call __mulsf3 534; SOFT: sllx %o0, 32, %i0 535 536define inreg float @test_call_libfunc(float %arg0, float %arg1) { 537entry: 538 %0 = tail call inreg float @cosf(float %arg1) 539 %1 = tail call inreg float @sinf(float %arg0) 540 %2 = fmul float %0, %1 541 ret float %2 542} 543 544declare inreg float @cosf(float %arg) readnone nounwind 545declare inreg float @sinf(float %arg) readnone nounwind 546