Author: Carl Friedrich Bolz <[email protected]>
Branch: regalloc-playground
Changeset: r92205:f6baf7f14279
Date: 2017-08-22 15:01 +0200
http://bitbucket.org/pypy/pypy/changeset/f6baf7f14279/

Log:    some fundamental data structures for supporting putting boxes into
        fixed registers

diff --git a/rpython/jit/backend/llsupport/regalloc.py 
b/rpython/jit/backend/llsupport/regalloc.py
--- a/rpython/jit/backend/llsupport/regalloc.py
+++ b/rpython/jit/backend/llsupport/regalloc.py
@@ -1,3 +1,4 @@
+import sys
 from rpython.jit.metainterp.history import Const, REF, JitCellToken
 from rpython.rlib.objectmodel import we_are_translated, specialize
 from rpython.jit.metainterp.resoperation import rop, AbstractValue
@@ -827,6 +828,10 @@
         # arguments or in failargs)
         self.real_usages = None
 
+        # fixed registers are positions where the variable *needs* to be in a
+        # specific register
+        self.fixed_positions = None
+
     def is_last_real_use_before(self, position):
         if self.real_usages is None:
             return True
@@ -846,6 +851,14 @@
                 low = mid + 1
         return l[low]
 
+    def fixed_register(self, position, reg):
+        assert self.definition_pos <= position <= self.last_usage
+        if self.fixed_positions is None:
+            self.fixed_positions = []
+        else:
+            assert position > self.fixed_positions[-1][0]
+        self.fixed_positions.append((position, reg))
+
     def _check_invariants(self):
         assert self.definition_pos <= self.last_usage
         if self.real_usages is not None:
@@ -856,12 +869,65 @@
     def __repr__(self):
         return "%s:%s(%s)" % (self.definition_pos, self.real_usages, 
self.last_usage)
 
+
+class FixedRegisterPositions(object):
+    def __init__(self, register):
+        self.register = register
+
+        self.index_lifetimes = []
+
+    def fixed_register(self, opindex, varlifetime):
+        if self.index_lifetimes:
+            assert opindex > self.index_lifetimes[-1][0]
+        self.index_lifetimes.append((opindex, varlifetime))
+
+    def compute_free_until_pos(self, opindex):
+        for (index, varlifetime) in self.index_lifetimes:
+            if opindex <= index:
+                if varlifetime.definition_pos >= opindex:
+                    return varlifetime.definition_pos
+                else:
+                    # the variable didn't make it into the register despite
+                    # being defined already. so we don't care too much, and can
+                    # say that the variable is free until index
+                    return index
+        return sys.maxint
+
 class LifetimeManager(object):
     def __init__(self, longevity):
         self.longevity = longevity
 
-    def register_hint(self, opindex, var, register):
-        raise NotImplementedError
+        # dictionary maps register to FixedRegisterPositions
+        self.fixed_register_use = {}
+
+    def fixed_register(self, opindex, register, var=None):
+        """ Tell the LifetimeManager that variable var *must* be in register at
+        operation opindex. var can be None, if no variable at all can be in
+        that register at the point."""
+        varlifetime = self.longevity[var]
+        if register not in self.fixed_register_use:
+            self.fixed_register_use[register] = 
FixedRegisterPositions(register)
+        self.fixed_register_use[register].fixed_register(opindex, varlifetime)
+        varlifetime.fixed_register(opindex, register)
+
+    def compute_longest_free_reg(self, position, free_regs):
+        """ for every register in free_regs, compute how far into the
+        future that register can remain free, according to the constraints of
+        the fixed registers. Find the register that is free the longest. 
Return a tuple
+        (reg, free_until_pos). """
+        free_until_pos = {}
+        max_free_pos = -1
+        best_reg = None
+        for reg in free_regs:
+            fixed_reg_pos = self.fixed_register_use.get(reg, None)
+            if fixed_reg_pos is None:
+                return reg, sys.maxint
+            else:
+                free_until_pos = fixed_reg_pos.compute_free_until_pos(position)
+                if free_until_pos > max_free_pos:
+                    best_reg = reg
+                    max_free_pos = free_until_pos
+        return best_reg, max_free_pos
 
     def __contains__(self, var):
         return var in self.longevity
diff --git a/rpython/jit/backend/llsupport/test/test_regalloc.py 
b/rpython/jit/backend/llsupport/test/test_regalloc.py
--- a/rpython/jit/backend/llsupport/test/test_regalloc.py
+++ b/rpython/jit/backend/llsupport/test/test_regalloc.py
@@ -1,4 +1,5 @@
 import py
+import sys
 from rpython.jit.metainterp.history import ConstInt, INT, FLOAT
 from rpython.jit.metainterp.history import BasicFailDescr, TargetToken
 from rpython.jit.metainterp.resoperation import rop
