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:
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 {
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)
;
; 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:
;
; 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:
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