[pypy-svn] pypy jit-longlong: Change the point at which we replace Constants of type LongLong.

arigo commits-noreply at bitbucket.org
Sun Jan 9 18:21:05 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: jit-longlong
Changeset: r40532:d026413dcaf5
Date: 2011-01-09 18:20 +0100
http://bitbucket.org/pypy/pypy/changeset/d026413dcaf5/

Log:	Change the point at which we replace Constants of type LongLong. Now
	it should be more general, and also handle Constants that appear in
	link.args.

diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py
--- a/pypy/jit/codewriter/test/test_longlong.py
+++ b/pypy/jit/codewriter/test/test_longlong.py
@@ -2,6 +2,7 @@
 
 from pypy.rlib.rarithmetic import r_longlong, intmask
 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
+from pypy.objspace.flow.model import Block, Link
 from pypy.translator.unsimplify import varoftype
 from pypy.rpython.lltypesystem import lltype
 from pypy.jit.codewriter.jtransform import Transformer, NotSupported
@@ -57,6 +58,42 @@
                                      if is_llf(v.concretetype)]
         assert op1.result == v_result
 
+    def test_remove_longlong_constant(self):
+        c1 = Constant(r_longlong(-123), lltype.SignedLongLong)
+        c2 = Constant(r_longlong(-124), lltype.SignedLongLong)
+        c3 = Constant(r_longlong(0x987654321), lltype.SignedLongLong)
+        v1 = varoftype(lltype.SignedLongLong)
+        v2 = varoftype(lltype.Bool)
+        block = Block([v1])
+        block.operations = [SpaceOperation('foo', [c1, v1, c3], v2)]
+        block.exitswitch = v2
+        block.closeblock(Link([c2], block, exitcase=False),
+                         Link([c1], block, exitcase=True))
+        tr = Transformer()
+        tr.remove_longlong_constants(block)
+        assert len(block.operations) == 4
+        assert block.operations[0].opname == 'cast_int_to_longlong'
+        assert block.operations[0].args[0].value == -123
+        assert block.operations[0].args[0].concretetype == lltype.Signed
+        v3 = block.operations[0].result
+        assert block.operations[1].opname == 'two_ints_to_longlong'
+        assert block.operations[1].args[0].value == intmask(0x87654321)
+        assert block.operations[1].args[0].concretetype == lltype.Signed
+        assert block.operations[1].args[1].value == 0x9
+        assert block.operations[1].args[1].concretetype == lltype.Signed
+        v4 = block.operations[1].result
+        assert block.operations[2].opname == 'foo'
+        assert block.operations[2].args[0] is v3
+        assert block.operations[2].args[1] is v1
+        assert block.operations[2].args[2] is v4
+        assert block.operations[2].result is v2
+        assert block.operations[3].opname == 'cast_int_to_longlong'
+        assert block.operations[3].args[0].value == -124
+        assert block.operations[3].args[0].concretetype == lltype.Signed
+        v5 = block.operations[3].result
+        assert block.exits[0].args[0] is v5
+        assert block.exits[1].args[0] is v3
+
     def test_is_true(self):
         for opname, T in [('llong_is_true', lltype.SignedLongLong),
                           ('ullong_is_true', lltype.UnsignedLongLong)]:
@@ -181,54 +218,3 @@
                       [lltype.Float], lltype.SignedLongLong)
         self.do_check('cast_longlong_to_float', EffectInfo.OS_LLONG_TO_FLOAT,
                       [lltype.SignedLongLong], lltype.Float)
