[pypy-svn] r62285 - in pypy/branch/pyjitpl5/pypy/jit/backend/x86: . test
fijal at codespeak.net
fijal at codespeak.net
Sun Mar 1 11:14:14 CET 2009
Author: fijal
Date: Sun Mar 1 11:14:13 2009
New Revision: 62285
Modified:
pypy/branch/pyjitpl5/pypy/jit/backend/x86/assembler.py
pypy/branch/pyjitpl5/pypy/jit/backend/x86/regalloc.py
pypy/branch/pyjitpl5/pypy/jit/backend/x86/runner.py
pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_exception.py
pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_regalloc.py
pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_runner.py
pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_tlc.py
pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_zrpy_tl.py
Log:
progress with x86 backend. More tests and pass more stuff
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/assembler.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/assembler.py Sun Mar 1 11:14:13 2009
@@ -26,6 +26,9 @@
self.mc2 = None
self.rtyper = cpu.rtyper
self.malloc_func_addr = 0
+ self._exception_data = lltype.malloc(rffi.CArray(lltype.Signed), 2,
+ zero=True, flavor='raw')
+ self._exception_addr = cpu.cast_ptr_to_int(self._exception_data)
def make_sure_mc_exists(self):
if self.mc is None:
@@ -36,7 +39,8 @@
self.generic_return_addr = self.assemble_generic_return()
# the address of the function called by 'new': directly use
# Boehm's GC_malloc function.
- self.malloc_func_addr = gc_malloc_fnaddr()
+ if self.malloc_func_addr == 0:
+ self.malloc_func_addr = gc_malloc_fnaddr()
def assemble(self, operations, guard_op, verbose=False):
self.verbose = verbose
@@ -178,15 +182,21 @@
getattr(self.mc, asmop)(arglocs[0], arglocs[1])
return genop_binary
- def _cmpop(cond):
+ def _cmpop(cond, rev_cond):
def genop_cmp(self, op, arglocs, result_loc):
- self.mc.CMP(arglocs[0], arglocs[1])
- self.mc.MOV(result_loc, imm8(0))
- getattr(self.mc, 'SET' + cond)(lower_byte(result_loc))
+ if isinstance(op.args[0], Const):
+ self.mc.CMP(arglocs[1], arglocs[0])
+ self.mc.MOV(result_loc, imm8(0))
+ getattr(self.mc, 'SET' + rev_cond)(lower_byte(result_loc))
+ else:
+ self.mc.CMP(arglocs[0], arglocs[1])
+ self.mc.MOV(result_loc, imm8(0))
+ getattr(self.mc, 'SET' + cond)(lower_byte(result_loc))
return genop_cmp
def call(self, addr, args, res):
- for arg in args:
+ for i in range(len(args)):
+ arg = args[i]
self.mc.PUSH(arg)
self.mc.CALL(rel32(addr))
self.mc.ADD(esp, imm(len(args) * WORD))
@@ -198,12 +208,12 @@
genop_int_mul = _binaryop("IMUL", True)
genop_int_and = _binaryop("AND", True)
- genop_int_lt = _cmpop("L")
- genop_int_le = _cmpop("LE")
- genop_int_eq = _cmpop("E")
- genop_int_ne = _cmpop("NE")
- genop_int_gt = _cmpop("G")
- genop_int_ge = _cmpop("GE")
+ genop_int_lt = _cmpop("L", "G")
+ genop_int_le = _cmpop("LE", "GE")
+ genop_int_eq = _cmpop("E", "NE")
+ genop_int_ne = _cmpop("NE", "E")
+ genop_int_gt = _cmpop("G", "L")
+ genop_int_ge = _cmpop("GE", "LE")
# for now all chars are being considered ints, although we should make
# a difference at some point
@@ -273,24 +283,43 @@
loc_size = arglocs[0]
self.call(self.malloc_func_addr, [loc_size], eax)
- def genop_newstr(self, op, arglocs, result_loc):
+ def genop_malloc_varsize(self, op, arglocs, result_loc):
loc_size = arglocs[0]
self.call(self.malloc_func_addr, [loc_size], eax)
def genop_getfield_gc(self, op, arglocs, resloc):
- base_loc, ofs_loc = arglocs
- #if isinstance(op.args[0], Constant):
- # x, _ = self.cpu.get_value_as_int(op.args[0].value)
- # pos = mem(None, offset + x)
- #else:
- # ...
- self.mc.MOV(resloc, addr_add(base_loc, ofs_loc))
+ base_loc, ofs_loc, size_loc = arglocs
+ size = size_loc.value
+ if size == 1:
+ self.mc.MOVZX(resloc, addr8_add(base_loc, ofs_loc))
+ elif size == WORD:
+ self.mc.MOV(resloc, addr_add(base_loc, ofs_loc))
+ else:
+ raise NotImplementedError("getfield size = %d" % size)
+
+ def genop_getarrayitem_gc(self, op, arglocs, resloc):
+ base_loc, ofs_loc, scale, ofs = arglocs
+ self.mc.MOV(resloc, addr_add(base_loc, ofs_loc, ofs.value, scale.value))
genop_getfield_raw = genop_getfield_gc
def genop_setfield_gc(self, op, arglocs):
- base_loc, ofs_loc, value_loc = arglocs
- self.mc.MOV(addr_add(base_loc, ofs_loc), value_loc)
+ base_loc, ofs_loc, size_loc, value_loc = arglocs
+ size = size_loc.value
+ if size == WORD:
+ self.mc.MOV(addr_add(base_loc, ofs_loc), value_loc)
+ elif size == 2:
+ raise NotImplementedError("shorts and friends")
+ self.mc.MOV(addr16_add(base_loc, ofs_loc), lower_2_bytes(value_loc))
+ elif size == 1:
+ self.mc.MOV(addr8_add(base_loc, ofs_loc), lower_byte(value_loc))
+ else:
+ raise NotImplementedError("Addr size %d" % size)
+
+ def genop_setarrayitem_gc(self, op, arglocs):
+ base_loc, ofs_loc, value_loc, scale_loc, baseofs = arglocs
+ self.mc.MOV(addr_add(base_loc, ofs_loc, baseofs.value, scale_loc.value),
+ value_loc)
def genop_strsetitem(self, op, arglocs):
base_loc, ofs_loc, val_loc = arglocs
@@ -311,21 +340,8 @@
self.mc.MOVZX(resloc, addr8_add(base_loc, ofs_loc, basesize))
def genop_merge_point(self, op, locs):
- # encode the current machine code position and the current stack
- # position of the live values into a flat array of c_long's.
- # XXX update comment
- # we load constants into arguments
op.position = self.mc.tell()
op.comeback_bootstrap_addr = self.assemble_comeback_bootstrap(op)
- #nb_args = len(op.args)
- #array_type = ctypes.c_long * (2 + nb_args)
- #label = array_type()
- #label[0] = nb_args
- #label[1] = self.mc.tell()
- #for i in range(nb_args):
- # v = op.args[i]
- # label[2 + i] = self.stack_positions[v]
- #op._asm_label = label
genop_catch = genop_merge_point
@@ -348,7 +364,20 @@
self.implement_guard(op, self.mc.JZ, locs[1:])
def genop_guard_no_exception(self, op, locs):
- pass # XXX # exception handling
+ loc = locs[0]
+ self.mc.MOV(loc, heap(self._exception_addr))
+ self.mc.TEST(loc, loc)
+ self.implement_guard(op, self.mc.JNZ, locs[1:])
+
+ def genop_guard_exception(self, op, locs, resloc):
+ loc = locs[0]
+ loc1 = locs[1]
+ self.mc.MOV(loc1, heap(self._exception_addr))
+ self.mc.CMP(loc1, loc)
+ self.implement_guard(op, self.mc.JNE, locs[2:])
+ if resloc is not None:
+ self.mc.MOV(resloc, addr_add(imm(self._exception_addr), imm(WORD)))
+ self.mc.MOV(heap(self._exception_addr), imm(0))
def genop_guard_false(self, op, locs):
loc = locs[0]
@@ -508,29 +537,44 @@
genop_discard_dict['call_void'] = Assembler386.genop_call_void
-def addr_add(reg_or_imm1, reg_or_imm2, offset=0):
+def addr_add(reg_or_imm1, reg_or_imm2, offset=0, scale=0):
+ if isinstance(reg_or_imm1, IMM32):
+ if isinstance(reg_or_imm2, IMM32):
+ return heap(reg_or_imm1.value + offset +
+ (reg_or_imm2.value << scale))
+ else:
+ return mem(reg_or_imm2, (reg_or_imm1.value << scale) + offset)
+ else:
+ if isinstance(reg_or_imm2, IMM32):
+ return mem(reg_or_imm1, offset + (reg_or_imm2.value << scale))
+ else:
+ return memSIB(reg_or_imm1, reg_or_imm2, scale, offset)
+
+def addr8_add(reg_or_imm1, reg_or_imm2, offset=0, scale=0):
if isinstance(reg_or_imm1, IMM32):
if isinstance(reg_or_imm2, IMM32):
- return heap(reg_or_imm1.value + offset + reg_or_imm2.value)
+ return heap8(reg_or_imm1.value + (offset << scale) +
+ reg_or_imm2.value)
else:
- return mem(reg_or_imm2, reg_or_imm1.value + offset)
+ return mem8(reg_or_imm2, reg_or_imm1.value + (offset << scale))
else:
if isinstance(reg_or_imm2, IMM32):
- return mem(reg_or_imm1, offset + reg_or_imm2.value)
+ return mem8(reg_or_imm1, (offset << scale) + reg_or_imm2.value)
else:
- return memSIB(reg_or_imm1, reg_or_imm2, 0, offset)
+ return memSIB8(reg_or_imm1, reg_or_imm2, scale, offset)
-def addr8_add(reg_or_imm1, reg_or_imm2, offset=0):
+def addr16_add(reg_or_imm1, reg_or_imm2, offset=0, scale=0):
if isinstance(reg_or_imm1, IMM32):
if isinstance(reg_or_imm2, IMM32):
- return heap8(reg_or_imm1.value + offset + reg_or_imm2.value)
+ return heap16(reg_or_imm1.value + (offset << scale) +
+ reg_or_imm2.value)
else:
- return mem8(reg_or_imm2, reg_or_imm1.value + offset)
+ return mem16(reg_or_imm2, reg_or_imm1.value + (offset << scale))
else:
if isinstance(reg_or_imm2, IMM32):
- return mem8(reg_or_imm1, offset + reg_or_imm2.value)
+ return mem16(reg_or_imm1, (offset << scale) + reg_or_imm2.value)
else:
- return memSIB8(reg_or_imm1, reg_or_imm2, 0, offset)
+ return memSIB16(reg_or_imm1, reg_or_imm2, scale, offset)
def addr_add_const(reg_or_imm1, offset):
if isinstance(reg_or_imm1, IMM32):
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/regalloc.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/regalloc.py Sun Mar 1 11:14:13 2009
@@ -9,6 +9,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.unroll import unrolling_iterable
from pypy.jit.backend.x86 import symbolic
+from pypy.jit.metainterp.heaptracker import operations_without_side_effects
# esi edi and ebp can be added to this list, provided they're correctly
# saved and restored
@@ -200,8 +201,19 @@
if op.opname.startswith('#'):
continue
self.position = i
- new_ops += opdict[op.opname](self, op)
- self._check_invariants()
+ canfold = True
+ if op.opname in operations_without_side_effects:
+ for result in op.results:
+ if result in self.longevity:
+ # means it's never used
+ canfold = False
+ break
+ else:
+ canfold = False
+ if not canfold:
+ new_ops += opdict[op.opname](self, op)
+ self.eventually_free_vars(op.results)
+ self._check_invariants()
return new_ops
def _compute_vars_longevity(self, operations):
@@ -266,10 +278,13 @@
def return_constant(self, v, forbidden_vars, selected_reg=None,
imm_fine=True):
assert isinstance(v, Const)
- if selected_reg:
+ if selected_reg or not imm_fine:
# this means we cannot have it in IMM, eh
if selected_reg in self.free_regs:
return selected_reg, [Load(v, convert_to_imm(v), selected_reg)]
+ if selected_reg is None and self.free_regs:
+ loc = self.free_regs.pop()
+ return loc, [Load(v, convert_to_imm(v), loc)]
v_to_spill = self.pick_variable_to_spill(v, forbidden_vars, selected_reg)
if v_to_spill not in self.stack_bindings or v_to_spill in self.dirty_stack:
newloc = self.stack_loc(v_to_spill)
@@ -314,6 +329,8 @@
locs = []
for arg in guard_op.liveboxes:
if isinstance(arg, Box):
+ if arg not in self.stack_bindings:
+ self.dirty_stack[arg] = True
stacklocs.append(self.stack_loc(arg).position)
locs.append(self.loc(arg))
if not we_are_translated():
@@ -353,7 +370,7 @@
def eventually_free_var(self, v):
if isinstance(v, Const) or v not in self.reg_bindings:
return
- if self.longevity[v][1] <= self.position:
+ 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]
@@ -401,10 +418,19 @@
""" 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, ops = self.make_sure_var_in_reg(v, forbidden_vars,
+ selected_reg,
+ 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, ops
ops = []
if v in self.reg_bindings and selected_reg:
_, ops = self.make_sure_var_in_reg(v, forbidden_vars, selected_reg)
elif v not in self.reg_bindings:
+ assert v not in self.dirty_stack
prev_loc = self.stack_bindings[v]
loc, o = self.force_allocate_reg(v, forbidden_vars, selected_reg)
ops += o
@@ -438,6 +464,8 @@
reg = self.try_allocate_reg(arg)
if reg:
locs[i] = reg
+ # it's better to say here that we're always in dirty stack
+ # than worry at the jump point
self.dirty_stack[arg] = True
else:
locs[i] = loc
@@ -469,13 +497,32 @@
self.eventually_free_vars(op.liveboxes)
return ops + [PerformDiscard(op, [loc] + locs)]
+ consider_guard_true = consider_guard
+ consider_guard_false = consider_guard
+
def consider_guard_no_exception(self, op):
+ box = TempBox()
+ loc, ops = self.force_allocate_reg(box, [])
locs = self._locs_from_liveboxes(op)
self.eventually_free_vars(op.liveboxes)
- return []
+ self.eventually_free_var(box)
+ return ops + [PerformDiscard(op, [loc] + locs)]
- consider_guard_true = consider_guard
- consider_guard_false = consider_guard
+ def consider_guard_exception(self, op):
+ loc, ops = self.make_sure_var_in_reg(op.args[0], [])
+ box = TempBox()
+ loc1, ops1 = self.force_allocate_reg(box, op.args)
+ if op.results[0] in self.longevity:
+ # this means, is it ever used
+ resloc, ops2 = self.force_allocate_reg(op.results[0],
+ op.args + [box])
+ else:
+ resloc, ops2 = None, []
+ locs = self._locs_from_liveboxes(op)
+ self.eventually_free_vars(op.liveboxes)
+ self.eventually_free_vars(op.args)
+ self.eventually_free_var(box)
+ return ops + ops1 + ops2 + [Perform(op, [loc, loc1] + locs, resloc)]
#def consider_guard2(self, op):
# loc1, ops1 = self.make_sure_var_in_reg(op.args[0], [])
@@ -539,6 +586,11 @@
consider_int_sub = consider_binop
consider_int_and = consider_binop
+ def consider_binop_ovf(self, op):
+ xxx
+
+ consider_int_mul_ovf = consider_binop_ovf
+
def consider_int_neg(self, op):
res, ops = self.force_result_in_reg(op.results[0], op.args[0], [])
return ops + [Perform(op, [res], res)]
@@ -597,16 +649,29 @@
consider_int_ne = consider_compop
consider_int_eq = consider_compop
+ def sync_var(self, v):
+ ops = []
+ if v in self.dirty_stack or v not in self.stack_bindings:
+ reg = self.reg_bindings[v]
+ ops.append(Store(v, reg, self.stack_loc(v)))
+ try:
+ del self.dirty_stack[v]
+ except KeyError:
+ pass
+ # otherwise it's clean
+ return ops
+
+ def sync_var_if_survives(self, v):
+ if self.longevity[v][1] > self.position:
+ return self.sync_var(v)
+ return []
+
def _call(self, op, arglocs, force_store=[]):
ops = []
# we need to store all variables which are now in registers
for v, reg in self.reg_bindings.items():
if self.longevity[v][1] > self.position or v in force_store:
- ops.append(Store(v, reg, self.stack_loc(v)))
- try:
- del self.dirty_stack[v]
- except KeyError:
- pass
+ ops += self.sync_var(v)
self.reg_bindings = newcheckdict()
if op.results:
self.reg_bindings = {op.results[0]: eax}
@@ -632,18 +697,45 @@
return self._call(op, [self.loc(arg) for arg in op.args])
def consider_newstr(self, op):
- ops = self._call(op, [self.loc(arg) for arg in op.args],
- [op.args[0]])
- loc, ops1 = self.make_sure_var_in_reg(op.args[0], [])
- assert self.loc(op.results[0]) == eax
- # now we have to reload length to some reasonable place
- # XXX hardcoded length offset
- self.eventually_free_var(op.args[0])
ofs = symbolic.get_field_token(rstr.STR, 'chars')[0]
- res = ops + ops1 + [PerformDiscard(ResOperation('setfield_gc', [], []),
- [eax, imm(ofs), loc])]
+ ofs_items = symbolic.get_field_token(rstr.STR.chars, 'items')[0]
+ ofs_length = symbolic.get_field_token(rstr.STR.chars, 'length')[0]
+ return self._malloc_varsize(ofs, ofs_items, ofs_length, 0, op.args[0],
+ op.results[0])
+
+ def _malloc_varsize(self, ofs, ofs_items, ofs_length, size, v, res_v):
+ if isinstance(v, Box):
+ loc, ops0 = self.make_sure_var_in_reg(v, [v])
+ ops0 += self.sync_var(v)
+ if size != 0:
+ # XXX lshift?
+ ops0.append(Perform(ResOperation('int_mul', [], []),
+ [loc, imm(1 << size)], loc))
+ ops0.append(Perform(ResOperation('int_add', [], []),
+ [loc, imm(ofs + ofs_items)], loc))
+ else:
+ ops0 = []
+ loc = imm(ofs + ofs_items + (v.getint() << size))
+ ops = self._call(ResOperation('malloc_varsize', [v], [res_v])
+ , [loc], [v])
+ loc, ops1 = self.make_sure_var_in_reg(v, [res_v])
+ assert self.loc(res_v) == eax
+ # now we have to reload length to some reasonable place
+ self.eventually_free_var(v)
+ res = (ops0 + ops + ops1 +
+ [PerformDiscard(ResOperation('setfield_gc', [], []),
+ [eax, imm(ofs + ofs_length), imm(WORD), loc])])
return res
+
+ def consider_new_array(self, op):
+ arraydescr = op.args[0].getint()
+ assert arraydescr
+ size_of_field = arraydescr >> 16
+ ofs = arraydescr & 0xffff
+ return self._malloc_varsize(0, ofs, 0, size_of_field, op.args[1],
+ op.results[0])
+
def consider_oononnull(self, op):
argloc = self.loc(op.args[0])
self.eventually_free_var(op.args[0])
@@ -651,27 +743,69 @@
assert reg
return [Perform(op, [argloc], reg)]
+ def _unpack_fielddescr(self, fielddescr):
+ if fielddescr < 0:
+ fielddescr = -fielddescr
+ ofs_loc = imm(fielddescr & 0xffff)
+ size_loc = imm(fielddescr >> 16)
+ return ofs_loc, size_loc
+
def consider_setfield_gc(self, op):
base_loc, ops0 = self.make_sure_var_in_reg(op.args[0], op.args)
- ofs_loc, ops1 = self.make_sure_var_in_reg(op.args[1], op.args)
+ ofs_loc, size_loc = self._unpack_fielddescr(op.args[1].getint())
+ value_loc, ops2 = self.make_sure_var_in_reg(op.args[2], op.args)
+ self.eventually_free_vars([op.args[0], op.args[1], op.args[2]])
+ return (ops0 + ops2 +
+ [PerformDiscard(op, [base_loc, ofs_loc, size_loc, value_loc])])
+
+ def consider_strsetitem(self, op):
+ base_loc, ops0 = self.make_sure_var_in_reg(op.args[0], op.args)
+ ofs_loc, ops1 = self.make_sure_var_in_reg(op.args[1], op.args)
value_loc, ops2 = self.make_sure_var_in_reg(op.args[2], op.args)
self.eventually_free_vars([op.args[0], op.args[1], op.args[2]])
return (ops0 + ops1 + ops2 +
[PerformDiscard(op, [base_loc, ofs_loc, value_loc])])
- # XXX location is a bit smaller, but we don't care too much
- consider_strsetitem = consider_setfield_gc
+ def consider_setarrayitem_gc(self, op):
+ arraydescr = op.args[1].getint()
+ assert arraydescr
+ scale = arraydescr >> 16
+ ofs = arraydescr & 0xffff
+ assert scale == 2
+ args = [op.args[0], op.args[2], op.args[3]]
+ base_loc, ops0 = self.make_sure_var_in_reg(op.args[0], args)
+ ofs_loc, ops1 = self.make_sure_var_in_reg(op.args[2], args)
+ value_loc, ops2 = self.make_sure_var_in_reg(op.args[3], args)
+ self.eventually_free_vars(op.args)
+ return (ops0 + ops2 + ops1 +
+ [PerformDiscard(op, [base_loc, ofs_loc, value_loc,
+ imm(scale), imm(ofs)])])
def consider_getfield_gc(self, op):
+ ofs_loc, size_loc = self._unpack_fielddescr(op.args[1].getint())
base_loc, ops0 = self.make_sure_var_in_reg(op.args[0], op.args)
- ofs_loc, ops1 = self.make_sure_var_in_reg(op.args[1], op.args)
self.eventually_free_vars([op.args[0], op.args[1]])
result_loc, more_ops = self.force_allocate_reg(op.results[0], [])
+ return (ops0 + more_ops +
+ [Perform(op, [base_loc, ofs_loc, size_loc], result_loc)])
+
+ def consider_getarrayitem_gc(self, op):
+ arraydescr = op.args[1].getint()
+ assert arraydescr
+ scale = arraydescr >> 16
+ ofs = arraydescr & 0xffff
+ assert scale == 2
+ args = [op.args[0], op.args[2]]
+ base_loc, ops0 = self.make_sure_var_in_reg(op.args[0], args)
+ ofs_loc, ops1 = self.make_sure_var_in_reg(op.args[2], args)
+ self.eventually_free_vars(op.args)
+ result_loc, more_ops = self.force_allocate_reg(op.results[0], [])
return (ops0 + ops1 + more_ops +
- [Perform(op, [base_loc, ofs_loc], result_loc)])
+ [Perform(op, [base_loc, ofs_loc, imm(scale), imm(ofs)],
+ result_loc)])
consider_getfield_raw = consider_getfield_gc
- consider_getfield_raw = consider_getfield_gc
+
def _consider_listop(self, op):
return self._call(op, [self.loc(arg) for arg in op.args])
@@ -808,6 +942,10 @@
def lower_byte(reg):
# argh
+ if isinstance(reg, MODRM):
+ return reg
+ if isinstance(reg, IMM32):
+ return imm8(reg.value)
if reg is eax:
return al
elif reg is ebx:
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/runner.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/runner.py Sun Mar 1 11:14:13 2009
@@ -2,13 +2,13 @@
import ctypes
import py
from pypy.rpython.lltypesystem import lltype, llmemory, ll2ctypes, rffi
-from pypy.rpython.llinterp import LLInterpreter
+from pypy.rpython.llinterp import LLInterpreter, LLException
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
from pypy.rlib.objectmodel import CDefinedIntSymbolic, specialize
from pypy.rlib.objectmodel import we_are_translated, keepalive_until_here
from pypy.annotation import model as annmodel
-
+from pypy.rpython.lltypesystem import rclass
from pypy.jit.metainterp import history
from pypy.jit.metainterp.history import (MergePoint, ResOperation, Box, Const,
ConstInt, ConstPtr, BoxInt, BoxPtr, ConstAddr)
@@ -27,9 +27,19 @@
self.stats = stats
self.translate_support_code = translate_support_code
if translate_support_code:
+ assert False, "need exception support"
self.mixlevelann = MixLevelHelperAnnotator(rtyper)
else:
self.current_interpreter = LLInterpreter(self.rtyper)
+
+ def _store_exception(lle):
+ tp_i = self.cast_ptr_to_int(lle.args[0])
+ v_i = self.cast_gcref_to_int(lle.args[1])
+ self.assembler._exception_data[0] = tp_i
+ self.assembler._exception_data[1] = v_i
+
+ self.current_interpreter._store_exception = _store_exception
+ TP = lltype.GcArray(llmemory.GCREF)
self.keepalives = []
self.keepalives_index = 0
self._bootstrap_cache = {}
@@ -102,6 +112,14 @@
def set_meta_interp(self, metainterp):
self.metainterp = metainterp
+ def get_exception(self, frame):
+ res = self.assembler._exception_data[0]
+ self.assembler._exception_data[0] = 0
+ return res
+
+ def get_exc_value(self, frame):
+ return self.cast_int_to_gcref(self.assembler._exception_data[1])
+
def execute_operation(self, opname, valueboxes, result_type):
# mostly a hack: fall back to compiling and executing the single
# operation.
@@ -109,13 +127,26 @@
return None
key = [opname, result_type]
for valuebox in valueboxes:
- key.append(valuebox.type)
- mp = self.get_compiled_single_operation(key)
+ if isinstance(valuebox, Box):
+ key.append(valuebox.type)
+ else:
+ key.append(repr(valuebox)) # XXX not RPython
+ mp = self.get_compiled_single_operation(key, valueboxes)
res = self.execute_operations_in_new_frame(opname, mp, valueboxes,
result_type)
+ if self.assembler._exception_data[0] != 0:
+ TP = lltype.Ptr(rclass.OBJECT_VTABLE)
+ TP_V = lltype.Ptr(rclass.OBJECT)
+ exc_t_a = self.cast_int_to_adr(self.assembler._exception_data[0])
+ exc_type = llmemory.cast_adr_to_ptr(exc_t_a, TP)
+ exc_v_a = self.cast_int_to_gcref(self.assembler._exception_data[1])
+ exc_val = lltype.cast_opaque_ptr(TP_V, exc_v_a)
+ # clean up the exception
+ self.assembler._exception_data[0] = 0
+ raise LLException(exc_type, exc_val)
return res
- def get_compiled_single_operation(self, key):
+ def get_compiled_single_operation(self, key, valueboxes):
real_key = ','.join([str(k) for k in key])
try:
return self._compiled_ops[real_key]
@@ -123,14 +154,20 @@
opname = key[0]
result_type = key[1]
livevarlist = []
- for type in key[2:]:
- if type == 'int':
- box = history.BoxInt()
- elif type == 'ptr':
- box = history.BoxPtr()
+ i = 0
+ # clonebox below is necessary, because sometimes we know
+ # that the value is constant (ie ArrayDescr), but we're not
+ # going to get the contant. So instead we get a box with correct
+ # value
+ for box in valueboxes:
+ if box.type == 'int':
+ box = valueboxes[i].clonebox()
+ elif box.type == 'ptr':
+ box = valueboxes[i].clonebox()
else:
raise ValueError(type)
livevarlist.append(box)
+ i += 1
mp = MergePoint('merge_point', livevarlist, [])
if result_type == 'void':
results = []
@@ -295,10 +332,6 @@
numof = sizeof
addresssuffix = str(symbolic.get_size(llmemory.Address))
- def offsetof(self, S, fieldname):
- ofs, size = symbolic.get_field_token(S, fieldname)
- return ofs
-
def itemoffsetof(self, A):
basesize, itemsize, ofs_length = symbolic.get_array_token(A)
return basesize
@@ -313,13 +346,34 @@
return res
@staticmethod
+ def cast_ptr_to_int(x):
+ adr = llmemory.cast_ptr_to_adr(x)
+ return CPU386.cast_adr_to_int(adr)
+
+ @staticmethod
+ def arraydescrof(A):
+ assert isinstance(A, lltype.GcArray)
+ basesize, itemsize, ofs_length = symbolic.get_array_token(A)
+ assert ofs_length == 0
+ counter = 0
+ while itemsize != 1:
+ itemsize >>= 1
+ counter += 1
+ return basesize + counter * 0x10000
+
+ @staticmethod
def fielddescrof(S, fieldname):
ofs, size = symbolic.get_field_token(S, fieldname)
- assert size == 4
- return ofs
+ val = (size << 16) + ofs
+ if (isinstance(getattr(S, fieldname), lltype.Ptr) and
+ getattr(S, fieldname).TO._gckind == 'gc'):
+ return ~val
+ return val
@staticmethod
def typefor(fielddesc):
+ if fielddesc < 0:
+ return "ptr"
return "int"
@staticmethod
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_exception.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_exception.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_exception.py Sun Mar 1 11:14:13 2009
@@ -3,8 +3,6 @@
from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
from pypy.jit.metainterp.test.test_exception import ExceptionTests
-py.test.skip("exceptions are broken")
-
class TestExceptions(Jit386Mixin, ExceptionTests):
# for the individual tests see
# ====> ../../../metainterp/test/test_exception.py
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_regalloc.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_regalloc.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_regalloc.py Sun Mar 1 11:14:13 2009
@@ -99,5 +99,32 @@
assert res.value == 42
assert meta_interp.recordedvalues == f()
-def test_xxx():
- pass
+def test_loop_with_const_and_var_swap():
+ meta_interp = FakeMetaInterp()
+ cpu = CPU(rtyper=None, stats=FakeStats())
+ cpu.set_meta_interp(meta_interp)
+ x = BoxInt(0)
+ y = BoxInt(0)
+ z = BoxInt(0)
+ i = BoxInt(0)
+ i0 = BoxInt(0)
+ v0 = BoxInt(0)
+ operations = [
+ MergePoint('merge_point', [x, y, z, i], []),
+ ResOperation('int_sub', [i, ConstInt(1)], [i0]),
+ ResOperation('int_gt', [i0, ConstInt(0)], [v0]),
+ GuardOp('guard_true', [v0], []),
+ ResOperation('jump', [x, z, y, i0], []),
+ ]
+ operations[-1].jump_target = operations[0]
+ operations[3].liveboxes = [v0, x, y, z, i0]
+
+ cpu.compile_operations(operations)
+
+ res = cpu.execute_operations_in_new_frame('foo', operations[0],
+ [BoxInt(1), BoxInt(2),
+ BoxInt(3), BoxInt(10)],
+ 'int')
+ assert res.value == 42
+ assert meta_interp.recordedvalues == [0, 1, 3, 2, 0]
+
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_runner.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_runner.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_runner.py Sun Mar 1 11:14:13 2009
@@ -2,8 +2,11 @@
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.jit.metainterp.history import ResOperation, MergePoint, Jump
from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr,
- GuardOp)
+ GuardOp, Box)
from pypy.jit.backend.x86.runner import CPU, GuardFailed
+from pypy.jit.backend.x86.regalloc import WORD
+from pypy.jit.backend.x86 import symbolic
+import ctypes
class FakeStats(object):
pass
@@ -31,16 +34,44 @@
# ____________________________________________________________
-def test_execute_int_operation():
- cpu = CPU(rtyper=None, stats=FakeStats())
- assert (cpu.execute_operation('int_sub', [BoxInt(45), BoxInt(3)], 'int')
- .value == 42)
- assert cpu.execute_operation('int_neg', [BoxInt(45)], 'int').value == -45
-
class TestX86(object):
def setup_class(cls):
cls.cpu = CPU(rtyper=None, stats=FakeStats())
+ def execute_operation(self, opname, valueboxes, result_type):
+ key = [opname, result_type]
+ mp = self.get_compiled_single_operation(opname, result_type, valueboxes)
+ boxes = [box for box in valueboxes if isinstance(box, Box)]
+ res = self.cpu.execute_operations_in_new_frame(opname, mp, boxes,
+ result_type)
+ return res
+
+ def get_compiled_single_operation(self, opname, result_type, valueboxes):
+ livevarlist = []
+ for box in valueboxes:
+ if isinstance(box, Box):
+ box = box.clonebox()
+ livevarlist.append(box)
+ mp = MergePoint('merge_point',
+ [box for box in livevarlist if isinstance(box, Box)],
+ [])
+ if result_type == 'void':
+ results = []
+ elif result_type == 'int':
+ results = [BoxInt()]
+ elif result_type == 'ptr':
+ results = [BoxPtr()]
+ else:
+ raise ValueError(result_type)
+ operations = [mp,
+ ResOperation(opname, livevarlist, results),
+ ResOperation('return', results, [])]
+ if opname.startswith('guard_'):
+ operations[1].liveboxes = []
+ self.cpu.compile_operations(operations, verbose=False)
+ return mp
+
+
def test_int_binary_ops(self):
for op, args, res in [
('int_sub', [BoxInt(42), BoxInt(40)], 2),
@@ -48,36 +79,34 @@
('int_sub', [ConstInt(42), BoxInt(40)], 2),
('int_add', [ConstInt(-3), ConstInt(-5)], -8),
]:
- assert self.cpu.execute_operation(op, args, 'int').value == res
+ assert self.execute_operation(op, args, 'int').value == res
def test_int_unary_ops(self):
for op, args, res in [
('int_neg', [BoxInt(42)], -42),
- ('int_neg', [ConstInt(-42)], 42),
]:
- assert self.cpu.execute_operation(op, args, 'int').value == res
+ assert self.execute_operation(op, args, 'int').value == res
def test_int_comp_ops(self):
for op, args, res in [
('int_lt', [BoxInt(40), BoxInt(39)], 0),
('int_lt', [BoxInt(40), ConstInt(41)], 1),
('int_lt', [ConstInt(41), BoxInt(40)], 0),
- ('int_lt', [ConstInt(40), ConstInt(141)], 1),
('int_le', [ConstInt(42), BoxInt(42)], 1),
('int_gt', [BoxInt(40), ConstInt(-100)], 1),
]:
- assert self.cpu.execute_operation(op, args, 'int').value == res
+ assert self.execute_operation(op, args, 'int').value == res
def test_execute_ptr_operation(self):
cpu = self.cpu
u = lltype.malloc(U)
u_box = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, u))
ofs_box = ConstInt(cpu.fielddescrof(S, 'value'))
- assert cpu.execute_operation('setfield_gc', [u_box, ofs_box, BoxInt(3)],
+ assert self.execute_operation('setfield_gc', [u_box, ofs_box, BoxInt(3)],
'void') == None
assert u.parent.parent.value == 3
u.parent.parent.value += 100
- assert (cpu.execute_operation('getfield_gc', [u_box, ofs_box], 'int')
+ assert (self.execute_operation('getfield_gc', [u_box, ofs_box], 'int')
.value == 103)
def test_execute_operations_in_env(self):
@@ -100,9 +129,9 @@
operations[-1].jump_target = startmp
operations[-2].liveboxes = [t, u, z]
cpu.compile_operations(operations)
- res = cpu.execute_operations_in_new_frame('foo', startmp,
- [BoxInt(0), BoxInt(10)],
- 'int')
+ res = self.cpu.execute_operations_in_new_frame('foo', startmp,
+ [BoxInt(0), BoxInt(10)],
+ 'int')
assert res.value == 42
gf = cpu.metainterp.gf
assert cpu.metainterp.recordedvalues == [0, True, 55]
@@ -115,13 +144,13 @@
for (opname, args) in [('guard_true', [BoxInt(1)]),
('guard_false', [BoxInt(0)]),
('guard_value', [BoxInt(42), BoxInt(42)])]:
- assert cpu.execute_operation(opname, args, 'void') == None
+ assert self.execute_operation(opname, args, 'void') == None
t = lltype.malloc(T)
t.parent.typeptr = vtable_for_T
t_box = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, t))
T_box = ConstInt(rffi.cast(lltype.Signed, vtable_for_T))
null_box = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(T)))
- assert cpu.execute_operation('guard_class', [t_box, T_box], 'void') == None
+ assert self.execute_operation('guard_class', [t_box, T_box], 'void') == None
def test_failing_guards(self):
vtable_for_T = lltype.malloc(MY_VTABLE, immortal=True)
@@ -145,7 +174,7 @@
('guard_class', [u_box, T_box]),
]:
cpu.metainterp.gf = None
- assert cpu.execute_operation(opname, args, 'void') == None
+ assert self.execute_operation(opname, args, 'void') == None
assert cpu.metainterp.gf is not None
def test_misc_int_ops(self):
@@ -155,15 +184,15 @@
('int_mod', [BoxInt(13), ConstInt(5)], 3),
('int_mod', [ConstInt(33), ConstInt(10)], 3),
('int_floordiv', [BoxInt(13), BoxInt(3)], 4),
- ('int_floordiv', [ConstInt(10), ConstInt(10)], 1),
('int_floordiv', [BoxInt(42), ConstInt(10)], 4),
('int_floordiv', [ConstInt(42), BoxInt(10)], 4),
('int_rshift', [ConstInt(3), BoxInt(4)], 3>>4),
('int_rshift', [BoxInt(3), ConstInt(10)], 3>>10),
]:
- assert self.cpu.execute_operation(op, args, 'int').value == res
+ assert self.execute_operation(op, args, 'int').value == res
def test_same_as(self):
+ py.test.skip("I think no longer needed")
u = lltype.malloc(U)
uadr = lltype.cast_opaque_ptr(llmemory.GCREF, u)
for op, args, tp, res in [
@@ -172,6 +201,137 @@
('same_as', [BoxPtr(uadr)], 'ptr', uadr),
('same_as', [ConstPtr(uadr)], 'ptr', uadr),
]:
- assert self.cpu.execute_operation(op, args, tp).value == res
-
+ assert self.execute_operation(op, args, tp).value == res
+ def test_allocations(self):
+ from pypy.rpython.lltypesystem import rstr
+
+ allocs = [None]
+ all = []
+ def f(size):
+ allocs.insert(0, size)
+ buf = ctypes.create_string_buffer(size)
+ all.append(buf)
+ return ctypes.cast(buf, ctypes.c_void_p).value
+ func = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)(f)
+ addr = ctypes.cast(func, ctypes.c_void_p).value
+
+ try:
+ saved_addr = self.cpu.assembler.malloc_func_addr
+ self.cpu.assembler.malloc_func_addr = addr
+ ofs = symbolic.get_field_token(rstr.STR, 'chars')[0]
+
+ res = self.execute_operation('newstr', [ConstInt(7)], 'ptr')
+ assert allocs[0] == 7 + ofs + WORD
+ resbuf = ctypes.cast(res.value.intval, ctypes.POINTER(ctypes.c_int))
+ assert resbuf[ofs/WORD] == 7
+
+ # ------------------------------------------------------------
+
+ res = self.execute_operation('newstr', [BoxInt(7)], 'ptr')
+ assert allocs[0] == 7 + ofs + WORD
+ resbuf = ctypes.cast(res.value.intval, ctypes.POINTER(ctypes.c_int))
+ assert resbuf[ofs/WORD] == 7
+
+ # ------------------------------------------------------------
+
+ TP = lltype.GcArray(lltype.Signed)
+ ofs = symbolic.get_field_token(TP, 'length')[0]
+ descr = ConstInt(self.cpu.arraydescrof(TP))
+
+ res = self.execute_operation('new_array', [descr, ConstInt(10)],
+ 'ptr')
+ assert allocs[0] == 10*WORD + ofs + WORD
+ resbuf = ctypes.cast(res.value.intval, ctypes.POINTER(ctypes.c_int))
+ assert resbuf[ofs/WORD] == 10
+
+ # ------------------------------------------------------------
+
+ res = self.execute_operation('new_array', [descr, BoxInt(10)],
+ 'ptr')
+ assert allocs[0] == 10*WORD + ofs + WORD
+ resbuf = ctypes.cast(res.value.intval, ctypes.POINTER(ctypes.c_int))
+ assert resbuf[ofs/WORD] == 10
+
+ finally:
+ self.cpu.assembler.malloc_func_addr = saved_addr
+
+ def test_stringitems(self):
+ from pypy.rpython.lltypesystem.rstr import STR
+ ofs = symbolic.get_field_token(STR, 'chars')[0]
+ ofs_items = symbolic.get_field_token(STR.chars, 'items')[0]
+
+ res = self.execute_operation('newstr', [ConstInt(10)], 'ptr')
+ self.execute_operation('strsetitem', [res, ConstInt(2), ConstInt(ord('d'))], 'void')
+ resbuf = ctypes.cast(res.value.intval, ctypes.POINTER(ctypes.c_char))
+ assert resbuf[ofs + ofs_items + 2] == 'd'
+ self.execute_operation('strsetitem', [res, BoxInt(2), ConstInt(ord('z'))], 'void')
+ assert resbuf[ofs + ofs_items + 2] == 'z'
+ r = self.execute_operation('strgetitem', [res, BoxInt(2)], 'int')
+ assert r.value == ord('z')
+
+ def test_arrayitems(self):
+ TP = lltype.GcArray(lltype.Signed)
+ ofs = symbolic.get_field_token(TP, 'length')[0]
+ itemsofs = symbolic.get_field_token(TP, 'items')[0]
+ descr = ConstInt(self.cpu.arraydescrof(TP))
+ res = self.execute_operation('new_array', [descr, ConstInt(10)],
+ 'ptr')
+ resbuf = ctypes.cast(res.value.intval, ctypes.POINTER(ctypes.c_int))
+ assert resbuf[ofs/WORD] == 10
+ self.execute_operation('setarrayitem_gc', [res, descr,
+ ConstInt(2), BoxInt(38)],
+ 'void')
+ assert resbuf[itemsofs/WORD + 2] == 38
+
+ self.execute_operation('setarrayitem_gc', [res, descr,
+ BoxInt(3), BoxInt(42)],
+ 'void')
+ assert resbuf[itemsofs/WORD + 3] == 42
+
+ r = self.execute_operation('getarrayitem_gc', [res, descr,
+ ConstInt(2)], 'int')
+ assert r.value == 38
+ r = self.execute_operation('getarrayitem_gc', [res, descr,
+ BoxInt(3)], 'int')
+ assert r.value == 42
+
+ def test_getfield_setfield(self):
+ TP = lltype.GcStruct('x', ('s', lltype.Signed),
+ ('f', lltype.Float),
+ ('u', rffi.USHORT),
+ ('c1', lltype.Char),
+ ('c2', lltype.Char),
+ ('c3', lltype.Char))
+ res = self.execute_operation('new', [ConstInt(self.cpu.sizeof(TP))],
+ 'ptr')
+ ofs_s = ConstInt(self.cpu.fielddescrof(TP, 's'))
+ ofs_f = ConstInt(self.cpu.fielddescrof(TP, 'f'))
+ ofs_u = ConstInt(self.cpu.fielddescrof(TP, 'u'))
+ ofsc1 = ConstInt(self.cpu.fielddescrof(TP, 'c1'))
+ ofsc2 = ConstInt(self.cpu.fielddescrof(TP, 'c2'))
+ ofsc3 = ConstInt(self.cpu.fielddescrof(TP, 'c3'))
+ self.execute_operation('setfield_gc', [res, ofs_s, ConstInt(3)], 'void')
+ # XXX ConstFloat
+ #self.execute_operation('setfield_gc', [res, ofs_f, 1e100], 'void')
+ # XXX we don't support shorts (at all)
+ #self.execute_operation('setfield_gc', [res, ofs_u, ConstInt(5)], 'void')
+ s = self.execute_operation('getfield_gc', [res, ofs_s], 'int')
+ assert s.value == 3
+ self.execute_operation('setfield_gc', [res, ofs_s, BoxInt(3)], 'void')
+ s = self.execute_operation('getfield_gc', [res, ofs_s], 'int')
+ assert s.value == 3
+ #u = self.execute_operation('getfield_gc', [res, ofs_u], 'int')
+ #assert u.value == 5
+ self.execute_operation('setfield_gc', [res, ofsc1, ConstInt(1)], 'void')
+ self.execute_operation('setfield_gc', [res, ofsc2, ConstInt(2)], 'void')
+ self.execute_operation('setfield_gc', [res, ofsc3, ConstInt(3)], 'void')
+ c = self.execute_operation('getfield_gc', [res, ofsc1], 'int')
+ assert c.value == 1
+ c = self.execute_operation('getfield_gc', [res, ofsc2], 'int')
+ assert c.value == 2
+ c = self.execute_operation('getfield_gc', [res, ofsc3], 'int')
+ assert c.value == 3
+
+ def test_ovf_ops(self):
+ xxx
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_tlc.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_tlc.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_tlc.py Sun Mar 1 11:14:13 2009
@@ -1,8 +1,7 @@
import py
-py.test.skip("XXX")
-from codegen386.test.test_basic import Jit386Mixin
-from test.test_tlc import TLCTests
+from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
+from pypy.jit.metainterp.test.test_tlc import TLCTests
from pypy.jit.tl import tlc
class TestTL(Jit386Mixin, TLCTests):
Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_zrpy_tl.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_zrpy_tl.py (original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_zrpy_tl.py Sun Mar 1 11:14:13 2009
@@ -1,7 +1,7 @@
import py
-from test.test_tl import ToyLanguageTests
-from codegen386.test.test_zrpy_slist import Jit386Mixin
+from pypy.jit.metainterp.test.test_tl import ToyLanguageTests
+from pypy.jit.backend.x86.test.test_zrpy_slist import Jit386Mixin
from pypy.jit.tl import tlc
class TestTL(Jit386Mixin, ToyLanguageTests):
More information about the Pypy-commit
mailing list