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