<div dir="ltr">Clarifying, before anybody gets too excited: That's only a 2% reduction for the pbqp allocator. Other allocators, including the default, are unaffected. ;)<div><br></div><div>- Lang.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Oct 18, 2014 at 10:26 AM, Lang Hames <span dir="ltr"><<a href="mailto:lhames@gmail.com" target="_blank">lhames@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: lhames<br>
Date: Sat Oct 18 12:26:07 2014<br>
New Revision: 220143<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=220143&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=220143&view=rev</a><br>
Log:<br>
[PBQP] Replace the interference-constraints algorithm with a faster version<br>
loosely based on linear scan.<br>
<br>
On x86-64 this is good for a ~2% drop in compile time on the nightly test suite.<br>
<br>
Modified:<br>
    llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp<br>
<br>
Modified: llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp?rev=220143&r1=220142&r2=220143&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp?rev=220143&r1=220142&r2=220143&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp Sat Oct 18 12:26:07 2014<br>
@@ -52,6 +52,7 @@<br>
 #include "llvm/Target/TargetSubtargetInfo.h"<br>
 #include <limits><br>
 #include <memory><br>
+#include <queue><br>
 #include <set><br>
 #include <sstream><br>
 #include <vector><br>
@@ -163,30 +164,128 @@ public:<br>
<br>
 /// @brief Add interference edges between overlapping vregs.<br>
 class Interference : public PBQPRAConstraint {<br>
+private:<br>
+<br>
+  // Holds (Interval, CurrentSegmentID, and NodeId). The first two are required<br>
+  // for the fast interference graph construction algorithm. The last is there<br>
+  // to save us from looking up node ids via the VRegToNode map in the graph<br>
+  // metadata.<br>
+  typedef std::tuple<LiveInterval*, size_t, PBQP::GraphBase::NodeId><br>
+    IntervalInfo;<br>
+<br>
+  static SlotIndex getStartPoint(const IntervalInfo &I) {<br>
+    return std::get<0>(I)->segments[std::get<1>(I)].start;<br>
+  }<br>
+<br>
+  static SlotIndex getEndPoint(const IntervalInfo &I) {<br>
+    return std::get<0>(I)->segments[std::get<1>(I)].end;<br>
+  }<br>
+<br>
+  static PBQP::GraphBase::NodeId getNodeId(const IntervalInfo &I) {<br>
+    return std::get<2>(I);<br>
+  }<br>
+<br>
+  static bool lowestStartPoint(const IntervalInfo &I1,<br>
+                               const IntervalInfo &I2) {<br>
+    // Condition reversed because priority queue has the *highest* element at<br>
+    // the front, rather than the lowest.<br>
+    return getStartPoint(I1) > getStartPoint(I2);<br>
+  }<br>
+<br>
+  static bool lowestEndPoint(const IntervalInfo &I1,<br>
+                             const IntervalInfo &I2) {<br>
+    SlotIndex E1 = getEndPoint(I1);<br>
+    SlotIndex E2 = getEndPoint(I2);<br>
+<br>
+    if (E1 < E2)<br>
+      return true;<br>
+<br>
+    if (E1 > E2)<br>
+      return false;<br>
+<br>
+    // If two intervals end at the same point, we need a way to break the tie or<br>
+    // the set will assume they're actually equal and refuse to insert a<br>
+    // "duplicate". Just compare the vregs - fast and guaranteed unique.<br>
+    return std::get<0>(I1)->reg < std::get<0>(I2)->reg;<br>
+  }<br>
+<br>
+  static bool isAtLastSegment(const IntervalInfo &I) {<br>
+    return std::get<1>(I) == std::get<0>(I)->size() - 1;<br>
+  }<br>
+<br>
+  static IntervalInfo nextSegment(const IntervalInfo &I) {<br>
+    return std::make_tuple(std::get<0>(I), std::get<1>(I) + 1, std::get<2>(I));<br>
+  }<br>
+<br>
 public:<br>
<br>
   void apply(PBQPRAGraph &G) override {<br>
+    // The following is loosely based on the linear scan algorithm introduced in<br>
+    // "Linear Scan Register Allocation" by Poletto and Sarkar. This version<br>
+    // isn't linear, because the size of the active set isn't bound by the<br>
+    // number of registers, but rather the size of the largest clique in the<br>
+    // graph. Still, we expect this to be better than N^2.<br>
     LiveIntervals &LIS = G.getMetadata().LIS;<br>
     const TargetRegisterInfo &TRI =<br>
       *G.getMetadata().MF.getTarget().getSubtargetImpl()->getRegisterInfo();<br>
<br>
-    for (auto NItr = G.nodeIds().begin(), NEnd = G.nodeIds().end();<br>
-         NItr != NEnd; ++NItr) {<br>
-      auto NId = *NItr;<br>
-      unsigned NVReg = G.getNodeMetadata(NId).getVReg();<br>
-      LiveInterval &NLI = LIS.getInterval(NVReg);<br>
-<br>
-      for (auto MItr = std::next(NItr); MItr != NEnd; ++MItr) {<br>
-        auto MId = *MItr;<br>
-        unsigned MVReg = G.getNodeMetadata(MId).getVReg();<br>
-        LiveInterval &MLI = LIS.getInterval(MVReg);<br>
-<br>
-        if (NLI.overlaps(MLI)) {<br>
-          const auto &NOpts = G.getNodeMetadata(NId).getOptionRegs();<br>
-          const auto &MOpts = G.getNodeMetadata(MId).getOptionRegs();<br>
-          G.addEdge(NId, MId, createInterferenceMatrix(TRI, NOpts, MOpts));<br>
-        }<br>
+    typedef std::set<IntervalInfo, decltype(&lowestEndPoint)> IntervalSet;<br>
+    typedef std::priority_queue<IntervalInfo, std::vector<IntervalInfo>,<br>
+                                decltype(&lowestStartPoint)> IntervalQueue;<br>
+    IntervalSet Active(lowestEndPoint);<br>
+    IntervalQueue Inactive(lowestStartPoint);<br>
+<br>
+    // Start by building the inactive set.<br>
+    for (auto NId : G.nodeIds()) {<br>
+      unsigned VReg = G.getNodeMetadata(NId).getVReg();<br>
+      LiveInterval &LI = LIS.getInterval(VReg);<br>
+      assert(!LI.empty() && "PBQP graph contains node for empty interval");<br>
+      Inactive.push(std::make_tuple(&LI, 0, NId));<br>
+    }<br>
+<br>
+    while (!Inactive.empty()) {<br>
+      // Tentatively grab the "next" interval - this choice may be overriden<br>
+      // below.<br>
+      IntervalInfo Cur = Inactive.top();<br>
+<br>
+      // Retire any active intervals that end before Cur starts.<br>
+      IntervalSet::iterator RetireItr = Active.begin();<br>
+      while (RetireItr != Active.end() &&<br>
+             (getEndPoint(*RetireItr) <= getStartPoint(Cur))) {<br>
+        // If this interval has subsequent segments, add the next one to the<br>
+        // inactive list.<br>
+        if (!isAtLastSegment(*RetireItr))<br>
+          Inactive.push(nextSegment(*RetireItr));<br>
+<br>
+        ++RetireItr;<br>
       }<br>
+      Active.erase(Active.begin(), RetireItr);<br>
+<br>
+      // One of the newly retired segments may actually start before the<br>
+      // Cur segment, so re-grab the front of the inactive list.<br>
+      Cur = Inactive.top();<br>
+      Inactive.pop();<br>
+<br>
+      // At this point we know that Cur overlaps all active intervals. Add the<br>
+      // interference edges.<br>
+      PBQP::GraphBase::NodeId NId = getNodeId(Cur);<br>
+      for (const auto &A : Active) {<br>
+        PBQP::GraphBase::NodeId MId = getNodeId(A);<br>
+<br>
+        // Check that we haven't already added this edge<br>
+        // FIXME: findEdge is expensive in the worst case (O(max_clique(G))).<br>
+        //        It might be better to replace this with a local bit-matrix.<br>
+        if (G.findEdge(NId, MId) != PBQP::GraphBase::invalidEdgeId())<br>
+          continue;<br>
+<br>
+        // This is a new edge - add it to the graph.<br>
+        const auto &NOpts = G.getNodeMetadata(NId).getOptionRegs();<br>
+        const auto &MOpts = G.getNodeMetadata(MId).getOptionRegs();<br>
+        G.addEdge(NId, MId, createInterferenceMatrix(TRI, NOpts, MOpts));<br>
+      }<br>
+<br>
+      // Finally, add Cur to the Active set.<br>
+      Active.insert(Cur);<br>
     }<br>
   }<br>
<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>