[pypy-commit] pypy jit-dynamic-getarrayitem: start working on the JIT optimization
alex_gaynor
noreply at buildbot.pypy.org
Sun Nov 13 18:13:14 CET 2011
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: jit-dynamic-getarrayitem
Changeset: r49373:48644296897a
Date: 2011-11-13 02:02 -0500
http://bitbucket.org/pypy/pypy/changeset/48644296897a/
Log: start working on the JIT optimization
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -1403,6 +1403,7 @@
struct = array._obj.container.getitem(index)
return cast_to_ptr(_getinteriorfield_gc(struct, fieldnum))
+
def _getfield_raw(struct, fieldnum):
STRUCT, fieldname = symbolic.TokenToField[fieldnum]
ptr = cast_from_int(lltype.Ptr(STRUCT), struct)
@@ -1479,7 +1480,7 @@
return do_setinteriorfield_gc
do_setinteriorfield_gc_int = new_setinteriorfield_gc(cast_from_int)
do_setinteriorfield_gc_float = new_setinteriorfield_gc(cast_from_floatstorage)
-do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)
+do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)
def do_setfield_raw_int(struct, fieldnum, newvalue):
STRUCT, fieldname = symbolic.TokenToField[fieldnum]
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -329,6 +329,18 @@
token = history.getkind(getattr(S, fieldname))
return self.getdescr(ofs, token[0], name=fieldname, extrainfo=ofs2)
+ def interiorfielddescrof_dynamic(self, offset, width, fieldsize,
+ is_pointer, is_float, is_signed):
+
+ if is_pointer:
+ typeinfo = REF
+ elif is_float:
+ typeinfo = FLOAT
+ else:
+ typeinfo = INT
+ # we abuse the arg_types field to distinguish dynamic and static descrs
+ return self.getdescr(offset, typeinfo, arg_types='dynamic', name='<dynamic interior field>', extrainfo=width)
+
def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
arg_types = []
for ARG in ARGS:
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -48,6 +48,8 @@
OS_LIBFFI_PREPARE = 60
OS_LIBFFI_PUSH_ARG = 61
OS_LIBFFI_CALL = 62
+ OS_LIBFFI_GETARRAYITEM = 63
+ OS_LIBFFI_SETARRAYITEM = 64
#
OS_LLONG_INVERT = 69
OS_LLONG_ADD = 70
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -1615,6 +1615,12 @@
elif oopspec_name.startswith('libffi_call_'):
oopspecindex = EffectInfo.OS_LIBFFI_CALL
extraeffect = EffectInfo.EF_RANDOM_EFFECTS
+ elif oopspec_name == 'libffi_array_getitem':
+ oopspecindex = EffectInfo.OS_LIBFFI_GETARRAYITEM
+ extraeffect = EffectInfo.EF_CANNOT_RAISE
+ elif oopspec_name == 'libffi_array_setitem':
+ oopspecindex = EffectInfo.OS_LIBFFI_SETARRAYITEM
+ extraeffect = EffectInfo.EF_CANNOT_RAISE
else:
assert False, 'unsupported oopspec: %s' % oopspec_name
return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -130,6 +130,16 @@
else:
return BoxInt(cpu.bh_getinteriorfield_gc_i(array, index, descr))
+def do_getinteriorfield_raw(cpu, _, arraybox, indexbox, descr):
+ array = arraybox.getref_base()
+ index = indexbox.getint()
+ if descr.is_pointer_field():
+ return BoxPtr(cpu.bh_getinteriorfield_raw_r(array, index, descr))
+ elif descr.is_float_field():
+ return BoxFloat(cpu.bh_getinteriorfield_raw_f(array, index, descr))
+ else:
+ return BoxInt(cpu.bh_getionteriorfield_raw_i(array, index, descr))
+
def do_setinteriorfield_gc(cpu, _, arraybox, indexbox, valuebox, descr):
array = arraybox.getref_base()
index = indexbox.getint()
@@ -143,6 +153,7 @@
cpu.bh_setinteriorfield_gc_i(array, index, descr,
valuebox.getint())
+
def do_getfield_gc(cpu, _, structbox, fielddescr):
struct = structbox.getref_base()
if fielddescr.is_pointer_field():
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ b/pypy/jit/metainterp/optimizeopt/fficall.py
@@ -1,11 +1,13 @@
+from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
+from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.rlib import clibffi, libffi
+from pypy.rlib.debug import debug_print
+from pypy.rlib.libffi import Func
+from pypy.rlib.objectmodel import we_are_translated
from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.libffi import Func
-from pypy.rlib.debug import debug_print
-from pypy.jit.codewriter.effectinfo import EffectInfo
-from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.rpython.lltypesystem import llmemory
class FuncInfo(object):
@@ -78,7 +80,7 @@
def new(self):
return OptFfiCall()
-
+
def begin_optimization(self, funcval, op):
self.rollback_maybe('begin_optimization', op)
self.funcinfo = FuncInfo(funcval, self.optimizer.cpu, op)
@@ -116,6 +118,8 @@
ops = self.do_push_arg(op)
elif oopspec == EffectInfo.OS_LIBFFI_CALL:
ops = self.do_call(op)
+ elif oopspec == EffectInfo.OS_LIBFFI_GETARRAYITEM:
+ ops = self.do_getarrayitem(op)
#
for op in ops:
self.emit_operation(op)
@@ -190,6 +194,48 @@
ops.append(newop)
return ops
+ def do_getarrayitem(self, op):
+ ffitypeval = self.getvalue(op.getarg(1))
+ widthval = self.getvalue(op.getarg(2))
+ offsetval = self.getvalue(op.getarg(5))
+ if not ffitypeval.is_constant() or not widthval.is_constant() or not offsetval.is_constant():
+ return [op]
+
+ ffitypeaddr = ffitypeval.box.getaddr()
+ ffitype = llmemory.cast_adr_to_ptr(ffitypeaddr, clibffi.FFI_TYPE_P)
+ offset = offsetval.box.getint()
+ width = offsetval.box.getint()
+ descr = self._get_interior_descr(ffitype, width, offset)
+
+ arglist = [
+ self.getvalue(op.getarg(3)).force_box(self.optimizer),
+ self.getvalue(op.getarg(4)).force_box(self.optimizer),
+ ]
+ return [
+ ResOperation(
+ rop.GETINTERIORFIELD_RAW, arglist, op.result, descr=descr
+ )
+ ]
+
+ def _get_interior_descr(self, ffitype, width, offset):
+ kind = libffi.types.getkind(ffitype)
+ is_pointer = is_float = is_signed = False
+ if ffitype is libffi.types.pointer:
+ is_pointer = True
+ elif kind == 'i':
+ is_signed = True
+ elif kind == 'f' or kind == 'I' or kind == 'U':
+ # longlongs are treated as floats, see
+ # e.g. llsupport/descr.py:getDescrClass
+ is_float = True
+ else:
+ assert False, "unsupported ffitype or kind"
+ #
+ fieldsize = ffitype.c_size
+ return self.optimizer.cpu.interiorfielddescrof_dynamic(
+ offset, width, fieldsize, is_pointer, is_float, is_signed
+ )
+
def propagate_forward(self, op):
if self.logops is not None:
debug_print(self.logops.repr_of_resop(op))
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -461,6 +461,7 @@
'GETARRAYITEM_GC/2d',
'GETARRAYITEM_RAW/2d',
'GETINTERIORFIELD_GC/2d',
+ 'GETINTERIORFIELD_RAW/2d',
'GETFIELD_GC/1d',
'GETFIELD_RAW/1d',
'_MALLOC_FIRST',
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -100,57 +100,55 @@
def test_array_fields(self):
myjitdriver = JitDriver(
greens = [],
- reds = ["n", "i", "signed_size", "points", "result_point"],
+ reds = ["n", "i", "points", "result_point"],
)
POINT = lltype.Struct("POINT",
("x", lltype.Signed),
("y", lltype.Signed),
)
- def f(n):
- points = lltype.malloc(rffi.CArray(POINT), n, flavor="raw")
- for i in xrange(n):
- points[i].x = i * 2
- points[i].y = i * 2 + 1
- points = rffi.cast(rffi.CArrayPtr(lltype.Char), points)
- result_point = lltype.malloc(rffi.CArray(POINT), 1, flavor="raw")
- result_point[0].x = 0
- result_point[0].y = 0
- result_point = rffi.cast(rffi.CArrayPtr(lltype.Char), result_point)
+ def f(points, result_point, n):
i = 0
- signed_size = rffi.sizeof(lltype.Signed)
while i < n:
myjitdriver.jit_merge_point(i=i, points=points, n=n,
- signed_size=signed_size,
result_point=result_point)
x = array_getitem(
- types.slong, signed_size * 2, points, i, 0
+ types.slong, rffi.sizeof(lltype.Signed) * 2, points, i, 0
)
y = array_getitem(
- types.slong, signed_size * 2, points, i, signed_size
+ types.slong, rffi.sizeof(lltype.Signed) * 2, points, i, rffi.sizeof(lltype.Signed)
)
cur_x = array_getitem(
- types.slong, signed_size * 2, result_point, 0, 0
+ types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, 0
)
cur_y = array_getitem(
- types.slong, signed_size * 2, result_point, 0, signed_size
+ types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, rffi.sizeof(lltype.Signed)
)
array_setitem(
- types.slong, signed_size * 2, result_point, 0, 0, cur_x + x
+ types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, 0, cur_x + x
)
array_setitem(
- types.slong, signed_size * 2, result_point, 0, signed_size, cur_y + y
+ types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, rffi.sizeof(lltype.Signed), cur_y + y
)
i += 1
- result_point = rffi.cast(rffi.CArrayPtr(POINT), result_point)
- result = result_point[0].x * result_point[0].y
- lltype.free(result_point, flavor="raw")
- lltype.free(points, flavor="raw")
- return result
- assert self.meta_interp(f, [10]) == f(10) == 9000
+ def main(n):
+ with lltype.scoped_alloc(rffi.CArray(POINT), n) as points:
+ with lltype.scoped_alloc(rffi.CArray(POINT), 1) as result_point:
+ for i in xrange(n):
+ points[i].x = i * 2
+ points[i].y = i * 2 + 1
+ points = rffi.cast(rffi.CArrayPtr(lltype.Char), points)
+ result_point[0].x = 0
+ result_point[0].y = 0
+ result_point = rffi.cast(rffi.CArrayPtr(lltype.Char), result_point)
+ f(points, result_point, n)
+ result_point = rffi.cast(rffi.CArrayPtr(POINT), result_point)
+ return result_point[0].x * result_point[0].y
+
+ assert self.meta_interp(main, [10]) == main(10) == 9000
self.check_loops({"int_add": 3, "jump": 1, "int_lt": 1,
"getinteriorfield_raw": 4, "setinteriorfield_raw": 2
})
diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py
--- a/pypy/rlib/libffi.py
+++ b/pypy/rlib/libffi.py
@@ -411,7 +411,7 @@
def getaddressindll(self, name):
return dlsym(self.lib, name)
- at jit.oopspec("libffi_array_getitem")
+ at jit.oopspec("libffi_array_getitem(ffitype, width, addr, index, offset)")
def array_getitem(ffitype, width, addr, index, offset):
for TYPE, ffitype2 in clibffi.ffitype_map:
if ffitype is ffitype2:
@@ -420,7 +420,7 @@
return rffi.cast(rffi.CArrayPtr(TYPE), addr)[0]
assert False
- at jit.oopspec("libffi_array_setitem")
+ at jit.oopspec("libffi_array_setitem(ffitype, width, addr, index, offset, value)")
def array_setitem(ffitype, width, addr, index, offset, value):
for TYPE, ffitype2 in clibffi.ffitype_map:
if ffitype is ffitype2:
More information about the pypy-commit
mailing list