Author: Carl Friedrich Bolz <[email protected]>
Branch: small-unroll-improvements
Changeset: r70488:8d213d6dda5c
Date: 2014-04-08 17:49 +0200
http://bitbucket.org/pypy/pypy/changeset/8d213d6dda5c/
Log: intermediate checkin
start refactoring generate_guards to no longer call
generalization_of (which I ultimately want to deprecate). for now,
carefully list all cases. intbounds are not supported yet.
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py
b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -31,6 +31,12 @@
def clone(self):
return LenBound(self.mode, self.descr, self.bound.clone())
+ def generalization_of(self, other):
+ return (other is not None and
+ self.mode == other.mode and
+ self.descr == other.descr and
+ self.lenbound.bound.contains_bound(other.lenbound.bound))
+
class OptValue(object):
__metaclass__ = extendabletype
_attrs_ = ('box', 'known_class', 'last_guard', 'level', 'intbound',
'lenbound')
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
@@ -9,6 +9,7 @@
from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin,
BaseTest, \
equaloplists
from rpython.jit.metainterp.optimizeopt.intutils import IntBound
+from rpython.jit.metainterp.optimizeopt.virtualize import VirtualValue
from rpython.jit.metainterp.history import TreeLoop, JitCellToken
from rpython.jit.metainterp.optimizeopt.test.test_optimizeopt import
FakeMetaInterpStaticData
from rpython.jit.metainterp.resoperation import ResOperation, rop
@@ -144,13 +145,17 @@
class BaseTestGenerateGuards(BaseTest):
- def guards(self, info1, info2, box_or_value, expected):
+ def _box_or_value(self, box_or_value):
if isinstance(box_or_value, OptValue):
value = box_or_value
box = value.box
else:
box = box_or_value
value = OptValue(box)
+ return value, box
+
+ def guards(self, info1, info2, box_or_value, expected):
+ value, box = self._box_or_value(box_or_value)
info1.position = info2.position = 0
guards = []
info1.generate_guards(info2, value, self.cpu, guards, {})
@@ -166,7 +171,139 @@
if op.is_guard():
op.setdescr(None)
assert equaloplists(guards, loop.operations, False,
- boxmap)
+ boxmap)
+
+ def check_no_guards(self, info1, info2, box_or_value):
+ value, _ = self._box_or_value(box_or_value)
+ guards = []
+ info1.generate_guards(info2, value, self.cpu, guards, {})
+ assert not guards
+
+ def check_invalid(self, info1, info2, box_or_value):
+ value, _ = self._box_or_value(box_or_value)
+ guards = []
+ with py.test.raises(InvalidLoop):
+ info1.generate_guards(info2, value, self.cpu, guards, {})
+
+ def test_nonvirtual_all_combinations(self):
+ # set up infos
+ unknown_val = OptValue(self.nodebox)
+ unknownnull_val = OptValue(BoxPtr(self.nullptr))
+ unknown_info = NotVirtualStateInfo(unknown_val)
+
+ nonnull_val = OptValue(self.nodebox)
+ nonnull_val.make_nonnull(None)
+ nonnull_info = NotVirtualStateInfo(nonnull_val)
+
+ knownclass_val = OptValue(self.nodebox)
+ classbox = self.cpu.ts.cls_of_box(self.nodebox)
+ knownclass_val.make_constant_class(classbox, -1)
+ knownclass_info = NotVirtualStateInfo(knownclass_val)
+ knownclass2_val = OptValue(self.nodebox2)
+ classbox = self.cpu.ts.cls_of_box(self.nodebox2)
+ knownclass2_val.make_constant_class(classbox, -1)
+ knownclass2_info = NotVirtualStateInfo(knownclass2_val)
+
+ constant_val = OptValue(BoxInt())
+ constant_val.make_constant(ConstInt(1))
+ constant_info = NotVirtualStateInfo(constant_val)
+ constclass_val = OptValue(self.nodebox)
+ constclass_val.make_constant(self.nodebox.constbox())
+ constclass_info = NotVirtualStateInfo(constclass_val)
+ constclass2_val = OptValue(self.nodebox)
+ constclass2_val.make_constant(self.nodebox2.constbox())
+ constclass2_info = NotVirtualStateInfo(constclass2_val)
+ constantnull_val = OptValue(ConstPtr(self.nullptr))
+ constantnull_info = NotVirtualStateInfo(constantnull_val)
+
+ # unknown unknown
+ self.check_no_guards(unknown_info, unknown_info, unknown_val)
+
+ # unknown nonnull
+ self.check_no_guards(unknown_info, nonnull_info, nonnull_val)
+
+ # unknown knownclass
+ self.check_no_guards(unknown_info, knownclass_info, knownclass_val)
+
+ # unknown constant
+ self.check_no_guards(unknown_info, constant_info, constant_val)
+
+
+ # nonnull unknown
+ expected = """
+ [p0]
+ guard_nonnull(p0) []
+ """
+ self.guards(nonnull_info, unknown_info, unknown_val, expected)
+ self.check_invalid(nonnull_info, unknown_info, unknownnull_val)
+
+ # nonnull nonnull
+ self.check_no_guards(nonnull_info, nonnull_info, nonnull_val)
+
+ # nonnull knownclass
+ self.check_no_guards(nonnull_info, knownclass_info, knownclass_val)
+
+ # nonnull constant
+ self.check_no_guards(nonnull_info, constant_info, constant_val)
+ self.check_invalid(nonnull_info, constantnull_info, constantnull_val)
+
+
+ # knownclass unknown
+ expected = """
+ [p0]
+ guard_nonnull(p0) []
+ guard_class(p0, ConstClass(node_vtable)) []
+ """
+ self.guards(knownclass_info, unknown_info, unknown_val, expected)
+ self.check_invalid(knownclass_info, unknown_info, unknownnull_val)
+ self.check_invalid(knownclass_info, unknown_info, knownclass2_val)
+
+ # knownclass nonnull
+ expected = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ """
+ self.guards(knownclass_info, nonnull_info, knownclass_val, expected)
+ self.check_invalid(knownclass_info, nonnull_info, knownclass2_val)
+
+ # knownclass knownclass
+ self.check_no_guards(knownclass_info, knownclass_info, knownclass_val)
+ self.check_invalid(knownclass_info, knownclass2_info, knownclass2_val)
+
+ # knownclass constant
+ self.check_invalid(knownclass_info, constantnull_info,
constantnull_val)
+ self.check_invalid(knownclass_info, constclass2_info, constclass2_val)
+
+
+ # constant unknown
+ expected = """
+ [i0]
+ guard_value(i0, 1) []
+ """
+ self.guards(constant_info, unknown_info, constant_val, expected)
+ self.check_invalid(constant_info, unknown_info, unknownnull_val)
+
+ # constant nonnull
+ expected = """
+ [i0]
+ guard_value(i0, 1) []
+ """
+ self.guards(constant_info, nonnull_info, constant_val, expected)
+ self.check_invalid(constant_info, nonnull_info, constclass2_val)
+
+ # constant knownclass
+ expected = """
+ [i0]
+ guard_value(i0, 1) []
+ """
+ self.guards(constant_info, knownclass_info, constant_val, expected)
+ self.check_invalid(constant_info, knownclass_info, unknownnull_val)
+
+ # constant constant
+ self.check_no_guards(constant_info, constant_info, constant_val)
+ self.check_invalid(constant_info, constantnull_info, constantnull_val)
+
+
def test_intbounds(self):
value1 = OptValue(BoxInt(15))
value1.intbound.make_ge(IntBound(0, 10))
@@ -280,6 +417,34 @@
vstate1.generate_guards(vstate2, [value2], self.cpu, guards)
self.compare(guards, expected, [box2])
+ def test_generate_guards_on_virtual_fields_matches(self):
+ py.test.skip("not yet")
+ innervalue1 = OptValue(self.nodebox)
+ constclassbox = self.cpu.ts.cls_of_box(self.nodebox)
+ innervalue1.make_constant_class(constclassbox, -1)
+ innerinfo1 = NotVirtualStateInfo(innervalue1)
+ innerinfo1.position = 1
+ innerinfo2 = NotVirtualStateInfo(OptValue(self.nodebox))
+ innerinfo2.position = 1
+
+ info1 = VirtualStateInfo(ConstInt(42), [1])
+ info1.fieldstate = [innerinfo1]
+
+ info2 = VirtualStateInfo(ConstInt(42), [1])
+ info2.fieldstate = [innerinfo2]
+
+ value1 = VirtualValue(self.cpu, constclassbox, BoxInt())
+ value1._fields = {1: OptValue(self.nodebox)}
+
+ expected = """
+ [p0]
+ guard_nonnull(p0) []
+ guard_class(p0, ConstClass(node_vtable)) []
+ """
+ self.guards(info1, info2, value1, expected)
+
+ # _________________________________________________________________________
+ # the below tests don't really have anything to do with guard generation
def test_virtuals_with_equal_fields(self):
info1 = VirtualStateInfo(ConstInt(42), [1, 2])
@@ -681,7 +846,7 @@
"""
self.optimize_bridge(loop, bridge, expected, p0=self.myptr)
- def test_virtual(self):
+ def test_simple_virtual(self):
loops = """
[p0, p1]
p2 = new_with_vtable(ConstClass(node_vtable))
diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py
b/rpython/jit/metainterp/optimizeopt/virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py
@@ -28,18 +28,23 @@
bad[self] = bad[other] = None
return result
- def generate_guards(self, other, value, cpu, extra_guards, renum):
+ def generate_guards(self, other, value, cpu, extra_guards, renum,
bad=None):
+ if bad is None:
+ bad = {}
assert isinstance(value, OptValue)
- if self.generalization_of(other, renum, {}):
- return
- if renum[self.position] != other.position:
- raise InvalidLoop('The numbering of the virtual states does not ' +
- 'match. This means that two virtual fields ' +
- 'have been set to the same Box in one of the ' +
- 'virtual states but not in the other.')
- self._generate_guards(other, value, cpu, extra_guards, renum)
+ if self.position in renum:
+ if renum[self.position] != other.position:
+ bad[self] = bad[other] = None
+ raise InvalidLoop('The numbering of the virtual states does
not ' +
+ 'match. This means that two virtual fields '
+
+ 'have been set to the same Box in one of the
' +
+ 'virtual states but not in the other.')
+ else:
+ renum[self.position] = other.position
+ self._generate_guards(other, value, cpu, extra_guards, renum, bad)
- def _generate_guards(self, other, value, cpu, extra_guards, renum):
+ def _generate_guards(self, other, value, cpu, extra_guards, renum, bad):
+ bad[self] = bad[other] = None
raise InvalidLoop('Generating guards for making the VirtualStates ' +
'at hand match have not been implemented')
@@ -126,6 +131,7 @@
return (isinstance(other, VirtualStateInfo) and
self.known_class.same_constant(other.known_class))
+
def debug_header(self, indent):
debug_print(indent + 'VirtualStateInfo(%d):' % self.position)
@@ -271,55 +277,101 @@
if not self.intbound.contains_bound(other.intbound):
return False
- if self.lenbound and other.lenbound:
- if self.lenbound.mode != other.lenbound.mode or \
- self.lenbound.descr != other.lenbound.descr or \
- not self.lenbound.bound.contains_bound(other.lenbound.bound):
- return False
- elif self.lenbound:
- return False
+ if self.lenbound:
+ return self.lenbound.generalization_of(other.lenbound)
return True
- def _generate_guards(self, other, value, cpu, extra_guards, renum):
+ def _generate_guards(self, other, value, cpu, extra_guards, renum, bad):
box = value.box
if not isinstance(other, NotVirtualStateInfo):
+ bad[self] = bad[other] = None
raise InvalidLoop('The VirtualStates does not match as a ' +
'virtual appears where a pointer is needed ' +
'and it is too late to force it.')
- if self.lenbound or other.lenbound:
- raise InvalidLoop('The array length bounds does not match.')
-
if self.is_opaque:
+ bad[self] = bad[other] = None
raise InvalidLoop('Generating guards for opaque pointers is not
safe')
- # the following conditions always peek into the runtime value that the
+ if self.lenbound and not
self.lenbound.generalization_of(other.lenbound):
+ raise InvalidLoop()
+
+
+ if self.level == LEVEL_UNKNOWN:
+ return
+
+ # the following conditions often peek into the runtime value that the
# box had when tracing. This value is only used as an educated guess.
# It is used here to choose between either emitting a guard and jumping
# to an existing compiled loop or retracing the loop. Both alternatives
# will always generate correct behaviour, but performance will differ.
- if (self.level == LEVEL_CONSTANT and
- self.constbox.same_constant(box.constbox())):
- op = ResOperation(rop.GUARD_VALUE, [box, self.constbox], None)
- extra_guards.append(op)
- return
+ elif self.level == LEVEL_NONNULL:
+ if other.level == LEVEL_UNKNOWN:
+ if box.nonnull():
+ op = ResOperation(rop.GUARD_NONNULL, [box], None)
+ extra_guards.append(op)
+ return
+ else:
+ raise InvalidLoop()
+ elif other.level == LEVEL_NONNULL:
+ return
+ elif other.level == LEVEL_KNOWNCLASS:
+ return # implies nonnull
+ else:
+ assert other.level == LEVEL_CONSTANT
+ assert other.constbox
+ if not other.constbox.nonnull():
+ raise InvalidLoop("XXX")
+ return
- if self.level == LEVEL_KNOWNCLASS and \
- box.nonnull() and \
- self.known_class.same_constant(cpu.ts.cls_of_box(box)):
- op = ResOperation(rop.GUARD_NONNULL, [box], None)
- extra_guards.append(op)
- op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None)
- extra_guards.append(op)
- return
+ elif self.level == LEVEL_KNOWNCLASS:
+ if other.level == LEVEL_UNKNOWN:
+ if (box.nonnull() and
+
self.known_class.same_constant(cpu.ts.cls_of_box(box))):
+ op = ResOperation(rop.GUARD_NONNULL, [box], None)
+ extra_guards.append(op)
+ op = ResOperation(rop.GUARD_CLASS, [box,
self.known_class], None)
+ extra_guards.append(op)
+ return
+ else:
+ raise InvalidLoop()
+ elif other.level == LEVEL_NONNULL:
+ if self.known_class.same_constant(cpu.ts.cls_of_box(box)):
+ op = ResOperation(rop.GUARD_CLASS, [box,
self.known_class], None)
+ extra_guards.append(op)
+ return
+ else:
+ raise InvalidLoop()
+ elif other.level == LEVEL_KNOWNCLASS:
+ if self.known_class.same_constant(other.known_class):
+ return
+ raise InvalidLoop()
+ else:
+ assert other.level == LEVEL_CONSTANT
+ if (other.constbox.nonnull() and
+
self.known_class.same_constant(cpu.ts.cls_of_box(other.constbox))):
+ return
+ else:
+ raise InvalidLoop()
- if (self.level == LEVEL_NONNULL and
- other.level == LEVEL_UNKNOWN and
- isinstance(box, BoxPtr) and
- box.nonnull()):
- op = ResOperation(rop.GUARD_NONNULL, [box], None)
- extra_guards.append(op)
- return
+ else:
+ assert self.level == LEVEL_CONSTANT
+ if other.level == LEVEL_CONSTANT:
+ if self.constbox.same_constant(other.constbox):
+ return
+ raise InvalidLoop()
+ if self.constbox.same_constant(box.constbox()):
+ op = ResOperation(rop.GUARD_VALUE, [box, self.constbox], None)
+ extra_guards.append(op)
+ return
+ else:
+ raise InvalidLoop()
+ raise InvalidLoop("XXX")
+
+ if self.lenbound or other.lenbound:
+ bad[self] = bad[other] = None
+ raise InvalidLoop('The array length bounds does not match.')
+
if (self.level == LEVEL_UNKNOWN and
other.level == LEVEL_UNKNOWN and
@@ -345,10 +397,6 @@
extra_guards.append(op)
return
- # Remaining cases are probably not interesting
- raise InvalidLoop('Generating guards for making the VirtualStates ' +
- 'at hand match have not been implemented')
-
def enum_forced_boxes(self, boxes, value, optimizer):
if self.level == LEVEL_CONSTANT:
return
@@ -410,12 +458,14 @@
return False
return True
- def generate_guards(self, other, values, cpu, extra_guards):
+ def generate_guards(self, other, values, cpu, extra_guards, bad=None):
+ if bad is None:
+ bad = {}
assert len(self.state) == len(other.state) == len(values)
renum = {}
for i in range(len(self.state)):
self.state[i].generate_guards(other.state[i], values[i],
- cpu, extra_guards, renum)
+ cpu, extra_guards, renum, bad)
def make_inputargs(self, values, optimizer, keyboxes=False):
if optimizer.optearlyforce:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit