[pypy-svn] r67947 - in pypy/branch/refactor-x86/pypy/jit/backend: llsupport llsupport/test x86 x86/test
arigo at codespeak.net
arigo at codespeak.net
Mon Sep 28 18:59:51 CEST 2009
Author: arigo
Date: Mon Sep 28 18:59:50 2009
New Revision: 67947
Modified:
pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py
pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py
pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py
pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py
pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py
Log:
Small clean-ups.
Improved docstrings for llsupport/regalloc.
Various small fixes in tests.
Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py
==============================================================================
--- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original)
+++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 18:59:50 2009
@@ -39,13 +39,12 @@
class RegisterManager(object):
""" Class that keeps track of register allocations
"""
+ all_regs = []
no_lower_byte_regs = []
save_around_call_regs = []
- def __init__(self, register_pool, longevity,
- stack_manager=None, assembler=None):
- self.free_regs = register_pool[:]
- self.all_regs = register_pool
+ def __init__(self, longevity, stack_manager=None, assembler=None):
+ self.free_regs = self.all_regs[:]
self.longevity = longevity
self.reg_bindings = {}
self.position = -1
@@ -59,7 +58,9 @@
self.position += incr
def possibly_free_var(self, v):
- """ Variable v might not be used any more, if not used any more
+ """ If v is stored in a register and v is not used beyond the
+ current position, then free it. Must be called at some
+ point for all variables that might be in registers.
"""
if isinstance(v, Const) or v not in self.reg_bindings:
return
@@ -68,7 +69,7 @@
del self.reg_bindings[v]
def possibly_free_vars(self, vars):
- """ Each of v in vars might not be used any more
+ """ Same as 'possibly_free_var', but for all v in vars.
"""
for v in vars:
self.possibly_free_var(v)
@@ -88,12 +89,12 @@
assert self.longevity[v][1] > self.position
def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False):
- """ Try allocate register, if we have on free
+ """ Try to allocate a register, if we have one free.
need_lower_byte - if True, allocate one that has a lower byte reg
- (ie eax has al)
- selected_reg - pick a register which you want
+ (e.g. eax has al)
+ selected_reg - if not None, force a specific register
- returns allocated register or None, if not possible
+ returns allocated register or None, if not possible.
"""
assert not isinstance(v, Const)
if selected_reg is not None:
@@ -134,7 +135,7 @@
def _spill_var(self, v, forbidden_vars, selected_reg,
need_lower_byte=False):
- v_to_spill = self.pick_variable_to_spill(v, forbidden_vars,
+ 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]
@@ -143,8 +144,8 @@
self.assembler.regalloc_mov(loc, newloc)
return loc
- def pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None,
- need_lower_byte=False):
+ def _pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None,
+ need_lower_byte=False):
""" Silly algorithm.
"""
candidates = []
@@ -164,11 +165,12 @@
def force_allocate_reg(self, v, forbidden_vars=[], selected_reg=None,
need_lower_byte=False):
- """ Force allocate register for variable v (which is not yet used)
- If we don't have a free register, spill some other variable,
- according to algorithm described in pick_variable_to_spill
+ """ Forcibly allocate a register for the new variable v.
+ It must not be used so far. If we don't have a free register,
+ spill some other variable, according to algorithm described in
+ '_pick_variable_to_spill'.
- Will not spill a variable from forbidden_vars
+ Will not spill a variable from 'forbidden_vars'.
"""
if isinstance(v, TempBox):
self.longevity[v] = (self.position, self.position)
@@ -185,7 +187,7 @@
return loc
def loc(self, box):
- """ Return a location of box
+ """ Return the location of 'box'.
"""
if isinstance(box, Const):
return self.convert_to_imm(box)
@@ -196,8 +198,10 @@
def return_constant(self, v, forbidden_vars=[], selected_reg=None,
imm_fine=True):
- """ Return a location of constant v, if imm_fine is set to False
- will move it's value to register
+ """ Return the location of the constant v. If 'imm_fine' is False,
+ or if 'selected_reg' is not None, it will first load its value into
+ a register. See 'force_allocate_reg' for the meaning of 'selected_reg'
+ and 'forbidden_vars'.
"""
assert isinstance(v, Const)
if selected_reg or not imm_fine:
@@ -217,8 +221,9 @@
def make_sure_var_in_reg(self, v, forbidden_vars=[], selected_reg=None,
imm_fine=True, need_lower_byte=False):
- """ Make sure that a variable v, which is already allocated
- is in some register
+ """ Make sure that an already-allocated variable v is in some
+ register. Return the register. See 'return_constant' and
+ 'force_allocate_reg' for the meaning of the optional arguments.
"""
if isinstance(v, Const):
return self.return_constant(v, forbidden_vars, selected_reg,
@@ -247,8 +252,9 @@
self.assembler.regalloc_mov(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
+ """ Make sure that result is in the same register as v.
+ The variable v is copied away if it's further used. The meaning
+ of 'forbidden_vars' is the same as in 'force_allocate_reg'.
"""
if isinstance(v, Const):
loc = self.make_sure_var_in_reg(v, forbidden_vars,
@@ -281,7 +287,10 @@
# otherwise it's clean
def before_call(self, force_store=[]):
- """ Sync registers before call, ones that we need
+ """ Spill registers before a call, as described by
+ 'self.save_around_call_regs'. Registers are not spilled if
+ they don't survive past the current operation, unless they
+ are listed in 'force_store'.
"""
for v, reg in self.reg_bindings.items():
if v not in force_store and self.longevity[v][1] <= self.position:
@@ -297,10 +306,11 @@
self.free_regs.append(reg)
def after_call(self, v):
- """ Adjust registers according to a call result
+ """ Adjust registers according to the result of the call,
+ which is in variable v.
"""
if v is not None:
- r = self.result_stored_in_reg(v)
+ r = self.call_result_location(v)
self.reg_bindings[v] = r
self.free_regs = [fr for fr in self.free_regs if fr is not r]
@@ -311,8 +321,8 @@
"""
raise NotImplementedError("Abstract")
- def result_stored_in_reg(self, v):
+ def call_result_location(self, v):
""" Platform specific - tell where the result of a call will
- be stored by a cpu, according to variable type
+ be stored by the cpu, according to the variable type
"""
raise NotImplementedError("Abstract")
Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py
==============================================================================
--- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original)
+++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 18:59:50 2009
@@ -3,10 +3,6 @@
from pypy.jit.backend.llsupport.regalloc import StackManager
from pypy.jit.backend.llsupport.regalloc import RegisterManager as BaseRegMan
-class RegisterManager(BaseRegMan):
- def convert_to_imm(self, v):
- return v
-
def newboxes(*values):
return [BoxInt(v) for v in values]
@@ -25,6 +21,11 @@
r0, r1, r2, r3 = [FakeReg() for _ in range(4)]
regs = [r0, r1, r2, r3]
+class RegisterManager(BaseRegMan):
+ all_regs = regs
+ def convert_to_imm(self, v):
+ return v
+
class TStackManager(StackManager):
def stack_pos(self, i):
return i
@@ -40,7 +41,7 @@
def test_freeing_vars(self):
b0, b1, b2 = newboxes(0, 0, 0)
longevity = {b0: (0, 1), b1: (0, 2), b2: (0, 2)}
- rm = RegisterManager(regs, longevity)
+ rm = RegisterManager(longevity)
rm.next_instruction()
for b in b0, b1, b2:
rm.try_allocate_reg(b)
@@ -65,7 +66,7 @@
def test_register_exhaustion(self):
boxes, longevity = boxes_and_longevity(5)
- rm = RegisterManager(regs, longevity)
+ rm = RegisterManager(longevity)
rm.next_instruction()
for b in boxes[:len(regs)]:
assert rm.try_allocate_reg(b)
@@ -79,7 +80,7 @@
class XRegisterManager(RegisterManager):
no_lower_byte_regs = [r2, r3]
- rm = XRegisterManager(regs, longevity)
+ rm = XRegisterManager(longevity)
rm.next_instruction()
loc0 = rm.try_allocate_reg(b0, need_lower_byte=True)
assert loc0 not in XRegisterManager.no_lower_byte_regs
@@ -93,7 +94,7 @@
def test_specific_register(self):
boxes, longevity = boxes_and_longevity(5)
- rm = RegisterManager(regs, longevity)
+ rm = RegisterManager(longevity)
rm.next_instruction()
loc = rm.try_allocate_reg(boxes[0], selected_reg=r1)
assert loc is r1
@@ -114,7 +115,7 @@
class XRegisterManager(RegisterManager):
no_lower_byte_regs = [r2, r3]
- rm = XRegisterManager(regs, longevity,
+ rm = XRegisterManager(longevity,
stack_manager=sm,
assembler=MockAsm())
rm.next_instruction()
@@ -140,7 +141,7 @@
def test_make_sure_var_in_reg(self):
boxes, longevity = boxes_and_longevity(5)
sm = TStackManager()
- rm = RegisterManager(regs, longevity, stack_manager=sm,
+ rm = RegisterManager(longevity, stack_manager=sm,
assembler=MockAsm())
rm.next_instruction()
# allocate a stack position
@@ -156,7 +157,7 @@
longevity = {b0: (0, 1), b1: (1, 3)}
sm = TStackManager()
asm = MockAsm()
- rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm)
+ rm = RegisterManager(longevity, stack_manager=sm, assembler=asm)
rm.next_instruction()
# first path, var is already in reg and dies
loc0 = rm.force_allocate_reg(b0)
@@ -172,7 +173,7 @@
longevity = {b0: (0, 2), b1: (1, 3)}
sm = TStackManager()
asm = MockAsm()
- rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm)
+ rm = RegisterManager(longevity, stack_manager=sm, assembler=asm)
rm.next_instruction()
loc0 = rm.force_allocate_reg(b0)
rm._check_invariants()
@@ -188,7 +189,7 @@
longevity = {b0: (0, 2), b1: (0, 2), b3: (0, 2), b2: (0, 2), b4: (1, 3)}
sm = TStackManager()
asm = MockAsm()
- rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm)
+ rm = RegisterManager(longevity, stack_manager=sm, assembler=asm)
rm.next_instruction()
for b in b0, b1, b2, b3:
rm.force_allocate_reg(b)
@@ -204,7 +205,7 @@
longevity = {b0: (0, 1), b1: (0, 1)}
sm = TStackManager()
asm = MockAsm()
- rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm)
+ rm = RegisterManager(longevity, stack_manager=sm, assembler=asm)
rm.next_instruction()
sm.loc(b0)
rm.force_result_in_reg(b1, b0)
@@ -219,7 +220,7 @@
asm = MockAsm()
boxes, longevity = boxes_and_longevity(5)
sm = TStackManager()
- rm = RegisterManager(regs, longevity, assembler=asm,
+ rm = RegisterManager(longevity, assembler=asm,
stack_manager=sm)
rm.next_instruction()
loc = rm.return_constant(ConstInt(0), imm_fine=False)
@@ -241,7 +242,7 @@
boxes, longevity = boxes_and_longevity(2)
sm = TStackManager()
asm = MockAsm()
- rm = RegisterManager(regs, longevity, stack_manager=sm,
+ rm = RegisterManager(longevity, stack_manager=sm,
assembler=asm)
rm.next_instruction()
c = ConstInt(0)
@@ -249,7 +250,7 @@
rm._check_invariants()
def test_loc_of_const(self):
- rm = RegisterManager(regs, {})
+ rm = RegisterManager({})
rm.next_instruction()
assert isinstance(rm.loc(ConstInt(1)), ConstInt)
@@ -257,13 +258,13 @@
class XRegisterManager(RegisterManager):
save_around_call_regs = [r1, r2]
- def result_stored_in_reg(self, v):
+ def call_result_location(self, v):
return r1
sm = TStackManager()
asm = MockAsm()
boxes, longevity = boxes_and_longevity(5)
- rm = XRegisterManager(regs, longevity, stack_manager=sm,
+ rm = XRegisterManager(longevity, stack_manager=sm,
assembler=asm)
for b in boxes[:-1]:
rm.force_allocate_reg(b)
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 18:59:50 2009
@@ -7,8 +7,7 @@
from pypy.rpython.lltypesystem.rclass import OBJECT
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)
+from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, 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 *
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 18:59:50 2009
@@ -17,25 +17,15 @@
from pypy.jit.backend.llsupport.regalloc import StackManager, RegisterManager,\
TempBox
-REGS = [eax, ecx, edx, ebx, esi, edi]
WORD = 4
-class checkdict(dict):
- def __setitem__(self, key, value):
- assert isinstance(key, Box)
- dict.__setitem__(self, key, value)
-
-def newcheckdict():
- if we_are_translated():
- return {}
- return checkdict()
-
class X86RegisterManager(RegisterManager):
+ all_regs = [eax, ecx, edx, ebx, esi, edi]
no_lower_byte_regs = [esi, edi]
save_around_call_regs = [eax, edx, ecx]
- def result_stored_in_reg(self, v):
+ def call_result_location(self, v):
return eax
def convert_to_imm(self, c):
@@ -71,29 +61,25 @@
# to be read/used by the assembler too
self.jump_target = None
- def prepare_loop(self, inputargs, operations):
+ def _prepare(self, inputargs, operations):
self.sm = X86StackManager()
cpu = self.assembler.cpu
cpu.gc_ll_descr.rewrite_assembler(cpu, operations)
# compute longevity of variables
longevity = self._compute_vars_longevity(inputargs, operations)
- self.rm = X86RegisterManager(REGS, longevity,
+ self.rm = X86RegisterManager(longevity,
stack_manager = self.sm,
assembler = self.assembler)
+
+ def prepare_loop(self, inputargs, operations):
+ self._prepare(inputargs, operations)
jump = operations[-1]
loop_consts = self._compute_loop_consts(inputargs, jump)
self.loop_consts = loop_consts
return self._process_inputargs(inputargs)
def prepare_bridge(self, prev_stack_depth, inputargs, arglocs, operations):
- self.sm = X86StackManager()
- cpu = self.assembler.cpu
- cpu.gc_ll_descr.rewrite_assembler(cpu, operations)
- # compute longevity of variables
- longevity = self._compute_vars_longevity(inputargs, operations)
- self.rm = X86RegisterManager(REGS, longevity,
- stack_manager = self.sm,
- assembler = self.assembler)
+ self._prepare(inputargs, operations)
self.loop_consts = {}
self._update_bindings(arglocs, inputargs)
self.sm.stack_depth = prev_stack_depth
@@ -102,10 +88,11 @@
# XXX we can sort out here by longevity if we need something
# more optimal
locs = [None] * len(inputargs)
- # Don't use REGS[0] for passing arguments around a loop.
+ # Don't use all_regs[0] for passing arguments around a loop.
# Must be kept in sync with consider_jump().
+ # XXX this should probably go to llsupport/regalloc.py
tmpreg = self.rm.free_regs.pop(0)
- assert tmpreg == REGS[0]
+ assert tmpreg == X86RegisterManager.all_regs[0]
for i in range(len(inputargs)):
arg = inputargs[i]
assert not isinstance(arg, Const)
@@ -151,7 +138,7 @@
else:
self.sm.stack_bindings[v] = loc
self.rm.free_regs = []
- for reg in REGS:
+ for reg in X86RegisterManager.all_regs:
if reg not in used:
self.rm.free_regs.append(reg)
self.rm._check_invariants()
@@ -169,7 +156,7 @@
def perform_with_guard(self, op, guard_op, arglocs, result_loc):
faillocs = self.locs_for_fail(guard_op)
- self.rm.next_instruction()
+ self.rm.position += 1
self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs,
arglocs, result_loc,
self.sm.stack_depth)
@@ -427,7 +414,7 @@
# See remember_young_pointer() in rpython/memory/gc/generation.py.
for v, reg in self.rm.reg_bindings.items():
if ((reg is eax or reg is ecx or reg is edx)
- and self.rm.longevity[v][1] > self.rm.position
+ and self.rm.stays_alive(v)
and reg not in arglocs[3:]):
arglocs.append(reg)
self.PerformDiscard(op, arglocs)
@@ -639,9 +626,10 @@
assert self.jump_target is None
self.jump_target = op.jump_target
arglocs = assembler.target_arglocs(self.jump_target)
- # compute 'tmploc' to be REGS[0] by spilling what is there
+ # compute 'tmploc' to be all_regs[0] by spilling what is there
box = TempBox()
- tmploc = self.rm.force_allocate_reg(box, [], selected_reg=REGS[0])
+ tmpreg = X86RegisterManager.all_regs[0]
+ tmploc = self.rm.force_allocate_reg(box, [], selected_reg=tmpreg)
src_locations = [self.rm.loc(arg) for arg in op.args]
dst_locations = arglocs
assert tmploc not in dst_locations
Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py
==============================================================================
--- pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py (original)
+++ pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py Mon Sep 28 18:59:50 2009
@@ -8,7 +8,7 @@
from pypy.jit.metainterp.resoperation import rop, ResOperation
from pypy.jit.backend.llsupport.descr import GcCache
from pypy.jit.backend.x86.runner import CPU
-from pypy.jit.backend.x86.regalloc import RegAlloc, REGS, WORD
+from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, X86RegisterManager
from pypy.jit.metainterp.test.oparser import parse
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.annlowlevel import llhelper
@@ -58,7 +58,7 @@
def fill_regs(regalloc, cls=BoxInt):
allboxes = []
- for reg in REGS:
+ for reg in X86RegisterManager.all_regs:
box = cls()
allboxes.append(box)
regalloc.reg_bindings[box] = reg
@@ -70,95 +70,6 @@
def _compute_next_usage(self, v, _):
return -1
-class TestRegallocDirect(object):
-
- def setup_class(cls):
- py.test.skip("look and eventually copy, but rather remove")
-
- def test_make_sure_var_in_reg(self):
- regalloc = RegAlloc(MockAssembler())
- boxes = fill_regs(regalloc)
- box = boxes[-1]
- oldloc = regalloc.loc(box)
- newloc = regalloc.make_sure_var_in_reg(box, [])
- assert oldloc is newloc
- regalloc._check_invariants()
-
- def test_make_sure_var_in_reg_need_lower_byte(self):
- regalloc = RegAlloc(MockAssembler())
- box = BoxInt()
- regalloc.reg_bindings[box] = edi
- regalloc.free_regs = [eax, ecx, edx, ebx, esi]
- loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True)
- assert loc is not edi and loc is not esi
- assert len(regalloc.assembler.loads) == 1
- regalloc._check_invariants()
-
- def test_make_sure_var_in_reg_need_lower_byte_no_free_reg(self):
- regalloc = RegAllocForTests(MockAssembler())
- box = BoxInt()
- regalloc.reg_bindings = {BoxInt(): eax, BoxInt(): ebx, BoxInt(): ecx,
- BoxInt(): edx, box:edi}
- regalloc.free_regs = [esi]
- regalloc._check_invariants()
- loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True)
- assert loc is not edi and loc is not esi
- assert len(regalloc.assembler.loads) == 1
- regalloc._check_invariants()
-
- def test_make_sure_var_in_reg_mem(self):
- regalloc = RegAlloc(MockAssembler())
- regalloc.free_regs = REGS[:]
- box = BoxInt()
- regalloc.stack_loc(box)
- loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True)
- assert loc is not edi and loc is not esi
- assert len(regalloc.assembler.loads) == 1
- regalloc._check_invariants()
-
- def test_registers_around_call(self):
- cpu = CPU(None, None)
- regalloc = RegAlloc(MockAssembler(cpu))
- boxes = fill_regs(regalloc)
- TP = lltype.FuncType([], lltype.Void)
- calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT)
- regalloc._check_invariants()
- regalloc.longevity = dict.fromkeys(boxes, (0, 1))
- box = boxes[0]
- regalloc.position = 0
- regalloc.consider_call(ResOperation(rop.CALL, [box], None, calldescr),
- None)
- assert len(regalloc.assembler.stores) == 3
- regalloc._check_invariants()
-
- def test_registers_around_newstr(self):
- cpu = CPU(None, None)
- regalloc = RegAllocForTests(MockAssembler(cpu))
- boxes = fill_regs(regalloc)
- regalloc._check_invariants()
- regalloc.longevity = dict.fromkeys(boxes, (0, 1))
- box = boxes[-1]
- regalloc.position = 0
- resbox = BoxInt()
- regalloc.longevity[resbox] = (1, 1)
- regalloc.consider_newstr(ResOperation(rop.NEWSTR, [box], resbox,
- None), None)
- regalloc._check_invariants()
-
- def test_move_away_does_not_spill(self):
- regalloc = RegAlloc(MockAssembler())
- regalloc.position = 0
- resbox = BoxInt()
- box = BoxInt()
- regalloc.reg_bindings = {box: eax}
- regalloc.free_regs = [ebx, ecx, edx, esi, edi]
- regalloc._check_invariants()
- regalloc.longevity = {resbox: (0, 1), box: (0, 1)}
- regalloc.consider_int_add(ResOperation(rop.INT_ADD, [box, ConstInt(1)],
- resbox), None)
- regalloc._check_invariants()
- assert len(regalloc.assembler.stores) == 0
-
class BaseTestRegalloc(object):
cpu = CPU(None, None)
More information about the Pypy-commit
mailing list