From f21e608771bbf4701a4364ce125c0de83aa2df71 Mon Sep 17 00:00:00 2001 From: Alex Bradbury Date: Fri, 25 Jan 2019 21:55:48 +0000 Subject: [PATCH] [RISCV] Add target DAG combine for bitcast fabs/fneg on RV32FD DAGCombiner::visitBITCAST will perform: fold (bitconvert (fneg x)) -> (xor (bitconvert x), signbit) fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) As shown in double-bitmanip-dagcombines.ll, this can be advantageous. But RV32FD doesn't use bitcast directly (as i64 isn't a legal type), and instead uses RISCVISD::SplitF64. This patch adds an equivalent DAG combine for SplitF64. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@352247 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/RISCV/RISCVISelLowering.cpp | 31 ++++++++++++++-- test/CodeGen/RISCV/double-arith.ll | 37 +++++++++++++------ .../RISCV/double-bitmanip-dagcombines.ll | 23 +++--------- test/CodeGen/RISCV/double-intrinsics.ll | 12 ++---- 4 files changed, 61 insertions(+), 42 deletions(-) diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp index 79385de07dd..d61297c801c 100644 --- a/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/lib/Target/RISCV/RISCVISelLowering.cpp @@ -584,16 +584,41 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N, SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + switch (N->getOpcode()) { default: break; case RISCVISD::SplitF64: { + SDValue Op0 = N->getOperand(0); // If the input to SplitF64 is just BuildPairF64 then the operation is // redundant. Instead, use BuildPairF64's operands directly. - SDValue Op0 = N->getOperand(0); - if (Op0->getOpcode() != RISCVISD::BuildPairF64) + if (Op0->getOpcode() == RISCVISD::BuildPairF64) + return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1)); + + SDLoc DL(N); + // This is a target-specific version of a DAGCombine performed in + // DAGCombiner::visitBITCAST. It performs the equivalent of: + // fold (bitconvert (fneg x)) -> (xor (bitconvert x), signbit) + // fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) + if (!(Op0.getOpcode() == ISD::FNEG || Op0.getOpcode() == ISD::FABS) || + !Op0.getNode()->hasOneUse()) break; - return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1)); + SDValue NewSplitF64 = + DAG.getNode(RISCVISD::SplitF64, DL, DAG.getVTList(MVT::i32, MVT::i32), + Op0.getOperand(0)); + SDValue Lo = NewSplitF64.getValue(0); + SDValue Hi = NewSplitF64.getValue(1); + APInt SignBit = APInt::getSignMask(32); + if (Op0.getOpcode() == ISD::FNEG) { + SDValue NewHi = DAG.getNode(ISD::XOR, DL, MVT::i32, Hi, + DAG.getConstant(SignBit, DL, MVT::i32)); + return DCI.CombineTo(N, Lo, NewHi); + } + assert(Op0.getOpcode() == ISD::FABS); + SDValue NewHi = DAG.getNode(ISD::AND, DL, MVT::i32, Hi, + DAG.getConstant(~SignBit, DL, MVT::i32)); + return DCI.CombineTo(N, Lo, NewHi); } case RISCVISD::SLLW: case RISCVISD::SRAW: diff --git a/test/CodeGen/RISCV/double-arith.ll b/test/CodeGen/RISCV/double-arith.ll index 7262eac4042..a5243ea18ab 100644 --- a/test/CodeGen/RISCV/double-arith.ll +++ b/test/CodeGen/RISCV/double-arith.ll @@ -127,21 +127,25 @@ define double @fsgnj_d(double %a, double %b) nounwind { ret double %1 } -define double @fneg_d(double %a) nounwind { +; This function performs extra work to ensure that +; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor. +define i32 @fneg_d(double %a, double %b) nounwind { ; RV32IFD-LABEL: fneg_d: ; RV32IFD: # %bb.0: ; RV32IFD-NEXT: addi sp, sp, -16 ; RV32IFD-NEXT: sw a0, 8(sp) ; RV32IFD-NEXT: sw a1, 12(sp) ; RV32IFD-NEXT: fld ft0, 8(sp) -; RV32IFD-NEXT: fneg.d ft0, ft0 -; RV32IFD-NEXT: fsd ft0, 8(sp) -; RV32IFD-NEXT: lw a0, 8(sp) -; RV32IFD-NEXT: lw a1, 12(sp) +; RV32IFD-NEXT: fadd.d ft0, ft0, ft0 +; RV32IFD-NEXT: fneg.d ft1, ft0 +; RV32IFD-NEXT: feq.d a0, ft0, ft1 ; RV32IFD-NEXT: addi sp, sp, 16 ; RV32IFD-NEXT: ret - %1 = fsub double -0.0, %a - ret double %1 + %1 = fadd double %a, %a + %2 = fneg double %1 + %3 = fcmp oeq double %1, %2 + %4 = zext i1 %3 to i32 + ret i32 %4 } define double @fsgnjn_d(double %a, double %b) nounwind { @@ -167,21 +171,30 @@ define double @fsgnjn_d(double %a, double %b) nounwind { declare double @llvm.fabs.f64(double) -define double @fabs_d(double %a) nounwind { +; This function performs extra work to ensure that +; DAGCombiner::visitBITCAST doesn't replace the fabs with an and. +define double @fabs_d(double %a, double %b) nounwind { ; RV32IFD-LABEL: fabs_d: ; RV32IFD: # %bb.0: ; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw a2, 8(sp) +; RV32IFD-NEXT: sw a3, 12(sp) +; RV32IFD-NEXT: fld ft0, 8(sp) ; RV32IFD-NEXT: sw a0, 8(sp) ; RV32IFD-NEXT: sw a1, 12(sp) -; RV32IFD-NEXT: fld ft0, 8(sp) -; RV32IFD-NEXT: fabs.d ft0, ft0 +; RV32IFD-NEXT: fld ft1, 8(sp) +; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 +; RV32IFD-NEXT: fabs.d ft1, ft0 +; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 ; RV32IFD-NEXT: fsd ft0, 8(sp) ; RV32IFD-NEXT: lw a0, 8(sp) ; RV32IFD-NEXT: lw a1, 12(sp) ; RV32IFD-NEXT: addi sp, sp, 16 ; RV32IFD-NEXT: ret - %1 = call double @llvm.fabs.f64(double %a) - ret double %1 + %1 = fadd double %a, %b + %2 = call double @llvm.fabs.f64(double %1) + %3 = fadd double %2, %1 + ret double %3 } declare double @llvm.minnum.f64(double, double) diff --git a/test/CodeGen/RISCV/double-bitmanip-dagcombines.ll b/test/CodeGen/RISCV/double-bitmanip-dagcombines.ll index 4e0fbbd35d6..25364cf4e48 100644 --- a/test/CodeGen/RISCV/double-bitmanip-dagcombines.ll +++ b/test/CodeGen/RISCV/double-bitmanip-dagcombines.ll @@ -24,15 +24,8 @@ define double @fneg(double %a) nounwind { ; ; RV32IFD-LABEL: fneg: ; RV32IFD: # %bb.0: -; RV32IFD-NEXT: addi sp, sp, -16 -; RV32IFD-NEXT: sw a0, 8(sp) -; RV32IFD-NEXT: sw a1, 12(sp) -; RV32IFD-NEXT: fld ft0, 8(sp) -; RV32IFD-NEXT: fneg.d ft0, ft0 -; RV32IFD-NEXT: fsd ft0, 8(sp) -; RV32IFD-NEXT: lw a0, 8(sp) -; RV32IFD-NEXT: lw a1, 12(sp) -; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: lui a2, 524288 +; RV32IFD-NEXT: xor a1, a1, a2 ; RV32IFD-NEXT: ret ; ; RV64I-LABEL: fneg: @@ -57,15 +50,9 @@ define double @fabs(double %a) nounwind { ; ; RV32IFD-LABEL: fabs: ; RV32IFD: # %bb.0: -; RV32IFD-NEXT: addi sp, sp, -16 -; RV32IFD-NEXT: sw a0, 8(sp) -; RV32IFD-NEXT: sw a1, 12(sp) -; RV32IFD-NEXT: fld ft0, 8(sp) -; RV32IFD-NEXT: fabs.d ft0, ft0 -; RV32IFD-NEXT: fsd ft0, 8(sp) -; RV32IFD-NEXT: lw a0, 8(sp) -; RV32IFD-NEXT: lw a1, 12(sp) -; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: lui a2, 524288 +; RV32IFD-NEXT: addi a2, a2, -1 +; RV32IFD-NEXT: and a1, a1, a2 ; RV32IFD-NEXT: ret ; ; RV64I-LABEL: fabs: diff --git a/test/CodeGen/RISCV/double-intrinsics.ll b/test/CodeGen/RISCV/double-intrinsics.ll index cd14c1932d4..7e69bb1743a 100644 --- a/test/CodeGen/RISCV/double-intrinsics.ll +++ b/test/CodeGen/RISCV/double-intrinsics.ll @@ -254,15 +254,9 @@ declare double @llvm.fabs.f64(double) define double @fabs_f64(double %a) nounwind { ; RV32IFD-LABEL: fabs_f64: ; RV32IFD: # %bb.0: -; RV32IFD-NEXT: addi sp, sp, -16 -; RV32IFD-NEXT: sw a0, 8(sp) -; RV32IFD-NEXT: sw a1, 12(sp) -; RV32IFD-NEXT: fld ft0, 8(sp) -; RV32IFD-NEXT: fabs.d ft0, ft0 -; RV32IFD-NEXT: fsd ft0, 8(sp) -; RV32IFD-NEXT: lw a0, 8(sp) -; RV32IFD-NEXT: lw a1, 12(sp) -; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: lui a2, 524288 +; RV32IFD-NEXT: addi a2, a2, -1 +; RV32IFD-NEXT: and a1, a1, a2 ; RV32IFD-NEXT: ret %1 = call double @llvm.fabs.f64(double %a) ret double %1 -- 2.50.1