[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