[pypy-commit] pypy optresult-unroll: * reimplement structs that are immutable constants, built during traces
arigo
noreply at buildbot.pypy.org
Tue Aug 25 13:23:12 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: optresult-unroll
Changeset: r79224:13fed87e2df5
Date: 2015-08-25 13:23 +0200
http://bitbucket.org/pypy/pypy/changeset/13fed87e2df5/
Log: * reimplement structs that are immutable constants, built during
traces
* in llsupport/descr.py, merge SizeDescrWithVTable with SizeDescr
diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -111,8 +111,8 @@
self.S)
return heaptracker.adr2int(llmemory.cast_ptr_to_adr(self._vtable))
- def count_fields_if_immutable(self):
- return heaptracker.count_fields_if_immutable(self.S)
+ def is_immutable(self):
+ return heaptracker.is_immutable_struct(self.S)
def __repr__(self):
return 'SizeDescr(%r)' % (self.S,)
diff --git a/rpython/jit/backend/llsupport/descr.py b/rpython/jit/backend/llsupport/descr.py
--- a/rpython/jit/backend/llsupport/descr.py
+++ b/rpython/jit/backend/llsupport/descr.py
@@ -36,37 +36,32 @@
size = 0 # help translation
tid = llop.combine_ushort(lltype.Signed, 0, 0)
vtable = lltype.nullptr(rclass.OBJECT_VTABLE)
+ immutable_flag = False
- def __init__(self, size, count_fields_if_immut=-1,
- gc_fielddescrs=None, all_fielddescrs=None,
- vtable=lltype.nullptr(rclass.OBJECT_VTABLE)):
+ def __init__(self, size, gc_fielddescrs=None, all_fielddescrs=None,
+ vtable=lltype.nullptr(rclass.OBJECT_VTABLE),
+ immutable_flag=False):
self.size = size
- self.count_fields_if_immut = count_fields_if_immut
self.gc_fielddescrs = gc_fielddescrs
self.all_fielddescrs = all_fielddescrs
self.vtable = vtable
+ self.immutable_flag = immutable_flag
def get_all_fielddescrs(self):
return self.all_fielddescrs
- def count_fields_if_immutable(self):
- return self.count_fields_if_immut
-
def repr_of_descr(self):
return '<SizeDescr %s>' % self.size
def is_object(self):
- return False
+ return bool(self.vtable)
-class SizeDescrWithVTable(SizeDescr):
- def is_object(self):
- return True
+ def is_immutable(self):
+ return self.immutable_flag
def get_vtable(self):
return heaptracker.adr2int(llmemory.cast_ptr_to_adr(self.vtable))
-BaseSizeDescr = SizeDescr
-
def get_size_descr(gccache, STRUCT, vtable):
cache = gccache._cache_size
assert not isinstance(vtable, bool)
@@ -74,16 +69,14 @@
return cache[STRUCT]
except KeyError:
size = symbolic.get_size(STRUCT, gccache.translate_support_code)
- count_fields_if_immut = heaptracker.count_fields_if_immutable(STRUCT)
+ immutable_flag = heaptracker.is_immutable_struct(STRUCT)
gc_fielddescrs = heaptracker.gc_fielddescrs(gccache, STRUCT)
if vtable:
assert heaptracker.has_gcstruct_a_vtable(STRUCT)
- sizedescr = SizeDescrWithVTable(size, count_fields_if_immut,
- gc_fielddescrs, None, vtable)
else:
assert not heaptracker.has_gcstruct_a_vtable(STRUCT)
- sizedescr = SizeDescr(size, count_fields_if_immut,
- gc_fielddescrs, None)
+ sizedescr = SizeDescr(size, gc_fielddescrs, vtable=vtable,
+ immutable_flag=immutable_flag)
gccache.init_size_descr(STRUCT, sizedescr)
cache[STRUCT] = sizedescr
all_fielddescrs = heaptracker.all_fielddescrs(gccache, STRUCT)
@@ -124,7 +117,7 @@
return 'FieldDescr<%s>' % (self.name,)
def check_correct_type(self, struct):
- if isinstance(self.parent_descr, SizeDescrWithVTable):
+ if self.parent_descr.is_object():
cls = llmemory.cast_adr_to_ptr(
heaptracker.int2adr(self.parent_descr.get_vtable()),
lltype.Ptr(rclass.OBJECT_VTABLE))
diff --git a/rpython/jit/backend/llsupport/test/test_descr.py b/rpython/jit/backend/llsupport/test/test_descr.py
--- a/rpython/jit/backend/llsupport/test/test_descr.py
+++ b/rpython/jit/backend/llsupport/test/test_descr.py
@@ -13,24 +13,24 @@
T = lltype.GcStruct('T')
S = lltype.GcStruct('S', ('x', lltype.Char),
('y', lltype.Ptr(T)))
- descr_s = get_size_descr(c0, S, False)
- descr_t = get_size_descr(c0, T, False)
+ descr_s = get_size_descr(c0, S, None)
+ descr_t = get_size_descr(c0, T, None)
assert descr_s.size == symbolic.get_size(S, False)
assert descr_t.size == symbolic.get_size(T, False)
- assert descr_s.count_fields_if_immutable() == -1
- assert descr_t.count_fields_if_immutable() == -1
+ assert descr_s.is_immutable() == False
+ assert descr_t.is_immutable() == False
assert descr_t.gc_fielddescrs == []
assert len(descr_s.gc_fielddescrs) == 1
- assert descr_s == get_size_descr(c0, S, False)
- assert descr_s != get_size_descr(c1, S, False)
+ assert descr_s == get_size_descr(c0, S, None)
+ assert descr_s != get_size_descr(c1, S, None)
#
- descr_s = get_size_descr(c1, S, False)
+ descr_s = get_size_descr(c1, S, None)
assert isinstance(descr_s.size, Symbolic)
- assert descr_s.count_fields_if_immutable() == -1
+ assert descr_s.is_immutable() == False
PARENT = lltype.Struct('P', ('x', lltype.Ptr(T)))
STRUCT = lltype.GcStruct('S', ('parent', PARENT), ('y', lltype.Ptr(T)))
- descr_struct = get_size_descr(c0, STRUCT, False)
+ descr_struct = get_size_descr(c0, STRUCT, None)
assert len(descr_struct.gc_fielddescrs) == 2
def test_get_size_descr_immut():
@@ -46,11 +46,11 @@
('miss1', lltype.Void),
('miss2', lltype.Void),
hints={'immutable': True})
- for STRUCT, expected in [(S, 0), (T, 1), (U, 3), (V, 3)]:
+ for STRUCT in [S, T, U, V]:
for translated in [False, True]:
c0 = GcCache(translated)
- descr_s = get_size_descr(c0, STRUCT, False)
- assert descr_s.count_fields_if_immutable() == expected
+ descr_s = get_size_descr(c0, STRUCT, None)
+ assert descr_s.is_immutable() == True
def test_get_field_descr():
U = lltype.Struct('U')
@@ -329,7 +329,7 @@
S = lltype.GcStruct('S', ('x', lltype.Char),
('y', lltype.Ptr(T)),
('z', lltype.Ptr(T)))
- descr1 = get_size_descr(c0, S, False)
+ descr1 = get_size_descr(c0, S, None)
s = symbolic.get_size(S, False)
assert repr_of_descr(descr1) == '<SizeDescr %d>' % s
#
diff --git a/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py b/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py
--- a/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py
+++ b/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py
@@ -1,7 +1,7 @@
from test_rewrite import get_size_descr, get_array_descr, get_description, BaseFakeCPU
from rpython.jit.backend.llsupport.descr import get_size_descr,\
get_field_descr, get_array_descr, ArrayDescr, FieldDescr,\
- SizeDescrWithVTable, get_interiorfield_descr
+ SizeDescr, get_interiorfield_descr
from rpython.jit.backend.llsupport.gc import GcLLDescr_boehm,\
GcLLDescr_framework, MovableObjectTracker
from rpython.jit.backend.llsupport import jitframe, gc
@@ -115,7 +115,7 @@
#
class FakeCPU(BaseFakeCPU):
def sizeof(self, STRUCT, is_object):
- descr = SizeDescrWithVTable(104)
+ descr = SizeDescr(104)
descr.tid = 9315
descr.vtable = 12
return descr
diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py b/rpython/jit/backend/llsupport/test/test_rewrite.py
--- a/rpython/jit/backend/llsupport/test/test_rewrite.py
+++ b/rpython/jit/backend/llsupport/test/test_rewrite.py
@@ -1,6 +1,6 @@
from rpython.jit.backend.llsupport.descr import get_size_descr,\
get_field_descr, get_array_descr, ArrayDescr, FieldDescr,\
- SizeDescrWithVTable, get_interiorfield_descr
+ SizeDescr, get_interiorfield_descr
from rpython.jit.backend.llsupport.gc import GcLLDescr_boehm,\
GcLLDescr_framework
from rpython.jit.backend.llsupport import jitframe
@@ -163,8 +163,8 @@
class FakeCPU(BaseFakeCPU):
def sizeof(self, STRUCT, is_object):
assert is_object
- return SizeDescrWithVTable(102, gc_fielddescrs=[],
- vtable=o_vtable)
+ return SizeDescr(102, gc_fielddescrs=[],
+ vtable=o_vtable)
self.cpu = FakeCPU()
self.gc_ll_descr = GcLLDescr_boehm(None, None, None)
@@ -301,7 +301,7 @@
#
class FakeCPU(BaseFakeCPU):
def sizeof(self, STRUCT, is_object):
- descr = SizeDescrWithVTable(104, gc_fielddescrs=[])
+ descr = SizeDescr(104, gc_fielddescrs=[])
descr.tid = 9315
return descr
self.cpu = FakeCPU()
diff --git a/rpython/jit/codewriter/heaptracker.py b/rpython/jit/codewriter/heaptracker.py
--- a/rpython/jit/codewriter/heaptracker.py
+++ b/rpython/jit/codewriter/heaptracker.py
@@ -20,30 +20,8 @@
a -= r_uint(1 << (b8 - 1)) # a -= 128
return intmask(a)
-def count_fields_if_immutable(STRUCT):
- if not isinstance(STRUCT, lltype.GcStruct):
- return -1
- if STRUCT._hints.get('immutable', False):
- try:
- return _count_fields(STRUCT)
- except ValueError:
- pass
- return -1
-
-def _count_fields(STRUCT):
- if STRUCT == rclass.OBJECT:
- return 0 # don't count 'typeptr'
- result = 0
- for fieldname, TYPE in STRUCT._flds.items():
- if TYPE is lltype.Void:
- pass # ignore Voids
- elif not isinstance(TYPE, lltype.ContainerType):
- result += 1
- elif isinstance(TYPE, lltype.GcStruct):
- result += _count_fields(TYPE)
- else:
- raise ValueError(TYPE)
- return result
+def is_immutable_struct(S):
+ return isinstance(S, lltype.GcStruct) and S._hints.get('immutable', False)
# ____________________________________________________________
diff --git a/rpython/jit/metainterp/optimizeopt/info.py b/rpython/jit/metainterp/optimizeopt/info.py
--- a/rpython/jit/metainterp/optimizeopt/info.py
+++ b/rpython/jit/metainterp/optimizeopt/info.py
@@ -5,6 +5,7 @@
from rpython.jit.metainterp.history import ConstInt, Const
from rpython.rtyper.lltypesystem import lltype
from rpython.jit.metainterp.optimizeopt.rawbuffer import RawBuffer, InvalidRawOperation
+from rpython.jit.metainterp.executor import execute
INFO_NULL = 0
@@ -22,7 +23,10 @@
def getconst(self):
raise Exception("not a constant")
-
+ def _is_immutable_and_filled_with_constants(self, optimizer, memo=None):
+ return False
+
+
class PtrInfo(AbstractInfo):
_attrs_ = ()
@@ -109,6 +113,15 @@
def force_box(self, op, optforce):
if self.is_virtual():
optforce.forget_numberings()
+ #
+ if self._is_immutable_and_filled_with_constants(optforce.optimizer):
+ constptr = optforce.optimizer.constant_fold(op)
+ op.set_forwarded(constptr)
+ descr = self.vdescr
+ self.vdescr = None
+ self._force_elements_immutable(descr, constptr, optforce)
+ return constptr
+ #
op.set_forwarded(None)
optforce._emit_operation(op)
newop = optforce.getlastop()
@@ -214,6 +227,46 @@
getfield_op = ResOperation(opnum, [structbox], descr=descr)
shortboxes.add_heap_op(op, getfield_op)
+ def _is_immutable_and_filled_with_constants(self, optimizer, memo=None):
+ # check if it is possible to force the given structure into a
+ # compile-time constant: this is allowed only if it is declared
+ # immutable, if all fields are already filled, and if each field
+ # is either a compile-time constant or (recursively) a structure
+ # which also answers True to the same question.
+ #
+ assert self.is_virtual()
+ if not self.vdescr.is_immutable():
+ return False
+ if memo is not None and self in memo:
+ return True # recursive case: assume yes
+ #
+ for op in self._fields:
+ if op is None:
+ return False # there is an uninitialized field
+ op = op.get_box_replacement()
+ if op.is_constant():
+ pass # it is a constant value: ok
+ else:
+ fieldinfo = optimizer.getptrinfo(op)
+ if fieldinfo and fieldinfo.is_virtual():
+ # recursive check
+ if memo is None:
+ memo = {self: None}
+ if not fieldinfo._is_immutable_and_filled_with_constants(
+ optimizer, memo):
+ return False
+ else:
+ return False # not a constant at all
+ return True
+
+ def _force_elements_immutable(self, descr, constptr, optforce):
+ for i, flddescr in enumerate(descr.get_all_fielddescrs()):
+ fld = self._fields[i]
+ subbox = optforce.force_box(fld)
+ assert isinstance(subbox, Const)
+ execute(optforce.optimizer.cpu, None, rop.SETFIELD_GC,
+ flddescr, constptr, subbox)
+
class InstancePtrInfo(AbstractStructPtrInfo):
_attrs_ = ('_known_class',)
_fields = None
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -6091,7 +6091,7 @@
# ----------
ops = """
[p1]
- p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+ p0 = new_with_vtable(descr=ptrobj_immut_descr)
setfield_gc(p0, p1, descr=immut_ptrval)
escape_n(p0)
jump(p1)
@@ -6100,8 +6100,8 @@
# ----------
ops = """
[]
- p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
- p1 = new_with_vtable(ConstClass(intobj_immut_vtable))
+ p0 = new_with_vtable(descr=ptrobj_immut_descr)
+ p1 = new_with_vtable(descr=immut_descr)
setfield_gc(p1, 1242, descr=immut_intval)
setfield_gc(p0, p1, descr=immut_ptrval)
escape_n(p0)
@@ -6115,6 +6115,8 @@
p1 = other.container.ptrval
p1cast = lltype.cast_pointer(lltype.Ptr(self.INTOBJ_IMMUT), p1)
return p1cast.intval == 1242
+ def _normalizedcontainer(self):
+ return self
self.namespace['ptrobj1242'] = lltype._ptr(llmemory.GCREF,
PtrObj1242())
expected = """
@@ -6191,6 +6193,8 @@
assert p2 != p1
p2cast = lltype.cast_pointer(lltype.Ptr(self.PTROBJ_IMMUT), p2)
return p2cast.ptrval == p1
+ def _normalizedcontainer(self):
+ return self
self.namespace['ptrobjself2'] = lltype._ptr(llmemory.GCREF,
PtrObjSelf2())
expected = """
More information about the pypy-commit
mailing list