Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r74738:68c97410a30e
Date: 2014-11-26 18:16 +0100
http://bitbucket.org/pypy/pypy/changeset/68c97410a30e/

Log:    Add 'int_signext' to replace the three instructions which have all
        very large constants when used to sign-extend a 32-bit integer into
        a full 64-bit word.

diff --git a/rpython/jit/backend/arm/codebuilder.py 
b/rpython/jit/backend/arm/codebuilder.py
--- a/rpython/jit/backend/arm/codebuilder.py
+++ b/rpython/jit/backend/arm/codebuilder.py
@@ -318,6 +318,18 @@
                     | (rd & 0xF) << 12
                     | imm16 & 0xFFF)
 
+    def SXTB_rr(self, rd, rm, c=cond.AL):
+        self.write32(c << 28
+                    | 0x06AF0070
+                    | (rd & 0xF) << 12
+                    | (rm & 0xF))
+
+    def SXTB16_rr(self, rd, rm, c=cond.AL):
+        self.write32(c << 28
+                    | 0x068F0070
+                    | (rd & 0xF) << 12
+                    | (rm & 0xF))
+
     def LDREX(self, rt, rn, c=cond.AL):
         self.write32(c << 28
                     | 0x01900f9f
diff --git a/rpython/jit/backend/arm/opassembler.py 
b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -102,6 +102,17 @@
         self.mc.MOV_rr(res.value, arg.value, cond=c.GE)
         return fcond
 
+    def emit_op_int_signext(self, op, arglocs, regalloc, fcond):
+        arg, numbytes, res = arglocs
+        assert numbytes.is_imm()
+        if numbytes.value == 1:
+            self.mc.SXTB_rr(res.value, arg.value)
+        elif numbytes.value == 2:
+            self.mc.SXTB16_rr(res.value, arg.value)
+        else:
+            raise AssertionError("bad number of bytes")
+        return fcond
+
     #ref: http://blogs.arm.com/software-enablement/detecting-overflow-from-mul/
     def emit_guard_int_mul_ovf(self, op, guard, arglocs, regalloc, fcond):
         reg1 = arglocs[0]
diff --git a/rpython/jit/backend/arm/regalloc.py 
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -458,6 +458,12 @@
         resloc = self.force_allocate_reg(op.result, [op.getarg(0)])
         return [argloc, resloc]
 
+    def prepare_op_int_signext(self, op, fcond):
+        argloc = self.make_sure_var_in_reg(op.getarg(0))
+        numbytes = op.getarg(1).getint()
+        resloc = self.force_allocate_reg(op.result)
+        return [argloc, imm(numbytes), resloc]
+
     def prepare_guard_int_mul_ovf(self, op, guard, fcond):
         boxes = op.getarglist()
         reg1 = self.make_sure_var_in_reg(boxes[0], forbidden_vars=boxes)
diff --git a/rpython/jit/backend/test/runner_test.py 
b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -3890,6 +3890,26 @@
             deadframe = self.cpu.execute_token(looptoken, inp)
             assert outp == self.cpu.get_int_value(deadframe, 0)
 
+    def test_int_signext(self):
+        numbytes_cases = [1, 2] if IS_32_BIT else [1, 2, 4]
+        for numbytes in numbytes_cases:
+            ops = """
+            [i0]
+            i1 = int_signext(i0, %d)
+            finish(i1, descr=descr)
+            """ % numbytes
+            descr = BasicFinalDescr()
+            loop = parse(ops, self.cpu, namespace=locals())
+            looptoken = JitCellToken()
+            self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+            test_cases = [random.randrange(-sys.maxint-1, sys.maxint+1)
+                          for _ in range(100)]
+            for test_case in test_cases:
+                deadframe = self.cpu.execute_token(looptoken, test_case)
+                got = self.cpu.get_int_value(deadframe, 0)
+                expected = heaptracker.int_signext(test_case, numbytes)
+                assert got == expected
+
     def test_compile_asmlen(self):
         from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
         if not isinstance(self.cpu, AbstractLLCPU):
diff --git a/rpython/jit/backend/x86/assembler.py 
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -1143,6 +1143,18 @@
     def genop_math_sqrt(self, op, arglocs, resloc):
         self.mc.SQRTSD(arglocs[0], resloc)
 
+    def genop_int_signext(self, op, arglocs, resloc):
+        argloc, numbytesloc = arglocs
+        assert isinstance(numbytesloc, ImmedLoc)
+        if numbytesloc.value == 1:
+            self.mc.MOVSX8(resloc, argloc)
+        elif numbytesloc.value == 2:
+            self.mc.MOVSX16(resloc, argloc)
+        elif IS_X86_64 and numbytesloc.value == 4:
+            self.mc.MOVSX32(resloc, argloc)
+        else:
+            raise AssertionError("bad number of bytes")
+
     def genop_guard_float_ne(self, op, guard_op, guard_token, arglocs, 
result_loc):
         guard_opnum = guard_op.getopnum()
         if isinstance(arglocs[0], RegLoc):
diff --git a/rpython/jit/backend/x86/regalloc.py 
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -474,6 +474,12 @@
 
     consider_int_invert = consider_int_neg
 
+    def consider_int_signext(self, op):
+        argloc = self.loc(op.getarg(0))
+        numbytesloc = self.loc(op.getarg(1))
+        resloc = self.force_allocate_reg(op.result)
+        self.perform(op, [argloc, numbytesloc], resloc)
+
     def consider_int_lshift(self, op):
         if isinstance(op.getarg(1), Const):
             loc2 = self.rm.convert_to_imm(op.getarg(1))
diff --git a/rpython/jit/codewriter/heaptracker.py 
b/rpython/jit/codewriter/heaptracker.py
--- a/rpython/jit/codewriter/heaptracker.py
+++ b/rpython/jit/codewriter/heaptracker.py
@@ -1,6 +1,7 @@
 from rpython.rtyper.lltypesystem import lltype, llmemory
 from rpython.rtyper import rclass
 from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rarithmetic import r_uint, intmask
 
 
 def adr2int(addr):
@@ -11,6 +12,14 @@
 def int2adr(int):
     return llmemory.cast_int_to_adr(int)
 
+def int_signext(value, numbytes):
+    b8 = numbytes * 8
+    a = r_uint(value)
+    a += r_uint(1 << (b8 - 1))     # a += 128
+    a &= r_uint((1 << b8) - 1)     # a &= 255
+    a -= r_uint(1 << (b8 - 1))     # a -= 128
+    return intmask(a)
+
 def count_fields_if_immutable(STRUCT):
     assert isinstance(STRUCT, lltype.GcStruct)
     if STRUCT._hints.get('immutable', False):
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
@@ -1267,19 +1267,12 @@
 
         result = []
         if min2:
-            c_min2 = Constant(min2, lltype.Signed)
-            v2 = varoftype(lltype.Signed)
-            result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2))
+            c_bytes = Constant(size2, lltype.Signed)
+            result.append(SpaceOperation('int_signext', [v_arg, c_bytes],
+                                         v_result))
         else:
