[pypy-svn] r67928 - pypy/branch/refactor-x86/pypy/jit/backend/x86

fijal at codespeak.net fijal at codespeak.net
Mon Sep 28 13:59:26 CEST 2009


Author: fijal
Date: Mon Sep 28 13:59:25 2009
New Revision: 67928

Modified:
   pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py
   pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py
Log:
Kill a lot of code and start using new interface, only few tests pass
so far


Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py	Mon Sep 28 13:59:25 2009
@@ -8,7 +8,7 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.tool.uid import fixid
 from pypy.jit.backend.x86.regalloc import (RegAlloc, WORD, REGS, TempBox,
-                                           lower_byte, stack_pos)
+                                           lower_byte)
 from pypy.rlib.objectmodel import we_are_translated, specialize
 from pypy.jit.backend.x86 import codebuf
 from pypy.jit.backend.x86.ri386 import *
@@ -168,7 +168,7 @@
         self.mc2.done()
         if we_are_translated() or self.cpu.dont_keepalive_stuff:
             self._regalloc = None   # else keep it around for debugging
-        stack_depth = regalloc.current_stack_depth
+        stack_depth = regalloc.sm.stack_depth
         jump_target = regalloc.jump_target
         if jump_target is not None:
             target_stack_depth = jump_target.executable_token._x86_stack_depth
@@ -235,11 +235,9 @@
 
     # ------------------------------------------------------------
 
-    def regalloc_load(self, from_loc, to_loc):
+    def regalloc_mov(self, from_loc, to_loc):
         self.mc.MOV(to_loc, from_loc)
 
-    regalloc_store = regalloc_load
-
     def regalloc_push(self, loc):
         self.mc.PUSH(loc)
 

Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py	Mon Sep 28 13:59:25 2009
@@ -14,20 +14,12 @@
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.backend.llsupport.descr import BaseFieldDescr, BaseArrayDescr
 from pypy.jit.backend.llsupport.descr import BaseCallDescr
+from pypy.jit.backend.llsupport.regalloc import StackManager, RegisterManager,\
+     TempBox
 
 REGS = [eax, ecx, edx, ebx, esi, edi]
 WORD = 4
 
-class NoVariableToSpill(Exception):
-    pass
-
-class TempBox(Box):
-    def __init__(self):
-        pass
-
-    def __repr__(self):
-        return "<TempVar at %s>" % (id(self),)
-
 class checkdict(dict):
     def __setitem__(self, key, value):
         assert isinstance(key, Box)
@@ -38,19 +30,28 @@
         return {}
     return checkdict()
 
-def convert_to_imm(c):
-    if isinstance(c, ConstInt):
-        return imm(c.value)
-    elif isinstance(c, ConstPtr):
-        if we_are_translated() and c.value and rgc.can_move(c.value):
-            print "convert_to_imm: ConstPtr needs special care"
+class X86RegisterManager(RegisterManager):
+    def convert_to_imm(self, c):
+        if isinstance(c, ConstInt):
+            return imm(c.value)
+        elif isinstance(c, ConstPtr):
+            if we_are_translated() and c.value and rgc.can_move(c.value):
+                print "convert_to_imm: ConstPtr needs special care"
+                raise AssertionError
+            return imm(rffi.cast(lltype.Signed, c.value))
+        elif isinstance(c, ConstAddr):
+            return imm(ll2ctypes.cast_adr_to_int(c.value))
+        else:
+            print "convert_to_imm: got a %s" % c
             raise AssertionError
-        return imm(rffi.cast(lltype.Signed, c.value))
-    elif isinstance(c, ConstAddr):
-        return imm(ll2ctypes.cast_adr_to_int(c.value))
-    else:
-        print "convert_to_imm: got a %s" % c
-        raise AssertionError
+
+class X86StackManager(StackManager):
+
+    @staticmethod
+    def stack_pos(i):
+        res = mem(ebp, get_ebp_ofs(i))
+        res.position = i
+        return res
 
 class RegAlloc(object):
     exc = False
@@ -60,28 +61,27 @@
         # variables that have place in register
         self.assembler = assembler
         self.translate_support_code = translate_support_code
-        self.reg_bindings = newcheckdict()
-        self.stack_bindings = newcheckdict()
         self.position = -1
-        self.longevity = None
-
         # to be read/used by the assembler too
-        self.current_stack_depth = 0
         self.jump_target = None
 
     def prepare_loop(self, inputargs, operations):
         cpu = self.assembler.cpu
         cpu.gc_ll_descr.rewrite_assembler(cpu, operations)
         # compute longevity of variables
-        self._compute_vars_longevity(inputargs, operations)
+        longevity = self._compute_vars_longevity(inputargs, operations)
+        self.sm = X86StackManager()
+        self.rm = X86RegisterManager(REGS, longevity,
+                                     no_lower_byte_regs = [esi, edi],
+                                     stack_manager = self.sm,
+                                     assembler = self.assembler)
         jump = operations[-1]
         loop_consts = self._compute_loop_consts(inputargs, jump)
         self.loop_consts = loop_consts
-        self.current_stack_depth = 0
-        self.free_regs = REGS[:]
         return self._process_inputargs(inputargs)
 
     def prepare_bridge(self, prev_stack_depth, inputargs, arglocs, operations):
+        xxxx
         cpu = self.assembler.cpu        
         cpu.gc_ll_descr.rewrite_assembler(cpu, operations)
         # compute longevity of variables
@@ -96,23 +96,23 @@
         locs = [None] * len(inputargs)
         # Don't use REGS[0] for passing arguments around a loop.
         # Must be kept in sync with consider_jump().
-        tmpreg = self.free_regs.pop(0)
+        tmpreg = self.rm.free_regs.pop(0)
         assert tmpreg == REGS[0]
         for i in range(len(inputargs)):
             arg = inputargs[i]
             assert not isinstance(arg, Const)
             reg = None
-            if arg not in self.loop_consts and self.longevity[arg][1] > -1:
-                reg = self.try_allocate_reg(arg)
+            if arg not in self.loop_consts and self.rm.longevity[arg][1] > -1:
+                reg = self.rm.try_allocate_reg(arg)
             if reg:
                 locs[i] = reg
             else:
-                loc = self.stack_loc(arg)
+                loc = self.sm.loc(arg)
                 locs[i] = loc
             # otherwise we have it saved on stack, so no worry
-        self.free_regs.insert(0, tmpreg)
+        self.rm.free_regs.insert(0, tmpreg)
         assert tmpreg not in locs
-        self.eventually_free_vars(inputargs)
+        self.rm.possibly_free_vars(inputargs)
         return locs
 
     def _compute_loop_consts(self, inputargs, jump):
@@ -147,32 +147,6 @@
                 self.free_regs.append(reg)
         self._check_invariants()
 
-    def _check_invariants(self):
-        if not we_are_translated():
-            # make sure no duplicates
-            assert len(dict.fromkeys(self.reg_bindings.values())) == len(self.reg_bindings)
-            assert (len(dict.fromkeys([str(i) for i in self.stack_bindings.values()]
-                                      )) == len(self.stack_bindings))
-            rev_regs = dict.fromkeys(self.reg_bindings.values())
-            for reg in self.free_regs:
-                assert reg not in rev_regs
-            assert len(rev_regs) + len(self.free_regs) == len(REGS)
-        else:
-            assert len(self.reg_bindings) + len(self.free_regs) == len(REGS)
-        if self.longevity:
-            for v in self.reg_bindings:
-                assert self.longevity[v][1] > self.position
-
-    def Load(self, v, from_loc, to_loc):
-        if not we_are_translated():
-            self.assembler.dump('%s <- %s(%s)' % (to_loc, v, from_loc))
-        self.assembler.regalloc_load(from_loc, to_loc)
-
-    def Store(self, v, from_loc, to_loc):
-        if not we_are_translated():
-            self.assembler.dump('%s(%s) -> %s' % (v, from_loc, to_loc))
-        self.assembler.regalloc_store(from_loc, to_loc)
-
     def Perform(self, op, arglocs, result_loc):
         if not we_are_translated():
             self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs))
@@ -187,16 +161,14 @@
     def perform_with_guard(self, op, guard_op, arglocs, result_loc):
         faillocs = self.locs_for_fail(guard_op)
         self.position += 1
