1; RUN: llc < %s -march=sparc -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD --check-prefix=CHECK-BE 2; RUN: llc < %s -march=sparcel -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD --check-prefix=CHECK-LE 3; RUN: llc < %s -march=sparc -disable-sparc-delay-filler -disable-sparc-leaf-proc -mattr=soft-float | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT --check-prefix=CHECK-BE 4 5; CHECK-LABEL: intarg: 6; The save/restore frame is not strictly necessary here, but we would need to 7; refer to %o registers instead. 8; CHECK: save %sp, -96, %sp 9; CHECK: ld [%fp+96], [[R2:%[gilo][0-7]]] 10; CHECK: ld [%fp+92], [[R1:%[gilo][0-7]]] 11; CHECK: stb %i0, [%i4] 12; CHECK: stb %i1, [%i4] 13; CHECK: sth %i2, [%i4] 14; CHECK: st %i3, [%i4] 15; CHECK: st %i4, [%i4] 16; CHECK: st %i5, [%i4] 17; CHECK: st [[R1]], [%i4] 18; CHECK: st [[R2]], [%i4] 19; CHECK: restore 20define void @intarg(i8 %a0, ; %i0 21 i8 %a1, ; %i1 22 i16 %a2, ; %i2 23 i32 %a3, ; %i3 24 i8* %a4, ; %i4 25 i32 %a5, ; %i5 26 i32 signext %a6, ; [%fp+92] 27 i8* %a7) { ; [%fp+96] 28 store i8 %a0, i8* %a4 29 store i8 %a1, i8* %a4 30 %p16 = bitcast i8* %a4 to i16* 31 store i16 %a2, i16* %p16 32 %p32 = bitcast i8* %a4 to i32* 33 store i32 %a3, i32* %p32 34 %pp = bitcast i8* %a4 to i8** 35 store i8* %a4, i8** %pp 36 store i32 %a5, i32* %p32 37 store i32 %a6, i32* %p32 38 store i8* %a7, i8** %pp 39 ret void 40} 41 42; CHECK-LABEL: call_intarg: 43; CHECK: save %sp, -104, %sp 44; Use %o0-%o5 for outgoing arguments 45; CHECK: mov 5, %o5 46; CHECK: st %i0, [%sp+92] 47; CHECK: call intarg 48; CHECK-NOT: add %sp 49; CHECK: restore 50define void @call_intarg(i32 %i0, i8* %i1) { 51 call void @intarg(i8 0, i8 1, i16 2, i32 3, i8* undef, i32 5, i32 %i0, i8* %i1) 52 ret void 53} 54 55;; Verify doubles starting with an even reg, starting with an odd reg, 56;; straddling the boundary of regs and mem, and floats in regs and mem. 57; 58; CHECK-LABEL: floatarg: 59; HARD: save %sp, -120, %sp 60; HARD: mov %i5, %g2 61; HARD-NEXT: ld [%fp+92], %g3 62; HARD-NEXT: mov %i4, %i5 63; HARD-NEXT: std %g2, [%fp+-24] 64; HARD-NEXT: mov %i3, %i4 65; HARD-NEXT: std %i4, [%fp+-16] 66; HARD-NEXT: std %i0, [%fp+-8] 67; HARD-NEXT: st %i2, [%fp+-28] 68; HARD-NEXT: ld [%fp+104], %f0 69; HARD-NEXT: ldd [%fp+96], %f2 70; HARD-NEXT: ld [%fp+-28], %f1 71; HARD-NEXT: ldd [%fp+-8], %f4 72; HARD-NEXT: ldd [%fp+-16], %f6 73; HARD-NEXT: ldd [%fp+-24], %f8 74; HARD-NEXT: fstod %f1, %f10 75; HARD-NEXT: faddd %f4, %f10, %f4 76; HARD-NEXT: faddd %f6, %f4, %f4 77; HARD-NEXT: faddd %f8, %f4, %f4 78; HARD-NEXT: faddd %f2, %f4, %f2 79; HARD-NEXT: fstod %f0, %f0 80; HARD-NEXT: faddd %f0, %f2, %f0 81; SOFT: save %sp, -96, %sp 82; SOFT: ld [%fp+104], %l0 83; SOFT-NEXT: ld [%fp+96], %l1 84; SOFT-NEXT: ld [%fp+100], %l2 85; SOFT-NEXT: ld [%fp+92], %l3 86; SOFT-NEXT: mov %i2, %o0 87; SOFT-NEXT: call __extendsfdf2 88; SOFT-NEXT: nop 89; SOFT-NEXT: mov %o0, %i2 90; SOFT-NEXT: mov %o1, %g2 91; SOFT-NEXT: mov %i0, %o0 92; SOFT-NEXT: mov %i1, %o1 93; SOFT-NEXT: mov %i2, %o2 94; SOFT-NEXT: mov %g2, %o3 95; SOFT-NEXT: call __adddf3 96; SOFT-NEXT: nop 97; SOFT-NEXT: mov %o0, %i0 98; SOFT-NEXT: mov %o1, %i1 99; SOFT-NEXT: mov %i3, %o0 100; SOFT-NEXT: mov %i4, %o1 101; SOFT-NEXT: mov %i0, %o2 102; SOFT-NEXT: mov %i1, %o3 103; SOFT-NEXT: call __adddf3 104; SOFT-NEXT: nop 105; SOFT-NEXT: mov %o0, %i0 106; SOFT-NEXT: mov %o1, %i1 107; SOFT-NEXT: mov %i5, %o0 108; SOFT-NEXT: mov %l3, %o1 109; SOFT-NEXT: mov %i0, %o2 110; SOFT-NEXT: mov %i1, %o3 111; SOFT-NEXT: call __adddf3 112; SOFT-NEXT: nop 113; SOFT-NEXT: mov %o0, %i0 114; SOFT-NEXT: mov %o1, %i1 115; SOFT-NEXT: mov %l1, %o0 116; SOFT-NEXT: mov %l2, %o1 117; SOFT-NEXT: mov %i0, %o2 118; SOFT-NEXT: mov %i1, %o3 119; SOFT-NEXT: call __adddf3 120; SOFT-NEXT: nop 121; SOFT-NEXT: mov %o0, %i0 122; SOFT-NEXT: mov %o1, %i1 123; SOFT-NEXT: mov %l0, %o0 124; SOFT-NEXT: call __extendsfdf2 125; SOFT-NEXT: nop 126; SOFT-NEXT: mov %i0, %o2 127; SOFT-NEXT: mov %i1, %o3 128; SOFT-NEXT: call __adddf3 129; SOFT-NEXT: nop 130; SOFT-NEXT: mov %o0, %i0 131; SOFT-NEXT: mov %o1, %i1 132; CHECK: restore 133define double @floatarg(double %a0, ; %i0,%i1 134 float %a1, ; %i2 135 double %a2, ; %i3, %i4 136 double %a3, ; %i5, [%fp+92] (using 4 bytes) 137 double %a4, ; [%fp+96] (using 8 bytes) 138 float %a5) { ; [%fp+104] (using 4 bytes) 139 %d1 = fpext float %a1 to double 140 %s1 = fadd double %a0, %d1 141 %s2 = fadd double %a2, %s1 142 %s3 = fadd double %a3, %s2 143 %s4 = fadd double %a4, %s3 144 %d5 = fpext float %a5 to double 145 %s5 = fadd double %d5, %s4 146 ret double %s5 147} 148 149; CHECK-LABEL: call_floatarg: 150; HARD: save %sp, -112, %sp 151; HARD: mov %i2, %o1 152; HARD-NEXT: mov %i1, %o0 153; HARD-NEXT: st %i0, [%sp+104] 154; HARD-NEXT: std %o0, [%sp+96] 155; HARD-NEXT: st %o1, [%sp+92] 156; HARD-NEXT: mov %i0, %o2 157; HARD-NEXT: mov %o0, %o3 158; HARD-NEXT: mov %o1, %o4 159; HARD-NEXT: mov %o0, %o5 160; HARD-NEXT: call floatarg 161; HARD: std %f0, [%i4] 162; SOFT: st %i0, [%sp+104] 163; SOFT-NEXT: st %i2, [%sp+100] 164; SOFT-NEXT: st %i1, [%sp+96] 165; SOFT-NEXT: st %i2, [%sp+92] 166; SOFT-NEXT: mov %i1, %o0 167; SOFT-NEXT: mov %i2, %o1 168; SOFT-NEXT: mov %i0, %o2 169; SOFT-NEXT: mov %i1, %o3 170; SOFT-NEXT: mov %i2, %o4 171; SOFT-NEXT: mov %i1, %o5 172; SOFT-NEXT: call floatarg 173; SOFT: std %o0, [%i4] 174; CHECK: restore 175define void @call_floatarg(float %f1, double %d2, float %f5, double *%p) { 176 %r = call double @floatarg(double %d2, float %f1, double %d2, double %d2, 177 double %d2, float %f1) 178 store double %r, double* %p 179 ret void 180} 181 182;; i64 arguments should effectively work the same as double: split 183;; into two locations. This is different for little-endian vs big 184;; endian, since the 64-bit math needs to be split 185; CHECK-LABEL: i64arg: 186; CHECK: save %sp, -96, %sp 187; CHECK-BE: ld [%fp+100], %g2 188; CHECK-BE-NEXT: ld [%fp+96], %g3 189; CHECK-BE-NEXT: ld [%fp+92], %g4 190; CHECK-BE-NEXT: addcc %i1, %i2, %i1 191; CHECK-BE-NEXT: addxcc %i0, 0, %i0 192; CHECK-BE-NEXT: addcc %i4, %i1, %i1 193; CHECK-BE-NEXT: addxcc %i3, %i0, %i0 194; CHECK-BE-NEXT: addcc %g4, %i1, %i1 195; CHECK-BE-NEXT: ld [%fp+104], %i2 196; CHECK-BE-NEXT: addxcc %i5, %i0, %i0 197; CHECK-BE-NEXT: addcc %g2, %i1, %i1 198; CHECK-BE-NEXT: addxcc %g3, %i0, %i0 199; CHECK-BE-NEXT: addcc %i2, %i1, %i1 200; CHECK-BE-NEXT: addxcc %i0, 0, %i0 201; 202; CHECK-LE: ld [%fp+96], %g2 203; CHECK-LE-NEXT: ld [%fp+100], %g3 204; CHECK-LE-NEXT: ld [%fp+92], %g4 205; CHECK-LE-NEXT: addcc %i0, %i2, %i0 206; CHECK-LE-NEXT: addxcc %i1, 0, %i1 207; CHECK-LE-NEXT: addcc %i3, %i0, %i0 208; CHECK-LE-NEXT: addxcc %i4, %i1, %i1 209; CHECK-LE-NEXT: addcc %i5, %i0, %i0 210; CHECK-LE-NEXT: ld [%fp+104], %i2 211; CHECK-LE-NEXT: addxcc %g4, %i1, %i1 212; CHECK-LE-NEXT: addcc %g2, %i0, %i0 213; CHECK-LE-NEXT: addxcc %g3, %i1, %i1 214; CHECK-LE-NEXT: addcc %i2, %i0, %i0 215; CHECK-LE-NEXT: addxcc %i1, 0, %i1 216; CHECK-NEXT: restore 217 218 219define i64 @i64arg(i64 %a0, ; %i0,%i1 220 i32 %a1, ; %i2 221 i64 %a2, ; %i3, %i4 222 i64 %a3, ; %i5, [%fp+92] (using 4 bytes) 223 i64 %a4, ; [%fp+96] (using 8 bytes) 224 i32 %a5) { ; [%fp+104] (using 4 bytes) 225 %a1L = zext i32 %a1 to i64 226 %s1 = add i64 %a0, %a1L 227 %s2 = add i64 %a2, %s1 228 %s3 = add i64 %a3, %s2 229 %s4 = add i64 %a4, %s3 230 %a5L = zext i32 %a5 to i64 231 %s5 = add i64 %a5L, %s4 232 ret i64 %s5 233} 234 235; CHECK-LABEL: call_i64arg: 236; CHECK: save %sp, -112, %sp 237; CHECK: st %i0, [%sp+104] 238; CHECK-NEXT: st %i2, [%sp+100] 239; CHECK-NEXT: st %i1, [%sp+96] 240; CHECK-NEXT: st %i2, [%sp+92] 241; CHECK-NEXT: mov %i1, %o0 242; CHECK-NEXT: mov %i2, %o1 243; CHECK-NEXT: mov %i0, %o2 244; CHECK-NEXT: mov %i1, %o3 245; CHECK-NEXT: mov %i2, %o4 246; CHECK-NEXT: mov %i1, %o5 247; CHECK-NEXT: call i64arg 248; CHECK: std %o0, [%i3] 249; CHECK-NEXT: restore 250 251define void @call_i64arg(i32 %a0, i64 %a1, i64* %p) { 252 %r = call i64 @i64arg(i64 %a1, i32 %a0, i64 %a1, i64 %a1, i64 %a1, i32 %a0) 253 store i64 %r, i64* %p 254 ret void 255} 256