[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