Author: Armin Rigo <[email protected]>
Branch: remove-raisingops
Changeset: r83993:36d247e2bc68
Date: 2016-04-27 19:35 +0200
http://bitbucket.org/pypy/pypy/changeset/36d247e2bc68/
Log: Revert the changes in flatten.py, and handle it by jtransform'ing
the graphs with calls to ll_int_add_ovf to graphs with 'int_add_ovf'
(which are then handled by flatten.py)
diff --git a/rpython/jit/codewriter/flatten.py
b/rpython/jit/codewriter/flatten.py
--- a/rpython/jit/codewriter/flatten.py
+++ b/rpython/jit/codewriter/flatten.py
@@ -103,7 +103,7 @@
self.seen_blocks = {}
self.make_bytecode_block(self.graph.startblock)
- def make_bytecode_block(self, block):
+ def make_bytecode_block(self, block, handling_ovf=False):
if block.exits == ():
self.make_return(block.inputargs)
return
@@ -117,10 +117,15 @@
#
operations = block.operations
for i, op in enumerate(operations):
- assert '_ovf' not in op.opname # should not exist any more
+ if '_ovf' in op.opname:
+ if (len(block.exits) not in (2, 3) or
+ block.exitswitch is not c_last_exception):
+ raise Exception("detected a block containing ovfcheck()"
+ " but no OverflowError is caught, this"
+ " is not legal in jitted blocks")
self.serialize_op(op)
#
- self.insert_exits(block)
+ self.insert_exits(block, handling_ovf)
def make_return(self, args):
if len(args) == 1:
@@ -140,16 +145,16 @@
raise Exception("?")
self.emitline("---")
- def make_link(self, link):
+ def make_link(self, link, handling_ovf):
if (link.target.exits == ()
and link.last_exception not in link.args
and link.last_exc_value not in link.args):
self.make_return(link.args) # optimization only
return
self.insert_renamings(link)
- self.make_bytecode_block(link.target)
+ self.make_bytecode_block(link.target, handling_ovf)
- def make_exception_link(self, link):
+ def make_exception_link(self, link, handling_ovf):
# Like make_link(), but also introduces the 'last_exception' and
# 'last_exc_value' as variables if needed. Also check if the link
# is jumping directly to the re-raising exception block.
@@ -157,31 +162,52 @@
assert link.last_exc_value is not None
if link.target.operations == () and link.args == [link.last_exception,
link.last_exc_value]:
- self.emitline("reraise")
+ if handling_ovf:
+ exc_data = self.cpu.rtyper.exceptiondata
+ ll_ovf = exc_data.get_standard_ll_exc_instance_by_class(
+ OverflowError)
+ c = Constant(ll_ovf, concretetype=lltype.typeOf(ll_ovf))
+ self.emitline("raise", c)
+ else:
+ self.emitline("reraise")
self.emitline("---")
return # done
- self.make_link(link)
+ self.make_link(link, handling_ovf)
- def insert_exits(self, block):
+ def insert_exits(self, block, handling_ovf=False):
if len(block.exits) == 1:
# A single link, fall-through
link = block.exits[0]
assert link.exitcase in (None, False, True)
# the cases False or True should not really occur, but can show
# up in the manually hacked graphs for generators...
- self.make_link(link)
+ self.make_link(link, handling_ovf)
#
elif block.canraise:
# An exception block. See test_exc_exitswitch in test_flatten.py
# for an example of what kind of code this makes.
index = -1
opname = block.operations[index].opname
- assert '_ovf' not in opname # should not exist any more
- while True:
- lastopname = block.operations[index].opname
- if lastopname != '-live-':
- break
- index -= 1
+ if '_ovf' in opname:
+ # ovf checking operation as a lat thing, -live- should be
+ # one before it
+ line = self.popline()
+ self.emitline(opname[:7] + '_jump_if_ovf',
+ TLabel(block.exits[1]), *line[1:])
+ assert len(block.exits) in (2, 3)
+ self.make_link(block.exits[0], False)
+ self.emitline(Label(block.exits[1]))
+ self.make_exception_link(block.exits[1], True)
+ if len(block.exits) == 3:
+ assert block.exits[2].exitcase is Exception
+ self.make_exception_link(block.exits[2], False)
+ return
+ else:
+ while True:
+ lastopname = block.operations[index].opname
+ if lastopname != '-live-':
+ break
+ index -= 1
assert block.exits[0].exitcase is None # is this always True?
#
if not self._include_all_exc_links:
@@ -235,10 +261,10 @@
#if not livebefore:
# self.emitline('-live-', TLabel(linkfalse))
# true path:
- self.make_link(linktrue)
+ self.make_link(linktrue, handling_ovf)
# false path:
self.emitline(Label(linkfalse))
- self.make_link(linkfalse)
+ self.make_link(linkfalse, handling_ovf)
#
else:
# A switch.
@@ -261,7 +287,7 @@
switchdict)
# emit the default path
if block.exits[-1].exitcase == 'default':
- self.make_link(block.exits[-1])
+ self.make_link(block.exits[-1], handling_ovf)
else:
self.emitline("unreachable")
self.emitline("---")
@@ -275,7 +301,7 @@
# if the switched value doesn't match any case.
self.emitline(Label(switch))
self.emitline('-live-')
- self.make_link(switch)
+ self.make_link(switch, handling_ovf)
def insert_renamings(self, link):
renamings = {}
diff --git a/rpython/jit/codewriter/jtransform.py
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -425,6 +425,8 @@
# dispatch to various implementations depending on the oopspec_name
if oopspec_name.startswith('list.') or
oopspec_name.startswith('newlist'):
prepare = self._handle_list_call
+ elif oopspec_name.startswith('int.'):
+ prepare = self._handle_int_ovf
elif oopspec_name.startswith('stroruni.'):
prepare = self._handle_stroruni_call
elif oopspec_name == 'str.str2unicode':
@@ -1900,6 +1902,14 @@
llmemory.cast_ptr_to_adr(c_func.value))
self.callcontrol.callinfocollection.add(oopspecindex, calldescr, func)
+ def _handle_int_ovf(self, op, oopspec_name, args):
+ assert oopspec_name in ('int.add_ovf', 'int.sub_ovf', 'int.mul_ovf')
+ op0 = SpaceOperation(oopspec_name.replace('.', '_'), args, op.result)
+ if oopspec_name != 'int.sub_ovf':
+ op0 = self._rewrite_symmetric(op0)
+ oplive = SpaceOperation('-live-', [], None)
+ return [oplive, op0]
+
def _handle_stroruni_call(self, op, oopspec_name, args):
SoU = args[0].concretetype # Ptr(STR) or Ptr(UNICODE)
can_raise_memoryerror = {
diff --git a/rpython/jit/codewriter/test/test_flatten.py
b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -71,6 +71,9 @@
_descr_cannot_raise = FakeDescr()
callinfocollection = FakeCallInfoCollection()
def guess_call_kind(self, op):
+ if op.args[0].value._obj._name.startswith(
+ ('ll_int_add_ovf', 'll_int_sub_ovf', 'll_int_mul_ovf')):
+ return 'builtin'
return 'residual'
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE,
extraeffect=None, extradescr=None):
@@ -478,7 +481,7 @@
except ZeroDivisionError:
return -42
self.encoding_test(f, [7, 2], """
- residual_call_ir_i $<* fn int_floordiv_ovf_zer>, I[%i0, %i1], R[],
<Descr> -> %i2
+ residual_call_ir_i $<* fn ll_int_floordiv_ovf_zer__Signed_Signed>,
I[%i0, %i1], R[], <Descr> -> %i2
-live-
catch_exception L1
int_return %i2
@@ -505,7 +508,7 @@
return 42
# XXX so far, this really produces a int_mod_ovf_zer...
self.encoding_test(f, [7, 2], """
- residual_call_ir_i $<* fn int_mod_ovf_zer>, I[%i0, %i1], R[],
<Descr> -> %i2
+ residual_call_ir_i $<* fn ll_int_mod_ovf_zer__Signed_Signed>,
I[%i0, %i1], R[], <Descr> -> %i2
-live-
catch_exception L1
int_return %i2
@@ -548,6 +551,36 @@
int_return $42
""", transform=True, liveness=True)
+ def test_int_sub_ovf(self):
+ def f(i, j):
+ try:
+ return ovfcheck(i - j)
+ except OverflowError:
+ return 42
+ self.encoding_test(f, [7, 2], """
+ -live- %i0, %i1
+ int_sub_jump_if_ovf L1, %i0, %i1 -> %i2
+ int_return %i2
+ ---
+ L1:
+ int_return $42
+ """, transform=True, liveness=True)
+
+ def test_int_mul_ovf(self):
+ def f(i, j):
+ try:
+ return ovfcheck(i * j)
+ except OverflowError:
+ return 42
+ self.encoding_test(f, [7, 2], """
+ -live- %i0, %i1
+ int_mul_jump_if_ovf L1, %i0, %i1 -> %i2
+ int_return %i2
+ ---
+ L1:
+ int_return $42
+ """, transform=True, liveness=True)
+
def test_multiple_int_add_ovf(self):
def f(i, j):
try:
diff --git a/rpython/rtyper/rint.py b/rpython/rtyper/rint.py
--- a/rpython/rtyper/rint.py
+++ b/rpython/rtyper/rint.py
@@ -378,7 +378,6 @@
LLONG_BITS_1 = r_longlong.BITS - 1
LLLONG_BITS_1 = r_longlonglong.BITS - 1
INT_MIN = int(-(1 << INT_BITS_1))
-LLONG_MIN = r_longlong(-(1 << LLONG_BITS_1))
# ---------- floordiv ----------
@@ -505,35 +504,28 @@
# ---------- add, sub, mul ----------
[email protected]("add_ovf")
[email protected]("int.add_ovf(x, y)")
def ll_int_add_ovf(x, y):
r = intmask(r_uint(x) + r_uint(y))
if r^x < 0 and r^y < 0:
raise OverflowError("integer addition")
return r
[email protected]("add_ovf")
[email protected]("int.add_ovf(x, y)")
def ll_int_add_nonneg_ovf(x, y): # y can be assumed >= 0
r = intmask(r_uint(x) + r_uint(y))
if r < x:
raise OverflowError("integer addition")
return r
[email protected]("sub_ovf")
[email protected]("int.sub_ovf(x, y)")
def ll_int_sub_ovf(x, y):
r = intmask(r_uint(x) - r_uint(y))
if r^x < 0 and r^~y < 0:
raise OverflowError("integer subtraction")
return r
[email protected]("sub_ovf")
-def ll_llong_sub_ovf(x, y):
- r = longlongmask(r_ulonglong(x) - r_ulonglong(y))
- if r^x < 0 and r^~y < 0:
- raise OverflowError("longlong subtraction")
- return r
-
[email protected]("mul_ovf")
[email protected]("int.mul_ovf(a, b)")
def ll_int_mul_ovf(a, b):
if INT_BITS_1 < LLONG_BITS_1:
rr = r_longlong(a) * r_longlong(b)
@@ -578,23 +570,11 @@
raise OverflowError
return -x
-def ll_llong_neg_ovf(x):
- if jit.we_are_jitted():
- return ll_llong_sub_ovf(0, x)
- if x == LLONG_MIN:
- raise OverflowError
- return -x
-
def ll_int_abs_ovf(x):
if x == INT_MIN:
raise OverflowError
return abs(x)
-def ll_llong_abs_ovf(x):
- if x == LLONG_MIN:
- raise OverflowError
- return abs(x)
-
#Helper functions for comparisons
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit