[pypy-svn] r77349 - in pypy/trunk/pypy/jit/backend/x86: . test

arigo at codespeak.net arigo at codespeak.net
Fri Sep 24 17:14:12 CEST 2010


Author: arigo
Date: Fri Sep 24 17:14:11 2010
New Revision: 77349

Modified:
   pypy/trunk/pypy/jit/backend/x86/regloc.py
   pypy/trunk/pypy/jit/backend/x86/test/test_regloc.py
Log:
More cases found by test_zll_random.  Rewrite a bit the logic that becomes huge.

Modified: pypy/trunk/pypy/jit/backend/x86/regloc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/regloc.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/regloc.py	Fri Sep 24 17:14:11 2010
@@ -33,6 +33,8 @@
     def value_a(self): raise AssertionError("value_a undefined")
     def value_m(self): raise AssertionError("value_m undefined")
 
+    def find_unused_reg(self): return eax
+
 class StackLoc(AssemblerLocation):
     _immutable_ = True
     def __init__(self, position, ebp_offset, num_words, type):
@@ -88,6 +90,12 @@
     def assembler(self):
         return '%' + repr(self)
 
+    def find_unused_reg(self):
+        if self.value == eax.value:
+            return edx
+        else:
+            return eax
+
 class ImmedLoc(AssemblerLocation):
     _immutable_ = True
     width = WORD
@@ -152,6 +160,21 @@
     def value_m(self):
         return self.loc_m
 
+    def find_unused_reg(self):
+        if self._location_code == 'm':
+            if self.loc_m[0] == eax.value:
+                return edx
+        elif self._location_code == 'a':
+            if self.loc_a[0] == eax.value:
+                if self.loc_a[1] == edx.value:
+                    return ecx
+                return edx
+            if self.loc_a[1] == eax.value:
+                if self.loc_a[0] == edx.value:
+                    return ecx
+                return edx
+        return eax
+
 class ConstFloatLoc(AssemblerLocation):
     # XXX: We have to use this class instead of just AddressLoc because
     # AddressLoc is "untyped" and also we to have need some sort of unique
@@ -215,6 +238,32 @@
     _scratch_register_value = 0
 
     def _binaryop(name):
+
+        def insn_with_64_bit_immediate(self, loc1, loc2):
+            # These are the worst cases:
+            val2 = loc2.value_i()
+            code1 = loc1.location_code()
+            if (code1 == 'j'
+                or (code1 == 'm' and not rx86.fits_in_32bits(loc1.value_m()[1]))
+                or (code1 == 'a' and not rx86.fits_in_32bits(loc1.value_a()[3]))):
+                # INSN_ji, and both operands are 64-bit; or INSN_mi or INSN_ai
+                # and the constant offset in the address is 64-bit.
+                # Hopefully this doesn't happen too often
+                freereg = loc1.find_unused_reg()
+                self.PUSH_r(freereg.value)
+                self.MOV_ri(freereg.value, val2)
+                INSN(self, loc1, freereg)
+                self.POP_r(freereg.value)
+            else:
+                # For this case, we should not need the scratch register more than here.
+                self._load_scratch(val2)
+                INSN(self, loc1, X86_64_SCRATCH_REG)
+
+        def invoke(self, codes, val1, val2):
+            methname = name + "_" + codes
+            _rx86_getattr(self, methname)(val1, val2)
+        invoke._annspecialcase_ = 'specialize:arg(1)'
+
         def INSN(self, loc1, loc2):
             code1 = loc1.location_code()
             code2 = loc2.location_code()
@@ -227,46 +276,38 @@
             if loc1 is X86_64_SCRATCH_REG and not name.startswith("MOV"):
                 assert code2 not in ('j', 'i')
 
-            for possible_code1 in unrolling_location_codes:
-                if code1 == possible_code1:
-                    for possible_code2 in unrolling_location_codes:
-                        if code2 == possible_code2:
+            for possible_code2 in unrolling_location_codes:
+                if code2 == possible_code2:
+                    val2 = getattr(loc2, "value_" + possible_code2)()
+                    #
+                    # Fake out certain operations for x86_64
+                    if self.WORD == 8 and possible_code2 == 'i' and not rx86.fits_in_32bits(val2):
+                        insn_with_64_bit_immediate(self, loc1, loc2)
+                        return
+                    #
+                    # Regular case
+                    for possible_code1 in unrolling_location_codes:
+                        if code1 == possible_code1:
                             val1 = getattr(loc1, "value_" + possible_code1)()