@@ -7,7 +8,8 @@
 from rpython.jit.backend.detect_cpu import getcpuclass
 from rpython.jit.backend.llsupport.regalloc import FrameManager, LinkedList
 from rpython.jit.backend.llsupport.regalloc import RegisterManager as 
BaseRegMan,\
-     Lifetime as RealLifetime, UNDEF_POS, BaseRegalloc, compute_vars_longevity
+     Lifetime as RealLifetime, UNDEF_POS, BaseRegalloc, 
compute_vars_longevity,\
+     LifetimeManager
 from rpython.jit.tool.oparser import parse
 from rpython.jit.codewriter.effectinfo import EffectInfo
 from rpython.rtyper.lltypesystem import lltype
@@ -123,6 +125,73 @@
         assert next > i
         assert lt.real_usages[lt.real_usages.index(next) - 1] <= i
 
+def test_fixed_position():
+    b0, b1, b2 = newboxes(0, 0, 0)
+    l0 = Lifetime(0, 5)
+    l1 = Lifetime(2, 9)
+    l2 = Lifetime(0, 9)
+    longevity = LifetimeManager({b0: l0, b1: l1, b2: l2})
+    longevity.fixed_register(1, r0, b0)
+    longevity.fixed_register(4, r2, b0)
+    longevity.fixed_register(5, r1, b1)
+    longevity.fixed_register(8, r1, b1)
+
+    assert l0.fixed_positions == [(1, r0), (4, r2)]
+    assert l1.fixed_positions == [(5, r1), (8, r1)]
+    assert l2.fixed_positions is None
+
+    fpr0 = longevity.fixed_register_use[r0]
+    fpr1 = longevity.fixed_register_use[r1]
+    fpr2 = longevity.fixed_register_use[r2]
+    assert r3 not in longevity.fixed_register_use
+    assert fpr0.index_lifetimes == [(1, l0)]
+    assert fpr1.index_lifetimes == [(5, l1), (8, l1)]
+    assert fpr2.index_lifetimes == [(4, l0)]
+
+
+def test_compute_free_until_pos():
+    b0, b1, b2 = newboxes(0, 0, 0)
+    l0 = Lifetime(0, 5)
+    l1 = Lifetime(2, 9)
+    l2 = Lifetime(30, 40)
+    longevity = LifetimeManager({b0: l0, b1: l1, b2: l2})
+    longevity.fixed_register(1, r0, b0)
+    longevity.fixed_register(4, r2, b0)
+    longevity.fixed_register(5, r1, b1)
+    longevity.fixed_register(8, r1, b1)
+    longevity.fixed_register(35, r1, b2)
+
+    fpr1 = longevity.fixed_register_use[r1]
+
+    # simple cases: we are before the beginning of the lifetime of the variable
+    # in the fixed register, then it's free until the definition of the
+    # variable
+    assert fpr1.compute_free_until_pos(0) == 2
+    assert fpr1.compute_free_until_pos(1) == 2
+    assert fpr1.compute_free_until_pos(2) == 2
+    assert fpr1.compute_free_until_pos(10) == 30
+    assert fpr1.compute_free_until_pos(20) == 30
+    assert fpr1.compute_free_until_pos(30) == 30
+
+    # after the fixed use, we are fined anyway
+    assert fpr1.compute_free_until_pos(36) == sys.maxint
+    assert fpr1.compute_free_until_pos(50) == sys.maxint
+
+    # asking for a position *after* the definition of the variable in the fixed
+    # register means the variable didn't make it into the fixed register, but
+    # at the latest by the use point it will have to go there
+    assert fpr1.compute_free_until_pos(3) == 5
+    assert fpr1.compute_free_until_pos(4) == 5
+    assert fpr1.compute_free_until_pos(5) == 5
+    assert fpr1.compute_free_until_pos(6) == 8
+    assert fpr1.compute_free_until_pos(7) == 8
+    assert fpr1.compute_free_until_pos(8) == 8
+    assert fpr1.compute_free_until_pos(31) == 35
+    assert fpr1.compute_free_until_pos(32) == 35
+    assert fpr1.compute_free_until_pos(33) == 35
+    assert fpr1.compute_free_until_pos(34) == 35
+    assert fpr1.compute_free_until_pos(35) == 35
+
 class TestRegalloc(object):
     def test_freeing_vars(self):
         b0, b1, b2 = newboxes(0, 0, 0)
@@ -223,7 +292,7 @@
         assert isinstance(loc, FakeReg)
         assert loc not in [r2, r3]
         rm._check_invariants()
-    
+
     def test_make_sure_var_in_reg(self):
         boxes, longevity = boxes_and_longevity(5)
         fm = TFrameManager()
@@ -237,7 +306,7 @@
         loc = rm.make_sure_var_in_reg(b0)
         assert isinstance(loc, FakeReg)
         rm._check_invariants()
-        
+
     def test_force_result_in_reg_1(self):
         b0, b1 = newboxes(0, 0)
         longevity = {b0: Lifetime(0, 1), b1: Lifetime(1, 3)}
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to