[llvm] [CodeGenPrepare][RISCV] Combine (X ^ Y) and (X == Y) where appropriate (PR #130922)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 13 12:50:14 PDT 2025


================
@@ -17194,12 +17194,58 @@ static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
     return true;
   }
 
+  // If XOR is reused and has an immediate that will fit in XORI,
+  // do not fold.
+  auto IsXorImmediate = [](const SDValue &Op) -> bool {
+    if (const auto XorCnst = dyn_cast<ConstantSDNode>(Op))
+      return isInt<12>(XorCnst->getSExtValue());
+    return false;
+  };
+  // Fold (X(i1) ^ 1) == 0 -> X != 0
+  auto SingleBitOp = [&DAG](const SDValue &VarOp,
+                            const SDValue &ConstOp) -> bool {
+    if (const auto XorCnst = dyn_cast<ConstantSDNode>(ConstOp)) {
+      const APInt Mask = APInt::getBitsSetFrom(VarOp.getValueSizeInBits(), 1);
+      return (XorCnst->getSExtValue() == 1) &&
+             DAG.MaskedValueIsZero(VarOp, Mask);
+    }
+    return false;
+  };
+  auto OnlyUsedBySelectOrBR = [](const SDValue &Op) -> bool {
+    for (const SDNode *UserNode : Op->users()) {
+      const unsigned Opcode = UserNode->getOpcode();
+      if (Opcode != RISCVISD::SELECT_CC && Opcode != RISCVISD::BR_CC)
+        return false;
+    }
+    return true;
+  };
+  auto IsFoldableXorEq = [IsXorImmediate, SingleBitOp, OnlyUsedBySelectOrBR](
+                             const SDValue &LHS, const SDValue &RHS) -> bool {
+    return LHS.getOpcode() == ISD::XOR && isNullConstant(RHS) &&
+           (!IsXorImmediate(LHS.getOperand(1)) ||
+            SingleBitOp(LHS.getOperand(0), LHS.getOperand(1)) ||
+            OnlyUsedBySelectOrBR(LHS));
+  };
   // Fold ((xor X, Y), 0, eq/ne) -> (X, Y, eq/ne)
-  if (LHS.getOpcode() == ISD::XOR && isNullConstant(RHS)) {
+  if (IsFoldableXorEq(LHS, RHS)) {
     RHS = LHS.getOperand(1);
     LHS = LHS.getOperand(0);
     return true;
   }
+  // Fold ((sext (xor X, C)), 0, eq/ne) -> ((sext(X), C, eq/ne)
+  if (LHS.getOpcode() == ISD::SIGN_EXTEND_INREG) {
+    const SDValue LHS0 = LHS.getOperand(0);
+    if (IsFoldableXorEq(LHS0, RHS) && isa<ConstantSDNode>(LHS0.getOperand(1))) {
+      // SEXT(XOR(X, Y)) -> XOR(SEXT(X), SEXT(Y)))
+      RHS = DAG.getNode(
+          ISD::SIGN_EXTEND_INREG, DL, LHS.getValueType(), LHS0.getOperand(1),
+          DAG.getValueType(cast<VTSDNode>(LHS.getOperand(1))->getVT()));
----------------
topperc wrote:

You can pass `LHS.getOperand(1)` directly for the last operand of the getNode. You don't need to extract the VT from it and re-create the VTSDNode.

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


More information about the llvm-commits mailing list