-        if not we_are_translated():
-            self.assembler.dump('%s <- %s(%s) [GUARDED]' % (result_loc, op,
-                                                            arglocs))
         self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs,
                                                    arglocs, result_loc,
-                                                   self.current_stack_depth)
-        self.eventually_free_var(op.result)        
-        self.eventually_free_vars(guard_op.suboperations[0].args)
+                                                   self.sm.stack_depth)
+        self.rm.possibly_free_var(op.result)
+        self.rm.possibly_free_vars(guard_op.suboperations[0].args)
 
     def perform_guard(self, guard_op, arglocs, result_loc):
+        xxx
         faillocs = self.locs_for_fail(guard_op)
         if not we_are_translated():
             if result_loc is not None:
@@ -223,7 +195,7 @@
             return False
         if operations[i + 1].args[0] is not op.result:
             return False
-        if (self.longevity[op.result][1] > i + 1 or
+        if (self.rm.longevity[op.result][1] > i + 1 or
             op.result in operations[i + 1].suboperations[0].args):
             return False
         return True
@@ -233,20 +205,20 @@
         #self.operations = operations
         while i < len(operations):
             op = operations[i]
-            self.position = i
-            if op.has_no_side_effect() and op.result not in self.longevity:
+            self.rm.position = i
+            if op.has_no_side_effect() and op.result not in self.rm.longevity:
                 i += 1
-                self.eventually_free_vars(op.args)
+                self.rm.possibly_free_vars(op.args)
                 continue
             if self.can_optimize_cmp_op(op, i, operations):
                 oplist[op.opnum](self, op, operations[i + 1])
                 i += 1
             else:
                 oplist[op.opnum](self, op, None)
-            self.eventually_free_var(op.result)
-            self._check_invariants()
+            self.rm.possibly_free_var(op.result)
+            self.rm._check_invariants()
             i += 1
-        assert not self.reg_bindings
+        assert not self.rm.reg_bindings
 
     def _compute_vars_longevity(self, inputargs, operations):
         # compute a dictionary that maps variables to index in
@@ -277,217 +249,10 @@
                 longevity[arg] = (-1, -1)
         for arg in longevity:
             assert isinstance(arg, Box)
-        self.longevity = longevity
-
-    def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False):
-        assert not isinstance(v, Const)
-        if selected_reg is not None:
-            res = self.reg_bindings.get(v, None)
-            if res:
-                if res is selected_reg:
-                    return res
-                else:
-                    del self.reg_bindings[v]
-                    self.free_regs.append(res)
-            if selected_reg in self.free_regs:
-                self.free_regs = [reg for reg in self.free_regs
-                                  if reg is not selected_reg]
-                self.reg_bindings[v] = selected_reg
-                return selected_reg
-            return None
-        if need_lower_byte:
-            loc = self.reg_bindings.get(v, None)
-            if loc is not None and loc is not edi and loc is not esi:
-                return loc
-            for i in range(len(self.free_regs)):
-                reg = self.free_regs[i]
-                if reg is not edi and reg is not esi:
-                    if loc is not None:
-                        self.free_regs[i] = loc
-                    else:
-                        del self.free_regs[i]
-                    self.reg_bindings[v] = reg
-                    return reg
-            return None
-        try:
-            return self.reg_bindings[v]
-        except KeyError:
-            if self.free_regs:
-                loc = self.free_regs.pop()
-                self.reg_bindings[v] = loc
-                return loc
-
-    def return_constant(self, v, forbidden_vars, selected_reg=None,
-                        imm_fine=True):
-        assert isinstance(v, Const)
-        if selected_reg or not imm_fine:
-            # this means we cannot have it in IMM, eh
-            if selected_reg in self.free_regs:
-                self.Load(v, convert_to_imm(v), selected_reg)
-                return selected_reg
-            if selected_reg is None and self.free_regs:
-                loc = self.free_regs.pop()
-                self.Load(v, convert_to_imm(v), loc)
-                return loc
-            loc = self._spill_var(v, forbidden_vars, selected_reg)
-            self.free_regs.append(loc)
-            self.Load(v, convert_to_imm(v), loc)
-            return loc
-        return convert_to_imm(v)
-
-    def force_allocate_reg(self, v, forbidden_vars, selected_reg=None,
-                           need_lower_byte=False):
-        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:
-            return loc
-        loc = self._spill_var(v, forbidden_vars, selected_reg,
-                              need_lower_byte=need_lower_byte)
-        prev_loc = self.reg_bindings.get(v, None)
-        if prev_loc is not None:
-            self.free_regs.append(prev_loc)
-        self.reg_bindings[v] = loc
-        return loc
-
-    def _spill_var(self, v, forbidden_vars, selected_reg,
-                   need_lower_byte=False):
-        v_to_spill = self.pick_variable_to_spill(v, forbidden_vars,
-                               selected_reg, need_lower_byte=need_lower_byte)
-        loc = self.reg_bindings[v_to_spill]
-        del self.reg_bindings[v_to_spill]
-        if v_to_spill not in self.stack_bindings:
-            newloc = self.stack_loc(v_to_spill)
-            self.Store(v_to_spill, loc, newloc)
-        return loc
-
-    def stack_loc(self, v):
-        try:
-            res = self.stack_bindings[v]
-        except KeyError:
-            newloc = stack_pos(self.current_stack_depth)
-            self.stack_bindings[v] = newloc
-            self.current_stack_depth += 1
-            res = newloc
-        assert isinstance(res, MODRM)
-        return res
-
-    def make_sure_var_in_reg(self, v, forbidden_vars, selected_reg=None,
-                             imm_fine=True, need_lower_byte=False):
-        if isinstance(v, Const):
-            return self.return_constant(v, forbidden_vars, selected_reg,
-                                        imm_fine)
-        
-        prev_loc = self.loc(v)
-        loc = self.force_allocate_reg(v, forbidden_vars, selected_reg,
-                                      need_lower_byte=need_lower_byte)
-        if prev_loc is not loc:
-            self.Load(v, prev_loc, loc)
-        return loc
-
-    def reallocate_from_to(self, from_v, to_v):
-        reg = self.reg_bindings[from_v]
-        del self.reg_bindings[from_v]
-        self.reg_bindings[to_v] = reg
-
-    def eventually_free_var(self, v):
-        if isinstance(v, Const) or v not in self.reg_bindings:
-            return
-        if v not in self.longevity or self.longevity[v][1] <= self.position:
-            self.free_regs.append(self.reg_bindings[v])
-            del self.reg_bindings[v]
-
-    def eventually_free_vars(self, vlist):
-        for v in vlist:
-            self.eventually_free_var(v)
+        return longevity
 
     def loc(self, v):
