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