-
-    def test_prebuilt_constant_32(self):
-        c_x = const(r_longlong(-171))
-        v_y = varoftype(lltype.SignedLongLong)
-        v_z = varoftype(lltype.SignedLongLong)
-        op = SpaceOperation('llong_add', [c_x, v_y], v_z)
-        tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
-        oplist = tr.rewrite_operation(op)
-        assert len(oplist) == 2
-        assert oplist[0].opname == 'residual_call_irf_f'
-        assert oplist[0].args[0].value == 'llong_from_int'
-        assert oplist[0].args[1] == 'calldescr-84'
-        assert list(oplist[0].args[2]) == [const(-171)]
-        assert list(oplist[0].args[3]) == []
-        assert list(oplist[0].args[4]) == []
-        v_x = oplist[0].result
-        assert isinstance(v_x, Variable)
-        assert oplist[1].opname == 'residual_call_irf_f'
-        assert oplist[1].args[0].value == 'llong_add'
-        assert oplist[1].args[1] == 'calldescr-70'
-        assert list(oplist[1].args[2]) == []
-        assert list(oplist[1].args[3]) == []
-        assert list(oplist[1].args[4]) == [v_x, v_y]
-        assert oplist[1].result == v_z
-
-    def test_prebuilt_constant_64(self):
-        for value in [3000000000, -3000000000, 12345678987654321]:
-            v_hi = intmask(value >> 32)
-            v_lo = intmask(value)
-            c_x = const(r_longlong(value))
-            v_y = varoftype(lltype.SignedLongLong)
-            v_z = varoftype(lltype.SignedLongLong)
-            op = SpaceOperation('llong_add', [c_x, v_y], v_z)
-            tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
-            oplist = tr.rewrite_operation(op)
-            assert len(oplist) == 2
-            assert oplist[0].opname == 'residual_call_irf_f'
-            assert oplist[0].args[0].value == 'llong_from_two_ints'
-            assert oplist[0].args[1] == 'calldescr-93'
-            assert list(oplist[0].args[2]) == [const(v_lo), const(v_hi)]
-            assert list(oplist[0].args[3]) == []
-            assert list(oplist[0].args[4]) == []
-            v_x = oplist[0].result
-            assert isinstance(v_x, Variable)
-            assert oplist[1].opname == 'residual_call_irf_f'
-            assert oplist[1].args[0].value == 'llong_add'
-            assert oplist[1].args[1] == 'calldescr-70'
-            assert list(oplist[1].args[2]) == []
-            assert list(oplist[1].args[3]) == []
-            assert list(oplist[1].args[4]) == [v_x, v_y]
-            assert oplist[1].result == v_z

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
@@ -39,6 +39,7 @@
     def optimize_block(self, block):
         if block.operations == ():
             return
+        self.remove_longlong_constants(block)
         self.vable_array_vars = {}
         self.vable_flags = {}
         renamings = {}
@@ -134,6 +135,55 @@
         block.exits = block.exits[:1]
         block.exitswitch = None
 
+    def remove_longlong_constants(self, block):
+        # remove all Constant({Un}signedLongLong), and replace them with
+        # cast_int_to_longlong(Constant(Signed)) or
+        # two_ints_to_longlong(Constant(Signed), Constant(Signed)).
+        operations = []
+        all_constants = {}
+        #
+        def _get_const_as_var(c):
+            v = all_constants.get(c)
+            if v is None:
+                from pypy.rlib.rarithmetic import intmask
+                v = varoftype(c.concretetype)
+                value = int(c.value)
+                c_hi = Constant(intmask(value >> 32), lltype.Signed)
+                c_lo = Constant(intmask(value), lltype.Signed)
+                if c_lo.value == value:
+                    # a long long constant, but it fits in 32 bits
+                    op1 = SpaceOperation('cast_int_to_longlong', [c_lo], v)
+                else:
+                    # a 64-bit long long constant, requires two ints
+                    op1 = SpaceOperation('two_ints_to_longlong', [c_lo, c_hi],
+                                         v)
+                operations.append(op1)
+                all_constants[c] = v
+            return v
+        #
+        for op in block.operations:
+            for i, v in enumerate(op.args):
+                if (isinstance(v, Constant) and
+                        self._is_longlong(v.concretetype)):
+                    args = op.args[:]
+                    args[i] = _get_const_as_var(v)
+                    op = SpaceOperation(op.opname, args, op.result)
+            operations.append(op)
+        #
+        last_op = None
+        if block.exitswitch == c_last_exception:
+            last_op = operations.pop()
+        for link in block.exits:
+            for i, v in enumerate(link.args):
+                if (isinstance(v, Constant) and
+                        self._is_longlong(v.concretetype)):
+                    args = link.args[:]
+                    args[i] = _get_const_as_var(v)
+                    link.args = args
+        if last_op is not None:
+            operations.append(last_op)
+        block.operations = operations
+
     # ----------
 
     def follow_constant_exit(self, block):
@@ -268,26 +318,10 @@
     # ----------
     # Various kinds of calls
 
-    def remove_longlong_constants(func):
-        """Decorator.  Detect and remove all Constants of type LongLong."""
-        def remove_and_call(self, op):
-            oplist = []
-            op = self._remove_longlong_constants(op, oplist)
-            ops = func(self, op)
-            if oplist:
-                if not isinstance(ops, list):
-                    assert isinstance(ops, SpaceOperation)
-                    ops = [ops]
-                ops = oplist + ops
-            return ops
-        return remove_and_call
-
-    @remove_longlong_constants
     def rewrite_op_direct_call(self, op):
         kind = self.callcontrol.guess_call_kind(op)
         return getattr(self, 'handle_%s_call' % kind)(op)
 
-    @remove_longlong_constants
     def rewrite_op_indirect_call(self, op):
         kind = self.callcontrol.guess_call_kind(op)
         return getattr(self, 'handle_%s_indirect_call' % kind)(op)
@@ -511,7 +545,6 @@
                               [op.args[0], arraydescr, op.args[1]],
                               op.result)
 
