Author: Richard Plangger <planri...@gmail.com>
Branch: fix-longevity
Changeset: r82460:98153a101dda
Date: 2016-02-23 19:09 +0100
http://bitbucket.org/pypy/pypy/changeset/98153a101dda/

Log:    (remi, plan_rich) refactored free_reg into two lists (caller saved
        and callee saved list)

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,7 +1,7 @@
 import os
-from rpython.jit.metainterp.history import Const, REF, JitCellToken
+from rpython.jit.metainterp.history import Const, Box, REF, JitCellToken
 from rpython.rlib.objectmodel import we_are_translated, specialize
-from rpython.jit.metainterp.resoperation import rop, AbstractValue
+from rpython.jit.metainterp.resoperation import rop
 from rpython.rtyper.lltypesystem import lltype
 from rpython.rtyper.lltypesystem.lloperation import llop
 
@@ -10,7 +10,7 @@
 except ImportError:
     OrderedDict = dict # too bad
 
-class TempVar(AbstractValue):
+class TempBox(Box):
     def __init__(self):
         pass
 
@@ -267,7 +267,6 @@
         raise NotImplementedError("Purely abstract")
 
 class RegisterManager(object):
-
     """ Class that keeps track of register allocations
     """
     box_types             = None       # or a list of acceptable types
@@ -276,10 +275,10 @@
     save_around_call_regs = []
     frame_reg             = None
 
-    def __init__(self, live_ranges, frame_manager=None, assembler=None):
+    def __init__(self, longevity, frame_manager=None, assembler=None):
         self.free_regs = self.all_regs[:]
         self.free_regs.reverse()
-        self.live_ranges = live_ranges
+        self.longevity = longevity
         self.temp_boxes = []
         if not we_are_translated():
             self.reg_bindings = OrderedDict()
@@ -293,19 +292,19 @@
     def is_still_alive(self, v):
         # Check if 'v' is alive at the current position.
         # Return False if the last usage is strictly before.
-        return self.live_ranges.last_use(v) >= self.position
+        return self.longevity[v][1] >= self.position
 
     def stays_alive(self, v):
         # Check if 'v' stays alive after the current position.
         # Return False if the last usage is before or at position.
-        return self.live_ranges.last_use(v) > self.position
+        return self.longevity[v][1] > self.position
 
     def next_instruction(self, incr=1):
         self.position += incr
 
     def _check_type(self, v):
         if not we_are_translated() and self.box_types is not None:
-            assert isinstance(v, TempVar) or v.type in self.box_types
+            assert isinstance(v, TempBox) or v.type in self.box_types
 
     def possibly_free_var(self, v):
         """ If v is stored in a register and v is not used beyond the
@@ -315,7 +314,7 @@
         self._check_type(v)
         if isinstance(v, Const):
             return
-        if not self.live_ranges.exists(v) or self.live_ranges.last_use(v) <= 
self.position:
+        if v not in self.longevity or self.longevity[v][1] <= self.position:
             if v in self.reg_bindings:
                 self.free_regs.append(self.reg_bindings[v])
                 del self.reg_bindings[v]
@@ -347,9 +346,9 @@
         else:
             assert len(self.reg_bindings) + len(self.free_regs) == 
len(self.all_regs)
         assert len(self.temp_boxes) == 0
-        if self.live_ranges.longevity:
+        if self.longevity:
             for v in self.reg_bindings:
-                assert self.live_ranges.last_use(v) > self.position
+                assert self.longevity[v][1] > self.position
 
     def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False):
         """ Try to allocate a register, if we have one free.
@@ -425,7 +424,7 @@
                     continue
             if need_lower_byte and reg in self.no_lower_byte_regs:
                 continue
-            max_age = self.live_ranges.last_use(next)
+            max_age = self.longevity[next][1]
             if cur_max_age < max_age:
                 cur_max_age = max_age
                 candidate = next
