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 tryFoldSWTestBRCC(SDNode *N); bool tryAsSingleRLDICL(SDNode *N); bool tryAsSingleRLDICR(SDNode *N); bool tryAsSingleRLWINM(SDNode *N); @@ -4380,6 +4381,81 @@ return true; } +// Return true if it's a software square-root/divide operand. +static bool isSWTestOp(SDValue N) { + if (N.getOpcode() == PPCISD::FTSQRT) + return true; + if (!isa(N.getOperand(0))) + return false; + switch (N.getConstantOperandVal(0)) { + case Intrinsic::ppc_vsx_xvtdivdp: + case Intrinsic::ppc_vsx_xvtdivsp: + case Intrinsic::ppc_vsx_xvtsqrtdp: + case Intrinsic::ppc_vsx_xvtsqrtsp: + return true; + } + return false; +} + +bool PPCDAGToDAGISel::tryFoldSWTestBRCC(SDNode *N) { + assert(N->getOpcode() == ISD::BR_CC && "ISD::BR_CC is expected."); + // We are looking for following patterns, where `truncate to i1` actually has + // the same semantic with `and 1`. + // (br_cc seteq, (truncateToi1 SWTestOp), 0) -> (BCC PRED_NU, SWTestOp) + // (br_cc seteq, (and SWTestOp, 2), 0) -> (BCC PRED_NE, SWTestOp) + // (br_cc seteq, (and SWTestOp, 4), 0) -> (BCC PRED_LE, SWTestOp) + // (br_cc seteq, (and SWTestOp, 8), 0) -> (BCC PRED_GE, SWTestOp) + // (br_cc setne, (truncateToi1 SWTestOp), 0) -> (BCC PRED_UN, SWTestOp) + // (br_cc setne, (and SWTestOp, 2), 0) -> (BCC PRED_EQ, SWTestOp) + // (br_cc setne, (and SWTestOp, 4), 0) -> (BCC PRED_GT, SWTestOp) + // (br_cc setne, (and SWTestOp, 8), 0) -> (BCC PRED_LT, SWTestOp) + ISD::CondCode CC = cast(N->getOperand(1))->get(); + if (CC != ISD::SETEQ && CC != ISD::SETNE) + return false; + + SDValue CmpRHS = N->getOperand(3); + if (!isa(CmpRHS) || + cast(CmpRHS)->getSExtValue() != 0) + return false; + + SDValue CmpLHS = N->getOperand(2); + if (!isSWTestOp(CmpLHS.getOperand(0))) + return false; + + unsigned PCC = 0; + bool IsCCNE = CC == ISD::SETNE; + if (CmpLHS.getOpcode() == ISD::AND && + isa(CmpLHS.getOperand(1))) + switch (CmpLHS.getConstantOperandVal(1)) { + case 1: + PCC = IsCCNE ? PPC::PRED_UN : PPC::PRED_NU; + break; + 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; + } + else if (CmpLHS.getOpcode() == ISD::TRUNCATE && + CmpLHS.getValueType() == MVT::i1) + PCC = IsCCNE ? PPC::PRED_UN : PPC::PRED_NU; + + if (PCC) { + SDLoc dl(N); + SDValue Ops[] = {getI32Imm(PCC, dl), CmpLHS.getOperand(0), N->getOperand(4), + N->getOperand(0)}; + CurDAG->SelectNodeTo(N, PPC::BCC, MVT::Other, Ops); + return true; + } + return false; +} + bool PPCDAGToDAGISel::tryAsSingleRLWINM(SDNode *N) { assert(N->getOpcode() == ISD::AND && "ISD::AND SDNode expected"); unsigned Imm; @@ -5249,6 +5325,8 @@ return; } case ISD::BR_CC: { + if (tryFoldSWTestBRCC(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_1_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, 1 -; CHECK-NEXT: bc 4, gt, .LBB0_2 +; CHECK-NEXT: bnu 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_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, .LBB1_2 +; CHECK-NEXT: bne 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_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, .LBB2_2 +; CHECK-NEXT: ble 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_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, .LBB3_2 +; CHECK-NEXT: bge 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_1_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, 1 -; CHECK-NEXT: bc 12, gt, .LBB4_2 +; CHECK-NEXT: bun 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_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, .LBB5_2 +; CHECK-NEXT: beq cr0, .LBB5_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100 @@ -189,10 +171,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, .LBB6_2 +; CHECK-NEXT: bgt cr0, .LBB6_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100 @@ -219,10 +198,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, .LBB7_2 +; CHECK-NEXT: blt cr0, .LBB7_2 ; CHECK-NEXT: # %bb.1: # %if.then ; CHECK-NEXT: addis r3, r2, .LC0@toc@ha ; CHECK-NEXT: li r4, 100