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: -target-abi=ilp32d | FileCheck -check-prefixes=CHECKIFD,RV32IFD %s 4; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \ 5; RUN: -target-abi=lp64d | FileCheck -check-prefixes=CHECKIFD,RV64IFD %s 6; RUN: llc -mtriple=riscv32 -mattr=+zdinx -verify-machineinstrs < %s \ 7; RUN: -target-abi=ilp32 | FileCheck -check-prefixes=RV32IZFINXZDINX %s 8; RUN: llc -mtriple=riscv64 -mattr=+zdinx -verify-machineinstrs < %s \ 9; RUN: -target-abi=lp64 | FileCheck -check-prefixes=RV64IZFINXZDINX %s 10 11define dso_local double @fld(ptr %a) nounwind { 12; CHECKIFD-LABEL: fld: 13; CHECKIFD: # %bb.0: 14; CHECKIFD-NEXT: fld fa5, 0(a0) 15; CHECKIFD-NEXT: fld fa4, 24(a0) 16; CHECKIFD-NEXT: fadd.d fa0, fa5, fa4 17; CHECKIFD-NEXT: ret 18; 19; RV32IZFINXZDINX-LABEL: fld: 20; RV32IZFINXZDINX: # %bb.0: 21; RV32IZFINXZDINX-NEXT: lw a2, 0(a0) 22; RV32IZFINXZDINX-NEXT: lw a3, 4(a0) 23; RV32IZFINXZDINX-NEXT: lw a1, 28(a0) 24; RV32IZFINXZDINX-NEXT: lw a0, 24(a0) 25; RV32IZFINXZDINX-NEXT: fadd.d a0, a2, a0 26; RV32IZFINXZDINX-NEXT: ret 27; 28; RV64IZFINXZDINX-LABEL: fld: 29; RV64IZFINXZDINX: # %bb.0: 30; RV64IZFINXZDINX-NEXT: ld a1, 0(a0) 31; RV64IZFINXZDINX-NEXT: ld a0, 24(a0) 32; RV64IZFINXZDINX-NEXT: fadd.d a0, a1, a0 33; RV64IZFINXZDINX-NEXT: ret 34 %1 = load double, ptr %a 35 %2 = getelementptr double, ptr %a, i32 3 36 %3 = load double, ptr %2 37; Use both loaded values in an FP op to ensure an fld is used, even for the 38; soft float ABI 39 %4 = fadd double %1, %3 40 ret double %4 41} 42 43define dso_local void @fsd(ptr %a, double %b, double %c) nounwind { 44; CHECKIFD-LABEL: fsd: 45; CHECKIFD: # %bb.0: 46; CHECKIFD-NEXT: fadd.d fa5, fa0, fa1 47; CHECKIFD-NEXT: fsd fa5, 0(a0) 48; CHECKIFD-NEXT: fsd fa5, 64(a0) 49; CHECKIFD-NEXT: ret 50; 51; RV32IZFINXZDINX-LABEL: fsd: 52; RV32IZFINXZDINX: # %bb.0: 53; RV32IZFINXZDINX-NEXT: mv a5, a4 54; RV32IZFINXZDINX-NEXT: mv a7, a2 55; RV32IZFINXZDINX-NEXT: mv a4, a3 56; RV32IZFINXZDINX-NEXT: mv a6, a1 57; RV32IZFINXZDINX-NEXT: fadd.d a2, a6, a4 58; RV32IZFINXZDINX-NEXT: sw a2, 0(a0) 59; RV32IZFINXZDINX-NEXT: sw a3, 4(a0) 60; RV32IZFINXZDINX-NEXT: sw a2, 64(a0) 61; RV32IZFINXZDINX-NEXT: sw a3, 68(a0) 62; RV32IZFINXZDINX-NEXT: ret 63; 64; RV64IZFINXZDINX-LABEL: fsd: 65; RV64IZFINXZDINX: # %bb.0: 66; RV64IZFINXZDINX-NEXT: fadd.d a1, a1, a2 67; RV64IZFINXZDINX-NEXT: sd a1, 0(a0) 68; RV64IZFINXZDINX-NEXT: sd a1, 64(a0) 69; RV64IZFINXZDINX-NEXT: ret 70; Use %b and %c in an FP op to ensure floating point registers are used, even 71; for the soft float ABI 72 %1 = fadd double %b, %c 73 store double %1, ptr %a 74 %2 = getelementptr double, ptr %a, i32 8 75 store double %1, ptr %2 76 ret void 77} 78 79; Check load and store to a global 80@G = dso_local global double 0.0 81 82define dso_local double @fld_fsd_global(double %a, double %b) nounwind { 83; CHECKIFD-LABEL: fld_fsd_global: 84; CHECKIFD: # %bb.0: 85; CHECKIFD-NEXT: fadd.d fa0, fa0, fa1 86; CHECKIFD-NEXT: lui a0, %hi(G) 87; CHECKIFD-NEXT: fld fa5, %lo(G)(a0) 88; CHECKIFD-NEXT: addi a1, a0, %lo(G) 89; CHECKIFD-NEXT: fsd fa0, %lo(G)(a0) 90; CHECKIFD-NEXT: fld fa5, 72(a1) 91; CHECKIFD-NEXT: fsd fa0, 72(a1) 92; CHECKIFD-NEXT: ret 93; 94; RV32IZFINXZDINX-LABEL: fld_fsd_global: 95; RV32IZFINXZDINX: # %bb.0: 96; RV32IZFINXZDINX-NEXT: lui a4, %hi(G) 97; RV32IZFINXZDINX-NEXT: fadd.d a0, a0, a2 98; RV32IZFINXZDINX-NEXT: lw a2, %lo(G)(a4) 99; RV32IZFINXZDINX-NEXT: lw a3, %lo(G+4)(a4) 100; RV32IZFINXZDINX-NEXT: addi a2, a4, %lo(G) 101; RV32IZFINXZDINX-NEXT: sw a0, %lo(G)(a4) 102; RV32IZFINXZDINX-NEXT: sw a1, %lo(G+4)(a4) 103; RV32IZFINXZDINX-NEXT: lw a4, 72(a2) 104; RV32IZFINXZDINX-NEXT: lw a5, 76(a2) 105; RV32IZFINXZDINX-NEXT: sw a0, 72(a2) 106; RV32IZFINXZDINX-NEXT: sw a1, 76(a2) 107; RV32IZFINXZDINX-NEXT: ret 108; 109; RV64IZFINXZDINX-LABEL: fld_fsd_global: 110; RV64IZFINXZDINX: # %bb.0: 111; RV64IZFINXZDINX-NEXT: fadd.d a0, a0, a1 112; RV64IZFINXZDINX-NEXT: lui a1, %hi(G) 113; RV64IZFINXZDINX-NEXT: ld zero, %lo(G)(a1) 114; RV64IZFINXZDINX-NEXT: addi a2, a1, %lo(G) 115; RV64IZFINXZDINX-NEXT: sd a0, %lo(G)(a1) 116; RV64IZFINXZDINX-NEXT: ld zero, 72(a2) 117; RV64IZFINXZDINX-NEXT: sd a0, 72(a2) 118; RV64IZFINXZDINX-NEXT: ret 119; Use %a and %b in an FP op to ensure floating point registers are used, even 120; for the soft float ABI 121 %1 = fadd double %a, %b 122 %2 = load volatile double, ptr @G 123 store double %1, ptr @G 124 %3 = getelementptr double, ptr @G, i32 9 125 %4 = load volatile double, ptr %3 126 store double %1, ptr %3 127 ret double %1 128} 129 130; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1 131define dso_local double @fld_fsd_constant(double %a) nounwind { 132; RV32IFD-LABEL: fld_fsd_constant: 133; RV32IFD: # %bb.0: 134; RV32IFD-NEXT: lui a0, 912092 135; RV32IFD-NEXT: fld fa5, -273(a0) 136; RV32IFD-NEXT: fadd.d fa0, fa0, fa5 137; RV32IFD-NEXT: fsd fa0, -273(a0) 138; RV32IFD-NEXT: ret 139; 140; RV64IFD-LABEL: fld_fsd_constant: 141; RV64IFD: # %bb.0: 142; RV64IFD-NEXT: lui a0, 228023 143; RV64IFD-NEXT: slli a0, a0, 2 144; RV64IFD-NEXT: fld fa5, -273(a0) 145; RV64IFD-NEXT: fadd.d fa0, fa0, fa5 146; RV64IFD-NEXT: fsd fa0, -273(a0) 147; RV64IFD-NEXT: ret 148; 149; RV32IZFINXZDINX-LABEL: fld_fsd_constant: 150; RV32IZFINXZDINX: # %bb.0: 151; RV32IZFINXZDINX-NEXT: lui a2, 912092 152; RV32IZFINXZDINX-NEXT: lw a4, -273(a2) 153; RV32IZFINXZDINX-NEXT: lw a5, -269(a2) 154; RV32IZFINXZDINX-NEXT: fadd.d a0, a0, a4 155; RV32IZFINXZDINX-NEXT: sw a0, -273(a2) 156; RV32IZFINXZDINX-NEXT: sw a1, -269(a2) 157; RV32IZFINXZDINX-NEXT: ret 158; 159; RV64IZFINXZDINX-LABEL: fld_fsd_constant: 160; RV64IZFINXZDINX: # %bb.0: 161; RV64IZFINXZDINX-NEXT: lui a1, 228023 162; RV64IZFINXZDINX-NEXT: slli a1, a1, 2 163; RV64IZFINXZDINX-NEXT: ld a2, -273(a1) 164; RV64IZFINXZDINX-NEXT: fadd.d a0, a0, a2 165; RV64IZFINXZDINX-NEXT: sd a0, -273(a1) 166; RV64IZFINXZDINX-NEXT: ret 167 %1 = inttoptr i32 3735928559 to ptr 168 %2 = load volatile double, ptr %1 169 %3 = fadd double %a, %2 170 store double %3, ptr %1 171 ret double %3 172} 173 174declare void @notdead(ptr) 175 176define dso_local double @fld_stack(double %a) nounwind { 177; RV32IFD-LABEL: fld_stack: 178; RV32IFD: # %bb.0: 179; RV32IFD-NEXT: addi sp, sp, -32 180; RV32IFD-NEXT: sw ra, 28(sp) # 4-byte Folded Spill 181; RV32IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill 182; RV32IFD-NEXT: fmv.d fs0, fa0 183; RV32IFD-NEXT: addi a0, sp, 8 184; RV32IFD-NEXT: call notdead 185; RV32IFD-NEXT: fld fa5, 8(sp) 186; RV32IFD-NEXT: fadd.d fa0, fa5, fs0 187; RV32IFD-NEXT: lw ra, 28(sp) # 4-byte Folded Reload 188; RV32IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload 189; RV32IFD-NEXT: addi sp, sp, 32 190; RV32IFD-NEXT: ret 191; 192; RV64IFD-LABEL: fld_stack: 193; RV64IFD: # %bb.0: 194; RV64IFD-NEXT: addi sp, sp, -32 195; RV64IFD-NEXT: sd ra, 24(sp) # 8-byte Folded Spill 196; RV64IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill 197; RV64IFD-NEXT: fmv.d fs0, fa0 198; RV64IFD-NEXT: addi a0, sp, 8 199; RV64IFD-NEXT: call notdead 200; RV64IFD-NEXT: fld fa5, 8(sp) 201; RV64IFD-NEXT: fadd.d fa0, fa5, fs0 202; RV64IFD-NEXT: ld ra, 24(sp) # 8-byte Folded Reload 203; RV64IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload 204; RV64IFD-NEXT: addi sp, sp, 32 205; RV64IFD-NEXT: ret 206; 207; RV32IZFINXZDINX-LABEL: fld_stack: 208; RV32IZFINXZDINX: # %bb.0: 209; RV32IZFINXZDINX-NEXT: addi sp, sp, -32 210; RV32IZFINXZDINX-NEXT: sw ra, 28(sp) # 4-byte Folded Spill 211; RV32IZFINXZDINX-NEXT: sw s0, 24(sp) # 4-byte Folded Spill 212; RV32IZFINXZDINX-NEXT: sw s1, 20(sp) # 4-byte Folded Spill 213; RV32IZFINXZDINX-NEXT: mv s1, a1 214; RV32IZFINXZDINX-NEXT: mv s0, a0 215; RV32IZFINXZDINX-NEXT: addi a0, sp, 8 216; RV32IZFINXZDINX-NEXT: call notdead 217; RV32IZFINXZDINX-NEXT: lw a0, 8(sp) 218; RV32IZFINXZDINX-NEXT: lw a1, 12(sp) 219; RV32IZFINXZDINX-NEXT: fadd.d a0, a0, s0 220; RV32IZFINXZDINX-NEXT: lw ra, 28(sp) # 4-byte Folded Reload 221; RV32IZFINXZDINX-NEXT: lw s0, 24(sp) # 4-byte Folded Reload 222; RV32IZFINXZDINX-NEXT: lw s1, 20(sp) # 4-byte Folded Reload 223; RV32IZFINXZDINX-NEXT: addi sp, sp, 32 224; RV32IZFINXZDINX-NEXT: ret 225; 226; RV64IZFINXZDINX-LABEL: fld_stack: 227; RV64IZFINXZDINX: # %bb.0: 228; RV64IZFINXZDINX-NEXT: addi sp, sp, -32 229; RV64IZFINXZDINX-NEXT: sd ra, 24(sp) # 8-byte Folded Spill 230; RV64IZFINXZDINX-NEXT: sd s0, 16(sp) # 8-byte Folded Spill 231; RV64IZFINXZDINX-NEXT: mv s0, a0 232; RV64IZFINXZDINX-NEXT: addi a0, sp, 8 233; RV64IZFINXZDINX-NEXT: call notdead 234; RV64IZFINXZDINX-NEXT: ld a0, 8(sp) 235; RV64IZFINXZDINX-NEXT: fadd.d a0, a0, s0 236; RV64IZFINXZDINX-NEXT: ld ra, 24(sp) # 8-byte Folded Reload 237; RV64IZFINXZDINX-NEXT: ld s0, 16(sp) # 8-byte Folded Reload 238; RV64IZFINXZDINX-NEXT: addi sp, sp, 32 239; RV64IZFINXZDINX-NEXT: ret 240 %1 = alloca double, align 8 241 call void @notdead(ptr %1) 242 %2 = load double, ptr %1 243 %3 = fadd double %2, %a ; force load in to FPR64 244 ret double %3 245} 246 247define dso_local void @fsd_stack(double %a, double %b) nounwind { 248; RV32IFD-LABEL: fsd_stack: 249; RV32IFD: # %bb.0: 250; RV32IFD-NEXT: addi sp, sp, -16 251; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill 252; RV32IFD-NEXT: fadd.d fa5, fa0, fa1 253; RV32IFD-NEXT: fsd fa5, 0(sp) 254; RV32IFD-NEXT: mv a0, sp 255; RV32IFD-NEXT: call notdead 256; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload 257; RV32IFD-NEXT: addi sp, sp, 16 258; RV32IFD-NEXT: ret 259; 260; RV64IFD-LABEL: fsd_stack: 261; RV64IFD: # %bb.0: 262; RV64IFD-NEXT: addi sp, sp, -16 263; RV64IFD-NEXT: sd ra, 8(sp) # 8-byte Folded Spill 264; RV64IFD-NEXT: fadd.d fa5, fa0, fa1 265; RV64IFD-NEXT: fsd fa5, 0(sp) 266; RV64IFD-NEXT: mv a0, sp 267; RV64IFD-NEXT: call notdead 268; RV64IFD-NEXT: ld ra, 8(sp) # 8-byte Folded Reload 269; RV64IFD-NEXT: addi sp, sp, 16 270; RV64IFD-NEXT: ret 271; 272; RV32IZFINXZDINX-LABEL: fsd_stack: 273; RV32IZFINXZDINX: # %bb.0: 274; RV32IZFINXZDINX-NEXT: addi sp, sp, -16 275; RV32IZFINXZDINX-NEXT: sw ra, 12(sp) # 4-byte Folded Spill 276; RV32IZFINXZDINX-NEXT: fadd.d a0, a0, a2 277; RV32IZFINXZDINX-NEXT: sw a0, 0(sp) 278; RV32IZFINXZDINX-NEXT: sw a1, 4(sp) 279; RV32IZFINXZDINX-NEXT: mv a0, sp 280; RV32IZFINXZDINX-NEXT: call notdead 281; RV32IZFINXZDINX-NEXT: lw ra, 12(sp) # 4-byte Folded Reload 282; RV32IZFINXZDINX-NEXT: addi sp, sp, 16 283; RV32IZFINXZDINX-NEXT: ret 284; 285; RV64IZFINXZDINX-LABEL: fsd_stack: 286; RV64IZFINXZDINX: # %bb.0: 287; RV64IZFINXZDINX-NEXT: addi sp, sp, -16 288; RV64IZFINXZDINX-NEXT: sd ra, 8(sp) # 8-byte Folded Spill 289; RV64IZFINXZDINX-NEXT: fadd.d a0, a0, a1 290; RV64IZFINXZDINX-NEXT: sd a0, 0(sp) 291; RV64IZFINXZDINX-NEXT: mv a0, sp 292; RV64IZFINXZDINX-NEXT: call notdead 293; RV64IZFINXZDINX-NEXT: ld ra, 8(sp) # 8-byte Folded Reload 294; RV64IZFINXZDINX-NEXT: addi sp, sp, 16 295; RV64IZFINXZDINX-NEXT: ret 296 %1 = fadd double %a, %b ; force store from FPR64 297 %2 = alloca double, align 8 298 store double %1, ptr %2 299 call void @notdead(ptr %2) 300 ret void 301} 302 303; Test selection of store<ST4[%a], trunc to f32>, .. 304define dso_local void @fsd_trunc(ptr %a, double %b) nounwind noinline optnone { 305; CHECKIFD-LABEL: fsd_trunc: 306; CHECKIFD: # %bb.0: 307; CHECKIFD-NEXT: fcvt.s.d fa5, fa0 308; CHECKIFD-NEXT: fsw fa5, 0(a0) 309; CHECKIFD-NEXT: ret 310; 311; RV32IZFINXZDINX-LABEL: fsd_trunc: 312; RV32IZFINXZDINX: # %bb.0: 313; RV32IZFINXZDINX-NEXT: mv a3, a2 314; RV32IZFINXZDINX-NEXT: mv a2, a1 315; RV32IZFINXZDINX-NEXT: fcvt.s.d a1, a2 316; RV32IZFINXZDINX-NEXT: sw a1, 0(a0) 317; RV32IZFINXZDINX-NEXT: ret 318; 319; RV64IZFINXZDINX-LABEL: fsd_trunc: 320; RV64IZFINXZDINX: # %bb.0: 321; RV64IZFINXZDINX-NEXT: fcvt.s.d a1, a1 322; RV64IZFINXZDINX-NEXT: sw a1, 0(a0) 323; RV64IZFINXZDINX-NEXT: ret 324 %1 = fptrunc double %b to float 325 store float %1, ptr %a, align 4 326 ret void 327} 328