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. 6 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 12 ; this check here. 13 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 18 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 23 24 ; 64-FP64A: LLVM ERROR: -mattr=+nooddspreg requires the O32 ABI. 25 26 declare double @dbl(); 27 28 define double @call1(double %d, ...) { 29 ret double %d 30 31 ; ALL-LABEL: call1: 32 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 36 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 40 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) 45 46 ; 64-NO-FP64A: daddiu $sp, $sp, -64 47 ; 64-NO-FP64A: mov.d $f0, $f12 48 } 49 50 define double @call2(i32 %i, double %d) { 51 ret double %d 52 53 ; ALL-LABEL: call2: 54 55 ; 32R2-NO-FP64A-LE: mtc1 $6, $f0 56 ; 32R2-NO-FP64A-LE: mthc1 $7, $f0 57 58 ; 32R2-NO-FP64A-BE: mtc1 $7, $f0 59 ; 32R2-NO-FP64A-BE: mthc1 $6, $f0 60 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) 65 66 ; 64-NO-FP64A-NOT: daddiu $sp, $sp 67 ; 64-NO-FP64A: mov.d $f0, $f13 68 } 69 70 define double @call3(float %f1, float %f2, double %d) { 71 ret double %d 72 73 ; ALL-LABEL: call3: 74 75 ; 32R2-NO-FP64A-LE: mtc1 $6, $f0 76 ; 32R2-NO-FP64A-LE: mthc1 $7, $f0 77 78 ; 32R2-NO-FP64A-BE: mtc1 $7, $f0 79 ; 32R2-NO-FP64A-BE: mthc1 $6, $f0 80 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) 85 86 ; 64-NO-FP64A-NOT: daddiu $sp, $sp 87 ; 64-NO-FP64A: mov.d $f0, $f14 88 } 89 90 define double @call4(float %f, double %d, ...) { 91 ret double %d 92 93 ; ALL-LABEL: call4: 94 95 ; 32R2-NO-FP64A-LE: mtc1 $6, $f0 96 ; 32R2-NO-FP64A-LE: mthc1 $7, $f0 97 98 ; 32R2-NO-FP64A-BE: mtc1 $7, $f0 99 ; 32R2-NO-FP64A-BE: mthc1 $6, $f0 100 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) 105 106 ; 64-NO-FP64A: daddiu $sp, $sp, -48 107 ; 64-NO-FP64A: mov.d $f0, $f13 108 } 109 110 define double @call5(double %a, double %b, ...) { 111 %1 = fsub double %a, %b 112 ret double %1 113 114 ; ALL-LABEL: call5: 115 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]] 121 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]] 127 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]] 136 137 ; 64-NO-FP64A: sub.d $f0, $f12, $f13 138 } 139 140 define double @move_from(double %d) { 141 %1 = call double @dbl() 142 %2 = call double @call2(i32 0, double %1) 143 ret double %2 144 145 ; ALL-LABEL: move_from: 146 147 ; 32R2-NO-FP64A-LE-DAG: mfc1 $6, $f0 148 ; 32R2-NO-FP64A-LE-DAG: mfhc1 $7, $f0 149 150 ; 32R2-NO-FP64A-BE-DAG: mfc1 $7, $f0 151 ; 32R2-NO-FP64A-BE-DAG: mfhc1 $6, $f0 152 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) 159 160 ; 64-NO-FP64A: mov.d $f13, $f0 161 } 162