Bug 1337367 - Postpone spilling bundles till after regalloc main loop r=bhackett
authorSander Mathijs van Veen <sander@leaningtech.com>
Tue, 07 Feb 2017 07:18:00 +0100
changeset 341165 b7adf3986079e0eb6d6273263766630327265019
parent 341164 626ab78642929ec4c322ee45133ec2bbd93492bb
child 341166 61b6e09d2f2a50edbc39438fec63d027029c6257
push id86643
push usercbook@mozilla.com
push dateTue, 07 Feb 2017 15:55:43 +0000
treeherdermozilla-inbound@61b6e09d2f2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs1337367
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1337367 - Postpone spilling bundles till after regalloc main loop r=bhackett MozReview-Commit-ID: EeYZ0JWoXLh
js/src/jit/BacktrackingAllocator.cpp
js/src/jit/BacktrackingAllocator.h
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -832,18 +832,22 @@ BacktrackingAllocator::go()
     while (!allocationQueue.empty()) {
         if (mir->shouldCancel("Backtracking Allocation"))
             return false;
 
         QueueItem item = allocationQueue.removeHighest();
         if (!processBundle(mir, item.bundle))
             return false;
     }
+
     JitSpew(JitSpew_RegAlloc, "Main allocation loop complete");
 
+    if (!tryAllocatingRegistersForSpillBundles())
+        return false;
+
     if (!pickStackSlots())
         return false;
 
     if (JitSpewEnabled(JitSpew_RegAlloc))
         dumpAllocations();
 
     if (!resolveControlFlow())
         return false;
@@ -1205,17 +1209,18 @@ BacktrackingAllocator::tryAllocateNonFix
         if (!tryAllocateRegister(registers[reg.code()], bundle, success, pfixed, conflicting))
             return false;
         if (*success)
             return true;
     }
 
     // Spill bundles which have no hint or register requirement.
     if (requirement.kind() == Requirement::NONE && hint.kind() != Requirement::REGISTER) {
-        if (!spill(bundle))
+        JitSpew(JitSpew_RegAlloc, "  postponed spill (no hint or register requirement)");
+        if (!spilledBundles.append(bundle))
             return false;
         *success = true;
         return true;
     }
 
     if (conflicting.empty() || minimalBundle(bundle)) {
         // Search for any available register which the bundle can be
         // allocated to.
@@ -1225,17 +1230,18 @@ BacktrackingAllocator::tryAllocateNonFix
             if (*success)
                 return true;
         }
     }
 
     // Spill bundles which have no register requirement if they didn't get
     // allocated.
     if (requirement.kind() == Requirement::NONE) {
-        if (!spill(bundle))
+        JitSpew(JitSpew_RegAlloc, "  postponed spill (no register requirement)");
+        if (!spilledBundles.append(bundle))
             return false;
         *success = true;
         return true;
     }
 
     // We failed to allocate this bundle.
     MOZ_ASSERT(!*success);
     return true;
@@ -1584,16 +1590,48 @@ BacktrackingAllocator::spill(LiveBundle*
         }
         return true;
     }
 
     return bundle->spillSet()->addSpilledBundle(bundle);
 }
 
 bool
+BacktrackingAllocator::tryAllocatingRegistersForSpillBundles()
+{
+    for (auto it = spilledBundles.begin(); it != spilledBundles.end(); it++) {
+        LiveBundle* bundle = *it;
+        LiveBundleVector conflicting;
+        bool fixed = false;
+        bool success = false;
+
+        if (mir->shouldCancel("Backtracking Try Allocating Spilled Bundles"))
+            return false;
+
+        if (JitSpewEnabled(JitSpew_RegAlloc))
+            JitSpew(JitSpew_RegAlloc, "Spill or allocate %s", bundle->toString().get());
+
+        // Search for any available register which the bundle can be
+        // allocated to.
+        for (size_t i = 0; i < AnyRegister::Total; i++) {
+            if (!tryAllocateRegister(registers[i], bundle, &success, &fixed, conflicting))
+                return false;
+            if (success)
+                break;
+        }
+
+        // If the bundle still has no register, spill the bundle.
+        if (!success && !spill(bundle))
+            return false;
+    }
+
+    return true;
+}
+
+bool
 BacktrackingAllocator::pickStackSlots()
 {
     for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
         VirtualRegister& reg = vregs[i];
 
         if (mir->shouldCancel("Backtracking Pick Stack Slots"))
             return false;
 
--- a/js/src/jit/BacktrackingAllocator.h
+++ b/js/src/jit/BacktrackingAllocator.h
@@ -667,16 +667,18 @@ class BacktrackingAllocator : protected 
           : alloc(slot), allocated(alloc)
         {}
     };
     typedef InlineForwardList<SpillSlot> SpillSlotList;
 
     // All allocated slots of each width.
     SpillSlotList normalSlots, doubleSlots, quadSlots;
 
+    Vector<LiveBundle*, 4, SystemAllocPolicy> spilledBundles;
+
   public:
     BacktrackingAllocator(MIRGenerator* mir, LIRGenerator* lir, LIRGraph& graph, bool testbed)
       : RegisterAllocator(mir, lir, graph),
         testbed(testbed),
         liveIn(nullptr),
         callRanges(nullptr)
     { }
 
@@ -715,16 +717,17 @@ class BacktrackingAllocator : protected 
                                          Requirement *phint);
     bool hasFixedUseOverlap(LiveBundle* bundle, const LiveBundleVector& conflicting);
     MOZ_MUST_USE bool tryAllocateRegister(PhysicalRegister& r, LiveBundle* bundle, bool* success,
                                           bool* pfixed, LiveBundleVector& conflicting);
     MOZ_MUST_USE bool evictBundle(LiveBundle* bundle);
     MOZ_MUST_USE bool splitAndRequeueBundles(LiveBundle* bundle,
                                              const LiveBundleVector& newBundles);
     MOZ_MUST_USE bool spill(LiveBundle* bundle);
+    MOZ_MUST_USE bool tryAllocatingRegistersForSpillBundles();
 
     bool isReusedInput(LUse* use, LNode* ins, bool considerCopy);
     bool isRegisterUse(UsePosition* use, LNode* ins, bool considerCopy = false);
     bool isRegisterDefinition(LiveRange* range);
     MOZ_MUST_USE bool pickStackSlot(SpillSet* spill);
     MOZ_MUST_USE bool insertAllRanges(LiveRangeSet& set, LiveBundle* bundle);
 
     // Reification methods.