-            v2 = v_arg
-        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))
+            c_mask = Constant(int((1 << (8 * size2)) - 1), lltype.Signed)
+            result.append(SpaceOperation('int_and', [v_arg, c_mask], v_result))
         return result
 
     def _float_to_float_cast(self, v_arg, v_result):
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
@@ -1,5 +1,6 @@
 import py, sys
 from rpython.jit.codewriter import support
+from rpython.jit.codewriter.heaptracker import int_signext
 from rpython.jit.codewriter.flatten import flatten_graph, reorder_renaming_list
 from rpython.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register
 from rpython.jit.codewriter.format import assert_format
@@ -780,53 +781,37 @@
             (rffi.SIGNEDCHAR, rffi.LONG, ""),
             (rffi.SIGNEDCHAR, rffi.ULONG, ""),
 
-            (rffi.UCHAR, rffi.SIGNEDCHAR, """int_sub %i0, $-128 -> %i1
-                                             int_and %i1, $255 -> %i2
-                                             int_add %i2, $-128 -> %i3"""),
+            (rffi.UCHAR, rffi.SIGNEDCHAR, "int_signext %i0, $1 -> %i1"),
             (rffi.UCHAR, rffi.UCHAR, ""),
             (rffi.UCHAR, rffi.SHORT, ""),
             (rffi.UCHAR, rffi.USHORT, ""),
             (rffi.UCHAR, rffi.LONG, ""),
             (rffi.UCHAR, rffi.ULONG, ""),
 
-            (rffi.SHORT, rffi.SIGNEDCHAR, """int_sub %i0, $-128 -> %i1
-                                             int_and %i1, $255 -> %i2
-                                             int_add %i2, $-128 -> %i3"""),
+            (rffi.SHORT, rffi.SIGNEDCHAR, "int_signext %i0, $1 -> %i1"),
             (rffi.SHORT, rffi.UCHAR, "int_and %i0, $255 -> %i1"),
             (rffi.SHORT, rffi.SHORT, ""),
             (rffi.SHORT, rffi.USHORT, "int_and %i0, $65535 -> %i1"),
             (rffi.SHORT, rffi.LONG, ""),
             (rffi.SHORT, rffi.ULONG, ""),
 
-            (rffi.USHORT, rffi.SIGNEDCHAR, """int_sub %i0, $-128 -> %i1
-                                              int_and %i1, $255 -> %i2
-                                              int_add %i2, $-128 -> %i3"""),
+            (rffi.USHORT, rffi.SIGNEDCHAR, "int_signext %i0, $1 -> %i1"),
             (rffi.USHORT, rffi.UCHAR, "int_and %i0, $255 -> %i1"),
-            (rffi.USHORT, rffi.SHORT, """int_sub %i0, $-32768 -> %i1
-                                         int_and %i1, $65535 -> %i2
-                                         int_add %i2, $-32768 -> %i3"""),
+            (rffi.USHORT, rffi.SHORT, "int_signext %i0, $2 -> %i1"),
             (rffi.USHORT, rffi.USHORT, ""),
             (rffi.USHORT, rffi.LONG, ""),
             (rffi.USHORT, rffi.ULONG, ""),
 
