1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=riscv32 -target-abi=ilp32 -verify-machineinstrs < %s \ 3; RUN: | FileCheck -check-prefix=RV32I %s 4; RUN: llc -mtriple=riscv32 -target-abi=ilp32 -mattr=+d -verify-machineinstrs < %s \ 5; RUN: | FileCheck -check-prefix=RV32IFD %s 6; RUN: llc -mtriple=riscv32 -target-abi=ilp32 -mattr=+zdinx -verify-machineinstrs < %s \ 7; RUN: | FileCheck -check-prefix=RV32IZFINXZDINX %s 8; RUN: llc -mtriple=riscv64 -target-abi=lp64 -verify-machineinstrs < %s \ 9; RUN: | FileCheck -check-prefix=RV64I %s 10; RUN: llc -mtriple=riscv64 -target-abi=lp64 -mattr=+d -verify-machineinstrs < %s \ 11; RUN: | FileCheck -check-prefix=RV64IFD %s 12; RUN: llc -mtriple=riscv64 -target-abi=lp64 -mattr=+zdinx -verify-machineinstrs < %s \ 13; RUN: | FileCheck -check-prefix=RV64IZFINXZDINX %s 14; 15; This file tests cases where simple floating point operations can be 16; profitably handled though bit manipulation if a soft-float ABI is being used 17; (e.g. fneg implemented by XORing the sign bit). This is typically handled in 18; DAGCombiner::visitBITCAST, but this target-independent code may not trigger 19; in cases where we perform custom legalisation (e.g. RV32IFD). 20 21; TODO: Add an appropriate target-specific DAG combine that can handle 22; RISCVISD::SplitF64/BuildPairF64 used for RV32IFD. 23 24define double @fneg(double %a) nounwind { 25; RV32I-LABEL: fneg: 26; RV32I: # %bb.0: 27; RV32I-NEXT: lui a2, 524288 28; RV32I-NEXT: xor a1, a1, a2 29; RV32I-NEXT: ret 30; 31; RV32IFD-LABEL: fneg: 32; RV32IFD: # %bb.0: 33; RV32IFD-NEXT: lui a2, 524288 34; RV32IFD-NEXT: xor a1, a1, a2 35; RV32IFD-NEXT: ret 36; 37; RV32IZFINXZDINX-LABEL: fneg: 38; RV32IZFINXZDINX: # %bb.0: 39; RV32IZFINXZDINX-NEXT: fneg.d a0, a0 40; RV32IZFINXZDINX-NEXT: ret 41; 42; RV64I-LABEL: fneg: 43; RV64I: # %bb.0: 44; RV64I-NEXT: li a1, -1 45; RV64I-NEXT: slli a1, a1, 63 46; RV64I-NEXT: xor a0, a0, a1 47; RV64I-NEXT: ret 48; 49; RV64IFD-LABEL: fneg: 50; RV64IFD: # %bb.0: 51; RV64IFD-NEXT: li a1, -1 52; RV64IFD-NEXT: slli a1, a1, 63 53; RV64IFD-NEXT: xor a0, a0, a1 54; RV64IFD-NEXT: ret 55; 56; RV64IZFINXZDINX-LABEL: fneg: 57; RV64IZFINXZDINX: # %bb.0: 58; RV64IZFINXZDINX-NEXT: fneg.d a0, a0 59; RV64IZFINXZDINX-NEXT: ret 60 %1 = fneg double %a 61 ret double %1 62} 63 64declare double @llvm.fabs.f64(double) 65 66define double @fabs(double %a) nounwind { 67; RV32I-LABEL: fabs: 68; RV32I: # %bb.0: 69; RV32I-NEXT: slli a1, a1, 1 70; RV32I-NEXT: srli a1, a1, 1 71; RV32I-NEXT: ret 72; 73; RV32IFD-LABEL: fabs: 74; RV32IFD: # %bb.0: 75; RV32IFD-NEXT: slli a1, a1, 1 76; RV32IFD-NEXT: srli a1, a1, 1 77; RV32IFD-NEXT: ret 78; 79; RV32IZFINXZDINX-LABEL: fabs: 80; RV32IZFINXZDINX: # %bb.0: 81; RV32IZFINXZDINX-NEXT: fabs.d a0, a0 82; RV32IZFINXZDINX-NEXT: ret 83; 84; RV64I-LABEL: fabs: 85; RV64I: # %bb.0: 86; RV64I-NEXT: slli a0, a0, 1 87; RV64I-NEXT: srli a0, a0, 1 88; RV64I-NEXT: ret 89; 90; RV64IFD-LABEL: fabs: 91; RV64IFD: # %bb.0: 92; RV64IFD-NEXT: slli a0, a0, 1 93; RV64IFD-NEXT: srli a0, a0, 1 94; RV64IFD-NEXT: ret 95; 96; RV64IZFINXZDINX-LABEL: fabs: 97; RV64IZFINXZDINX: # %bb.0: 98; RV64IZFINXZDINX-NEXT: fabs.d a0, a0 99; RV64IZFINXZDINX-NEXT: ret 100 %1 = call double @llvm.fabs.f64(double %a) 101 ret double %1 102} 103 104declare double @llvm.copysign.f64(double, double) 105 106; DAGTypeLegalizer::SoftenFloatRes_FCOPYSIGN will convert to bitwise 107; operations if floating point isn't supported. A combine could be written to 108; do the same even when f64 is legal. 109 110define double @fcopysign_fneg(double %a, double %b) nounwind { 111; RV32I-LABEL: fcopysign_fneg: 112; RV32I: # %bb.0: 113; RV32I-NEXT: not a2, a3 114; RV32I-NEXT: lui a3, 524288 115; RV32I-NEXT: slli a1, a1, 1 116; RV32I-NEXT: and a2, a2, a3 117; RV32I-NEXT: srli a1, a1, 1 118; RV32I-NEXT: or a1, a1, a2 119; RV32I-NEXT: ret 120; 121; RV32IFD-LABEL: fcopysign_fneg: 122; RV32IFD: # %bb.0: 123; RV32IFD-NEXT: addi sp, sp, -16 124; RV32IFD-NEXT: sw a2, 8(sp) 125; RV32IFD-NEXT: sw a3, 12(sp) 126; RV32IFD-NEXT: fld fa5, 8(sp) 127; RV32IFD-NEXT: sw a0, 8(sp) 128; RV32IFD-NEXT: sw a1, 12(sp) 129; RV32IFD-NEXT: fld fa4, 8(sp) 130; RV32IFD-NEXT: fsgnjn.d fa5, fa4, fa5 131; RV32IFD-NEXT: fsd fa5, 8(sp) 132; RV32IFD-NEXT: lw a0, 8(sp) 133; RV32IFD-NEXT: lw a1, 12(sp) 134; RV32IFD-NEXT: addi sp, sp, 16 135; RV32IFD-NEXT: ret 136; 137; RV32IZFINXZDINX-LABEL: fcopysign_fneg: 138; RV32IZFINXZDINX: # %bb.0: 139; RV32IZFINXZDINX-NEXT: fsgnjn.d a0, a0, a2 140; RV32IZFINXZDINX-NEXT: ret 141; 142; RV64I-LABEL: fcopysign_fneg: 143; RV64I: # %bb.0: 144; RV64I-NEXT: not a1, a1 145; RV64I-NEXT: slli a0, a0, 1 146; RV64I-NEXT: srli a0, a0, 1 147; RV64I-NEXT: srli a1, a1, 63 148; RV64I-NEXT: slli a1, a1, 63 149; RV64I-NEXT: or a0, a0, a1 150; RV64I-NEXT: ret 151; 152; RV64IFD-LABEL: fcopysign_fneg: 153; RV64IFD: # %bb.0: 154; RV64IFD-NEXT: fmv.d.x fa5, a0 155; RV64IFD-NEXT: not a0, a1 156; RV64IFD-NEXT: fmv.d.x fa4, a0 157; RV64IFD-NEXT: fsgnj.d fa5, fa5, fa4 158; RV64IFD-NEXT: fmv.x.d a0, fa5 159; RV64IFD-NEXT: ret 160; 161; RV64IZFINXZDINX-LABEL: fcopysign_fneg: 162; RV64IZFINXZDINX: # %bb.0: 163; RV64IZFINXZDINX-NEXT: fsgnjn.d a0, a0, a1 164; RV64IZFINXZDINX-NEXT: ret 165 %1 = fneg double %b 166 %2 = call double @llvm.copysign.f64(double %a, double %1) 167 ret double %2 168} 169