@@ -443,8 +442,8 @@
         Will not spill a variable from 'forbidden_vars'.
         """
         self._check_type(v)
-        if isinstance(v, TempVar):
-            self.live_ranges.new_live_range(v, self.position, self.position)
+        if isinstance(v, TempBox):
+            self.longevity[v] = (self.position, self.position)
         loc = self.try_allocate_reg(v, selected_reg,
                                     need_lower_byte=need_lower_byte)
         if loc:
@@ -554,14 +553,13 @@
             loc = self.force_allocate_reg(v, forbidden_vars)
             self.assembler.regalloc_mov(prev_loc, loc)
         assert v in self.reg_bindings
-        if self.live_ranges.last_use(v) > self.position:
+        if self.longevity[v][1] > self.position:
             # we need to find a new place for variable v and
             # store result in the same place
             loc = self.reg_bindings[v]
             del self.reg_bindings[v]
-            if self.frame_manager.get(v) is None or self.free_regs:
+            if self.frame_manager.get(v) is None:
                 self._move_variable_away(v, loc)
-
             self.reg_bindings[result_v] = loc
         else:
             self._reallocate_from_to(v, result_v)
@@ -583,7 +581,7 @@
         1 (save all), or 2 (save default+PTRs).
         """
         for v, reg in self.reg_bindings.items():
-            if v not in force_store and self.live_ranges.last_use(v) <= 
self.position:
+            if v not in force_store and self.longevity[v][1] <= self.position:
                 # variable dies
                 del self.reg_bindings[v]
                 self.free_regs.append(reg)
@@ -635,78 +633,69 @@
         locs = []
         base_ofs = self.assembler.cpu.get_baseofs_of_frame_field()
         for box in inputargs:
-            assert not isinstance(box, Const)
+            assert isinstance(box, Box)
             loc = self.fm.get_new_loc(box)
             locs.append(loc.value - base_ofs)
-        if looptoken.compiled_loop_token is not None:   # <- for tests
+        if looptoken.compiled_loop_token is not None:
+            # for tests
             looptoken.compiled_loop_token._ll_initial_locs = locs
 
-    def next_op_can_accept_cc(self, operations, i):
-        op = operations[i]
-        next_op = operations[i + 1]
-        opnum = next_op.getopnum()
-        if (opnum != rop.GUARD_TRUE and opnum != rop.GUARD_FALSE
-                                    and opnum != rop.COND_CALL):
+    def can_merge_with_next_guard(self, op, i, operations):
+        if (op.getopnum() == rop.CALL_MAY_FORCE or
+            op.getopnum() == rop.CALL_ASSEMBLER or
+            op.getopnum() == rop.CALL_RELEASE_GIL):
+            assert operations[i + 1].getopnum() == rop.GUARD_NOT_FORCED
+            return True
+        if not op.is_comparison():
+            if op.is_ovf():
+                if (operations[i + 1].getopnum() != rop.GUARD_NO_OVERFLOW and
+                    operations[i + 1].getopnum() != rop.GUARD_OVERFLOW):
+                    not_implemented("int_xxx_ovf not followed by "
+                                    "guard_(no)_overflow")
+                return True
             return False
-        if next_op.getarg(0) is not op:
+        if (operations[i + 1].getopnum() != rop.GUARD_TRUE and
+            operations[i + 1].getopnum() != rop.GUARD_FALSE):
             return False
-        if self.longevity[op][1] > i + 1:
+        if operations[i + 1].getarg(0) is not op.result:
             return False
-        if opnum != rop.COND_CALL:
-            if op in operations[i + 1].getfailargs():
-                return False
-        else:
-            if op in operations[i + 1].getarglist()[1:]:
-                return False
+        if (self.longevity[op.result][1] > i + 1 or
+            op.result in operations[i + 1].getfailargs()):
+            return False
         return True
 