-        if isinstance(v, Const):
-            return convert_to_imm(v)
-        try:
-            return self.reg_bindings[v]
-        except KeyError:
-            return self.stack_bindings[v]
-
-    def _compute_next_usage(self, v, pos):
-        for i in range(pos, len(self.operations)):
-            if v in self.operations[i].args:
-                return i
-            if i > self.longevity[v][1]:
-                return -1
-        return -1
-
-    def pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None,
-                               need_lower_byte=False):
-        candidates = []
-        for next in self.reg_bindings:
-            reg = self.reg_bindings[next]
-            if next in forbidden_vars:
-                continue
-            if selected_reg is not None:
-                if reg is selected_reg:
-                    return next
-                else:
-                    continue
-            if need_lower_byte and (reg is esi or reg is edi):
-                continue
-            return next
-        raise NoVariableToSpill
-        # below is the slightly better (even optimal, under certain
-        # assumptions) algorithm, which is slow. Just go with the
-        # first hit
-        #if len(candidates) == 1:
-        #    return candidates[0]
-        #max = 0
-        #chosen = None
-        #for one in candidates:
-        #    next_usage = self._compute_next_usage(one, self.position)
-        #    if next_usage == -1:
-        #        return one
-        #    elif next_usage > max:
-        #        next_usage = max
-        #        chosen = one
-        #return chosen
-
-    def move_variable_away(self, v, prev_loc):
-        reg = None
-        if self.free_regs:
-            loc = self.free_regs.pop()
-            self.reg_bindings[v] = loc
-            self.Load(v, prev_loc, loc)
-        else:
-            loc = self.stack_loc(v)
-            self.Store(v, prev_loc, loc)
-
-    def force_result_in_reg(self, result_v, v, forbidden_vars):
-        """ Make sure that result is in the same register as v
-        and v is copied away if it's further used
-        """
-        if isinstance(v, Const):
-            loc = self.make_sure_var_in_reg(v, forbidden_vars,
-                                            imm_fine=False)
-            assert not isinstance(loc, IMM8)
-            self.reg_bindings[result_v] = loc
-            self.free_regs = [reg for reg in self.free_regs if reg is not loc]
-            return loc
-        if v not in self.reg_bindings:
-            prev_loc = self.stack_bindings[v]
-            loc = self.force_allocate_reg(v, forbidden_vars)
-            self.Load(v, prev_loc, loc)
-        assert v in self.reg_bindings
-        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 v not in self.stack_bindings:
-                self.move_variable_away(v, loc)
-            self.reg_bindings[result_v] = loc
-        else:
-            self.reallocate_from_to(v, result_v)
-            loc = self.reg_bindings[result_v]
-        return loc
+        return self.rm.loc(v)
 
     def _consider_guard(self, op, ignored):
         loc = self.make_sure_var_in_reg(op.args[0], [])