-                            val2 = getattr(loc2, "value_" + possible_code2)()
-                            # Fake out certain operations for x86_64
-                            if self.WORD == 8 and possible_code2 == 'i' and not rx86.fits_in_32bits(val2):
-                                if possible_code1 == 'j':
-                                    # This is the worst case: INSN_ji, and both operands are 64-bit
-                                    # Hopefully this doesn't happen too often
-                                    self.PUSH_r(eax.value)
-                                    self.MOV_ri(eax.value, val1)
-                                    self.MOV_ri(X86_64_SCRATCH_REG.value, val2)
-                                    methname = name + "_mr"
-                                    _rx86_getattr(self, methname)((eax.value, 0), X86_64_SCRATCH_REG.value)
-                                    self.POP_r(eax.value)
-                                else:
-                                    self.MOV_ri(X86_64_SCRATCH_REG.value, val2)
-                                    methname = name + "_" + possible_code1 + "r"
-                                    _rx86_getattr(self, methname)(val1, X86_64_SCRATCH_REG.value)
-                            elif self.WORD == 8 and possible_code1 == 'j':
-                                reg_offset = self._addr_as_reg_offset(val1)
-                                methname = name + "_" + "m" + possible_code2
-                                _rx86_getattr(self, methname)(reg_offset, val2)
+                            # More faking out of certain operations for x86_64
+                            if self.WORD == 8 and possible_code1 == 'j':
+                                val1 = self._addr_as_reg_offset(val1)
+                                invoke(self, "m" + possible_code2, val1, val2)
                             elif self.WORD == 8 and possible_code2 == 'j':
-                                reg_offset = self._addr_as_reg_offset(val2)
-                                methname = name + "_" + possible_code1 + "m"
-                                _rx86_getattr(self, methname)(val1, reg_offset)
+                                val2 = self._addr_as_reg_offset(val2)
+                                invoke(self, possible_code1 + "m", val1, val2)
+                            elif possible_code1 == 'm' and not rx86.fits_in_32bits(val1[1]):
+                                val1 = self._fix_static_offset_64_m(val1)
+                                invoke(self, "a" + possible_code2, val1, val2)
+                            elif possible_code2 == 'm' and not rx86.fits_in_32bits(val2[1]):
+                                val2 = self._fix_static_offset_64_m(val2)
+                                invoke(self, possible_code1 + "a", val1, val2)
                             else:
-                                if possible_code1 == 'm' and not rx86.fits_in_32bits(val1[1]):
-                                    val1 = self._fix_static_offset_64_m(val1)
-                                if possible_code2 == 'm' and not rx86.fits_in_32bits(val2[1]):
-                                    val2 = self._fix_static_offset_64_m(val2)
                                 if possible_code1 == 'a' and not rx86.fits_in_32bits(val1[3]):
                                     val1 = self._fix_static_offset_64_a(val1)
                                 if possible_code2 == 'a' and not rx86.fits_in_32bits(val2[3]):
                                     val2 = self._fix_static_offset_64_a(val2)
-                                methname = name + "_" + possible_code1 + possible_code2
-                                _rx86_getattr(self, methname)(val1, val2)
+                                invoke(self, possible_code1 + possible_code2, val1, val2)
 
         return func_with_new_name(INSN, "INSN_" + name)
 
@@ -277,7 +318,7 @@
                 if code == possible_code:
                     val = getattr(loc, "value_" + possible_code)()
                     if self.WORD == 8 and possible_code == 'i' and not rx86.fits_in_32bits(val):
-                        self.MOV_ri(X86_64_SCRATCH_REG.value, val)
+                        self._load_scratch(val)
                         _rx86_getattr(self, name + "_r")(X86_64_SCRATCH_REG.value)
                     else:
                         methname = name + "_" + possible_code
@@ -297,7 +338,7 @@
                             _rx86_getattr(self, name + "_l")(val)
                         else:
                             assert self.WORD == 8
-                            self.MOV_ri(X86_64_SCRATCH_REG.value, val)
+                            self._load_scratch(val)
                             _rx86_getattr(self, name + "_r")(X86_64_SCRATCH_REG.value)
                     else:
                         methname = name + "_" + possible_code
@@ -337,15 +378,12 @@
     def _fix_static_offset_64_m(self, (basereg, static_offset)):
         # For cases where an AddressLoc has the location_code 'm', but
         # where the static offset does not fit in 32-bits.  We have to fall
