[pypy-commit] pypy default: merged jit-codewriter-force-cast-refactor. This branch cleans up the implementation of force_cast in the JIT, fixing bugs, and extending support for between any integer type and any float type.
alex_gaynor
noreply at buildbot.pypy.org
Sun Aug 28 06:56:07 CEST 2011
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch:
Changeset: r46844:9db83e93127d
Date: 2011-08-28 00:55 -0400
http://bitbucket.org/pypy/pypy/changeset/9db83e93127d/
Log: merged jit-codewriter-force-cast-refactor. This branch cleans up
the implementation of force_cast in the JIT, fixing bugs, and
extending support for between any integer type and any float type.
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
@@ -1,4 +1,5 @@
import py
+
from pypy.jit.codewriter import support, heaptracker, longlong
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
@@ -22,6 +23,11 @@
t = Transformer(cpu, callcontrol, portal_jd)
t.transform(graph)
+def integer_bounds(size, unsigned):
+ if unsigned:
+ return 0, 1 << (8 * size)
+ else:
+ return -(1 << (8 * size - 1)), 1 << (8 * size - 1)
class Transformer(object):
vable_array_vars = None
@@ -780,81 +786,127 @@
raise NotImplementedError("cast_ptr_to_int")
def rewrite_op_force_cast(self, op):
- assert not self._is_gc(op.args[0])
- fromll = longlong.is_longlong(op.args[0].concretetype)
- toll = longlong.is_longlong(op.result.concretetype)
- if fromll and toll:
+ v_arg = op.args[0]
+ v_result = op.result
+ assert not self._is_gc(v_arg)
+
+ if v_arg.concretetype == v_result.concretetype:
return
- if fromll:
- args = op.args
- opname = 'truncate_longlong_to_int'
- RESULT = lltype.Signed
- v = varoftype(RESULT)
- op1 = SpaceOperation(opname, args, v)
- op2 = self.rewrite_operation(op1)
- oplist = self.force_cast_without_longlong(op2.result, op.result)
+
+ float_arg = v_arg.concretetype in [lltype.Float, lltype.SingleFloat]
+ float_res = v_result.concretetype in [lltype.Float, lltype.SingleFloat]
+ if not float_arg and not float_res:
+ # some int -> some int cast
+ return self._int_to_int_cast(v_arg, v_result)
+ elif float_arg and float_res:
+ # some float -> some float cast
+ return self._float_to_float_cast(v_arg, v_result)
+ elif not float_arg and float_res:
+ # some int -> some float
+ ops = []
+ v1 = varoftype(lltype.Signed)
+ oplist = self.rewrite_operation(
+ SpaceOperation('force_cast', [v_arg], v1)
+ )
if oplist:
- return [op2] + oplist
- #
- # force a renaming to put the correct result in place, even though
- # it might be slightly mistyped (e.g. Signed versus Unsigned)
- assert op2.result is v
- op2.result = op.result
- return op2
- elif toll:
- size, unsigned = rffi.size_and_sign(op.args[0].concretetype)
- if unsigned:
+ ops.extend(oplist)
+ else:
+ v1 = v_arg
+ v2 = varoftype(lltype.Float)
+ op = self.rewrite_operation(
+ SpaceOperation('cast_int_to_float', [v1], v2)
+ )
+ ops.append(op)
+ op2 = self.rewrite_operation(
+ SpaceOperation('force_cast', [v2], v_result)
+ )
+ if op2:
+ ops.append(op2)
+ else:
+ op.result = v_result
+ return ops
+ elif float_arg and not float_res:
+ # some float -> some int
+ ops = []
+ v1 = varoftype(lltype.Float)
+ op1 = self.rewrite_operation(
+ SpaceOperation('force_cast', [v_arg], v1)
+ )
+ if op1:
+ ops.append(op1)
+ else:
+ v1 = v_arg
+ v2 = varoftype(lltype.Signed)
+ op = self.rewrite_operation(
+ SpaceOperation('cast_float_to_int', [v1], v2)
+ )
+ ops.append(op)
+ oplist = self.rewrite_operation(
+ SpaceOperation('force_cast', [v2], v_result)
+ )
+ if oplist:
+ ops.extend(oplist)
+ else:
+ op.result = v_result
+ return ops
+ else:
+ assert False
+
+ def _int_to_int_cast(self, v_arg, v_result):
+ longlong_arg = longlong.is_longlong(v_arg.concretetype)
+ longlong_res = longlong.is_longlong(v_result.concretetype)
+ size1, unsigned1 = rffi.size_and_sign(v_arg.concretetype)
+ size2, unsigned2 = rffi.size_and_sign(v_result.concretetype)
+
+ if longlong_arg and longlong_res:
+ return
+ elif longlong_arg:
+ v = varoftype(lltype.Signed)
+ op1 = self.rewrite_operation(
+ SpaceOperation('truncate_longlong_to_int', [v_arg], v)
+ )
+ op2 = SpaceOperation('force_cast', [v], v_result)
+ oplist = self.rewrite_operation(op2)
+ if not oplist:
+ op1.result = v_result
+ oplist = []
+ return [op1] + oplist
+ elif longlong_res:
+ if unsigned1:
INTERMEDIATE = lltype.Unsigned
else:
INTERMEDIATE = lltype.Signed
v = varoftype(INTERMEDIATE)
- oplist = self.force_cast_without_longlong(op.args[0], v)
+ op1 = SpaceOperation('force_cast', [v_arg], v)
+ oplist = self.rewrite_operation(op1)
if not oplist:
- v = op.args[0]
+ v = v_arg
oplist = []
- if unsigned:
+ if unsigned1:
opname = 'cast_uint_to_longlong'
else:
opname = 'cast_int_to_longlong'
- op1 = SpaceOperation(opname, [v], op.result)
- op2 = self.rewrite_operation(op1)
+ op2 = self.rewrite_operation(
+ SpaceOperation(opname, [v], v_result)
+ )
return oplist + [op2]
- else:
- return self.force_cast_without_longlong(op.args[0], op.result)
- def force_cast_without_longlong(self, v_arg, v_result):
- if v_result.concretetype == v_arg.concretetype:
+ # We've now, ostensibly, dealt with the longlongs, everything should be
+ # a Signed or smaller
+ assert size1 <= rffi.sizeof(lltype.Signed)
+ assert size2 <= rffi.sizeof(lltype.Signed)
+
+ # the target type is LONG or ULONG
+ if size2 == rffi.sizeof(lltype.Signed):
return
- if v_arg.concretetype == rffi.FLOAT:
- assert v_result.concretetype == lltype.Float, "cast %s -> %s" % (
- v_arg.concretetype, v_result.concretetype)
- return SpaceOperation('cast_singlefloat_to_float', [v_arg],
- v_result)
- if v_result.concretetype == rffi.FLOAT:
- assert v_arg.concretetype == lltype.Float, "cast %s -> %s" % (
- v_arg.concretetype, v_result.concretetype)
- return SpaceOperation('cast_float_to_singlefloat', [v_arg],
- v_result)
- return self.force_cast_without_singlefloat(v_arg, v_result)
- def force_cast_without_singlefloat(self, v_arg, v_result):
- size2, unsigned2 = rffi.size_and_sign(v_result.concretetype)
- assert size2 <= rffi.sizeof(lltype.Signed)
- if size2 == rffi.sizeof(lltype.Signed):
- return # the target type is LONG or ULONG
- size1, unsigned1 = rffi.size_and_sign(v_arg.concretetype)
- assert size1 <= rffi.sizeof(lltype.Signed)
- #
- def bounds(size, unsigned):
- if unsigned:
- return 0, 1<<(8*size)
- else:
- return -(1<<(8*size-1)), 1<<(8*size-1)
- min1, max1 = bounds(size1, unsigned1)
- min2, max2 = bounds(size2, unsigned2)
+ min1, max1 = integer_bounds(size1, unsigned1)
+ min2, max2 = integer_bounds(size2, unsigned2)
+
+ # the target type includes the source range
if min2 <= min1 <= max1 <= max2:
- return # the target type includes the source range
- #
+ return
+
result = []
if min2:
c_min2 = Constant(min2, lltype.Signed)
@@ -862,15 +914,28 @@
result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2))
else:
v2 = v_arg
- c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed)
- v3 = varoftype(lltype.Signed)
+ c_mask = Constant(int((1 << (8 * size2)) - 1), lltype.Signed)
+ if min2:
+ v3 = varoftype(lltype.Signed)
+ else:
+ v3 = v_result
result.append(SpaceOperation('int_and', [v2, c_mask], v3))
if min2:
result.append(SpaceOperation('int_add', [v3, c_min2], v_result))
- else:
- result[-1].result = v_result
return result
+ def _float_to_float_cast(self, v_arg, v_result):
+ if v_arg.concretetype == lltype.SingleFloat:
+ assert v_result.concretetype == lltype.Float, "cast %s -> %s" % (
+ v_arg.concretetype, v_result.concretetype)
+ return SpaceOperation('cast_singlefloat_to_float', [v_arg],
+ v_result)
+ if v_result.concretetype == lltype.SingleFloat:
+ assert v_arg.concretetype == lltype.Float, "cast %s -> %s" % (
+ v_arg.concretetype, v_result.concretetype)
+ return SpaceOperation('cast_float_to_singlefloat', [v_arg],
+ v_result)
+
def rewrite_op_direct_ptradd(self, op):
# xxx otherwise, not implemented:
assert op.args[0].concretetype == rffi.CCHARP
diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py
--- a/pypy/jit/codewriter/test/test_flatten.py
+++ b/pypy/jit/codewriter/test/test_flatten.py
@@ -324,7 +324,7 @@
def test_exc_exitswitch(self):
def g(i):
pass
-
+
def f(i):
try:
g(i)
@@ -854,13 +854,51 @@
int_return %i0
""", transform=True)
- def test_force_cast_float(self):
+ def test_force_cast_floats(self):
from pypy.rpython.lltypesystem import rffi
+ # Caststs to lltype.Float
def f(n):
return rffi.cast(lltype.Float, n)
self.encoding_test(f, [12.456], """
float_return %f0
""", transform=True)
+ self.encoding_test(f, [rffi.cast(rffi.SIGNEDCHAR, 42)], """
+ cast_int_to_float %i0 -> %f0
+ float_return %f0
+ """, transform=True)
+
+ # Casts to lltype.SingleFloat
+ def g(n):
+ return rffi.cast(lltype.SingleFloat, n)
+ self.encoding_test(g, [12.456], """
+ cast_float_to_singlefloat %f0 -> %i0
+ int_return %i0
+ """, transform=True)
+ self.encoding_test(g, [rffi.cast(rffi.SIGNEDCHAR, 42)], """
+ cast_int_to_float %i0 -> %f0
+ cast_float_to_singlefloat %f0 -> %i1
+ int_return %i1
+ """, transform=True)
+
+ # Casts from floats
+ def f(n):
+ return rffi.cast(rffi.SIGNEDCHAR, n)
+ self.encoding_test(f, [12.456], """
+ cast_float_to_int %f0 -> %i0
+ int_sub %i0, $-128 -> %i1
+ int_and %i1, $255 -> %i2
+ int_add %i2, $-128 -> %i3
+ int_return %i3
+ """, transform=True)
+ self.encoding_test(f, [rffi.cast(lltype.SingleFloat, 12.456)], """
+ cast_singlefloat_to_float %i0 -> %f0
+ cast_float_to_int %f0 -> %i1
+ int_sub %i1, $-128 -> %i2
+ int_and %i2, $255 -> %i3
+ int_add %i3, $-128 -> %i4
+ int_return %i4
+ """, transform=True)
+
def test_direct_ptradd(self):
from pypy.rpython.lltypesystem import rffi
More information about the pypy-commit
mailing list