@@ -501,7 +266,7 @@
         locs = [self.loc(arg) for arg in op.args]
         self.assembler.generate_failure(self.assembler.mc, op.descr, op.args,
                                         locs, self.exc)
-        self.eventually_free_vars(op.args)
+        self.rm.possibly_free_vars(op.args)
 
     consider_finish = consider_fail # for now
 
@@ -540,8 +305,8 @@
     def _consider_binop_part(self, op, ignored):
         x = op.args[0]
         argloc = self.loc(op.args[1])
-        loc = self.force_result_in_reg(op.result, x, op.args)
-        self.eventually_free_var(op.args[1])
+        loc = self.rm.force_result_in_reg(op.result, x, op.args)
+        self.rm.possibly_free_var(op.args[1])
         return loc, argloc
 
     def _consider_binop(self, op, ignored):
@@ -601,13 +366,12 @@
         vx = op.args[0]
         vy = op.args[1]
         arglocs = [self.loc(vx), self.loc(vy)]
-        if (vx in self.reg_bindings or vy in self.reg_bindings or
+        if (vx in self.rm.reg_bindings or vy in self.rm.reg_bindings or
             isinstance(vx, Const) or isinstance(vy, Const)):
             pass
         else:
             arglocs[0] = self.make_sure_var_in_reg(vx, [])
-        self.eventually_free_var(vx)
-        self.eventually_free_var(vy)
+        self.rm.possibly_free_vars(op.args)
         if guard_op is None:
             loc = self.force_allocate_reg(op.result, op.args,
                                           need_lower_byte=True)
@@ -885,13 +649,13 @@
         arglocs = assembler.target_arglocs(self.jump_target)
         # compute 'tmploc' to be REGS[0] by spilling what is there
         box = TempBox()
-        tmploc = self.force_allocate_reg(box, [], selected_reg=REGS[0])
-        src_locations = [self.loc(arg) for arg in op.args]
+        tmploc = self.rm.force_allocate_reg(box, [], selected_reg=REGS[0])
+        src_locations = [self.rm.loc(arg) for arg in op.args]
         dst_locations = arglocs
         assert tmploc not in dst_locations
         remap_stack_layout(assembler, src_locations, dst_locations, tmploc)
-        self.eventually_free_var(box)
-        self.eventually_free_vars(op.args)
+        self.rm.possibly_free_var(box)
+        self.rm.possibly_free_vars(op.args)
         assembler.closing_jump(self.jump_target)
 
     def consider_debug_merge_point(self, op, ignored):
@@ -936,11 +700,6 @@
     # exactly 4 PUSHes.
     return -WORD * (4 + position)
 
-def stack_pos(i):
-    res = mem(ebp, get_ebp_ofs(i))
-    res.position = i
-    return res
-
 def lower_byte(reg):
     # argh, kill, use lowest8bits instead
     if isinstance(reg, MODRM):



More information about the Pypy-commit mailing list