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 5define 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 26define 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 53define 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 87define 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 110declare void @notdead(i8*) 111 112define 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 144define 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>, .. 171define 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