From 6832709dc0ccf73a97ca5e2029d9a289f2d6437c Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Fri, 3 Apr 2026 19:03:00 +0100 Subject: [PATCH] [DAG] SDPatternMatch - rename m_Opc -> m_SpecificOpc (#190215) Match naming convention for other m_Specific* matchers, and frees up the m_Opc() matcher for future use in #84940 to allow us to capture the opcode of a unknown binop Moving to m_SpecificOpc does mess up the formatting in a few places, I've tried to refactor to use the m_Value(SDValue, ....) matcher where I can to retrieve some whitespace --- llvm/include/llvm/CodeGen/SDPatternMatch.h | 25 +++++----- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 16 ++++--- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 2 +- llvm/lib/Target/X86/X86ISelLowering.cpp | 11 +++-- .../CodeGen/SelectionDAGPatternMatchTest.cpp | 47 +++++++++++-------- 5 files changed, 57 insertions(+), 44 deletions(-) diff --git a/llvm/include/llvm/CodeGen/SDPatternMatch.h b/llvm/include/llvm/CodeGen/SDPatternMatch.h index 62762d0c50d6..6c356d6ca37a 100644 --- a/llvm/include/llvm/CodeGen/SDPatternMatch.h +++ b/llvm/include/llvm/CodeGen/SDPatternMatch.h @@ -28,8 +28,8 @@ namespace llvm { namespace SDPatternMatch { /// MatchContext can repurpose existing patterns to behave differently under -/// a certain context. For instance, `m_Opc(ISD::ADD)` matches plain ADD nodes -/// in normal circumstances, but matches VP_ADD nodes under a custom +/// a certain context. For instance, `m_SpecificOpc(ISD::ADD)` matches plain ADD +/// nodes in normal circumstances, but matches VP_ADD nodes under a custom /// VPMatchContext. This design is meant to facilitate code / pattern reusing. class BasicMatchContext { const SelectionDAG *DAG; @@ -223,7 +223,9 @@ template auto m_NoneOf(const Preds &...preds) { return m_Unless(m_AnyOf(preds...)); } -inline Opcode_match m_Opc(unsigned Opcode) { return Opcode_match(Opcode); } +inline Opcode_match m_SpecificOpc(unsigned Opcode) { + return Opcode_match(Opcode); +} inline auto m_Undef() { return m_AnyOf(Opcode_match(ISD::UNDEF), Opcode_match(ISD::POISON)); @@ -496,7 +498,8 @@ struct Operands_match template auto m_Node(unsigned Opcode, const OpndPreds &...preds) { - return m_AllOf(m_Opc(Opcode), Operands_match<0, OpndPreds...>(preds...)); + return m_AllOf(m_SpecificOpc(Opcode), + Operands_match<0, OpndPreds...>(preds...)); } /// Provide number of operands that are not chain or glue, as well as the first @@ -546,7 +549,7 @@ struct TernaryOpc_match { template bool match(const MatchContext &Ctx, SDValue N) { - if (sd_context_match(N, Ctx, m_Opc(Opcode))) { + if (sd_context_match(N, Ctx, m_SpecificOpc(Opcode))) { EffectiveOperands EO(N, Ctx); assert(EO.Size == 3); return ((Op0.match(Ctx, N->getOperand(EO.FirstIndex)) && @@ -648,7 +651,7 @@ struct BinaryOpc_match { template bool match(const MatchContext &Ctx, SDValue N) { - if (sd_context_match(N, Ctx, m_Opc(Opcode))) { + if (sd_context_match(N, Ctx, m_SpecificOpc(Opcode))) { EffectiveOperands EO(N, Ctx); assert(EO.Size == 2); if (!((LHS.match(Ctx, N->getOperand(EO.FirstIndex)) && @@ -723,15 +726,15 @@ struct MaxMin_match { (Commutable && LHS.match(Ctx, R) && RHS.match(Ctx, L)); }; - if (sd_context_match(N, Ctx, m_Opc(ISD::SELECT)) || - sd_context_match(N, Ctx, m_Opc(ISD::VSELECT))) { + if (sd_context_match(N, Ctx, m_SpecificOpc(ISD::SELECT)) || + sd_context_match(N, Ctx, m_SpecificOpc(ISD::VSELECT))) { EffectiveOperands EO_SELECT(N, Ctx); assert(EO_SELECT.Size == 3); SDValue Cond = N->getOperand(EO_SELECT.FirstIndex); SDValue TrueValue = N->getOperand(EO_SELECT.FirstIndex + 1); SDValue FalseValue = N->getOperand(EO_SELECT.FirstIndex + 2); - if (sd_context_match(Cond, Ctx, m_Opc(ISD::SETCC))) { + if (sd_context_match(Cond, Ctx, m_SpecificOpc(ISD::SETCC))) { EffectiveOperands EO_SETCC(Cond, Ctx); assert(EO_SETCC.Size == 3); SDValue L = Cond->getOperand(EO_SETCC.FirstIndex); @@ -742,7 +745,7 @@ struct MaxMin_match { } } - if (sd_context_match(N, Ctx, m_Opc(ISD::SELECT_CC))) { + if (sd_context_match(N, Ctx, m_SpecificOpc(ISD::SELECT_CC))) { EffectiveOperands EO_SELECT(N, Ctx); assert(EO_SELECT.Size == 5); SDValue L = N->getOperand(EO_SELECT.FirstIndex); @@ -1025,7 +1028,7 @@ template struct UnaryOpc_match { template bool match(const MatchContext &Ctx, SDValue N) { - if (sd_context_match(N, Ctx, m_Opc(Opcode))) { + if (sd_context_match(N, Ctx, m_SpecificOpc(Opcode))) { EffectiveOperands EO(N, Ctx); assert(EO.Size == 1); if (!Opnd.match(Ctx, N->getOperand(EO.FirstIndex))) diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 70d48895a47b..383e45c5ea3a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4935,7 +4935,7 @@ template SDValue DAGCombiner::visitMUL(SDNode *N) { } // fold (mul (add x, c1), c2) -> (add (mul x, c2), c1*c2) - if (sd_context_match(N0, Matcher, m_Opc(ISD::ADD)) && + if (sd_context_match(N0, Matcher, m_SpecificOpc(ISD::ADD)) && isConstantOrConstantVector(N1) && isConstantOrConstantVector(N0.getOperand(1)) && isMulAddWithConstProfitable(N, N0, N1)) @@ -11561,15 +11561,17 @@ SDValue DAGCombiner::visitSRL(SDNode *N) { // fold (srl (logic_op x, (shl (zext y), c1)), c1) // -> (logic_op (srl x, c1), (zext y)) // c1 <= leadingzeros(zext(y)) + // TODO: Replace c1 with valuetracking? SDValue X, ZExtY; - if (N1C && sd_match(N0, m_OneUse(m_BitwiseLogic( - m_Value(X), - m_OneUse(m_Shl(m_AllOf(m_Value(ZExtY), - m_Opc(ISD::ZERO_EXTEND)), - m_Specific(N1))))))) { + if (sd_match( + N0, + m_OneUse(m_BitwiseLogic( + m_Value(X), + m_OneUse(m_Shl(m_Value(ZExtY, m_SpecificOpc(ISD::ZERO_EXTEND)), + m_Specific(N1))))))) { unsigned NumLeadingZeros = ZExtY.getScalarValueSizeInBits() - ZExtY.getOperand(0).getScalarValueSizeInBits(); - if (N1C->getZExtValue() <= NumLeadingZeros) + if (N1C && N1C->getZExtValue() <= NumLeadingZeros) return DAG.getNode(N0.getOpcode(), SDLoc(N0), VT, DAG.getNode(ISD::SRL, SDLoc(N0), VT, X, N1), ZExtY); } diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 0650bbdedc08..d00b734f6450 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -17077,7 +17077,7 @@ static SDValue combineNarrowableShiftedLoad(SDNode *N, SelectionDAG &DAG) { APInt MaskVal, ShiftVal; // (and (shl (load ...), ShiftAmt), Mask) if (!sd_match( - N, m_And(m_OneUse(m_Shl(m_AllOf(m_Opc(ISD::LOAD), m_Value(LoadNode)), + N, m_And(m_OneUse(m_Shl(m_Value(LoadNode, m_SpecificOpc(ISD::LOAD)), m_ConstInt(ShiftVal))), m_ConstInt(MaskVal)))) { return SDValue(); diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index ffd9468a491e..67d25e4eabba 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -58877,11 +58877,12 @@ static SDValue matchPMADDWD(SelectionDAG &DAG, SDNode *N, return SDValue(); SDValue Op0, Op1, Accum; - if (!sd_match(N, m_Add(m_AllOf(m_Opc(ISD::BUILD_VECTOR), m_Value(Op0)), - m_AllOf(m_Opc(ISD::BUILD_VECTOR), m_Value(Op1)))) && - !sd_match(N, m_Add(m_AllOf(m_Opc(ISD::BUILD_VECTOR), m_Value(Op0)), - m_Add(m_Value(Accum), m_AllOf(m_Opc(ISD::BUILD_VECTOR), - m_Value(Op1)))))) + if (!sd_match(N, m_Add(m_Value(Op0, m_SpecificOpc(ISD::BUILD_VECTOR)), + m_Value(Op1, m_SpecificOpc(ISD::BUILD_VECTOR)))) && + !sd_match(N, + m_Add(m_Value(Op0, m_SpecificOpc(ISD::BUILD_VECTOR)), + m_Add(m_Value(Accum), + m_Value(Op1, m_SpecificOpc(ISD::BUILD_VECTOR)))))) return SDValue(); // Check if one of Op0,Op1 is of the form: diff --git a/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp b/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp index e3f4ce20f423..810363c8f638 100644 --- a/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp +++ b/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp @@ -320,8 +320,8 @@ TEST_F(SelectionDAGPatternMatchTest, matchBinaryOp) { EXPECT_TRUE(sd_match(Add, m_c_BinOp(ISD::ADD, m_Value(), m_Value()))); EXPECT_TRUE(sd_match(Add, m_Add(m_Value(), m_Value()))); EXPECT_TRUE(sd_match(Add, m_AddLike(m_Value(), m_Value()))); - EXPECT_TRUE(sd_match( - Mul, m_Mul(m_OneUse(m_Opc(ISD::SUB)), m_NUses<2>(m_Specific(Add))))); + EXPECT_TRUE(sd_match(Mul, m_Mul(m_OneUse(m_SpecificOpc(ISD::SUB)), + m_NUses<2>(m_Specific(Add))))); EXPECT_TRUE( sd_match(SFAdd, m_ChainedBinOp(ISD::STRICT_FADD, m_SpecificVT(Float32VT), m_SpecificVT(Float32VT)))); @@ -467,21 +467,25 @@ TEST_F(SelectionDAGPatternMatchTest, matchBinaryOp) { SDValue BindVal; // By default, it matches any of the results. - EXPECT_TRUE( - sd_match(PartsDiff, m_Sub(m_Opc(ISD::SMUL_LOHI), m_Opc(ISD::SMUL_LOHI)))); + EXPECT_TRUE(sd_match(PartsDiff, m_Sub(m_SpecificOpc(ISD::SMUL_LOHI), + m_SpecificOpc(ISD::SMUL_LOHI)))); // Matching a specific result. - EXPECT_TRUE(sd_match(PartsDiff, m_Sub(m_Opc(ISD::SMUL_LOHI), - m_Result<1>(m_Opc(ISD::SMUL_LOHI))))); - EXPECT_FALSE(sd_match(PartsDiff, m_Sub(m_Opc(ISD::SMUL_LOHI), - m_Result<0>(m_Opc(ISD::SMUL_LOHI))))); + EXPECT_TRUE( + sd_match(PartsDiff, m_Sub(m_SpecificOpc(ISD::SMUL_LOHI), + m_Result<1>(m_SpecificOpc(ISD::SMUL_LOHI))))); + EXPECT_FALSE( + sd_match(PartsDiff, m_Sub(m_SpecificOpc(ISD::SMUL_LOHI), + m_Result<0>(m_SpecificOpc(ISD::SMUL_LOHI))))); // Conditionally bind the value from a certain sub-pattern. - EXPECT_TRUE(sd_match(PartsDiff, m_Sub(m_Value(BindVal, m_Opc(ISD::SMUL_LOHI)), - m_Opc(ISD::SMUL_LOHI)))); + EXPECT_TRUE( + sd_match(PartsDiff, m_Sub(m_Value(BindVal, m_SpecificOpc(ISD::SMUL_LOHI)), + m_SpecificOpc(ISD::SMUL_LOHI)))); EXPECT_EQ(BindVal, SMulLoHi); BindVal = SDValue(); - EXPECT_FALSE(sd_match(PartsDiff, m_Sub(m_Value(BindVal, m_Opc(ISD::ADD)), - m_Opc(ISD::SMUL_LOHI)))); + EXPECT_FALSE( + sd_match(PartsDiff, m_Sub(m_Value(BindVal, m_SpecificOpc(ISD::ADD)), + m_SpecificOpc(ISD::SMUL_LOHI)))); EXPECT_NE(BindVal, SMulLoHi); BindVal = SDValue(); @@ -894,10 +898,12 @@ TEST_F(SelectionDAGPatternMatchTest, patternCombinators) { SDValue Sub = DAG->getNode(ISD::SUB, DL, Int32VT, Add, Op0); using namespace SDPatternMatch; + EXPECT_TRUE( + sd_match(Sub, m_AnyOf(m_SpecificOpc(ISD::ADD), m_SpecificOpc(ISD::SUB), + m_SpecificOpc(ISD::MUL)))); + EXPECT_TRUE(sd_match(Add, m_AllOf(m_SpecificOpc(ISD::ADD), m_OneUse()))); EXPECT_TRUE(sd_match( - Sub, m_AnyOf(m_Opc(ISD::ADD), m_Opc(ISD::SUB), m_Opc(ISD::MUL)))); - EXPECT_TRUE(sd_match(Add, m_AllOf(m_Opc(ISD::ADD), m_OneUse()))); - EXPECT_TRUE(sd_match(Add, m_NoneOf(m_Opc(ISD::SUB), m_Opc(ISD::MUL)))); + Add, m_NoneOf(m_SpecificOpc(ISD::SUB), m_SpecificOpc(ISD::MUL)))); } TEST_F(SelectionDAGPatternMatchTest, optionalResizing) { @@ -1073,7 +1079,7 @@ TEST_F(SelectionDAGPatternMatchTest, matchContext) { using namespace SDPatternMatch; VPMatchContext VPCtx(DAG.get()); - EXPECT_TRUE(sd_context_match(VPAdd, VPCtx, m_Opc(ISD::ADD))); + EXPECT_TRUE(sd_context_match(VPAdd, VPCtx, m_SpecificOpc(ISD::ADD))); EXPECT_TRUE( sd_context_match(VPAdd, VPCtx, m_Node(ISD::ADD, m_Value(), m_Value()))); // VPMatchContext can't match pattern using explicit VP Opcode @@ -1086,11 +1092,12 @@ TEST_F(SelectionDAGPatternMatchTest, matchContext) { EXPECT_TRUE(sd_context_match(VPAdd, VPCtx, m_Add(m_Value(), m_Value()))); // VP_REDUCE_ADD doesn't have a based opcode, so we use a normal // sd_match before switching to VPMatchContext when checking VPAdd. - EXPECT_TRUE(sd_match(VPReduceAdd, m_Node(ISD::VP_REDUCE_ADD, m_Value(), - m_Context(VPCtx, m_Opc(ISD::ADD)), - m_Value(), m_Value()))); + EXPECT_TRUE( + sd_match(VPReduceAdd, m_Node(ISD::VP_REDUCE_ADD, m_Value(), + m_Context(VPCtx, m_SpecificOpc(ISD::ADD)), + m_Value(), m_Value()))); // non-vector predicated should match too - EXPECT_TRUE(sd_context_match(Add, VPCtx, m_Opc(ISD::ADD))); + EXPECT_TRUE(sd_context_match(Add, VPCtx, m_SpecificOpc(ISD::ADD))); EXPECT_TRUE( sd_context_match(Add, VPCtx, m_Node(ISD::ADD, m_Value(), m_Value()))); EXPECT_FALSE(sd_context_match(