diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -354,6 +354,7 @@ private: bool trySETCC(SDNode *N); + bool tryFoldSqrtTestBr(SDNode *N); bool tryAsSingleRLDICL(SDNode *N); bool tryAsSingleRLDICR(SDNode *N); bool tryAsSingleRLWINM(SDNode *N); @@ -4380,6 +4381,87 @@ return true; } +static unsigned getTestSqrtOpcode(SDValue N) { + if (N.getOpcode() == PPCISD::FTSQRT) { + if (N.getOperand(0).getValueType() == MVT::i32) + return PPC::FTSQRT; + if (N.getOperand(0).getValueType() == MVT::f64) + return PPC::XSTSQRTDP; + } + if (!isa(N.getOperand(0))) + return 0; + switch (N.getConstantOperandVal(0)) { + case Intrinsic::ppc_vsx_xvtdivdp: + assert(N.getOperand(1).getValueType() == MVT::v2f64 && + "Invalid input type for XVTDIVDP."); + return PPC::XVTDIVDP; + case Intrinsic::ppc_vsx_xvtdivsp: + assert(N.getOperand(1).getValueType() == MVT::v4f32 && + "Invalid input type for XVTDIVSP."); + return PPC::XVTDIVSP; + case Intrinsic::ppc_vsx_xvtsqrtdp: + assert(N.getOperand(1).getValueType() == MVT::v2f64 && + "Invalid input type for XVTSQRTDP."); + return PPC::XVTSQRTDP; + case Intrinsic::ppc_vsx_xvtsqrtsp: + assert(N.getOperand(1).getValueType() == MVT::v4f32 && + "Invalid input type for XVTSQRTSP."); + return PPC::XVTSQRTSP; + } + return 0; +} + +bool PPCDAGToDAGISel::tryFoldSqrtTestBr(SDNode *N) { + // We are looking for following patterns. + // (br_cc seteq, (and Node_test, 2), 0) -> (BCC PRED_NE, PPCNode_test) + // (br_cc seteq, (and Node_test, 4), 0) -> (BCC PRED_LE, PPCNode_test) + // (br_cc seteq, (and Node_test, 8), 0) -> (BCC PRED_GE, PPCNode_test) + // (br_cc setne, (and Node_test, 2), 0) -> (BCC PRED_EQ, PPCNode_test) + // (br_cc setne, (and Node_test, 4), 0) -> (BCC PRED_GT, PPCNode_test) + // (br_cc setne, (and Node_test, 8), 0) -> (BCC PRED_LT, PPCNode_test) + SDValue CmpLHS = N->getOperand(2); + ISD::CondCode CC = cast(N->getOperand(1))->get(); + if (!isa(N->getOperand(3)) || + N->getConstantOperandVal(3) != 0 || + (CC != ISD::SETEQ && CC != ISD::SETNE) || + CmpLHS.getOpcode() != ISD::AND || + !isa(CmpLHS.getOperand(1))) + return false; + unsigned TestOpcode = getTestSqrtOpcode(CmpLHS.getOperand(0)); + if (!TestOpcode) + return false; + + unsigned PCC; + bool IsCCNE = CC == ISD::SETNE; + switch (cast(CmpLHS.getOperand(1))->getZExtValue()) { + case 2: + PCC = IsCCNE ? PPC::PRED_EQ : PPC::PRED_NE; + break; + case 4: + PCC = IsCCNE ? PPC::PRED_GT : PPC::PRED_LE; + break; + case 8: + PCC = IsCCNE ? PPC::PRED_LT : PPC::PRED_GE; + break; + default: + return false; + } + + SDLoc dl(N); + SDNode *TestNode = CmpLHS.getOperand(0).getNode(); + if (TestNode->getNumOperands() == 3) + TestNode = CurDAG->getMachineNode(TestOpcode, dl, TestNode->getValueType(0), + TestNode->getOperand(1), + TestNode->getOperand(2)); + else + TestNode = CurDAG->getMachineNode(TestOpcode, dl, TestNode->getValueType(0), + TestNode->getOperand(1)); + SDValue Ops[] = {getI32Imm(PCC, dl), SDValue(TestNode, 0), N->getOperand(4), + N->getOperand(0)}; + CurDAG->SelectNodeTo(N, PPC::BCC, MVT::Other, Ops); + return true; +} + bool PPCDAGToDAGISel::tryAsSingleRLWINM(SDNode *N) { assert(N->getOpcode() == ISD::AND && "ISD::AND SDNode expected"); unsigned Imm; @@ -5249,6 +5331,8 @@ return; } case ISD::BR_CC: { + if (tryFoldSqrtTestBr(N)) + return; ISD::CondCode CC = cast(N->getOperand(1))->get(); unsigned PCC = getPredicateForSetCC(CC, N->getOperand(2).getValueType(), Subtarget); diff --git a/llvm/test/CodeGen/PowerPC/branch_test.ll b/llvm/test/CodeGen/PowerPC/branch_test.ll --- a/llvm/test/CodeGen/PowerPC/branch_test.ll +++ b/llvm/test/CodeGen/PowerPC/branch_test.ll @@ -9,10 +9,7 @@ ; CHECK-LABEL: xvtsqrtdp_and_2_eq: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: xvtsqrtdp cr0, v2 -; CHECK-NEXT: mfocrf r3, 128 -; CHECK-NEXT: srwi r3, r3, 28 -; CHECK-NEXT: andi. r3, r3, 2 -; CHECK-NEXT: beq cr0, .LBB0_2 +; CHECK-NEXT: bne cr0, .LBB0_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100 @@ -39,10 +36,7 @@ ; CHECK-LABEL: xvtsqrtdp_and_4_eq: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: xvtsqrtdp cr0, v2 -; CHECK-NEXT: mfocrf r3, 128 -; CHECK-NEXT: srwi r3, r3, 28 -; CHECK-NEXT: andi. r3, r3, 4 -; CHECK-NEXT: beq cr0, .LBB1_2 +; CHECK-NEXT: ble cr0, .LBB1_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100 @@ -69,10 +63,7 @@ ; CHECK-LABEL: xvtsqrtdp_and_8_eq: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: xvtsqrtdp cr0, v2 -; CHECK-NEXT: mfocrf r3, 128 -; CHECK-NEXT: srwi r3, r3, 28 -; CHECK-NEXT: andi. r3, r3, 8 -; CHECK-NEXT: beq cr0, .LBB2_2 +; CHECK-NEXT: bge cr0, .LBB2_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100 @@ -99,10 +90,7 @@ ; CHECK-LABEL: xvtsqrtdp_and_2_ne: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: xvtsqrtdp cr0, v2 -; CHECK-NEXT: mfocrf r3, 128 -; CHECK-NEXT: srwi r3, r3, 28 -; CHECK-NEXT: andi. r3, r3, 2 -; CHECK-NEXT: bne cr0, .LBB3_2 +; CHECK-NEXT: beq cr0, .LBB3_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100 @@ -129,10 +117,7 @@ ; CHECK-LABEL: xvtsqrtdp_and_4_ne: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: xvtsqrtdp cr0, v2 -; CHECK-NEXT: mfocrf r3, 128 -; CHECK-NEXT: srwi r3, r3, 28 -; CHECK-NEXT: andi. r3, r3, 4 -; CHECK-NEXT: bne cr0, .LBB4_2 +; CHECK-NEXT: bgt cr0, .LBB4_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100 @@ -159,10 +144,7 @@ ; CHECK-LABEL: xvtsqrtdp_and_8_ne: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: xvtsqrtdp cr0, v2 -; CHECK-NEXT: mfocrf r3, 128 -; CHECK-NEXT: srwi r3, r3, 28 -; CHECK-NEXT: andi. r3, r3, 8 -; CHECK-NEXT: bne cr0, .LBB5_2 +; CHECK-NEXT: blt cr0, .LBB5_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100