Author: Alex Gaynor <alex.gay...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit