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