@@ -33881,6 +33881,8 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
33881
33881
NODE_NAME_CASE(TESTUI)
33882
33882
NODE_NAME_CASE(FP80_ADD)
33883
33883
NODE_NAME_CASE(STRICT_FP80_ADD)
33884
+ NODE_NAME_CASE(CCMP)
33885
+ NODE_NAME_CASE(CTEST)
33884
33886
}
33885
33887
return nullptr;
33886
33888
#undef NODE_NAME_CASE
@@ -54508,7 +54510,156 @@ static bool onlyZeroFlagUsed(SDValue Flags) {
54508
54510
return true;
54509
54511
}
54510
54512
54513
+
54514
+ static int getCondFlagsFromCondCode(X86::CondCode CC) {
54515
+ // CCMP/CTEST has two conditional operands:
54516
+ // - SCC: source conditonal code (same as CMOV)
54517
+ // - DCF: destination conditional flags, which has 4 valid bits
54518
+ //
54519
+ // +----+----+----+----+
54520
+ // | OF | SF | ZF | CF |
54521
+ // +----+----+----+----+
54522
+ //
54523
+ // If SCC(source conditional code) evaluates to false, CCMP/CTEST will updates
54524
+ // the conditional flags by as follows:
54525
+ //
54526
+ // OF = DCF.OF
54527
+ // SF = DCF.SF
54528
+ // ZF = DCF.ZF
54529
+ // CF = DCF.CF
54530
+ // PF = DCF.CF
54531
+ // AF = 0 (Auxiliary Carry Flag)
54532
+ //
54533
+ // Otherwise, the CMP or TEST is executed and it updates the
54534
+ // CSPAZO flags normally.
54535
+ //
54536
+ // NOTE:
54537
+ // If SCC = P, then SCC evaluates to true regardless of the CSPAZO value.
54538
+ // If SCC = NP, then SCC evaluates to false regardless of the CSPAZO value.
54539
+
54540
+ enum { CF = 1, ZF = 2, SF = 4, OF = 8, PF = CF };
54541
+
54542
+
54543
+ switch (CC) {
54544
+ default:
54545
+ llvm_unreachable("Illegal condition code!");
54546
+ case X86::COND_NO:
54547
+ case X86::COND_NE:
54548
+ case X86::COND_GE:
54549
+ case X86::COND_G:
54550
+ case X86::COND_AE:
54551
+ case X86::COND_A:
54552
+ case X86::COND_NS:
54553
+ case X86::COND_NP:
54554
+ return 0;
54555
+ case X86::COND_O:
54556
+ return OF;
54557
+ case X86::COND_B:
54558
+ case X86::COND_BE:
54559
+ return CF;
54560
+ break;
54561
+ case X86::COND_E:
54562
+ case X86::COND_LE:
54563
+ return ZF;
54564
+ case X86::COND_S:
54565
+ case X86::COND_L:
54566
+ return SF;
54567
+ case X86::COND_P:
54568
+ return PF;
54569
+ }
54570
+ }
54571
+
54572
+ static SDValue
54573
+ combineX86SubCmpToCcmpHelper(SDNode *N, SDValue Flag, SelectionDAG &DAG,
54574
+ TargetLowering::DAGCombinerInfo &DCI,
54575
+ const X86Subtarget &ST) {
54576
+ SDValue LHS = N->getOperand(0);
54577
+
54578
+ if (!ST.hasCCMP() || LHS.getOpcode() != ISD::AND || !Flag.hasOneUse())
54579
+ return SDValue();
54580
+
54581
+ SDValue SetCC0 = LHS.getOperand(0);
54582
+ SDValue SetCC1 = LHS.getOperand(1);
54583
+ if (SetCC0.getOpcode() != X86ISD::SETCC &&
54584
+ SetCC1.getOpcode() != X86ISD::SETCC)
54585
+ return SDValue();
54586
+
54587
+ SDValue Sub = SetCC1.getOperand(1);
54588
+ // and is commutable. Try to commute the operands and then test again.
54589
+ if (Sub.getOpcode() != X86ISD::SUB)
54590
+ return SDValue();
54591
+
54592
+ SDNode *BrCond = *Flag->uses().begin();
54593
+ if (BrCond->getOpcode() != X86ISD::BRCOND)
54594
+ return SDValue();
54595
+
54596
+ X86::CondCode CC0 =
54597
+ static_cast<X86::CondCode>(SetCC0.getConstantOperandVal(0));
54598
+ if (CC0 == X86::COND_P || CC0 == X86::COND_NP)
54599
+ return SDValue();
54600
+
54601
+ SDValue CFlags = DAG.getTargetConstant(
54602
+ getCondFlagsFromCondCode(X86::GetOppositeBranchCondition(
54603
+ static_cast<X86::CondCode>(SetCC1.getConstantOperandVal(0)))),
54604
+ SDLoc(BrCond), MVT::i8);
54605
+ SDValue CCMP = DAG.getNode(X86ISD::CCMP, SDLoc(N), Flag.getValueType(),
54606
+ {Sub.getOperand(0), Sub.getOperand(1), CFlags,
54607
+ SetCC0.getOperand(0), SetCC0.getOperand(1)});
54608
+ DAG.ReplaceAllUsesOfValueWith(Flag, CCMP);
54609
+
54610
+ SmallVector<SDValue> Ops(BrCond->op_values());
54611
+ unsigned CondNo = 2;
54612
+ X86::CondCode OldCC =
54613
+ static_cast<X86::CondCode>(BrCond->getConstantOperandVal(CondNo));
54614
+ assert(OldCC == X86::COND_NE && "Unexpected CC");
54615
+ if (Ops[CondNo] != SetCC1.getOperand(0)) {
54616
+ Ops[CondNo] = SetCC1.getOperand(0);
54617
+ SDValue NewBrCond =
54618
+ DAG.getNode(X86ISD::BRCOND, SDLoc(BrCond), BrCond->getValueType(0), Ops);
54619
+ DAG.ReplaceAllUsesWith(BrCond, &NewBrCond);
54620
+ DCI.recursivelyDeleteUnusedNodes(BrCond);
54621
+ }
54622
+ return CCMP;
54623
+ }
54624
+
54625
+ static SDValue combineX86CmpToCcmp(SDNode *N, SelectionDAG &DAG,
54626
+ TargetLowering::DAGCombinerInfo &DCI,
54627
+ const X86Subtarget &ST) {
54628
+ // cmp(and(setcc(cc0, flag0), setcc(cc1, sub (X, Y))), 0)
54629
+ // brcond ne
54630
+ //
54631
+ // ->
54632
+ //
54633
+ // ccmp(X, Y, cflags, cc0, flag0)
54634
+ // brcond cc1
54635
+ //
54636
+ // where cflags is determined by cc1.
54637
+
54638
+ return combineX86SubCmpToCcmpHelper(N, SDValue(N, 0), DAG, DCI, ST);
54639
+ }
54640
+
54641
+ static SDValue combineX86SubToCcmp(SDNode *N, SelectionDAG &DAG,
54642
+ TargetLowering::DAGCombinerInfo &DCI,
54643
+ const X86Subtarget &ST) {
54644
+ // sub(and(setcc(cc0, flag0), setcc(cc1, sub (X, Y))), 1)
54645
+ // brcond ne
54646
+ //
54647
+ // ->
54648
+ //
54649
+ // ccmp(X, Y, cflags, cc0, flag0)
54650
+ // brcond cc1
54651
+ //
54652
+ // if only flag has users, where cflags is determined by cc1.
54653
+
54654
+ if (N->getOpcode() != X86ISD::SUB || !isOneConstant(N->getOperand(1)) ||
54655
+ N->hasAnyUseOfValue(0))
54656
+ return SDValue();
54657
+
54658
+ return combineX86SubCmpToCcmpHelper(N, SDValue(N, 1), DAG, DCI, ST);
54659
+ }
54660
+
54511
54661
static SDValue combineCMP(SDNode *N, SelectionDAG &DAG,
54662
+ TargetLowering::DAGCombinerInfo &DCI,
54512
54663
const X86Subtarget &Subtarget) {
54513
54664
// Only handle test patterns.
54514
54665
if (!isNullConstant(N->getOperand(1)))
@@ -54523,6 +54674,9 @@ static SDValue combineCMP(SDNode *N, SelectionDAG &DAG,
54523
54674
EVT VT = Op.getValueType();
54524
54675
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
54525
54676
54677
+ if (SDValue CCMP = combineX86CmpToCcmp(N, DAG, DCI, Subtarget))
54678
+ return CCMP;
54679
+
54526
54680
// If we have a constant logical shift that's only used in a comparison
54527
54681
// against zero turn it into an equivalent AND. This allows turning it into
54528
54682
// a TEST instruction later.
@@ -54651,7 +54805,8 @@ static SDValue combineCMP(SDNode *N, SelectionDAG &DAG,
54651
54805
}
54652
54806
54653
54807
static SDValue combineX86AddSub(SDNode *N, SelectionDAG &DAG,
54654
- TargetLowering::DAGCombinerInfo &DCI) {
54808
+ TargetLowering::DAGCombinerInfo &DCI,
54809
+ const X86Subtarget &ST) {
54655
54810
assert((X86ISD::ADD == N->getOpcode() || X86ISD::SUB == N->getOpcode()) &&
54656
54811
"Expected X86ISD::ADD or X86ISD::SUB");
54657
54812
@@ -54662,6 +54817,9 @@ static SDValue combineX86AddSub(SDNode *N, SelectionDAG &DAG,
54662
54817
bool IsSub = X86ISD::SUB == N->getOpcode();
54663
54818
unsigned GenericOpc = IsSub ? ISD::SUB : ISD::ADD;
54664
54819
54820
+ if (SDValue CCMP = combineX86SubToCcmp(N, DAG, DCI, ST))
54821
+ return CCMP;
54822
+
54665
54823
// If we don't use the flag result, simplify back to a generic ADD/SUB.
54666
54824
if (!N->hasAnyUseOfValue(1)) {
54667
54825
SDValue Res = DAG.getNode(GenericOpc, DL, VT, LHS, RHS);
@@ -56960,11 +57118,11 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
56960
57118
case X86ISD::BLENDV: return combineSelect(N, DAG, DCI, Subtarget);
56961
57119
case ISD::BITCAST: return combineBitcast(N, DAG, DCI, Subtarget);
56962
57120
case X86ISD::CMOV: return combineCMov(N, DAG, DCI, Subtarget);
56963
- case X86ISD::CMP: return combineCMP(N, DAG, Subtarget);
57121
+ case X86ISD::CMP: return combineCMP(N, DAG, DCI, Subtarget);
56964
57122
case ISD::ADD: return combineAdd(N, DAG, DCI, Subtarget);
56965
57123
case ISD::SUB: return combineSub(N, DAG, DCI, Subtarget);
56966
57124
case X86ISD::ADD:
56967
- case X86ISD::SUB: return combineX86AddSub(N, DAG, DCI);
57125
+ case X86ISD::SUB: return combineX86AddSub(N, DAG, DCI, Subtarget );
56968
57126
case X86ISD::SBB: return combineSBB(N, DAG);
56969
57127
case X86ISD::ADC: return combineADC(N, DAG, DCI);
56970
57128
case ISD::MUL: return combineMul(N, DAG, DCI, Subtarget);
0 commit comments