[DAG] SDPatternMatch - Replace runtime data structures with lengths known at compile time (#172064)

Following the suggestions in #170061, I replaced `SmallVector<SDValue>`
with `std::array<SDValue, NumPatterns>` and `SmallBitVector` with
`Bitset<NumPatterns>`.

I had to make some changes to the `collectLeaves` and
`reassociatableMatchHelper` functions. In `collectLeaves` specifically,
I changed the return type so I could propagate a failure in case the
number of found leaves is greater than the number of expected patterns.
I also added a new unit test that, together with the one already present
in the previous line, checks if the matching fails in the cases where
the number of patterns is less or more than the number of leaves.

I don't think this is going to completely address the increased compile
time reported in #169644, but hopefully it leads to an improvement.
This commit is contained in:
Artur Bermond Torres
2025-12-14 07:48:08 -03:00
committed by GitHub
parent f785ca0d72
commit 755a693299
2 changed files with 22 additions and 15 deletions

View File

@@ -1302,20 +1302,20 @@ inline BinaryOpc_match<ValTy, AllOnes_match, true> m_Not(const ValTy &V) {
template <typename... PatternTs> struct ReassociatableOpc_match {
unsigned Opcode;
std::tuple<PatternTs...> Patterns;
constexpr static size_t NumPatterns =
std::tuple_size_v<std::tuple<PatternTs...>>;
ReassociatableOpc_match(unsigned Opcode, const PatternTs &...Patterns)
: Opcode(Opcode), Patterns(Patterns...) {}
template <typename MatchContext>
bool match(const MatchContext &Ctx, SDValue N) {
constexpr size_t NumPatterns = std::tuple_size_v<std::tuple<PatternTs...>>;
SmallVector<SDValue> Leaves;
collectLeaves(N, Leaves);
if (Leaves.size() != NumPatterns)
std::array<SDValue, NumPatterns> Leaves;
size_t LeavesIdx = 0;
if (!(collectLeaves(N, Leaves, LeavesIdx) && (LeavesIdx == NumPatterns)))
return false;
SmallBitVector Used(NumPatterns);
Bitset<NumPatterns> Used;
return std::apply(
[&](auto &...P) -> bool {
return reassociatableMatchHelper(Ctx, Leaves, Used, P...);
@@ -1323,36 +1323,41 @@ template <typename... PatternTs> struct ReassociatableOpc_match {
Patterns);
}
void collectLeaves(SDValue V, SmallVector<SDValue> &Leaves) {
bool collectLeaves(SDValue V, std::array<SDValue, NumPatterns> &Leaves,
std::size_t &LeafIdx) {
if (V->getOpcode() == Opcode) {
for (size_t I = 0, N = V->getNumOperands(); I < N; I++)
collectLeaves(V->getOperand(I), Leaves);
if ((LeafIdx == NumPatterns) ||
!collectLeaves(V->getOperand(I), Leaves, LeafIdx))
return false;
} else {
Leaves.emplace_back(V);
Leaves[LeafIdx] = V;
LeafIdx++;
}
return true;
}
// Searchs for a matching leaf for every sub-pattern.
template <typename MatchContext, typename PatternHd, typename... PatternTl>
[[nodiscard]] inline bool
reassociatableMatchHelper(const MatchContext &Ctx, ArrayRef<SDValue> Leaves,
SmallBitVector &Used, PatternHd &HeadPattern,
Bitset<NumPatterns> &Used, PatternHd &HeadPattern,
PatternTl &...TailPatterns) {
for (size_t Match = 0, N = Used.size(); Match < N; Match++) {
if (Used[Match] || !(sd_context_match(Leaves[Match], Ctx, HeadPattern)))
continue;
Used[Match] = true;
Used.set(Match);
if (reassociatableMatchHelper(Ctx, Leaves, Used, TailPatterns...))
return true;
Used[Match] = false;
Used.reset(Match);
}
return false;
}
template <typename MatchContext>
[[nodiscard]] inline bool reassociatableMatchHelper(const MatchContext &Ctx,
ArrayRef<SDValue> Leaves,
SmallBitVector &Used) {
[[nodiscard]] inline bool
reassociatableMatchHelper(const MatchContext &Ctx, ArrayRef<SDValue> Leaves,
Bitset<NumPatterns> &Used) {
return true;
}
};

View File

@@ -803,6 +803,8 @@ TEST_F(SelectionDAGPatternMatchTest, matchReassociatableOp) {
SDValue ADD = DAG->getNode(ISD::ADD, DL, Int32VT, ADD01, ADD23);
EXPECT_FALSE(sd_match(ADD01, m_ReassociatableAdd(m_Value())));
EXPECT_FALSE(
sd_match(ADD01, m_ReassociatableAdd(m_Value(), m_Value(), m_Value())));
EXPECT_TRUE(sd_match(ADD01, m_ReassociatableAdd(m_Value(), m_Value())));
EXPECT_TRUE(sd_match(ADD23, m_ReassociatableAdd(m_Value(), m_Value())));
EXPECT_TRUE(sd_match(