1 ; Test that the FP64A ABI performs double precision moves via a spill/reload.
2 ; The requirement is really that odd-numbered double precision registers do not
3 ; use mfc1/mtc1 to move the bottom 32-bits (because the hardware will redirect
4 ; this to the top 32-bits of the even register) but we have to make the decision
5 ; before register allocation so we do this for all double-precision values.
7 ; We don't test MIPS32r1 since support for 64-bit coprocessors (such as a 64-bit
8 ; FPU) on a 32-bit architecture was added in MIPS32r2.
9 ; FIXME: We currently don't test that attempting to use FP64 on MIPS32r1 is an
10 ; error either. This is because a large number of CodeGen tests are
11 ; incorrectly using this case. We should fix those test cases then add
14 ; RUN: llc -march=mips -mcpu=mips32r2 -mattr=fp64 < %s | FileCheck %s -check-prefixes=ALL,32R2-NO-FP64A-BE
15 ; RUN: llc -march=mips -mcpu=mips32r2 -mattr=fp64,nooddspreg < %s | FileCheck %s -check-prefixes=ALL,32R2-FP64A
16 ; RUN: llc -march=mipsel -mcpu=mips32r2 -mattr=fp64 < %s | FileCheck %s -check-prefixes=ALL,32R2-NO-FP64A-LE
17 ; RUN: llc -march=mipsel -mcpu=mips32r2 -mattr=fp64,nooddspreg < %s | FileCheck %s -check-prefixes=ALL,32R2-FP64A
19 ; RUN: llc -march=mips64 -mcpu=mips64 -mattr=fp64 < %s | FileCheck %s -check-prefixes=ALL,64-NO-FP64A
20 ; RUN: not llc -march=mips64 -mcpu=mips64 -mattr=fp64,nooddspreg < %s 2>&1 | FileCheck %s -check-prefix=64-FP64A
21 ; RUN: llc -march=mips64el -mcpu=mips64 -mattr=fp64 < %s | FileCheck %s -check-prefixes=ALL,64-NO-FP64A
22 ; RUN: not llc -march=mips64el -mcpu=mips64 -mattr=fp64,nooddspreg < %s 2>&1 | FileCheck %s -check-prefix=64-FP64A
24 ; 64-FP64A: LLVM ERROR: -mattr=+nooddspreg requires the O32 ABI.
26 declare double @dbl();
28 define double @call1(double %d, ...) {
33 ; 32R2-NO-FP64A-LE-NOT: addiu $sp, $sp
34 ; 32R2-NO-FP64A-LE: mtc1 $4, $f0
35 ; 32R2-NO-FP64A-LE: mthc1 $5, $f0
37 ; 32R2-NO-FP64A-BE-NOT: addiu $sp, $sp
38 ; 32R2-NO-FP64A-BE: mtc1 $5, $f0
39 ; 32R2-NO-FP64A-BE: mthc1 $4, $f0
41 ; 32R2-FP64A: addiu $sp, $sp, -8
42 ; 32R2-FP64A: sw $4, 0($sp)
43 ; 32R2-FP64A: sw $5, 4($sp)
44 ; 32R2-FP64A: ldc1 $f0, 0($sp)
46 ; 64-NO-FP64A: daddiu $sp, $sp, -64
47 ; 64-NO-FP64A: mov.d $f0, $f12
50 define double @call2(i32 %i, double %d) {
55 ; 32R2-NO-FP64A-LE: mtc1 $6, $f0
56 ; 32R2-NO-FP64A-LE: mthc1 $7, $f0
58 ; 32R2-NO-FP64A-BE: mtc1 $7, $f0
59 ; 32R2-NO-FP64A-BE: mthc1 $6, $f0
61 ; 32R2-FP64A: addiu $sp, $sp, -8
62 ; 32R2-FP64A: sw $6, 0($sp)
63 ; 32R2-FP64A: sw $7, 4($sp)
64 ; 32R2-FP64A: ldc1 $f0, 0($sp)
66 ; 64-NO-FP64A-NOT: daddiu $sp, $sp
67 ; 64-NO-FP64A: mov.d $f0, $f13
70 define double @call3(float %f1, float %f2, double %d) {
75 ; 32R2-NO-FP64A-LE: mtc1 $6, $f0
76 ; 32R2-NO-FP64A-LE: mthc1 $7, $f0
78 ; 32R2-NO-FP64A-BE: mtc1 $7, $f0
79 ; 32R2-NO-FP64A-BE: mthc1 $6, $f0
81 ; 32R2-FP64A: addiu $sp, $sp, -8
82 ; 32R2-FP64A: sw $6, 0($sp)
83 ; 32R2-FP64A: sw $7, 4($sp)
84 ; 32R2-FP64A: ldc1 $f0, 0($sp)
86 ; 64-NO-FP64A-NOT: daddiu $sp, $sp
87 ; 64-NO-FP64A: mov.d $f0, $f14
90 define double @call4(float %f, double %d, ...) {
95 ; 32R2-NO-FP64A-LE: mtc1 $6, $f0
96 ; 32R2-NO-FP64A-LE: mthc1 $7, $f0
98 ; 32R2-NO-FP64A-BE: mtc1 $7, $f0
99 ; 32R2-NO-FP64A-BE: mthc1 $6, $f0
101 ; 32R2-FP64A: addiu $sp, $sp, -8
102 ; 32R2-FP64A: sw $6, 0($sp)
103 ; 32R2-FP64A: sw $7, 4($sp)
104 ; 32R2-FP64A: ldc1 $f0, 0($sp)
106 ; 64-NO-FP64A: daddiu $sp, $sp, -48
107 ; 64-NO-FP64A: mov.d $f0, $f13
110 define double @call5(double %a, double %b, ...) {
111 %1 = fsub double %a, %b
116 ; 32R2-NO-FP64A-LE-DAG: mtc1 $4, $[[T0:f[0-9]+]]
117 ; 32R2-NO-FP64A-LE-DAG: mthc1 $5, $[[T0:f[0-9]+]]
118 ; 32R2-NO-FP64A-LE-DAG: mtc1 $6, $[[T1:f[0-9]+]]
119 ; 32R2-NO-FP64A-LE-DAG: mthc1 $7, $[[T1:f[0-9]+]]
120 ; 32R2-NO-FP64A-LE: sub.d $f0, $[[T0]], $[[T1]]
122 ; 32R2-NO-FP64A-BE-DAG: mtc1 $5, $[[T0:f[0-9]+]]
123 ; 32R2-NO-FP64A-BE-DAG: mthc1 $4, $[[T0:f[0-9]+]]
124 ; 32R2-NO-FP64A-BE-DAG: mtc1 $7, $[[T1:f[0-9]+]]
125 ; 32R2-NO-FP64A-BE-DAG: mthc1 $6, $[[T1:f[0-9]+]]
126 ; 32R2-NO-FP64A-BE: sub.d $f0, $[[T0]], $[[T1]]
128 ; 32R2-FP64A: addiu $sp, $sp, -8
129 ; 32R2-FP64A: sw $6, 0($sp)
130 ; 32R2-FP64A: sw $7, 4($sp)
131 ; 32R2-FP64A: ldc1 $[[T1:f[0-9]+]], 0($sp)
132 ; 32R2-FP64A: sw $4, 0($sp)
133 ; 32R2-FP64A: sw $5, 4($sp)
134 ; 32R2-FP64A: ldc1 $[[T0:f[0-9]+]], 0($sp)
135 ; 32R2-FP64A: sub.d $f0, $[[T0]], $[[T1]]
137 ; 64-NO-FP64A: sub.d $f0, $f12, $f13
140 define double @move_from(double %d) {
141 %1 = call double @dbl()
142 %2 = call double @call2(i32 0, double %1)
145 ; ALL-LABEL: move_from:
147 ; 32R2-NO-FP64A-LE-DAG: mfc1 $6, $f0
148 ; 32R2-NO-FP64A-LE-DAG: mfhc1 $7, $f0
150 ; 32R2-NO-FP64A-BE-DAG: mfc1 $7, $f0
151 ; 32R2-NO-FP64A-BE-DAG: mfhc1 $6, $f0
153 ; 32R2-FP64A: addiu $sp, $sp, -32
154 ; 32R2-FP64A: sdc1 $f0, 16($sp)
155 ; 32R2-FP64A: lw $6, 16($sp)
156 ; FIXME: This store is redundant
157 ; 32R2-FP64A: sdc1 $f0, 16($sp)
158 ; 32R2-FP64A: lw $7, 20($sp)
160 ; 64-NO-FP64A: mov.d $f13, $f0