1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2 ; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ 3 ; RUN: | FileCheck -check-prefix=RV32IFD %s 4 5 define double @fld(double *%a) nounwind { 6 ; RV32IFD-LABEL: fld: 7 ; RV32IFD: # %bb.0: 8 ; RV32IFD-NEXT: addi sp, sp, -16 9 ; RV32IFD-NEXT: fld ft0, 24(a0) 10 ; RV32IFD-NEXT: fld ft1, 0(a0) 11 ; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 12 ; RV32IFD-NEXT: fsd ft0, 8(sp) 13 ; RV32IFD-NEXT: lw a0, 8(sp) 14 ; RV32IFD-NEXT: lw a1, 12(sp) 15 ; RV32IFD-NEXT: addi sp, sp, 16 16 ; RV32IFD-NEXT: ret 17 %1 = load double, double* %a 18 %2 = getelementptr double, double* %a, i32 3 19 %3 = load double, double* %2 20 ; Use both loaded values in an FP op to ensure an fld is used, even for the 21 ; soft float ABI 22 %4 = fadd double %1, %3 23 ret double %4 24 } 25 26 define void @fsd(double *%a, double %b, double %c) nounwind { 27 ; RV32IFD-LABEL: fsd: 28 ; RV32IFD: # %bb.0: 29 ; RV32IFD-NEXT: addi sp, sp, -16 30 ; RV32IFD-NEXT: sw a3, 8(sp) 31 ; RV32IFD-NEXT: sw a4, 12(sp) 32 ; RV32IFD-NEXT: fld ft0, 8(sp) 33 ; RV32IFD-NEXT: sw a1, 8(sp) 34 ; RV32IFD-NEXT: sw a2, 12(sp) 35 ; RV32IFD-NEXT: fld ft1, 8(sp) 36 ; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 37 ; RV32IFD-NEXT: fsd ft0, 64(a0) 38 ; RV32IFD-NEXT: fsd ft0, 0(a0) 39 ; RV32IFD-NEXT: addi sp, sp, 16 40 ; RV32IFD-NEXT: ret 41 ; Use %b and %c in an FP op to ensure floating point registers are used, even 42 ; for the soft float ABI 43 %1 = fadd double %b, %c 44 store double %1, double* %a 45 %2 = getelementptr double, double* %a, i32 8 46 store double %1, double* %2 47 ret void 48 } 49 50 ; Check load and store to a global 51 @G = global double 0.0 52 53 define double @fld_fsd_global(double %a, double %b) nounwind { 54 ; RV32IFD-LABEL: fld_fsd_global: 55 ; RV32IFD: # %bb.0: 56 ; RV32IFD-NEXT: addi sp, sp, -16 57 ; RV32IFD-NEXT: sw a2, 8(sp) 58 ; RV32IFD-NEXT: sw a3, 12(sp) 59 ; RV32IFD-NEXT: fld ft0, 8(sp) 60 ; RV32IFD-NEXT: sw a0, 8(sp) 61 ; RV32IFD-NEXT: sw a1, 12(sp) 62 ; RV32IFD-NEXT: fld ft1, 8(sp) 63 ; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 64 ; RV32IFD-NEXT: lui a0, %hi(G) 65 ; RV32IFD-NEXT: fld ft1, %lo(G)(a0) 66 ; RV32IFD-NEXT: fsd ft0, %lo(G)(a0) 67 ; RV32IFD-NEXT: addi a0, a0, %lo(G) 68 ; RV32IFD-NEXT: fld ft1, 72(a0) 69 ; RV32IFD-NEXT: fsd ft0, 72(a0) 70 ; RV32IFD-NEXT: fsd ft0, 8(sp) 71 ; RV32IFD-NEXT: lw a0, 8(sp) 72 ; RV32IFD-NEXT: lw a1, 12(sp) 73 ; RV32IFD-NEXT: addi sp, sp, 16 74 ; RV32IFD-NEXT: ret 75 ; Use %a and %b in an FP op to ensure floating point registers are used, even 76 ; for the soft float ABI 77 %1 = fadd double %a, %b 78 %2 = load volatile double, double* @G 79 store double %1, double* @G 80 %3 = getelementptr double, double* @G, i32 9 81 %4 = load volatile double, double* %3 82 store double %1, double* %3 83 ret double %1 84 } 85 86 ; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1 87 define double @fld_fsd_constant(double %a) nounwind { 88 ; RV32IFD-LABEL: fld_fsd_constant: 89 ; RV32IFD: # %bb.0: 90 ; RV32IFD-NEXT: addi sp, sp, -16 91 ; RV32IFD-NEXT: sw a0, 8(sp) 92 ; RV32IFD-NEXT: sw a1, 12(sp) 93 ; RV32IFD-NEXT: fld ft0, 8(sp) 94 ; RV32IFD-NEXT: lui a0, 912092 95 ; RV32IFD-NEXT: fld ft1, -273(a0) 96 ; RV32IFD-NEXT: fadd.d ft0, ft0, ft1 97 ; RV32IFD-NEXT: fsd ft0, -273(a0) 98 ; RV32IFD-NEXT: fsd ft0, 8(sp) 99 ; RV32IFD-NEXT: lw a0, 8(sp) 100 ; RV32IFD-NEXT: lw a1, 12(sp) 101 ; RV32IFD-NEXT: addi sp, sp, 16 102 ; RV32IFD-NEXT: ret 103 %1 = inttoptr i32 3735928559 to double* 104 %2 = load volatile double, double* %1 105 %3 = fadd double %a, %2 106 store double %3, double* %1 107 ret double %3 108 } 109 110 declare void @notdead(i8*) 111 112 define double @fld_stack(double %a) nounwind { 113 ; RV32IFD-LABEL: fld_stack: 114 ; RV32IFD: # %bb.0: 115 ; RV32IFD-NEXT: addi sp, sp, -32 116 ; RV32IFD-NEXT: sw ra, 28(sp) 117 ; RV32IFD-NEXT: sw s1, 24(sp) 118 ; RV32IFD-NEXT: sw s2, 20(sp) 119 ; RV32IFD-NEXT: mv s2, a1 120 ; RV32IFD-NEXT: mv s1, a0 121 ; RV32IFD-NEXT: addi a0, sp, 8 122 ; RV32IFD-NEXT: call notdead 123 ; RV32IFD-NEXT: sw s1, 0(sp) 124 ; RV32IFD-NEXT: sw s2, 4(sp) 125 ; RV32IFD-NEXT: fld ft0, 0(sp) 126 ; RV32IFD-NEXT: fld ft1, 8(sp) 127 ; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 128 ; RV32IFD-NEXT: fsd ft0, 0(sp) 129 ; RV32IFD-NEXT: lw a0, 0(sp) 130 ; RV32IFD-NEXT: lw a1, 4(sp) 131 ; RV32IFD-NEXT: lw s2, 20(sp) 132 ; RV32IFD-NEXT: lw s1, 24(sp) 133 ; RV32IFD-NEXT: lw ra, 28(sp) 134 ; RV32IFD-NEXT: addi sp, sp, 32 135 ; RV32IFD-NEXT: ret 136 %1 = alloca double, align 8 137 %2 = bitcast double* %1 to i8* 138 call void @notdead(i8* %2) 139 %3 = load double, double* %1 140 %4 = fadd double %3, %a ; force load in to FPR64 141 ret double %4 142 } 143 144 define void @fsd_stack(double %a, double %b) nounwind { 145 ; RV32IFD-LABEL: fsd_stack: 146 ; RV32IFD: # %bb.0: 147 ; RV32IFD-NEXT: addi sp, sp, -32 148 ; RV32IFD-NEXT: sw ra, 28(sp) 149 ; RV32IFD-NEXT: sw a2, 8(sp) 150 ; RV32IFD-NEXT: sw a3, 12(sp) 151 ; RV32IFD-NEXT: fld ft0, 8(sp) 152 ; RV32IFD-NEXT: sw a0, 8(sp) 153 ; RV32IFD-NEXT: sw a1, 12(sp) 154 ; RV32IFD-NEXT: fld ft1, 8(sp) 155 ; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 156 ; RV32IFD-NEXT: fsd ft0, 16(sp) 157 ; RV32IFD-NEXT: addi a0, sp, 16 158 ; RV32IFD-NEXT: call notdead 159 ; RV32IFD-NEXT: lw ra, 28(sp) 160 ; RV32IFD-NEXT: addi sp, sp, 32 161 ; RV32IFD-NEXT: ret 162 %1 = fadd double %a, %b ; force store from FPR64 163 %2 = alloca double, align 8 164 store double %1, double* %2 165 %3 = bitcast double* %2 to i8* 166 call void @notdead(i8* %3) 167 ret void 168 } 169 170 ; Test selection of store<ST4[%a], trunc to f32>, .. 171 define void @fsd_trunc(float* %a, double %b) nounwind noinline optnone { 172 ; RV32IFD-LABEL: fsd_trunc: 173 ; RV32IFD: # %bb.0: 174 ; RV32IFD-NEXT: addi sp, sp, -16 175 ; RV32IFD-NEXT: sw a1, 8(sp) 176 ; RV32IFD-NEXT: sw a2, 12(sp) 177 ; RV32IFD-NEXT: fld ft0, 8(sp) 178 ; RV32IFD-NEXT: fcvt.s.d ft0, ft0 179 ; RV32IFD-NEXT: fsw ft0, 0(a0) 180 ; RV32IFD-NEXT: addi sp, sp, 16 181 ; RV32IFD-NEXT: ret 182 %1 = fptrunc double %b to float 183 store float %1, float* %a, align 4 184 ret void 185 } 186