1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \ 3; RUN: -target-abi=ilp32f | FileCheck -check-prefixes=CHECKIF,RV32IF %s 4; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \ 5; RUN: -target-abi=lp64f | FileCheck -check-prefixes=CHECKIF,RV64IF %s 6 7define dso_local float @flw(float *%a) nounwind { 8; CHECKIF-LABEL: flw: 9; CHECKIF: # %bb.0: 10; CHECKIF-NEXT: flw ft0, 0(a0) 11; CHECKIF-NEXT: flw ft1, 12(a0) 12; CHECKIF-NEXT: fadd.s fa0, ft0, ft1 13; CHECKIF-NEXT: ret 14 %1 = load float, float* %a 15 %2 = getelementptr float, float* %a, i32 3 16 %3 = load float, float* %2 17; Use both loaded values in an FP op to ensure an flw is used, even for the 18; soft float ABI 19 %4 = fadd float %1, %3 20 ret float %4 21} 22 23define dso_local void @fsw(float *%a, float %b, float %c) nounwind { 24; Use %b and %c in an FP op to ensure floating point registers are used, even 25; for the soft float ABI 26; CHECKIF-LABEL: fsw: 27; CHECKIF: # %bb.0: 28; CHECKIF-NEXT: fadd.s ft0, fa0, fa1 29; CHECKIF-NEXT: fsw ft0, 0(a0) 30; CHECKIF-NEXT: fsw ft0, 32(a0) 31; CHECKIF-NEXT: ret 32 %1 = fadd float %b, %c 33 store float %1, float* %a 34 %2 = getelementptr float, float* %a, i32 8 35 store float %1, float* %2 36 ret void 37} 38 39; Check load and store to a global 40@G = dso_local global float 0.0 41 42define dso_local float @flw_fsw_global(float %a, float %b) nounwind { 43; Use %a and %b in an FP op to ensure floating point registers are used, even 44; for the soft float ABI 45; CHECKIF-LABEL: flw_fsw_global: 46; CHECKIF: # %bb.0: 47; CHECKIF-NEXT: fadd.s fa0, fa0, fa1 48; CHECKIF-NEXT: lui a0, %hi(G) 49; CHECKIF-NEXT: flw ft0, %lo(G)(a0) 50; CHECKIF-NEXT: addi a1, a0, %lo(G) 51; CHECKIF-NEXT: fsw fa0, %lo(G)(a0) 52; CHECKIF-NEXT: flw ft0, 36(a1) 53; CHECKIF-NEXT: fsw fa0, 36(a1) 54; CHECKIF-NEXT: ret 55 %1 = fadd float %a, %b 56 %2 = load volatile float, float* @G 57 store float %1, float* @G 58 %3 = getelementptr float, float* @G, i32 9 59 %4 = load volatile float, float* %3 60 store float %1, float* %3 61 ret float %1 62} 63 64; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1 65define dso_local float @flw_fsw_constant(float %a) nounwind { 66; RV32IF-LABEL: flw_fsw_constant: 67; RV32IF: # %bb.0: 68; RV32IF-NEXT: lui a0, 912092 69; RV32IF-NEXT: flw ft0, -273(a0) 70; RV32IF-NEXT: fadd.s fa0, fa0, ft0 71; RV32IF-NEXT: fsw fa0, -273(a0) 72; RV32IF-NEXT: ret 73; 74; RV64IF-LABEL: flw_fsw_constant: 75; RV64IF: # %bb.0: 76; RV64IF-NEXT: lui a0, 228023 77; RV64IF-NEXT: slli a0, a0, 2 78; RV64IF-NEXT: flw ft0, -273(a0) 79; RV64IF-NEXT: fadd.s fa0, fa0, ft0 80; RV64IF-NEXT: fsw fa0, -273(a0) 81; RV64IF-NEXT: ret 82 %1 = inttoptr i32 3735928559 to float* 83 %2 = load volatile float, float* %1 84 %3 = fadd float %a, %2 85 store float %3, float* %1 86 ret float %3 87} 88 89declare void @notdead(i8*) 90 91define dso_local float @flw_stack(float %a) nounwind { 92; RV32IF-LABEL: flw_stack: 93; RV32IF: # %bb.0: 94; RV32IF-NEXT: addi sp, sp, -16 95; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill 96; RV32IF-NEXT: fsw fs0, 8(sp) # 4-byte Folded Spill 97; RV32IF-NEXT: fmv.s fs0, fa0 98; RV32IF-NEXT: addi a0, sp, 4 99; RV32IF-NEXT: call notdead@plt 100; RV32IF-NEXT: flw ft0, 4(sp) 101; RV32IF-NEXT: fadd.s fa0, ft0, fs0 102; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload 103; RV32IF-NEXT: flw fs0, 8(sp) # 4-byte Folded Reload 104; RV32IF-NEXT: addi sp, sp, 16 105; RV32IF-NEXT: ret 106; 107; RV64IF-LABEL: flw_stack: 108; RV64IF: # %bb.0: 109; RV64IF-NEXT: addi sp, sp, -16 110; RV64IF-NEXT: sd ra, 8(sp) # 8-byte Folded Spill 111; RV64IF-NEXT: fsw fs0, 4(sp) # 4-byte Folded Spill 112; RV64IF-NEXT: fmv.s fs0, fa0 113; RV64IF-NEXT: mv a0, sp 114; RV64IF-NEXT: call notdead@plt 115; RV64IF-NEXT: flw ft0, 0(sp) 116; RV64IF-NEXT: fadd.s fa0, ft0, fs0 117; RV64IF-NEXT: ld ra, 8(sp) # 8-byte Folded Reload 118; RV64IF-NEXT: flw fs0, 4(sp) # 4-byte Folded Reload 119; RV64IF-NEXT: addi sp, sp, 16 120; RV64IF-NEXT: ret 121 %1 = alloca float, align 4 122 %2 = bitcast float* %1 to i8* 123 call void @notdead(i8* %2) 124 %3 = load float, float* %1 125 %4 = fadd float %3, %a ; force load in to FPR32 126 ret float %4 127} 128 129define dso_local void @fsw_stack(float %a, float %b) nounwind { 130; RV32IF-LABEL: fsw_stack: 131; RV32IF: # %bb.0: 132; RV32IF-NEXT: addi sp, sp, -16 133; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill 134; RV32IF-NEXT: fadd.s ft0, fa0, fa1 135; RV32IF-NEXT: fsw ft0, 8(sp) 136; RV32IF-NEXT: addi a0, sp, 8 137; RV32IF-NEXT: call notdead@plt 138; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload 139; RV32IF-NEXT: addi sp, sp, 16 140; RV32IF-NEXT: ret 141; 142; RV64IF-LABEL: fsw_stack: 143; RV64IF: # %bb.0: 144; RV64IF-NEXT: addi sp, sp, -16 145; RV64IF-NEXT: sd ra, 8(sp) # 8-byte Folded Spill 146; RV64IF-NEXT: fadd.s ft0, fa0, fa1 147; RV64IF-NEXT: fsw ft0, 4(sp) 148; RV64IF-NEXT: addi a0, sp, 4 149; RV64IF-NEXT: call notdead@plt 150; RV64IF-NEXT: ld ra, 8(sp) # 8-byte Folded Reload 151; RV64IF-NEXT: addi sp, sp, 16 152; RV64IF-NEXT: ret 153 %1 = fadd float %a, %b ; force store from FPR32 154 %2 = alloca float, align 4 155 store float %1, float* %2 156 %3 = bitcast float* %2 to i8* 157 call void @notdead(i8* %3) 158 ret void 159} 160