[llvm] [X86][CodeGen] Support lowering for CCMP/CTEST (PR #91747)
Shengchen Kan via llvm-commits
llvm-commits at lists.llvm.org
Sun May 26 00:22:32 PDT 2024
================
@@ -49217,6 +49228,148 @@ static SDValue combineBMILogicOp(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
+static SDValue combineX86SubCmpForFlags(SDNode *N, SDValue Flag,
+ SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &ST) {
+ // cmp(setcc(cc, X), 0)
+ // brcond ne
+ // ->
+ // X
+ // brcond cc
+
+ // sub(setcc(cc, X), 1)
+ // brcond ne
+ // ->
+ // X
+ // brcond ~cc
+ //
+ // if only flag has users
+
+ SDValue SetCC = N->getOperand(0);
+
+ // TODO: Remove the check hasCCMP() and update the non-APX tests.
+ if (!ST.hasCCMP() || SetCC.getOpcode() != X86ISD::SETCC || !Flag.hasOneUse())
+ return SDValue();
+
+ // Check the only user of flag is `brcond ne`.
+ SDNode *BrCond = *Flag->uses().begin();
+ if (BrCond->getOpcode() != X86ISD::BRCOND)
+ return SDValue();
+ unsigned CondNo = 2;
+ if (static_cast<X86::CondCode>(BrCond->getConstantOperandVal(CondNo)) !=
+ X86::COND_NE)
+ return SDValue();
+
+ SDValue X = SetCC.getOperand(1);
+ // Replace API is called manually here b/c the number of results may change.
+ DAG.ReplaceAllUsesOfValueWith(Flag, X);
+
+ SDValue CCN = SetCC.getOperand(0);
+ X86::CondCode CC =
+ static_cast<X86::CondCode>(CCN->getAsAPIntVal().getSExtValue());
+ X86::CondCode OppositeCC = X86::GetOppositeBranchCondition(CC);
+ // Update CC for the consumer of the flag.
+ // The old CC is `ne`. Hence, when comparing the result with 0, we are
+ // checking if the second condition evaluates to true. When comparing the
+ // result with 1, we are checking uf the second condition evaluates to false.
+ SmallVector<SDValue> Ops(BrCond->op_values());
+ if (isNullConstant(N->getOperand(1)))
+ Ops[CondNo] = CCN;
+ else if (isOneConstant(N->getOperand(1)))
+ Ops[CondNo] = DAG.getTargetConstant(OppositeCC, SDLoc(BrCond), MVT::i8);
+
+ SDValue NewBrCond =
+ DAG.getNode(X86ISD::BRCOND, SDLoc(BrCond), BrCond->getValueType(0), Ops);
+ // Avoid self-assign error b/c CC1 can be `e/ne`.
+ // Replace API is called manually here b/c we're updating the user of the node
+ // being visited instead of the node itself.
+ if (BrCond != NewBrCond.getNode()) {
+ DAG.ReplaceAllUsesWith(BrCond, &NewBrCond);
+ DCI.recursivelyDeleteUnusedNodes(BrCond);
+ }
+ return X;
+}
+
+static SDValue combineAndOrForCcmpCtest(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &ST) {
+ // and/or(setcc(cc0, flag0), setcc(cc1, sub (X, Y)))
+ // ->
+ // setcc(cc1, ccmp(X, Y, ~cflags/cflags, cc0/~cc0, flag0))
+
+ // and/or(setcc(cc0, flag0), setcc(cc1, cmp (X, 0)))
+ // ->
+ // setcc(cc1, ctest(X, X, ~cflags/cflags, cc0/~cc0, flag0))
+ //
+ // where cflags is determined by cc1.
+
+ if (!ST.hasCCMP())
+ return SDValue();
+
+ SDValue SetCC0 = N->getOperand(0);
+ SDValue SetCC1 = N->getOperand(1);
+ if (SetCC0.getOpcode() != X86ISD::SETCC ||
+ SetCC1.getOpcode() != X86ISD::SETCC)
+ return SDValue();
+
+ auto GetCombineToOpc = [&](SDValue V) -> unsigned {
+ SDValue Op = V.getOperand(1);
+ unsigned Opc = Op.getOpcode();
+ if (Opc == X86ISD::SUB)
+ return X86ISD::CCMP;
+ if (Opc == X86ISD::CMP && isNullConstant(Op.getOperand(1)))
+ return X86ISD::CTEST;
+ return 0U;
+ };
+
+ unsigned NewOpc = 0;
+
+ // AND/OR is commutable. Canonicalize the operands to make SETCC with SUB/CMP
+ // appear on the right.
+ if (!(NewOpc = GetCombineToOpc(SetCC1))) {
+ std::swap(SetCC0, SetCC1);
+ if (!(NewOpc = GetCombineToOpc(SetCC1)))
+ return SDValue();
+ }
+
+ X86::CondCode CC0 =
+ static_cast<X86::CondCode>(SetCC0.getConstantOperandVal(0));
+ // CCMP/CTEST is not conditional when the source condition is COND_P/COND_NP.
+ if (CC0 == X86::COND_P || CC0 == X86::COND_NP)
+ return SDValue();
+
+ bool IsOR = N->getOpcode() == ISD::OR;
+
+ // CMP/TEST is executed and updates the EFLAGS normally only when SCC
+ // evaluates to true. So we need to inverse CC0 as SCC when the logic operator
+ // is OR. Similar for CC1.
+ SDValue SCC =
----------------
KanRobert wrote:
Done.
https://github.com/llvm/llvm-project/pull/91747
More information about the llvm-commits
mailing list