-        # back to the X86_64_SCRATCH_REG.  It is even more annoying because
-        # we want to keep using the mode 'm'.  These are all possibly rare
-        # cases; don't try to reuse a past value of the scratch register at
-        # all.
+        # back to the X86_64_SCRATCH_REG.  Note that this returns a location
+        # encoded as mode 'a'.  These are all possibly rare cases; don't try
+        # to reuse a past value of the scratch register at all.
         self._scratch_register_known = False
         self.MOV_ri(X86_64_SCRATCH_REG.value, static_offset)
-        self.LEA_ra(X86_64_SCRATCH_REG.value,
-                    (basereg, X86_64_SCRATCH_REG.value, 0, 0))
-        return (X86_64_SCRATCH_REG.value, 0)
+        return (basereg, X86_64_SCRATCH_REG.value, 0, 0)
 
     def _fix_static_offset_64_a(self, (basereg, scalereg,
                                        scale, static_offset)):
@@ -362,6 +400,15 @@
                         (basereg, X86_64_SCRATCH_REG.value, 0, 0))
         return (X86_64_SCRATCH_REG.value, scalereg, scale, 0)
 
+    def _load_scratch(self, value):
+        if (self._scratch_register_known
+            and value == self._scratch_register_value):
+            return
+        if self._reuse_scratch_register:
+            self._scratch_register_known = True
+            self._scratch_register_value = value
+        self.MOV_ri(X86_64_SCRATCH_REG.value, value)
+
     def begin_reuse_scratch_register(self):
         # Flag the beginning of a block where it is okay to reuse the value
         # of the scratch register. In theory we shouldn't have to do this if

Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regloc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_regloc.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_regloc.py	Fri Sep 24 17:14:11 2010
@@ -83,10 +83,13 @@
         )
         assert cb.getvalue() == expected_instructions
 
+    # ------------------------------------------------------------
+
     def test_64bit_address_1(self):
         base_addr = 0xFEDCBA9876543210
         cb = LocationCodeBuilder64()
         cb.CMP(ecx, AddressLoc(ImmedLoc(0), ImmedLoc(0), 0, base_addr))