-            (rffi.LONG, rffi.SIGNEDCHAR, """int_sub %i0, $-128 -> %i1
-                                            int_and %i1, $255 -> %i2
-                                            int_add %i2, $-128 -> %i3"""),
+            (rffi.LONG, rffi.SIGNEDCHAR, "int_signext %i0, $1 -> %i1"),
             (rffi.LONG, rffi.UCHAR, "int_and %i0, $255 -> %i1"),
-            (rffi.LONG, rffi.SHORT, """int_sub %i0, $-32768 -> %i1
-                                       int_and %i1, $65535 -> %i2
-                                       int_add %i2, $-32768 -> %i3"""),
+            (rffi.LONG, rffi.SHORT, "int_signext %i0, $2 -> %i1"),
             (rffi.LONG, rffi.USHORT, "int_and %i0, $65535 -> %i1"),
             (rffi.LONG, rffi.LONG, ""),
             (rffi.LONG, rffi.ULONG, ""),
 
-            (rffi.ULONG, rffi.SIGNEDCHAR, """int_sub %i0, $-128 -> %i1
-                                             int_and %i1, $255 -> %i2
-                                             int_add %i2, $-128 -> %i3"""),
+            (rffi.ULONG, rffi.SIGNEDCHAR, "int_signext %i0, $1 -> %i1"),
             (rffi.ULONG, rffi.UCHAR, "int_and %i0, $255 -> %i1"),
-            (rffi.ULONG, rffi.SHORT, """int_sub %i0, $-32768 -> %i1
-                                        int_and %i1, $65535 -> %i2
-                                        int_add %i2, $-32768 -> %i3"""),
+            (rffi.ULONG, rffi.SHORT, "int_signext %i0, $2 -> %i1"),
             (rffi.ULONG, rffi.USHORT, "int_and %i0, $65535 -> %i1"),
             (rffi.ULONG, rffi.LONG, ""),
             (rffi.ULONG, rffi.ULONG, ""),
@@ -910,18 +895,14 @@
             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
+            int_signext %i0, $1 -> %i1
+            int_return %i1
         """, 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
+            int_signext %i1, $1 -> %i2
+            int_return %i2
         """, transform=True)
 
         def f(dbl):
@@ -1068,9 +1049,12 @@
         match = r.match(op)
         assert match, "line %r does not match regexp" % (op,)
         opname = match.group(1)
-        if   opname == 'int_add': value += int(match.group(2))
-        elif opname == 'int_sub': value -= int(match.group(2))
-        elif opname == 'int_and': value &= int(match.group(2))
-        else: assert 0, opname
+        if opname == 'int_and':
+            value &= int(match.group(2))
+        elif opname == 'int_signext':
+            numbytes = int(match.group(2))
+            value = int_signext(value, numbytes)
+        else:
+            assert 0, opname
     #
     assert rffi.cast(lltype.Signed, value) == expected_value
diff --git a/rpython/jit/metainterp/blackhole.py 
b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -489,6 +489,9 @@
         if i < 0:
             return 0
         return i
+    @arguments("i", "i", returns="i")
+    def bhimpl_int_signext(a, b):
+        return heaptracker.int_signext(a, b)
 
     @arguments("i", "i", returns="i")
     def bhimpl_uint_lt(a, b):
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -197,7 +197,7 @@
     # ------------------------------
 
     for _opimpl in ['int_add', 'int_sub', 'int_mul', 'int_floordiv', 'int_mod',
-                    'int_and', 'int_or', 'int_xor',
+                    'int_and', 'int_or', 'int_xor', 'int_signext',
                     'int_rshift', 'int_lshift', 'uint_rshift',
                     'uint_lt', 'uint_le', 'uint_gt', 'uint_ge',
                     'uint_floordiv',
diff --git a/rpython/jit/metainterp/resoperation.py 
b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -419,6 +419,7 @@
     'INT_RSHIFT/2',
     'INT_LSHIFT/2',
     'UINT_RSHIFT/2',
+    'INT_SIGNEXT/2',
     'FLOAT_ADD/2',
     'FLOAT_SUB/2',
     'FLOAT_MUL/2',
diff --git a/rpython/jit/metainterp/test/test_ajit.py 
b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -3048,6 +3048,16 @@
         res = self.meta_interp(f, [32])
         assert res == f(32)
 
+    def test_int_signext(self):
+        def f(n):
+            return rffi.cast(rffi.SIGNEDCHAR, n)
+        res = self.interp_operations(f, [128])
+        assert res == -128
+        res = self.interp_operations(f, [-35 + 256 * 29])
+        assert res == -35
+        res = self.interp_operations(f, [127 - 256 * 29])
+        assert res == 127
+
 class BaseLLtypeTests(BasicTests):
 
     def test_identityhash(self):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to