[pypy-svn] r72969 - in pypy/branch/asmgcc-64/pypy/translator/c/gcc: . test test/elf64
arigo at codespeak.net
arigo at codespeak.net
Sat Mar 27 20:14:53 CET 2010
Author: arigo
Date: Sat Mar 27 20:14:50 2010
New Revision: 72969
Added:
pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/elf64/
pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/elf64/track_basic_rsp.s
Modified:
pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/conftest.py
pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/test_trackgcroot.py
pypy/branch/asmgcc-64/pypy/translator/c/gcc/trackgcroot.py
Log:
Start whacking. The first test passes.
Modified: pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/conftest.py
==============================================================================
--- pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/conftest.py (original)
+++ pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/conftest.py Sat Mar 27 20:14:50 2010
@@ -4,6 +4,6 @@
class Module(py.test.collect.Module):
def collect(self):
cpu = detect_cpu.autodetect()
- if cpu != 'x86':
- py.test.skip("x86 directory skipped: cpu is %r" % (cpu,))
+ if cpu not in ('x86', 'x86_64'):
+ py.test.skip("c/gcc directory skipped: cpu is %r" % (cpu,))
return super(Module, self).collect()
Added: pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/elf64/track_basic_rsp.s
==============================================================================
--- (empty file)
+++ pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/elf64/track_basic_rsp.s Sat Mar 27 20:14:50 2010
@@ -0,0 +1,38 @@
+ .type main, @function
+main:
+ call somewhere
+ ;; expected {(%rsp) | %rbp, %rbx, %r12, %r13, %r14, %r15 | }
+
+ pushq %r13
+ call somewhere
+ ;; expected {8(%rsp) | %rbp, %rbx, %r12, (%rsp), %r14, %r15 | }
+
+ pushq %rbx
+ call somewhere
+ ;; expected {16(%rsp) | %rbp, (%rsp), %r12, 8(%rsp), %r14, %r15 | }
+
+ pushq %r12
+ call somewhere
+ ;; expected {24(%rsp) | %rbp, 8(%rsp), (%rsp), 16(%rsp), %r14, %r15 | }
+
+ pushq %r15
+ call somewhere
+ ;; expected {32(%rsp) | %rbp, 16(%rsp), 8(%rsp), 24(%rsp), %r14, (%rsp) | }
+
+ pushq %rbp
+ call somewhere
+ ;; expected {40(%rsp) | (%rsp), 24(%rsp), 16(%rsp), 32(%rsp), %r14, 8(%rsp) | }
+
+ pushq %r14
+ call somewhere
+ ;; expected {48(%rsp) | 8(%rsp), 32(%rsp), 24(%rsp), 40(%rsp), (%rsp), 16(%rsp) | }
+
+ popq %r14
+ popq %rbp
+ popq %r15
+ popq %r12
+ popq %rbx
+ popq %r13
+ ret
+
+ .size main, .-main
Modified: pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/test_trackgcroot.py
==============================================================================
--- pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/test_trackgcroot.py (original)
+++ pypy/branch/asmgcc-64/pypy/translator/c/gcc/test/test_trackgcroot.py Sat Mar 27 20:14:50 2010
@@ -10,6 +10,7 @@
from pypy.translator.c.gcc.trackgcroot import compress_callshape
from pypy.translator.c.gcc.trackgcroot import decompress_callshape
from pypy.translator.c.gcc.trackgcroot import PARSERS
+from pypy.translator.c.gcc.trackgcroot import Elf64FunctionGcRootTracker
from StringIO import StringIO
this_dir = py.path.local(__file__).dirpath()
@@ -39,6 +40,37 @@
LOC_EBP_PLUS+24,
LOC_EBP_PLUS+28)) == expected
+def test_format_location_64():
+ cls64 = Elf64FunctionGcRootTracker
+ assert format_location(LOC_NOWHERE, cls=cls64) == '?'
+ assert format_location(LOC_REG | (1<<2), cls=cls64) == '%rbp'
+ assert format_location(LOC_REG | (2<<2), cls=cls64) == '%rbx'
+ assert format_location(LOC_REG | (3<<2), cls=cls64) == '%r12'
+ assert format_location(LOC_REG | (4<<2), cls=cls64) == '%r13'
+ assert format_location(LOC_REG | (5<<2), cls=cls64) == '%r14'
+ assert format_location(LOC_REG | (6<<2), cls=cls64) == '%r15'
+ assert format_location(LOC_EBP_PLUS + 0, cls=cls64) == '(%rbp)'
+ assert format_location(LOC_EBP_PLUS + 8, cls=cls64) == '8(%rbp)'
+ assert format_location(LOC_EBP_MINUS + 8, cls=cls64) == '-8(%rbp)'
+ assert format_location(LOC_ESP_PLUS + 0, cls=cls64) == '(%rsp)'
+ assert format_location(LOC_ESP_PLUS + 8, cls=cls64) == '8(%rsp)'
+
+def test_format_callshape_64():
+ cls64 = Elf64FunctionGcRootTracker
+ expected = ('{8(%rbp) ' # position of the return address
+ '| 16(%rbp), 24(%rbp), 32(%rbp), 40(%rbp), ' # 6 saved regs
+ '48(%rbp), 56(%rbp) '
+ '| 64(%rbp), 72(%rbp)}') # GC roots
+ assert format_callshape((LOC_EBP_PLUS+8,
+ LOC_EBP_PLUS+16,
+ LOC_EBP_PLUS+24,
+ LOC_EBP_PLUS+32,
+ LOC_EBP_PLUS+40,
+ LOC_EBP_PLUS+48,
+ LOC_EBP_PLUS+56,
+ LOC_EBP_PLUS+64,
+ LOC_EBP_PLUS+72), cls=cls64) == expected
+
def test_compress_callshape():
shape = (1, 127, 0x1234, 0x5678, 0x234567,
0x765432, 0x61626364, 0x41424344)
@@ -108,7 +140,7 @@
def test_computegcmaptable():
tests = []
- for format in ('elf', 'darwin', 'msvc'):
+ for format in ('elf', 'darwin', 'msvc', 'elf64'):
for path in this_dir.join(format).listdir("track*.s"):
n = path.purebasename[5:]
try:
@@ -133,12 +165,13 @@
print path.dirpath().basename + '/' + path.basename
lines = path.readlines()
expectedlines = lines[:]
- tracker = PARSERS[format].FunctionGcRootTracker(lines)
+ trackercls = PARSERS[format].FunctionGcRootTracker
+ tracker = trackercls(lines)
table = tracker.computegcmaptable(verbose=sys.maxint)
tabledict = {}
seen = {}
for entry in table:
- print '%s: %s' % (entry[0], format_callshape(entry[1]))
+ print '%s: %s' % (entry[0], format_callshape(entry[1], cls=trackercls))
tabledict[entry[0]] = entry[1]
# find the ";; expected" lines
prevline = ""
@@ -151,7 +184,7 @@
label = prevmatch.group(1)
assert label in tabledict
got = tabledict[label]
- assert format_callshape(got) == expected
+ assert format_callshape(got, cls=trackercls) == expected
seen[label] = True
if format == 'msvc':
expectedlines.insert(i-2, 'PUBLIC\t%s\n' % (label,))
Modified: pypy/branch/asmgcc-64/pypy/translator/c/gcc/trackgcroot.py
==============================================================================
--- pypy/branch/asmgcc-64/pypy/translator/c/gcc/trackgcroot.py (original)
+++ pypy/branch/asmgcc-64/pypy/translator/c/gcc/trackgcroot.py Sat Mar 27 20:14:50 2010
@@ -17,6 +17,9 @@
class FunctionGcRootTracker(object):
skip = 0
+ WORD = 4
+ BITS = 32
+ SUFFIX = 'l'
@classmethod
def init_regexp(cls):
@@ -187,15 +190,28 @@
del self.currentlineno
- @classmethod
- def find_missing_visit_method(cls, opname):
- # only for operations that are no-ops as far as we are concerned
+ def find_missing_visit_method(self, opname):
+ # if opname ends with an 'l' (on 32-bit) or a 'q' (on 64-bit),
+ # try to find the method that ends with an 'X'. On Windows,
+ # where SUFFIX='', try to just append 'X'.
+ if opname.endswith(self.SUFFIX):
+ basename = opname[:len(opname)-len(self.SUFFIX)]
+ try:
+ method = getattr(self, 'visit_' + basename + 'X')
+ except AttributeError:
+ pass # not found
+ else:
+ setattr(self, 'visit_' + opname, method)
+ return
+ # not found. This is the case only for operations that are
+ # no-ops as far as we are concerned, but check if it is really
+ # in IGNORE_OPS_WITH_PREFIXES.
prefix = opname
- while prefix not in cls.IGNORE_OPS_WITH_PREFIXES:
+ while prefix not in self.IGNORE_OPS_WITH_PREFIXES:
prefix = prefix[:-1]
if not prefix:
raise UnrecognizedOperation(opname)
- setattr(cls, 'visit_' + opname, cls.visit_nop)
+ setattr(self, 'visit_' + opname, self.visit_nop)
def list_collecting_call_insns(self):
return [insn for insn in self.insns if isinstance(insn, InsnCall)
@@ -206,7 +222,7 @@
# in the frame at this point. This doesn't count the return address
# which is the word immediately following the frame in memory.
# The 'framesize' is set to an odd value if it is only an estimate
- # (see visit_andl()).
+ # (see visit_andX()).
def walker(insn, size_delta):
check = deltas.setdefault(insn, size_delta)
@@ -399,7 +415,7 @@
visit_xorb = visit_nop
visit_xorw = visit_nop
- def visit_addl(self, line, sign=+1):
+ def visit_addX(self, line, sign=+1):
match = self.r_binaryinsn.match(line)
source = match.group("source")
target = match.group("target")
@@ -414,8 +430,8 @@
else:
return []
- def visit_subl(self, line):
- return self.visit_addl(line, sign=-1)
+ def visit_subX(self, line):
+ return self.visit_addX(line, sign=-1)
def unary_insn(self, line):
match = self.r_unaryinsn.match(line)
@@ -438,16 +454,16 @@
else:
return []
- visit_xorl = binary_insn # used in "xor reg, reg" to create a NULL GC ptr
- visit_orl = binary_insn
+ visit_xorX = binary_insn # used in "xor reg, reg" to create a NULL GC ptr
+ visit_orX = binary_insn
# The various cmov* operations
for name in '''
e ne g ge l le a ae b be p np s ns o no
'''.split():
locals()['visit_cmov' + name] = binary_insn
- locals()['visit_cmov' + name + 'l'] = binary_insn
+ locals()['visit_cmov' + name + 'X'] = binary_insn
- def visit_andl(self, line):
+ def visit_andX(self, line):
match = self.r_binaryinsn.match(line)
target = match.group("target")
if target == self.ESP:
@@ -459,9 +475,7 @@
else:
return self.binary_insn(line)
- visit_and = visit_andl
-
- def visit_leal(self, line):
+ def visit_leaX(self, line):
match = self.r_binaryinsn.match(line)
target = match.group("target")
if target == self.ESP:
@@ -473,7 +487,7 @@
raise UnrecognizedOperation('epilogue without prologue')
ofs_from_ebp = int(match.group(1) or '0')
assert ofs_from_ebp <= 0
- framesize = 4 - ofs_from_ebp
+ framesize = self.WORD - ofs_from_ebp
else:
match = self.r_localvar_esp.match(source)
# leal 12(%esp), %esp
@@ -498,7 +512,7 @@
else:
return []
- def visit_movl(self, line):
+ def visit_movX(self, line):
match = self.r_binaryinsn.match(line)
source = match.group("source")
target = match.group("target")
@@ -512,20 +526,20 @@
# gcc -fno-unit-at-a-time.
return self.insns_for_copy(source, target)
- visit_mov = visit_movl
-
- def visit_pushl(self, line):
+ def visit_pushX(self, line):
match = self.r_unaryinsn.match(line)
source = match.group(1)
- return [InsnStackAdjust(-4)] + self.insns_for_copy(source, self.TOP_OF_STACK)
+ return ([InsnStackAdjust(-self.WORD)] +
+ self.insns_for_copy(source, self.TOP_OF_STACK))
def visit_pushw(self, line):
return [InsnStackAdjust(-2)] # rare but not impossible
def _visit_pop(self, target):
- return self.insns_for_copy(self.TOP_OF_STACK, target) + [InsnStackAdjust(+4)]
+ return (self.insns_for_copy(self.TOP_OF_STACK, target) +
+ [InsnStackAdjust(+self.WORD)])
- def visit_popl(self, line):
+ def visit_popX(self, line):
match = self.r_unaryinsn.match(line)
target = match.group(1)
return self._visit_pop(target)
@@ -660,7 +674,7 @@
visit_jc = conditional_jump
visit_jnc = conditional_jump
- def visit_xchgl(self, line):
+ def visit_xchgX(self, line):
# only support the format used in VALGRIND_DISCARD_TRANSLATIONS
# which is to use a marker no-op "xchgl %ebx, %ebx"
match = self.r_binaryinsn.match(line)
@@ -747,32 +761,10 @@
EBP = '%ebp'
EAX = '%eax'
CALLEE_SAVE_REGISTERS = ['%ebx', '%esi', '%edi', '%ebp']
- REG2LOC = dict((_reg, LOC_REG | ((_i+1)<<2))
- for _i, _reg in enumerate(CALLEE_SAVE_REGISTERS))
OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])'
LABEL = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)'
OFFSET_LABELS = 2**30
- TOP_OF_STACK = '0(%esp)'
-
- r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$")
- r_functionend = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$")
LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|\d*[(]%esp[)]"
- LOCALVARFP = LOCALVAR + r"|-?\d*[(]%ebp[)]"
- r_localvarnofp = re.compile(LOCALVAR)
- r_localvarfp = re.compile(LOCALVARFP)
- r_localvar_esp = re.compile(r"(\d*)[(]%esp[)]")
- r_localvar_ebp = re.compile(r"(-?\d*)[(]%ebp[)]")
-
- r_rel_label = re.compile(r"(\d+):\s*$")
- r_jump_rel_label = re.compile(r"\tj\w+\s+"+"(\d+)f"+"\s*$")
-
- r_unaryinsn_star= re.compile(r"\t[a-z]\w*\s+[*]("+OPERAND+")\s*$")
- r_jmptable_item = re.compile(r"\t.long\t"+LABEL+"(-\"[A-Za-z0-9$]+\")?\s*$")
- r_jmptable_end = re.compile(r"\t.text|\t.section\s+.text|\t\.align|"+LABEL)
-
- r_gcroot_marker = re.compile(r"\t/[*] GCROOT ("+LOCALVARFP+") [*]/")
- r_gcnocollect_marker = re.compile(r"\t/[*] GC_NOCOLLECT ("+OPERAND+") [*]/")
- r_bottom_marker = re.compile(r"\t/[*] GC_STACK_BOTTOM [*]/")
FUNCTIONS_NOT_RETURNING = {
'abort': None,
@@ -792,6 +784,41 @@
super(ElfFunctionGcRootTracker, self).__init__(
funcname, lines, filetag)
+ @classmethod
+ def init_regexp(cls):
+ cls.REG2LOC = dict((reg, LOC_REG | ((i+1)<<2))
+ for i, reg in enumerate(cls.CALLEE_SAVE_REGISTERS))
+ cls.TOP_OF_STACK = '0(%s)' % cls.ESP
+ cls.LOCALVARFP = cls.LOCALVAR + r"|-?\d*[(]%s[)]" % cls.EBP
+
+ cls.r_localvarnofp = re.compile(cls.LOCALVAR)
+ cls.r_localvarfp = re.compile(cls.LOCALVARFP)
+ cls.r_localvar_esp = re.compile(r"(\d*)[(]%s[)]" % cls.ESP)
+ cls.r_localvar_ebp = re.compile(r"(-?\d*)[(]%s[)]" % cls.EBP)
+
+ cls.r_functionstart = re.compile(r"\t.type\s+"+cls.LABEL+
+ r",\s*[@]function\s*$")
+ cls.r_functionend = re.compile(r"\t.size\s+"+cls.LABEL+
+ r",\s*[.]-"+cls.LABEL+"\s*$")
+
+ cls.r_rel_label = re.compile(r"(\d+):\s*$")
+ cls.r_jump_rel_label = re.compile(r"\tj\w+\s+"+r"(\d+)f"+r"\s*$")
+
+ cls.r_unaryinsn_star= re.compile(r"\t[a-z]\w*\s+[*]("+cls.OPERAND+
+ r")\s*$")
+ cls.r_jmptable_item = re.compile(r"\t.(?:long|quad)\t"+cls.LABEL+
+ r'(-"[A-Za-z0-9$]+")?\s*$')
+ cls.r_jmptable_end = re.compile(r"\t.text|\t.section\s+.text|"
+ r"\t\.align|"+cls.LABEL)
+
+ cls.r_gcroot_marker = re.compile(r"\t/[*] GCROOT ("+cls.LOCALVARFP+
+ r") [*]/")
+ cls.r_gcnocollect_marker = re.compile(r"\t/[*] GC_NOCOLLECT ("+
+ cls.OPERAND+r") [*]/")
+ cls.r_bottom_marker = re.compile(r"\t/[*] GC_STACK_BOTTOM [*]/")
+
+ super(ElfFunctionGcRootTracker, cls).init_regexp()
+
def extract_immediate(self, value):
if not value.startswith('$'):
return None
@@ -799,6 +826,19 @@
ElfFunctionGcRootTracker.init_regexp()
+class Elf64FunctionGcRootTracker(ElfFunctionGcRootTracker):
+ WORD = 8
+ BITS = 64
+ SUFFIX = 'q'
+ ESP = '%rsp'
+ EBP = '%rbp'
+ EAX = '%rax'
+ CALLEE_SAVE_REGISTERS = ['%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15']
+ LOCALVAR = (r"%rax|%rdx|%rcx|%rbx|%rsi|%rdi|%rbp|"
+ r"%r8|%r9|%r10|%r11|%r12|%r13|%r14|%r15|\d*[(]%rsp[)]")
+
+Elf64FunctionGcRootTracker.init_regexp()
+
class DarwinFunctionGcRootTracker(ElfFunctionGcRootTracker):
format = 'darwin'
@@ -821,6 +861,7 @@
class MsvcFunctionGcRootTracker(FunctionGcRootTracker):
format = 'msvc'
+ SUFFIX = ''
ESP = 'esp'
EBP = 'ebp'
EAX = 'eax'
@@ -898,13 +939,6 @@
operand = operand.replace(name, str(value))
return operand
- for name in '''
- push pop mov lea
- xor sub add
- '''.split():
- locals()['visit_' + name] = getattr(FunctionGcRootTracker,
- 'visit_' + name + 'l')
-
visit_int = FunctionGcRootTracker.visit_nop
# probably not GC pointers
visit_cdq = FunctionGcRootTracker.visit_nop
@@ -1068,6 +1102,10 @@
"missed the end of the previous function")
yield False, functionlines
+class Elf64AssemblerParser(AssemblerParser):
+ format = "elf64"
+ FunctionGcRootTracker = Elf64FunctionGcRootTracker
+
class DarwinAssemblerParser(AssemblerParser):
format = "darwin"
FunctionGcRootTracker = DarwinFunctionGcRootTracker
@@ -1213,6 +1251,7 @@
PARSERS = {
'elf': ElfAssemblerParser,
+ 'elf64': Elf64AssemblerParser,
'darwin': DarwinAssemblerParser,
'mingw32': Mingw32AssemblerParser,
'msvc': MsvcAssemblerParser,
@@ -1471,7 +1510,7 @@
# __________ debugging output __________
-def format_location(loc):
+def format_location(loc, cls=ElfFunctionGcRootTracker):
# A 'location' is a single number describing where a value is stored
# across a call. It can be in one of the CALLEE_SAVE_REGISTERS, or
# in the stack frame at an address relative to either %esp or %ebp.
@@ -1483,23 +1522,23 @@
if loc == LOC_NOWHERE:
return '?'
reg = (loc >> 2) - 1
- return ElfFunctionGcRootTracker.CALLEE_SAVE_REGISTERS[reg]
+ return cls.CALLEE_SAVE_REGISTERS[reg]
else:
offset = loc & ~ LOC_MASK
if kind == LOC_EBP_PLUS:
- result = '(%ebp)'
+ result = '(%s)' % cls.EBP
elif kind == LOC_EBP_MINUS:
- result = '(%ebp)'
+ result = '(%s)' % cls.EBP
offset = -offset
elif kind == LOC_ESP_PLUS:
- result = '(%esp)'
+ result = '(%s)' % cls.ESP
else:
assert 0, kind
if offset != 0:
result = str(offset) + result
return result
-def format_callshape(shape):
+def format_callshape(shape, cls=ElfFunctionGcRootTracker):
# A 'call shape' is a tuple of locations in the sense of format_location().
# They describe where in a function frame interesting values are stored,
# when this function executes a 'call' instruction.
@@ -1512,12 +1551,15 @@
# shape[4] is where the fn saved its own caller's %ebp value
# shape[>=5] are GC roots: where the fn has put its local GCPTR vars
#
+ # On 64-bit, there are 6 registers instead of 4 that are callee-saved.
+ #
assert isinstance(shape, tuple)
- assert len(shape) >= 5
- result = [format_location(loc) for loc in shape]
+ N = len(cls.CALLEE_SAVE_REGISTERS) + 1
+ assert len(shape) >= N
+ result = [format_location(loc, cls) for loc in shape]
return '{%s | %s | %s}' % (result[0],
- ', '.join(result[1:5]),
- ', '.join(result[5:]))
+ ', '.join(result[1:N]),
+ ', '.join(result[N:]))
# __________ table compression __________
More information about the Pypy-commit
mailing list