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