[llvm] [CodeGen] Speed up ReachingDefAnalysis (NFC) (PR #100913)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 13 12:43:43 PDT 2024


================
@@ -33,35 +32,156 @@ namespace llvm {
 class MachineBasicBlock;
 class MachineInstr;
 
-/// Thin wrapper around "int" used to store reaching definitions,
-/// using an encoding that makes it compatible with TinyPtrVector.
-/// The 0th LSB is forced zero (and will be used for pointer union tagging),
-/// The 1st LSB is forced one (to make sure the value is non-zero).
-class ReachingDef {
-  uintptr_t Encoded;
-  friend struct PointerLikeTypeTraits<ReachingDef>;
-  explicit ReachingDef(uintptr_t Encoded) : Encoded(Encoded) {}
-
+// An implementation of multimap from (MBBNumber, Unit) to reaching definitions.
+//
+// This implementation only supports modification operations just enough
+// to serve our needs:
+//
+// - addDef
+// - prependDef
+// - replaceFront
+//
+// Internally, the multimap is implemented as a collection of singly linked
+// lists represented on top of a single array.  Each singly-linked list
+// contains reaching definitions for a given pair of MBBNumber and Unit.
+//
+// This design has the following highlights:
+//
+// - Unlike SparseMultiset or other maps, we do not store keys as part of values
+//   or anywhere else in the data structure.
+//
+// - The single array design minimizes malloc traffic.
+//
+// - Reaching definitions share one array.  This means that if one pair of
+//   (MBBNumber, Unit) has multiple reaching definitions while another pair of
+//   (MBBNumber, Unit) has none, they cancel each other to some extent.
+class MBBReachingDefsInfo {
 public:
-  ReachingDef(std::nullptr_t) : Encoded(0) {}
-  ReachingDef(int Instr) : Encoded(((uintptr_t) Instr << 2) | 2) {}
-  operator int() const { return ((int) Encoded) >> 2; }
-};
+  MBBReachingDefsInfo() = default;
+  MBBReachingDefsInfo(const MBBReachingDefsInfo &) = delete;
+  MBBReachingDefsInfo &operator=(const MBBReachingDefsInfo &) = delete;
+
+  // Initialize the multimap with the number of basic blocks and the number of
+  // register units.
+  void init(unsigned BBs, unsigned Regs) {
+    assert(NumBlockIDs == 0 && "can initialize only once");
+    assert(NumRegUnits == 0 && "can initialize only once");
+    assert(Storage.empty() && "can initialize only once");
+    NumBlockIDs = BBs;
+    NumRegUnits = Regs;
+    unsigned NumIndexes = NumBlockIDs * NumRegUnits;
+    // Reserve space for reaching definitions.  Note that the first NumIndexes
+    // elements are used for indexes to various chains.  The second half
+    // accommodates up to one reaching def per (MBBNumber, Unit) pair on
+    // average.
+    Storage.reserve(NumIndexes * 2);
+    Storage.assign(NumIndexes, std::make_pair(0, 0));
+  }
 
-template<>
-struct PointerLikeTypeTraits<ReachingDef> {
-  static constexpr int NumLowBitsAvailable = 1;
+  // Clear the entire data structure.
+  void clear() {
+    NumBlockIDs = 0;
+    NumRegUnits = 0;
+    Storage.clear();
+  }
+
+  // Add a reaching definition Def to the end of the singly-linked list of
+  // definitions for (MBBNumber, Unit).
+  void addDef(unsigned MBBNumber, unsigned Unit, int Def) {
+    unsigned Key = computeKey(MBBNumber, Unit);
+    unsigned NewIndex = Storage.size();
+    Storage.emplace_back(Def, 0);
+    if (Storage[Key].first == 0) {
+      // Update the index of the first element.
+      Storage[Key].first = NewIndex;
+      // Update the index of the last element.
+      Storage[Key].second = NewIndex;
+    } else {
+      unsigned OldLastPos = Storage[Key].second;
+      // The old last element now points to the new element.
+      Storage[OldLastPos].second = NewIndex;
+      // Update the index of the last element.
+      Storage[Key].second = NewIndex;
+    }
+  }
+
+  // Add a reaching definition Def to the beginning of the singly-linked list of
+  // definitions for (MBBNumber, Unit).
+  void prependDef(unsigned MBBNumber, unsigned Unit, int Def) {
+    unsigned Key = computeKey(MBBNumber, Unit);
+    unsigned NewIndex = Storage.size();
+    Storage.emplace_back(Def, 0);
+    if (Storage[Key].first == 0) {
+      // Update the index of the first element.
+      Storage[Key].first = NewIndex;
+      // Update the index of the last element.
+      Storage[Key].second = NewIndex;
----------------
arsenm wrote:

Looking up twice? 

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


More information about the llvm-commits mailing list