V4 regalloc: fix the case where too few regs are available.
authorErik Verbruggen <erik.verbruggen@me.com>
Wed, 25 Sep 2013 10:11:14 +0000 (12:11 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Sat, 28 Sep 2013 21:56:53 +0000 (23:56 +0200)
When all registers are allocated, and a new range gets active, some
other range will have to be split and spilled to the stack. This gets
slightly more complicated when the temporary is defined by a phi-node,
so in that case, the temporary is immediately spilled.

Change-Id: Iaab8b8e88849866e5841ae752377796e8540e30f
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/compiler/qv4regalloc.cpp
src/qml/compiler/qv4regalloc_p.h

index ecf35d4..20036d3 100644 (file)
@@ -1265,12 +1265,18 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int
     Q_ASSERT(!current.isFixedInterval());
     Q_ASSERT(current.reg() == LifeTimeInterval::Invalid);
 
+    const bool isPhiTarget = _info->isPhiTarget(current.temp());
+    if (isPhiTarget && !current.isSplitFromInterval()) {
+        split(current, position + 1, true);
+        _inactive.append(current);
+        return;
+    }
+
     const bool needsFPReg = isFP(current.temp());
     QVector<int> nextUsePos(needsFPReg ? _fpRegisters.size() : _normalRegisters.size(), INT_MAX);
     QVector<LifeTimeInterval *> nextUseRangeForReg(nextUsePos.size(), 0);
     Q_ASSERT(nextUsePos.size() > 0);
 
-    const bool isPhiTarget = _info->isPhiTarget(current.temp());
     for (int i = 0, ei = _active.size(); i != ei; ++i) {
         LifeTimeInterval &it = _active[i];
         if (it.isFP() == needsFPReg) {
@@ -1278,6 +1284,9 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int
             if (nu != -1 && nu < nextUsePos[it.reg()]) {
                 nextUsePos[it.reg()] = nu;
                 nextUseRangeForReg[it.reg()] = &it;
+            } else if (nu == -1 && nextUsePos[it.reg()] == INT_MAX) {
+                // in a loop, the range can be active, but only used before the current position (e.g. in a loop header or phi node)
+                nextUseRangeForReg[it.reg()] = &it;
             }
         }
     }
@@ -1298,12 +1307,10 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int
     }
 
     int reg, nextUsePos_reg;
-    longestAvailableReg(nextUsePos, reg, nextUsePos_reg);
+    longestAvailableReg(nextUsePos, reg, nextUsePos_reg, current.end());
 
     if (current.start() > nextUsePos_reg) {
         // all other intervals are used before current, so it is best to spill current itself
-        // Note: even if we absolutely need a register (e.g. with a floating-point add), we have
-        // a scratch register available, and so we can still use a spill slot as the destination.
 #ifdef DEBUG_REGALLOC
         QTextStream out(stderr, QIODevice::WriteOnly);
         out << "*** splitting current for range ";current.dump(out);out<<endl;
@@ -1320,6 +1327,7 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int
         current.setReg(reg);
         _lastAssignedRegister.insert(current.temp(), reg);
         Q_ASSERT(nextUseRangeForReg[reg]);
+        Q_ASSERT(!nextUseRangeForReg[reg]->isFixedInterval());
         split(*nextUseRangeForReg[reg], position);
         splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position);
 
@@ -1331,7 +1339,7 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int
 #ifdef DEBUG_REGALLOC
             out << "***-- current range intersects with a fixed reg use at "<<ni<<", so splitting it."<<endl;
 #endif // DEBUG_REGALLOC
-            split(current, ni);
+            split(current, ni, true);
         }
     }
 }
@@ -1465,6 +1473,8 @@ void RegisterAllocator::splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg,
 {
     for (int i = 0, ei = _inactive.size(); i != ei; ++i) {
         LifeTimeInterval &interval = _inactive[i];
+        if (interval.isFixedInterval())
+            continue;
         if (isFPReg == interval.isFP() && interval.reg() == reg) {
             LifeTimeInterval::Ranges ranges = interval.ranges();
             int endOfLifetimeHole = -1;
index e843fd0..40e88c1 100644 (file)
@@ -84,7 +84,7 @@ private:
     void tryAllocateFreeReg(LifeTimeInterval &current, const int position);
     void allocateBlockedReg(LifeTimeInterval &current, const int position);
     void longestAvailableReg(const QVector<int> &nextUses, int &reg, int &nextUsePos_reg,
-                             int lastUse = -1) const;
+                             int lastUse) const;
     int nextIntersection(const LifeTimeInterval &current, const LifeTimeInterval &another,
                          const int position) const;
     int nextUse(const V4IR::Temp &t, int startPosition) const;