+        # this case is a CMP_rj
         #
         expected_instructions = (
                 # mov r11, 0xFEDCBA9876543210
@@ -100,6 +103,7 @@
         base_addr = 0xFEDCBA9876543210
         cb = LocationCodeBuilder64()
         cb.MOV(ecx, AddressLoc(ImmedLoc(0), edx, 3, base_addr))
+        # this case is a CMP_ra
         #
         expected_instructions = (
                 # mov r11, 0xFEDCBA9876543210
@@ -113,17 +117,13 @@
         base_addr = 0xFEDCBA9876543210
         cb = LocationCodeBuilder64()
         cb.MOV(ecx, AddressLoc(edx, ImmedLoc(0), 0, base_addr))
+        # this case is a CMP_rm
         #
-        # sub-efficient instruction generated in that particular case:
-        # the LEA is not really needed, but it's useful because we can
-        # keep the same mode 'm' for generating the final instruction
         expected_instructions = (
                 # mov r11, 0xFEDCBA9876543210
                 '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
-                # lea r11, [rdx+r11]
-                '\x4E\x8D\x1C\x1A'
-                # mov rcx, [r11]
-                '\x49\x8B\x0B'
+                # mov rcx, [rdx+r11]
+                '\x4A\x8B\x0C\x1A'
         )
         assert cb.getvalue() == expected_instructions
 
@@ -136,6 +136,7 @@
         cb.MOV(ecx, AddressLoc(edx, esi, 2, base_addr))
         assert cb._reuse_scratch_register is True
         assert cb._scratch_register_known is False
+        # this case is a CMP_ra
         #
         expected_instructions = (
                 # mov r11, 0xFEDCBA9876543210
@@ -146,3 +147,161 @@
                 '\x49\x8B\x0C\xB3'
         )
         assert cb.getvalue() == expected_instructions
+
+    # ------------------------------------------------------------
+
+    def test_MOV_immed32_into_64bit_address_1(self):
+        immed = -0x01234567
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(AddressLoc(ImmedLoc(0), ImmedLoc(0), 0, base_addr),
+               ImmedLoc(immed))
+        # this case is a MOV_ji
+        #
+        expected_instructions = (
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+                # mov [r11], -0x01234567
+                '\x49\xC7\x03\x99\xBA\xDC\xFE'
+        )
+        assert cb.getvalue() == expected_instructions
+
+    def test_MOV_immed32_into_64bit_address_2(self):
+        immed = -0x01234567
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(AddressLoc(ImmedLoc(0), edx, 3, base_addr),
+               ImmedLoc(immed))
+        # this case is a MOV_ai
+        #
+        expected_instructions = (
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+                # mov [r11+8*rdx], -0x01234567
+                '\x49\xC7\x04\xD3\x99\xBA\xDC\xFE'
+        )
+        assert cb.getvalue() == expected_instructions
+
+    def test_MOV_immed32_into_64bit_address_3(self):
+        immed = -0x01234567
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(AddressLoc(edx, ImmedLoc(0), 0, base_addr),
+               ImmedLoc(immed))
+        # this case is a MOV_mi
+        #
+        expected_instructions = (
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+                # mov [rdx+r11], -0x01234567
+                '\x4A\xC7\x04\x1A\x99\xBA\xDC\xFE'
+        )
+        assert cb.getvalue() == expected_instructions
+
+    def test_MOV_immed32_into_64bit_address_4(self):
+        immed = -0x01234567
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(AddressLoc(edx, esi, 2, base_addr), ImmedLoc(immed))
+        # this case is a MOV_ai
+        #
+        expected_instructions = (
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+                # lea r11, [rdx+r11]
+                '\x4E\x8D\x1C\x1A'
+                # mov [r11+4*rsi], -0x01234567
+                '\x49\xC7\x04\xB3\x99\xBA\xDC\xFE'
+        )
+        assert cb.getvalue() == expected_instructions
+
+    # ------------------------------------------------------------
+
+    def test_MOV_immed64_into_64bit_address_1(self):
+        immed = 0x0123456789ABCDEF
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(AddressLoc(ImmedLoc(0), ImmedLoc(0), 0, base_addr),
+               ImmedLoc(immed))
+        # this case is a MOV_ji
+        #
+        expected_instructions = (
+                # push rax
+                '\x50'
+                # mov rax, 0x0123456789ABCDEF
+                '\x48\xB8\xEF\xCD\xAB\x89\x67\x45\x23\x01'
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+                # mov [r11], rax
+                '\x49\x89\x03'
+                # pop rax
+                '\x58'
+        )
+        assert cb.getvalue() == expected_instructions
+
+    def test_MOV_immed64_into_64bit_address_2(self):
+        immed = 0x0123456789ABCDEF
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(AddressLoc(ImmedLoc(0), edx, 3, base_addr),
+               ImmedLoc(immed))
+        # this case is a MOV_ai
+        #
+        expected_instructions = (
+                # push rax
+                '\x50'
+                # mov rax, 0x0123456789ABCDEF
+                '\x48\xB8\xEF\xCD\xAB\x89\x67\x45\x23\x01'
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+                # mov [r11+8*rdx], rax
+                '\x49\x89\x04\xD3'
+                # pop rax
+                '\x58'
+        )
+        assert cb.getvalue() == expected_instructions
+
+    def test_MOV_immed64_into_64bit_address_3(self):
+        immed = 0x0123456789ABCDEF
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(AddressLoc(eax, ImmedLoc(0), 0, base_addr),
+               ImmedLoc(immed))
+        # this case is a MOV_mi
+        #
+        expected_instructions = (
+                # push rdx
+                '\x52'
+                # mov rdx, 0x0123456789ABCDEF
+                '\x48\xBA\xEF\xCD\xAB\x89\x67\x45\x23\x01'
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+                # mov [rax+r11], rdx
+                '\x4A\x89\x14\x18'
+                # pop rdx
+                '\x5A'
+        )
+        assert cb.getvalue() == expected_instructions
+
+    def test_MOV_immed64_into_64bit_address_4(self):
+        immed = 0x0123456789ABCDEF
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(AddressLoc(edx, eax, 2, base_addr), ImmedLoc(immed))
+        # this case is a MOV_ai
+        #
+        expected_instructions = (
+                # push rcx
+                '\x51'
+                # mov rcx, 0x0123456789ABCDEF
+                '\x48\xB9\xEF\xCD\xAB\x89\x67\x45\x23\x01'
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+                # lea r11, [rdx+r11]
+                '\x4E\x8D\x1C\x1A'
+                # mov [r11+4*rax], rcx
+                '\x49\x89\x0C\x83'
+                # pop rcx
+                '\x59'
+        )
+        assert cb.getvalue() == expected_instructions



More information about the Pypy-commit mailing list