-    @remove_longlong_constants
     def rewrite_op_setarrayitem(self, op):
         ARRAY = op.args[0].concretetype.TO
         if self._array_of_voids(ARRAY):
@@ -594,7 +627,6 @@
         return SpaceOperation('getfield_%s_%s%s' % (argname, kind, pure),
                               [v_inst, descr], op.result)
 
-    @remove_longlong_constants
     def rewrite_op_setfield(self, op):
         if self.is_typeptr_getset(op):
             # ignore the operation completely -- instead, it's done by 'new'
@@ -809,43 +841,16 @@
     # and unsupported ones are turned into a call to a function from
     # jit.codewriter.support.
 
-    @staticmethod
-    def _is_longlong(TYPE):
-        return TYPE == lltype.SignedLongLong or TYPE == lltype.UnsignedLongLong
-
-    def _remove_longlong_constants(self, op, oplist):
-        args = op.args
-        for i in range(len(args)):
-            if (isinstance(args[i], Constant) and
-                    self._is_longlong(args[i].concretetype)):
-                from pypy.rlib.rarithmetic import intmask
-                v_x = varoftype(args[i].concretetype)
-                value = int(args[i].value)
-                if value == intmask(value):
-                    # a long long constant, but it fits in 32 bits
-                    c_x = Constant(value, lltype.Signed)
-                    op0 = SpaceOperation('llong_from_int', [c_x], v_x)
-                    op1 = self.prepare_builtin_call(op0, "llong_from_int",
-                                                    [c_x])
-                    op2 = self._handle_oopspec_call(op1, [c_x],
-                                                  EffectInfo.OS_LLONG_FROM_INT)
-                else:
-                    # a long long constant, requires two ints
-                    c_hi = Constant(intmask(value >> 32), lltype.Signed)
-                    c_lo = Constant(intmask(value), lltype.Signed)
-                    op0 = SpaceOperation('llong_from_two_ints', [c_lo, c_hi],
-                                         v_x)
-                    op1 = self.prepare_builtin_call(op0, "llong_from_two_ints",
-                                                    [c_lo, c_hi])
-                    op2 = self._handle_oopspec_call(op1, [c_lo, c_hi],
-                                             EffectInfo.OS_LLONG_FROM_TWO_INTS)
-                oplist.append(op2)
-                args = args[:]
-                args[i] = v_x
-        if args is op.args:
-            return op
-        else:
-            return SpaceOperation(op.opname, args, op.result)
+    if lltype.SignedLongLong != lltype.Signed:
+        @staticmethod
+        def _is_longlong(TYPE):
+            return (TYPE == lltype.SignedLongLong or
+                    TYPE == lltype.UnsignedLongLong)
+    else:
+        # on 64-bit, _is_longlong() returns always False
+        @staticmethod
+        def _is_longlong(TYPE):
+            return False
 
     for _op, _oopspec in [('llong_invert',  'INVERT'),
                           ('ullong_invert', 'INVERT'),
@@ -885,7 +890,6 @@
                           ('two_ints_to_longlong',     'FROM_TWO_INTS'),
                           ]:
         exec py.code.Source('''
-            @remove_longlong_constants
             def rewrite_op_%s(self, op):
                 args = op.args
                 op1 = self.prepare_builtin_call(op, "llong_%s", args)
@@ -894,15 +898,32 @@
                 return op2
         ''' % (_op, _oopspec.lower(), _oopspec)).compile()
 
+    def _normalize(self, oplist):
+        if isinstance(oplist, SpaceOperation):
+            return [oplist]
+        else:
+            assert type(oplist) is list
+            return oplist
+
     def rewrite_op_llong_neg(self, op):
-        args = [Constant(0, lltype.SignedLongLong), op.args[0]]
+        v = varoftype(lltype.SignedLongLong)
+        op0 = SpaceOperation('cast_int_to_longlong',
+                             [Constant(0, lltype.Signed)],
+                             v)
+        args = [v, op.args[0]]
         op1 = SpaceOperation('llong_sub', args, op.result)
-        return self.rewrite_operation(op1)
+        return (self._normalize(self.rewrite_operation(op0)) +
+                self._normalize(self.rewrite_operation(op1)))
 
     def rewrite_op_llong_is_true(self, op):
-        args = [op.args[0], Constant(0, lltype.SignedLongLong)]
+        v = varoftype(lltype.SignedLongLong)
+        op0 = SpaceOperation('cast_int_to_longlong',
+                             [Constant(0, lltype.Signed)],
+                             v)
+        args = [op.args[0], v]
         op1 = SpaceOperation('llong_ne', args, op.result)
-        return self.rewrite_operation(op1)
+        return (self._normalize(self.rewrite_operation(op0)) +
+                self._normalize(self.rewrite_operation(op1)))
 
     rewrite_op_ullong_is_true = rewrite_op_llong_is_true
 


More information about the Pypy-commit mailing list