[llvm] [X86][CodeGen] Support lowering for CCMP/CTEST (PR #91747)

via llvm-commits llvm-commits at lists.llvm.org
Mon May 20 08:45:55 PDT 2024


================
@@ -54605,7 +54610,132 @@ static bool onlyZeroFlagUsed(SDValue Flags) {
   return true;
 }
 
+static SDValue combineX86SubCmpToCcmpCtest(SDNode *N, SDValue Flag,
+                                           SelectionDAG &DAG,
+                                           TargetLowering::DAGCombinerInfo &DCI,
+                                           const X86Subtarget &ST) {
+  // cmp(and/or(setcc(cc0, flag0), setcc(cc1, sub (X, Y))), 0)
+  // brcond ne
+  //
+  //  ->
+  //
+  // ccmp(X, Y, cflags/~cflags, cc0/~cc0, flag0)
+  // brcond cc1
+  //
+  //
+  // sub(and/or(setcc(cc0, flag0), setcc(cc1, sub (X, Y))), 1)
+  // brcond ne
+  //
+  // ->
+  //
+  // ccmp(X, Y, cflags/~cflags, cc0/~cc0, flag0)
+  // brcond ~cc1
+
+  // cmp(and/or(setcc(cc0, flag0), setcc(cc1, cmp (X, 0))), 0)
+  // brcond ne
+  //
+  //  ->
+  //
+  // ctest(X, X, cflags/~cflags, cc0/~cc0, flag0)
+  // brcond cc1
+  //
+  //
+  // sub(and/or(setcc(cc0, flag0), setcc(cc1, cmp (X, 0))), 1)
+  // brcond ne
+  //
+  //  ->
+  //
+  // ctest(X, X, cflags/~cflags, cc0/~cc0, flag0)
+  // brcond ~cc1
+
+  // if only flag has users, where cflags is determined by cc1.
+
+  SDValue LHS = N->getOperand(0);
+
+  if (!ST.hasCCMP() ||
+      (LHS.getOpcode() != ISD::AND && LHS.getOpcode() != ISD::OR) ||
+      !Flag.hasOneUse())
+    return SDValue();
+
+  SDValue SetCC0 = LHS.getOperand(0);
+  SDValue SetCC1 = LHS.getOperand(1);
+  if (SetCC0.getOpcode() != X86ISD::SETCC ||
+      SetCC1.getOpcode() != X86ISD::SETCC)
+    return SDValue();
+
+  auto GetCombineToOpc = [&](SDValue V) {
+    SDValue Op = V.getOperand(1);
+    unsigned Opc = Op.getOpcode();
+    return (Opc == X86ISD::SUB) ? X86ISD::CCMP
+           : (Opc == X86ISD::CMP && isNullConstant(Op.getOperand(1)))
+               ? X86ISD::CTEST
+               : 0U;
+  };
+
+  unsigned NewOpc = 0;
+
+  // and/or is commutable. Try to commute the operands and then test again.
+  if (!(NewOpc = GetCombineToOpc(SetCC1))) {
+    std::swap(SetCC0, SetCC1);
+    if (!(NewOpc = GetCombineToOpc(SetCC1)))
+      return SDValue();
+  }
+
+  SDValue Sub = SetCC1.getOperand(1);
+  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();
+
+  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();
----------------
goldsteinn wrote:

What about SetCC1? Also think this should be above where you do the `X86ISD::SETCC` opcode checks.

https://github.com/llvm/llvm-project/pull/91747


More information about the llvm-commits mailing list