[llvm] [PowerPC] Fix inefficient code for __builtin_ppc_test_data_class (PR #181420)
zhijian lin via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 18 10:54:09 PST 2026
================
@@ -17198,6 +17214,173 @@ static SDValue DAGCombineAddc(SDNode *N,
return SDValue();
}
+/// Optimize zero-extension of setcc when the compared value is known to be 0
+/// or 1.
+///
+/// Pattern: zext(setcc(Value, 0, seteq/setne)) where Value is 0 or 1
+/// -> zext(xor(Value, 1)) for seteq
+/// -> zext(Value) for setne
+///
+/// This optimization avoids the i32 -> i1 -> i32/i64 conversion sequence
+/// by keeping the value in its original i32 type throughout.
+///
+/// Example:
+/// Before: zext(setcc(test_data_class(...), 0, seteq))
+/// // test_data_class returns 0 or 1 in i32
+/// // setcc converts i32 -> i1
+/// // zext converts i1 -> i64
+/// After: zext(xor(test_data_class(...), 1))
+/// // Stays in i32, then extends to i64
+///
+/// This is beneficial because:
+/// 1. Eliminates the setcc instruction
+/// 2. Avoids i32 -> i1 truncation
+/// 3. Keeps computation in native integer width
+
+static SDValue combineZextSetccWithZero(SDNode *N, SelectionDAG &DAG) {
+ // Check if this is a zero_extend
+ if (N->getOpcode() != ISD::ZERO_EXTEND)
+ return SDValue();
+
+ SDValue Src = N->getOperand(0);
+
+ // Check if the source is a setcc
+ if (Src.getOpcode() != ISD::SETCC)
+ return SDValue();
+
+ SDValue LHS = Src.getOperand(0);
+ SDValue RHS = Src.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Src.getOperand(2))->get();
+
+ if(!isNullConstant(RHS) && !isNullConstant(LHS))
+ return SDValue();
+
+ SDValue NonNullConstant = isNullConstant(RHS) ? LHS : RHS ;
+
+ auto isZeroOrOne = [=](SDValue &V) {
+ if (V.getOpcode() == ISD::INTRINSIC_WO_CHAIN &&
+ V.getConstantOperandVal(0) == Intrinsic::ppc_test_data_class)
+ return true;
+ return false;
+ };
+
+ if (!isZeroOrOne(NonNullConstant))
+ return SDValue();
+
+ // Check for pattern: zext(setcc (Value), 0, seteq)) or
+ // zext(setcc (Value), 0, setne))
+ if (CC == ISD::SETEQ || CC == ISD::SETNE) {
+ // Replace with: zext(xor(Value, 1)) for seteq
+ // or: zext(Value) for setne
+ // This keeps the value in i32 instead of converting to i1
+ SDLoc DL(N);
+ EVT VType = N->getValueType(0);
+ SDValue NewNonNullConstant =
+ DAG.getZExtOrTrunc(NonNullConstant, DL, VType);
+
+ if (CC == ISD::SETNE)
+ return NewNonNullConstant;
+
+ SDValue One = DAG.getConstant(1, DL, VType);
+ return DAG.getNode(ISD::XOR, DL, VType, NewNonNullConstant, One);
+ }
+
+ return SDValue();
+}
+
+// Combine XOR patterns with SELECT_CC_I4/I8, for Example:
+// 1. XOR(SELECT_CC_I4(cond, 1, 0, cc), 1) -> SELECT_CC_I4(cond, 0, 1, cc)
+// 2. XOR(ZEXT(SELECT_CC_I4(cond, 1, 0, cc)), 1) -> SELECT_CC_I4/I8(cond, 0,
+// 1, cc))
+// 3. XOR(ANYEXT(SELECT_CC_I4(cond, 1, 0, cc)), 1) -> SELECT_CC_I4/I8(cond,
+// 0, 1, cc))
+// 4. etc
+static SDValue combineXorSelectCC(SDNode *N, SelectionDAG &DAG) {
+ assert(N->getOpcode() == ISD::XOR && "Expected XOR node");
+
+ EVT XorVT = N->getValueType(0);
+ if ((XorVT != MVT::i32 && XorVT != MVT::i64))
+ return SDValue();
+
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+
+ // Check for XOR with constant 1
+ ConstantSDNode *XorConst = dyn_cast<ConstantSDNode>(RHS);
+ if (!XorConst || !XorConst->isOne()) {
+ XorConst = dyn_cast<ConstantSDNode>(LHS);
+ if (!XorConst || !XorConst->isOne())
+ return SDValue();
+ // Swap so LHS is the SELECT_CC_I4 (or extension) and RHS is the constant
+ std::swap(LHS, RHS);
+ }
+
+ // Check if LHS has only one use
+ if (!LHS.hasOneUse())
+ return SDValue();
+
+ // Handle extensions: ZEXT, ANYEXT
+ SDValue SelectNode = LHS;
+
+ if (LHS.getOpcode() == ISD::ZERO_EXTEND ||
+ LHS.getOpcode() == ISD::ANY_EXTEND) {
+ SelectNode = LHS.getOperand(0);
+
+ // Check if the extension input has only one use
+ if (!SelectNode.hasOneUse())
+ return SDValue();
+ }
+
+ // Check if SelectNode is a MachineSDNode with SELECT_CC_I4/I8 opcode
+ if (!SelectNode.isMachineOpcode())
+ return SDValue();
+
+ unsigned MachineOpc = SelectNode.getMachineOpcode();
+
+ // Handle both SELECT_CC_I4 and SELECT_CC_I8
+ if (MachineOpc != PPC::SELECT_CC_I4 && MachineOpc != PPC::SELECT_CC_I8)
+ return SDValue();
+
+ // SELECT_CC_I4 operands: (cond, true_val, false_val, bropc)
+ if (SelectNode.getNumOperands() != 4)
+ return SDValue();
+
+ SDValue Cond = SelectNode.getOperand(0);
+ SDValue TrueVal = SelectNode.getOperand(1);
+ SDValue FalseVal = SelectNode.getOperand(2);
+ SDValue BrOpcode = SelectNode.getOperand(3);
+
+ // Check if true_val is constant 1 and false_val is constant 0
+ ConstantSDNode *TrueConst = dyn_cast<ConstantSDNode>(TrueVal);
+ ConstantSDNode *FalseConst = dyn_cast<ConstantSDNode>(FalseVal);
+
+ if (!TrueConst || !FalseConst)
+ return SDValue();
+
+ if (!((TrueConst->isOne() && FalseConst->isZero()) ||
+ (TrueConst->isZero() && FalseConst->isOne())))
+ return SDValue();
----------------
diggerlin wrote:
I changed the variable name.
https://github.com/llvm/llvm-project/pull/181420
More information about the llvm-commits
mailing list