Home | History | Annotate | Download | only in SPARC
      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
     20 define 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
     50 define 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: ! kill
     64 ; HARD-NEXT: std %g2, [%fp+-24]
     65 ; HARD-NEXT: mov %i3, %i4
     66 ; HARD-NEXT: std %i4, [%fp+-16]
     67 ; HARD-NEXT: ! kill
     68 ; HARD-NEXT: std %i0, [%fp+-8]
     69 ; HARD-NEXT: st %i2, [%fp+-28]
     70 ; HARD-NEXT: ld [%fp+104], %f0
     71 ; HARD-NEXT: ldd [%fp+96], %f2
     72 ; HARD-NEXT: ld [%fp+-28], %f1
     73 ; HARD-NEXT: ldd [%fp+-8], %f4
     74 ; HARD-NEXT: ldd [%fp+-16], %f6
     75 ; HARD-NEXT: ldd [%fp+-24], %f8
     76 ; HARD-NEXT: fstod %f1, %f10
     77 ; HARD-NEXT: faddd %f4, %f10, %f4
     78 ; HARD-NEXT: faddd %f6, %f4, %f4
     79 ; HARD-NEXT: faddd %f8, %f4, %f4
     80 ; HARD-NEXT: faddd %f2, %f4, %f2
     81 ; HARD-NEXT: fstod %f0, %f0
     82 ; HARD-NEXT: faddd %f0, %f2, %f0
     83 ; SOFT: save %sp, -96, %sp
     84 ; SOFT: ld [%fp+104], %l0
     85 ; SOFT-NEXT: ld [%fp+96], %l1
     86 ; SOFT-NEXT: ld [%fp+100], %l2
     87 ; SOFT-NEXT: ld [%fp+92], %l3
     88 ; SOFT-NEXT:  mov  %i2, %o0
     89 ; SOFT-NEXT: call __extendsfdf2
     90 ; SOFT-NEXT: nop
     91 ; SOFT-NEXT:  mov  %o0, %i2
     92 ; SOFT-NEXT:  mov  %o1, %g2
     93 ; SOFT-NEXT:  mov  %i0, %o0
     94 ; SOFT-NEXT:  mov  %i1, %o1
     95 ; SOFT-NEXT:  mov  %i2, %o2
     96 ; SOFT-NEXT:  mov  %g2, %o3
     97 ; SOFT-NEXT:  call __adddf3
     98 ; SOFT-NEXT:  nop
     99 ; SOFT-NEXT:  mov  %o0, %i0
    100 ; SOFT-NEXT:  mov  %o1, %i1
    101 ; SOFT-NEXT:  mov  %i3, %o0
    102 ; SOFT-NEXT:  mov  %i4, %o1
    103 ; SOFT-NEXT:  mov  %i0, %o2
    104 ; SOFT-NEXT:  mov  %i1, %o3
    105 ; SOFT-NEXT:  call __adddf3
    106 ; SOFT-NEXT:  nop
    107 ; SOFT-NEXT:  mov  %o0, %i0
    108 ; SOFT-NEXT:  mov  %o1, %i1
    109 ; SOFT-NEXT:  mov  %i5, %o0
    110 ; SOFT-NEXT:  mov  %l3, %o1
    111 ; SOFT-NEXT:  mov  %i0, %o2
    112 ; SOFT-NEXT:  mov  %i1, %o3
    113 ; SOFT-NEXT:  call __adddf3
    114 ; SOFT-NEXT:  nop
    115 ; SOFT-NEXT:  mov  %o0, %i0
    116 ; SOFT-NEXT:  mov  %o1, %i1
    117 ; SOFT-NEXT:  mov  %l1, %o0
    118 ; SOFT-NEXT:  mov  %l2, %o1
    119 ; SOFT-NEXT:  mov  %i0, %o2
    120 ; SOFT-NEXT:  mov  %i1, %o3
    121 ; SOFT-NEXT:  call __adddf3
    122 ; SOFT-NEXT:  nop
    123 ; SOFT-NEXT:  mov  %o0, %i0
    124 ; SOFT-NEXT:  mov  %o1, %i1
    125 ; SOFT-NEXT:  mov  %l0, %o0
    126 ; SOFT-NEXT:  call __extendsfdf2
    127 ; SOFT-NEXT:  nop
    128 ; SOFT-NEXT:  mov  %i0, %o2
    129 ; SOFT-NEXT:  mov  %i1, %o3
    130 ; SOFT-NEXT:  call __adddf3
    131 ; SOFT-NEXT:  nop
    132 ; SOFT-NEXT:  mov  %o0, %i0
    133 ; SOFT-NEXT:  mov  %o1, %i1
    134 ; CHECK: restore
    135 define double @floatarg(double %a0,   ; %i0,%i1
    136                         float %a1,    ; %i2
    137                         double %a2,   ; %i3, %i4
    138                         double %a3,   ; %i5, [%fp+92] (using 4 bytes)
    139                         double %a4,   ; [%fp+96] (using 8 bytes)
    140                         float %a5) {  ; [%fp+104] (using 4 bytes)
    141   %d1 = fpext float %a1 to double
    142   %s1 = fadd double %a0, %d1
    143   %s2 = fadd double %a2, %s1
    144   %s3 = fadd double %a3, %s2
    145   %s4 = fadd double %a4, %s3
    146   %d5 = fpext float %a5 to double
    147   %s5 = fadd double %d5, %s4
    148   ret double %s5
    149 }
    150 
    151 ; CHECK-LABEL: call_floatarg:
    152 ; HARD: save %sp, -112, %sp
    153 ; HARD: mov %i2, %o1
    154 ; HARD-NEXT: mov %i1, %o0
    155 ; HARD-NEXT: st %i0, [%sp+104]
    156 ; HARD-NEXT: std %o0, [%sp+96]
    157 ; HARD-NEXT: st %o1, [%sp+92]
    158 ; HARD-NEXT: mov %i0, %o2
    159 ; HARD-NEXT: mov %o0, %o3
    160 ; HARD-NEXT: mov %o1, %o4
    161 ; HARD-NEXT: mov %o0, %o5
    162 ; HARD-NEXT: call floatarg
    163 ; HARD: std %f0, [%i4]
    164 ; SOFT: st %i0, [%sp+104]
    165 ; SOFT-NEXT:  st %i2, [%sp+100]
    166 ; SOFT-NEXT:  st %i1, [%sp+96]
    167 ; SOFT-NEXT:  st %i2, [%sp+92]
    168 ; SOFT-NEXT:  mov  %i1, %o0
    169 ; SOFT-NEXT:  mov  %i2, %o1
    170 ; SOFT-NEXT:  mov  %i0, %o2
    171 ; SOFT-NEXT:  mov  %i1, %o3
    172 ; SOFT-NEXT:  mov  %i2, %o4
    173 ; SOFT-NEXT:  mov  %i1, %o5
    174 ; SOFT-NEXT:  call floatarg
    175 ; SOFT:  std %o0, [%i4]
    176 ; CHECK: restore
    177 define void @call_floatarg(float %f1, double %d2, float %f5, double *%p) {
    178   %r = call double @floatarg(double %d2, float %f1, double %d2, double %d2,
    179                              double %d2, float %f1)
    180   store double %r, double* %p
    181   ret void
    182 }
    183 
    184 ;; i64 arguments should effectively work the same as double: split
    185 ;; into two locations.  This is different for little-endian vs big
    186 ;; endian, since the 64-bit math needs to be split
    187 ; CHECK-LABEL: i64arg:
    188 ; CHECK:  save %sp, -96, %sp
    189 ; CHECK-BE: ld [%fp+100], %g2
    190 ; CHECK-BE-NEXT: ld [%fp+96], %g3
    191 ; CHECK-BE-NEXT: ld [%fp+92], %g4
    192 ; CHECK-BE-NEXT: addcc %i1, %i2, %i1
    193 ; CHECK-BE-NEXT: addxcc %i0, 0, %i0
    194 ; CHECK-BE-NEXT: addcc %i4, %i1, %i1
    195 ; CHECK-BE-NEXT: addxcc %i3, %i0, %i0
    196 ; CHECK-BE-NEXT: addcc %g4, %i1, %i1
    197 ; CHECK-BE-NEXT: ld [%fp+104], %i2
    198 ; CHECK-BE-NEXT: addxcc %i5, %i0, %i0
    199 ; CHECK-BE-NEXT: addcc %g2, %i1, %i1
    200 ; CHECK-BE-NEXT: addxcc %g3, %i0, %i0
    201 ; CHECK-BE-NEXT: addcc %i2, %i1, %i1
    202 ; CHECK-BE-NEXT: addxcc %i0, 0, %i0
    203 ;
    204 ; CHECK-LE: ld [%fp+96], %g2
    205 ; CHECK-LE-NEXT: ld [%fp+100], %g3
    206 ; CHECK-LE-NEXT: ld [%fp+92], %g4
    207 ; CHECK-LE-NEXT: addcc %i0, %i2, %i0
    208 ; CHECK-LE-NEXT: addxcc %i1, 0, %i1
    209 ; CHECK-LE-NEXT: addcc %i3, %i0, %i0
    210 ; CHECK-LE-NEXT: addxcc %i4, %i1, %i1
    211 ; CHECK-LE-NEXT: addcc %i5, %i0, %i0
    212 ; CHECK-LE-NEXT: ld [%fp+104], %i2
    213 ; CHECK-LE-NEXT: addxcc %g4, %i1, %i1
    214 ; CHECK-LE-NEXT: addcc %g2, %i0, %i0
    215 ; CHECK-LE-NEXT: addxcc %g3, %i1, %i1
    216 ; CHECK-LE-NEXT: addcc %i2, %i0, %i0
    217 ; CHECK-LE-NEXT: addxcc %i1, 0, %i1
    218 ; CHECK-NEXT: restore
    219 
    220 
    221 define i64 @i64arg(i64 %a0,    ; %i0,%i1
    222 		   i32 %a1,    ; %i2
    223 		   i64 %a2,    ; %i3, %i4
    224 		   i64 %a3,    ; %i5, [%fp+92] (using 4 bytes)
    225 		   i64 %a4,    ; [%fp+96] (using 8 bytes)
    226                    i32 %a5) {  ; [%fp+104] (using 4 bytes)
    227   %a1L = zext i32 %a1 to i64
    228   %s1 = add i64 %a0, %a1L
    229   %s2 = add i64 %a2, %s1
    230   %s3 = add i64 %a3, %s2
    231   %s4 = add i64 %a4, %s3
    232   %a5L = zext i32 %a5 to i64
    233   %s5 = add i64 %a5L, %s4
    234   ret i64 %s5
    235 }
    236 
    237 ; CHECK-LABEL: call_i64arg:
    238 ; CHECK: save %sp, -112, %sp
    239 ; CHECK: st %i0, [%sp+104]
    240 ; CHECK-NEXT: st %i2, [%sp+100]
    241 ; CHECK-NEXT: st %i1, [%sp+96]
    242 ; CHECK-NEXT: st %i2, [%sp+92]
    243 ; CHECK-NEXT: mov      %i1, %o0
    244 ; CHECK-NEXT: mov      %i2, %o1
    245 ; CHECK-NEXT: mov      %i0, %o2
    246 ; CHECK-NEXT: mov      %i1, %o3
    247 ; CHECK-NEXT: mov      %i2, %o4
    248 ; CHECK-NEXT: mov      %i1, %o5
    249 ; CHECK-NEXT: call i64arg
    250 ; CHECK: std %o0, [%i3]
    251 ; CHECK-NEXT: restore
    252 
    253 define void @call_i64arg(i32 %a0, i64 %a1, i64* %p) {
    254   %r = call i64 @i64arg(i64 %a1, i32 %a0, i64 %a1, i64 %a1, i64 %a1, i32 %a0)
    255   store i64 %r, i64* %p
    256   ret void
    257 }
    258