-    def locs_for_call_assembler(self, op):
+    def locs_for_call_assembler(self, op, guard_op):
         descr = op.getdescr()
         assert isinstance(descr, JitCellToken)
         if op.numargs() == 2:
             self.rm._sync_var(op.getarg(1))
             return [self.loc(op.getarg(0)), self.fm.loc(op.getarg(1))]
         else:
-            assert op.numargs() == 1
             return [self.loc(op.getarg(0))]
 
 
-class LiveRanges(object):
-    def __init__(self, longevity, last_real_usage, dist_to_next_call):
-        self.longevity = longevity
-        self.last_real_usage = last_real_usage
-        self.dist_to_next_call = dist_to_next_call
-
-    def exists(self, var):
-         return var in self.longevity
-
-    def last_use(self, var):
-         return self.longevity[var][1]
-
-    def new_live_range(self, var, start, end):
-         self.longevity[var] = (start, end)
-
-def compute_var_live_ranges(inputargs, operations):
+def compute_vars_longevity(inputargs, operations):
     # compute a dictionary that maps variables to index in
     # operations that is a "last-time-seen"
 
-    # returns a Longevity object with longevity/useful. Non-useful variables 
are ones that
+    # returns a pair longevity/useful. Non-useful variables are ones that
     # never appear in the assembler or it does not matter if they appear on
     # stack or in registers. Main example is loop arguments that go
     # only to guard operations or to jump or to finish
+    produced = {}
     last_used = {}
     last_real_usage = {}
-    dist_to_next_call = [0] * len(operations)
-    last_call_pos = -1
     for i in range(len(operations)-1, -1, -1):
         op = operations[i]
-        if op.type != 'v':
-            if op not in last_used and op.has_no_side_effect():
+        if op.result:
+            if op.result not in last_used and op.has_no_side_effect():
                 continue
+            assert op.result not in produced
+            produced[op.result] = i
         opnum = op.getopnum()
         for j in range(op.numargs()):
             arg = op.getarg(j)
-            if isinstance(arg, Const):
+            if not isinstance(arg, Box):
                 continue
             if arg not in last_used:
                 last_used[arg] = i
@@ -717,40 +706,26 @@
             for arg in op.getfailargs():
                 if arg is None: # hole
                     continue
-                assert not isinstance(arg, Const)
+                assert isinstance(arg, Box)
                 if arg not in last_used:
                     last_used[arg] = i
-        if op.is_call():
-            last_call_pos = i
-        dist_to_next_call[i] = last_call_pos - i
     #
     longevity = {}
-    for i, arg in enumerate(operations):
-        if arg.type != 'v' and arg in last_used:
-            assert not isinstance(arg, Const)
-            assert i < last_used[arg]
-            longevity[arg] = (i, last_used[arg])
+    for arg in produced:
+        if arg in last_used:
+            assert isinstance(arg, Box)
+            assert produced[arg] < last_used[arg]
+            longevity[arg] = (produced[arg], last_used[arg])
             del last_used[arg]
     for arg in inputargs:
-        assert not isinstance(arg, Const)
+        assert isinstance(arg, Box)
         if arg not in last_used:
             longevity[arg] = (-1, -1)
         else:
             longevity[arg] = (0, last_used[arg])
             del last_used[arg]
     assert len(last_used) == 0
-
-    if not we_are_translated():
-        produced = {}
-        for arg in inputargs:
-            produced[arg] = None
-        for op in operations:
-            for arg in op.getarglist():
-                if not isinstance(arg, Const):
-                    assert arg in produced
-            produced[op] = None
-
-    return LiveRanges(longevity, last_real_usage, dist_to_next_call)
+    return longevity, last_real_usage
 
 def is_comparison_or_ovf_op(opnum):
     from rpython.jit.metainterp.resoperation import opclasses
@@ -759,7 +734,7 @@
     # any instance field, we can use a fake object
     class Fake(cls):
         pass
-    op = Fake()
+    op = Fake(None)
     return op.is_comparison() or op.is_ovf()
 
 def valid_addressing_size(size):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to