[llvm] [TableGen] Introduce MatcherList to manage a linked list of Matchers. NFC (PR #177875)

Sergei Barannikov via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 18 07:27:31 PST 2026


================
@@ -195,34 +180,238 @@ class Matcher {
   virtual bool isContradictoryImpl(const Matcher *M) const { return false; }
 };
 
+/// Manages a singly linked list of Matcher objects. Interface based on
+/// std::forward_list. Once a Matcher is added to a list, it cannot be removed.
+/// It can only be erased or spliced to another position in this list or another
+/// list.
+class MatcherList {
+  MatcherBase BeforeBegin;
+
+  // Emitted size of all of the nodes in this list.
+  unsigned Size = 0;
+
+public:
+  MatcherList() = default;
+  MatcherList(const MatcherList &RHS) = delete;
+  MatcherList(MatcherList &&RHS) {
+    splice_after(before_begin(), RHS);
+    Size = RHS.Size;
+    RHS.Size = 0;
+  }
+  ~MatcherList() { clear(); }
+
+  MatcherList &operator=(const MatcherList &) = delete;
+  MatcherList &operator=(MatcherList &&RHS) {
+    clear();
+    splice_after(before_begin(), RHS);
+    Size = RHS.Size;
+    RHS.Size = 0;
+    return *this;
+  }
+
+  void clear() {
+    for (MatcherBase *P = BeforeBegin.Next; P != nullptr;) {
+      MatcherBase *Next = P->Next;
+      delete static_cast<Matcher *>(P);
+      P = Next;
+    }
+    BeforeBegin.Next = nullptr;
+    Size = 0;
+  }
+
+  template <bool IsConst> class iterator_impl {
+    friend class MatcherList;
+    using Base = std::conditional_t<IsConst, const MatcherBase, MatcherBase>;
+
+    Base *Pointer;
+
+    explicit iterator_impl(Base *P) { Pointer = P; }
+
+  public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = std::conditional_t<IsConst, const Matcher *, Matcher *>;
+    using difference_type = std::ptrdiff_t;
+    using pointer = value_type *;
+    using reference = value_type &;
+
+    iterator_impl &operator++() {
+      Pointer = Pointer->Next;
+      return *this;
+    }
+
+    iterator_impl operator++(int) {
+      iterator Tmp(*this);
+      Pointer = Pointer->Next;
+      return Tmp;
+    }
+
+    value_type operator*() const { return static_cast<value_type>(Pointer); }
+
+    value_type operator->() const { return operator*(); }
+
+    bool operator==(const iterator_impl &X) const {
+      return Pointer == X.Pointer;
+    }
+    bool operator!=(const iterator_impl &X) const { return !operator==(X); }
+
+    // Allow conversion to a const iterator.
+    operator iterator_impl<true>() const {
+      return iterator_impl<true>(Pointer);
+    }
+  };
+
+  using iterator = iterator_impl<false>;
+  using const_iterator = iterator_impl<true>;
+
+  /// Return an iterator before the first Matcher in the list. This iterator
+  /// cannot be dereferenced. Incrementing returns the iterator to begin().
+  iterator before_begin() { return iterator(&BeforeBegin); }
+  const_iterator before_begin() const { return const_iterator(&BeforeBegin); }
+
+  iterator begin() { return iterator(BeforeBegin.Next); }
+  const_iterator begin() const { return const_iterator(BeforeBegin.Next); }
+
+  iterator end() { return iterator(nullptr); }
+  const_iterator end() const { return const_iterator(nullptr); }
+
+  Matcher *front() { return *begin(); }
+  const Matcher *front() const { return *begin(); }
+
+  bool empty() const { return BeforeBegin.Next == nullptr; }
+
+  void push_front(Matcher *M) { insert_after(before_begin(), M); }
+
+  /// Delete the first Matcher from the list.
+  void pop_front() {
+    assert(Size == 0 && "Should not modify list once size is set");
+    assert(!empty());
+    Matcher *N = *std::next(before_begin());
+    before_begin()->Next = N->Next;
+    delete N;
+  }
+
+  /// Insert the matcher \p N into this list after \p Pos.
+  iterator insert_after(iterator Pos, Matcher *N) {
+    assert(Size == 0 && "Should not modify list once size is set");
+    N->Next = Pos->Next;
+    Pos->Next = N;
+    return iterator(N);
+  }
+
+  /// Insert Matchers in the range [F, L) into this list.
+  template <class InIt> iterator insert_after(iterator Pos, InIt F, InIt L) {
+    MatcherBase *R = *Pos;
+    if (F != L) {
+      MatcherBase *First = *F;
+      MatcherBase *Last = First;
+
+      // Link the Matchers together.
+      for (++F; F != L; ++F, Last = Last->Next)
+        Last->Next = *F;
+
+      // Insert them into the list.
+      Last->Next = R->Next;
+      R->Next = First;
+      R = Last;
+    }
+
+    return iterator(R);
+  }
+
+  /// Insert multiple matchers into this list.
+  iterator insert_after(iterator Pos, std::initializer_list<Matcher *> IL) {
+    return insert_after(Pos, IL.begin(), IL.end());
+  }
+
+  /// Erase the Matcher after \p Pos.
+  iterator erase_after(iterator Pos) {
+    assert(Size == 0 && "Should not modify list once size is set");
+    Matcher *N = *std::next(Pos);
+    Pos->Next = N->Next;
+    delete N;
+    return iterator(Pos->Next);
+  }
+
+  iterator erase_after(iterator F, iterator L) {
+    Matcher *E = *L;
+    if (F != L) {
+      Matcher *N = *std::next(F);
+      if (N != E) {
+        F->Next = E;
+        do {
+          Matcher *Tmp = static_cast<Matcher *>(N->Next);
+          delete N;
+          N = Tmp;
+        } while (N != E);
+      }
+    }
+    return iterator(E);
+  }
+
+  /// Splice the contents of list \p X after \p Pos in this list.
+  void splice_after(iterator Pos, MatcherList &X) {
+    assert(Size == 0 && "Should not modify list once size is set");
+    if (!X.empty()) {
+      if (Pos->Next != nullptr) {
+        auto LM1 = X.before_begin();
+        while (LM1->Next != nullptr)
+          ++LM1;
+        LM1->Next = Pos->Next;
+      }
+      Pos->Next = X.before_begin()->Next;
+      X.before_begin()->Next = nullptr;
+    }
+  }
+
+  /// Splice the Matcher after \p I into this list after \p Pos.
+  void splice_after(iterator Pos, MatcherList &, iterator I) {
+    assert(Size == 0 && "Should not modify list once size is set");
+    auto LM1 = std::next(I);
+    if (Pos != I && Pos != LM1) {
+      I->Next = LM1->Next;
+      LM1->Next = Pos->Next;
+      Pos->Next = LM1.Pointer;
+    }
+  }
+
+  /// Splice the Matchers in the range (\p F, \p L) into this list after \p Pos.
+  void splice_after(iterator Pos, MatcherList &, iterator F, iterator L) {
+    assert(Size == 0 && "Should not modify list once size is set");
+    if (F != L && Pos != F) {
+      auto LM1 = F;
+      while (std::next(LM1) != L)
+        ++LM1;
+      if (F != LM1) {
+        LM1->Next = Pos->Next;
+        Pos->Next = F->Next;
+        F->Next = L.Pointer;
+      }
+    }
+  }
+
+  void setSize(unsigned Sz) { Size = Sz; }
+  unsigned getSize() const { return Size; }
+
+  void print(raw_ostream &OS, indent Indent = indent(0)) const;
+  void dump() const;
+};
+
 /// ScopeMatcher - This attempts to match each of its children to find the first
 /// one that successfully matches.  If one child fails, it tries the next child.
 /// If none of the children match then this check fails.  It never has a 'next'.
 class ScopeMatcher : public Matcher {
-  SmallVector<Matcher *, 4> Children;
+  SmallVector<MatcherList, 4> Children;
----------------
s-barannikov wrote:

I mean MatcherList is essentially the same as ScopeMatcher (which is a Matcher). The only difference between them (AFAICT) is that MatcherList requires *all* child matchers to match in order to succeed, while ScopeMatcher requires *any* of the child matchers to succeed.
That is, MatcherList could be implemented similarly to ScopeMatcher, by deriving from Matcher and providing all the same accessors. This might (or might not) simplify DAGISelMatcherOpt as well.

In turn, ScopeMatcher could have arbitrary children, not only MatcherList (to reduce memory usage if MatcherList contains only one element).


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


More information about the llvm-commits mailing list