[pypy-svn] r50137 - in pypy/branch/llvmgcroot/pypy: config translator/c
arigo at codespeak.net
arigo at codespeak.net
Thu Dec 27 16:10:27 CET 2007
Author: arigo
Date: Thu Dec 27 16:10:26 2007
New Revision: 50137
Added:
pypy/branch/llvmgcroot/pypy/translator/c/trackgcroot.py (contents, props changed)
Modified:
pypy/branch/llvmgcroot/pypy/config/translationoption.py
pypy/branch/llvmgcroot/pypy/translator/c/funcgen.py
pypy/branch/llvmgcroot/pypy/translator/c/genc.py
Log:
Fooling around with a '.s' file parser.
Modified: pypy/branch/llvmgcroot/pypy/config/translationoption.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/config/translationoption.py (original)
+++ pypy/branch/llvmgcroot/pypy/config/translationoption.py Thu Dec 27 16:10:26 2007
@@ -64,8 +64,8 @@
suggests=[("translation.gc", "marksweep")]),
BoolOption("llvmgcroot", "Use the 'llvm.gcroot' primitive to find roots",
default=False, cmdline="--llvmgcroot",
- requires=[("translation.backend", "llvm"),
- ("translation.gctransformer", "framework")]),
+ requires=[("translation.gctransformer", "framework")],
+ suggests=[("translation.backend", "llvm")]),
BoolOption("thread", "enable use of threading primitives",
default=False, cmdline="--thread",
requires=[("translation.gc", "boehm")]),
Modified: pypy/branch/llvmgcroot/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/translator/c/funcgen.py (original)
+++ pypy/branch/llvmgcroot/pypy/translator/c/funcgen.py Thu Dec 27 16:10:26 2007
@@ -218,6 +218,15 @@
def cfunction_body(self):
graph = self.graph
+ gcrootscount = 0
+ for block in graph.iterblocks():
+ for op in block.operations:
+ if op.opname == 'llvm_store_gcroot':
+ index = op.args[0].value
+ gcrootscount = max(gcrootscount, index+1)
+ for i in range(gcrootscount):
+ yield 'void* gcroot%d;' % i
+
# generate the body of each block
for block in graph.iterblocks():
self.currentblock = block
@@ -722,5 +731,17 @@
def OP_IS_EARLY_CONSTANT(self, op):
return self.expr(op.result) + ' = 0;' # Allways false
-
+
+ def OP_LLVM_STORE_GCROOT(self, op):
+ index = op.args[0].value
+ value = self.expr(op.args[1])
+ return ('gcroot%d = %s; ' % (index, value) +
+ 'asm volatile ("/*STORE GCROOT %%0*/"::"m"(gcroot%d));' % (index,))
+
+ def OP_LLVM_LOAD_GCROOT(self, op):
+ index = op.args[0].value
+ result = self.expr(op.result)
+ return ('%s = gcroot%d; ' % (result, index) +
+ 'asm volatile ("/*LOAD GCROOT %%0*/"::"m"(gcroot%d));' % (index,))
+
assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)
Modified: pypy/branch/llvmgcroot/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/translator/c/genc.py (original)
+++ pypy/branch/llvmgcroot/pypy/translator/c/genc.py Thu Dec 27 16:10:26 2007
@@ -315,7 +315,7 @@
if self.config.translation.linkerflags:
compiler.link_extra.append(self.config.translation.linkerflags)
cfiles = []
- ofiles = []
+ sfiles = []
for fn in compiler.cfilenames:
fn = py.path.local(fn)
if fn.dirpath() == targetdir:
@@ -324,7 +324,7 @@
assert fn.dirpath().dirpath() == udir
name = '../' + fn.relto(udir)
cfiles.append(name)
- ofiles.append(name[:-2] + '.o')
+ sfiles.append(name[:-2] + '.s')
if self.config.translation.cc:
cc = self.config.translation.cc
@@ -342,7 +342,7 @@
print >> f
write_list(cfiles, 'SOURCES =')
print >> f
- write_list(ofiles, 'OBJECTS =')
+ write_list(sfiles, 'ASMFILES =')
print >> f
args = ['-l'+libname for libname in self.eci.libraries]
print >> f, 'LIBS =', ' '.join(args)
@@ -773,14 +773,14 @@
MAKEFILE = '''
-$(TARGET): $(OBJECTS)
-\t$(CC) $(LDFLAGS) $(TFLAGS) -o $@ $(OBJECTS) $(LIBDIRS) $(LIBS)
+$(TARGET): $(ASMFILES)
+\t$(CC) $(LDFLAGS) $(TFLAGS) -o $@ $(ASMFILES) $(LIBDIRS) $(LIBS)
-%.o: %.c
-\t$(CC) $(CFLAGS) -o $@ -c $< $(INCLUDEDIRS)
+%.s: %.c
+\t$(CC) $(CFLAGS) -o $@ -S $< $(INCLUDEDIRS)
clean:
-\trm -f $(OBJECTS) $(TARGET)
+\trm -f $(ASMFILES) $(TARGET)
debug:
\t$(MAKE) CFLAGS="-g -DRPY_ASSERT"
@@ -803,6 +803,6 @@
profopt:
\t$(MAKE) CFLAGS="-fprofile-generate $(CFLAGS)" LDFLAGS="-fprofile-generate $(LDFLAGS)"
\t./$(TARGET) $(PROFOPT)
-\trm -f $(OBJECTS) $(TARGET)
+\trm -f $(ASMFILES) $(TARGET)
\t$(MAKE) CFLAGS="-fprofile-use $(CFLAGS)" LDFLAGS="-fprofile-use $(LDFLAGS)"
'''
Added: pypy/branch/llvmgcroot/pypy/translator/c/trackgcroot.py
==============================================================================
--- (empty file)
+++ pypy/branch/llvmgcroot/pypy/translator/c/trackgcroot.py Thu Dec 27 16:10:26 2007
@@ -0,0 +1,247 @@
+#! /usr/bin/env python
+
+import re, sys
+
+r_functionstart = re.compile(r"\t.type\s+(\w+),\s*[@]function\s*$")
+r_functionend = re.compile(r"\t.size\s+\w+,\s*[.]-\w+\s*$")
+r_label = re.compile(r"([.]?\w+)[:]\s*$")
+r_insn = re.compile(r"\t([a-z]\w*)\s")
+r_jump = re.compile(r"\tj\w+\s+([.]?\w+)\s*$")
+OPERAND = r"[\w$%-+]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)]"
+r_unaryinsn = re.compile(r"\t[a-z]\w*\s+("+OPERAND+")\s*$")
+r_binaryinsn = re.compile(r"\t[a-z]\w*\s+("+OPERAND+"),\s*("+OPERAND+")\s*$")
+r_gcroot_marker = re.compile(r"\t/[*](STORE|LOAD) GCROOT ")
+r_gcroot_op = re.compile(r"\t/[*](STORE|LOAD) GCROOT (\d*)[(]%esp[)][*]/\s*$")
+
+# for sanity-checking, %esp should only appear as a way to access locals,
+# i.e. inside parenthesis, except if explicitly recognized otherwise
+r_esp_outside_paren = re.compile(r"(.+[)])?[^(]*[%]esp")
+
+
+class GcRootTracker(object):
+
+ def __init__(self):
+ self.gcmaptable = []
+
+ def dump(self, output):
+ pass
+
+ def process(self, iterlines):
+ functionlines = None
+ for line in iterlines:
+ if r_functionstart.match(line):
+ assert functionlines is None, (
+ "missed the end of the previous function")
+ functionlines = []
+ if functionlines is not None:
+ functionlines.append(line)
+ if r_functionend.match(line):
+ assert functionlines is not None, (
+ "missed the start of the current function")
+ self.process_function(functionlines)
+ functionlines = None
+
+ def process_function(self, lines):
+ tracker = FunctionGcRootTracker(lines)
+ print >> sys.stderr, tracker.funcname
+ self.gcmaptable.extend(tracker.computegcmaptable())
+
+
+class FunctionGcRootTracker(object):
+ VISIT_OPERATION = {}
+
+ def __init__(self, lines):
+ match = r_functionstart.match(lines[0])
+ self.funcname = match.group(1)
+ self.lines = lines
+
+ def computegcmaptable(self):
+ self.findlabels()
+ self.calls = {}
+ self.follow_control_flow()
+ print self.calls
+ self.table = []
+ #xxx
+ return self.table
+
+ def findlabels(self):
+ self.labels = {}
+ for i, line in enumerate(self.lines):
+ match = r_label.match(line)
+ if match:
+ label = match.group(1)
+ assert label not in self.labels, "duplicate label"
+ self.labels[label] = i
+
+ def follow_control_flow(self):
+ # 'states' is a list [(framesize, gcroot0, gcroot1, gcroot2...)]
+ self.states = [None] * len(self.lines)
+ self.pending = []
+ self.framesize = 0
+ self.gcroots = {}
+ self.propagate_state_to(1)
+ while self.pending:
+ lin = self.pending.pop()
+ self.follow_basic_block(lin)
+
+ def getstate(self):
+ gcroots = self.gcroots.keys()
+ gcroots.sort()
+ return (self.framesize,) + tuple(gcroots)
+
+ def propagate_state_to(self, lin):
+ state = self.getstate()
+ if self.states[lin] is None:
+ self.states[lin] = state
+ self.pending.append(lin)
+ else:
+ assert self.states[lin] == state
+
+ def follow_basic_block(self, lin):
+ state = self.states[lin]
+ self.framesize = state[0]
+ self.gcroots = dict.fromkeys(state[1:])
+ line = '?'
+ try:
+ while 1:
+ self.currentlinenum = lin
+ line = self.lines[lin]
+ match = r_insn.match(line)
+ if match:
+ insn = match.group(1)
+ try:
+ meth = self.VISIT_OPERATION[insn]
+ except KeyError:
+ meth = self.find_visitor(insn)
+ meth(self, line)
+ elif r_label.match(line):
+ self.propagate_state_to(lin+1)
+ break
+ elif r_gcroot_marker.match(line):
+ self.handle_gcroot_marker(line)
+ lin += 1
+ except LeaveBasicBlock:
+ pass
+ except Exception, e:
+ print >> sys.stderr, '*'*60
+ print >> sys.stderr, "%s while processing line:" % (
+ e.__class__.__name__,)
+ print >> sys.stderr, line
+ raise
+
+ def handle_gcroot_marker(self, line):
+ match = r_gcroot_op.match(line)
+ op = match.group(1)
+ position = int(match.group(2) or '0')
+ assert position % 4 == 0
+ if op == 'STORE':
+ assert position not in self.gcroots
+ self.gcroots[position] = None
+ elif op == 'LOAD':
+ assert position in self.gcroots
+ del self.gcroots[position]
+ else:
+ raise UnrecognizedOperation(line)
+
+ def find_visitor(self, insn):
+ opname = insn
+ while 1:
+ try:
+ meth = getattr(self.__class__, 'visit_' + opname)
+ break
+ except AttributeError:
+ assert opname
+ opname = opname[:-1]
+ self.VISIT_OPERATION[insn] = meth
+ return meth
+
+ def visit_(self, line):
+ # fallback for all operations. By default, ignore the operation,
+ # unless it appears to do something with %esp
+ if r_esp_outside_paren.match(line):
+ raise UnrecognizedOperation(line)
+
+ def visit_push(self, line):
+ raise UnrecognizedOperation(line)
+
+ def visit_pushl(self, line):
+ self.framesize += 4
+
+ def visit_pop(self, line):
+ raise UnrecognizedOperation(line)
+
+ def visit_popl(self, line):
+ self.framesize -= 4
+ assert self.framesize >= 0, "stack underflow"
+
+ def visit_subl(self, line):
+ match = r_binaryinsn.match(line)
+ if match.group(2) == '%esp':
+ count = match.group(1)
+ assert count.startswith('$')
+ count = int(count[1:])
+ assert count % 4 == 0
+ self.framesize += count
+
+ def visit_addl(self, line):
+ match = r_binaryinsn.match(line)
+ if match.group(2) == '%esp':
+ count = match.group(1)
+ assert count.startswith('$')
+ count = int(count[1:])
+ assert count % 4 == 0
+ self.framesize -= count
+ assert self.framesize >= 0, "stack underflow"
+
+ def visit_ret(self, line):
+ raise LeaveBasicBlock
+
+ def visit_j(self, line):
+ raise UnrecognizedOperation(line)
+
+ def visit_jmp(self, line):
+ try:
+ self.conditional_jump(line)
+ except KeyError:
+ pass # label not found: assume a tail-call turned into a jump
+ raise LeaveBasicBlock
+
+ def conditional_jump(self, line):
+ match = r_jump.match(line)
+ label = match.group(1)
+ targetlin = self.labels[label]
+ self.propagate_state_to(targetlin)
+
+ visit_je = conditional_jump
+ visit_jne = conditional_jump
+ visit_jg = conditional_jump
+ visit_jge = conditional_jump
+ visit_jl = conditional_jump
+ visit_jle = conditional_jump
+ visit_ja = conditional_jump
+ visit_jae = conditional_jump
+ visit_jb = conditional_jump
+ visit_jbe = conditional_jump
+
+ def visit_call(self, line):
+ match = r_unaryinsn.match(line)
+ target = match.group(1)
+ if target == "abort":
+ raise LeaveBasicBlock
+ self.calls[self.currentlinenum] = self.getstate()
+
+
+class LeaveBasicBlock(Exception):
+ pass
+
+class UnrecognizedOperation(Exception):
+ pass
+
+
+if __name__ == '__main__':
+ tracker = GcRootTracker()
+ for fn in sys.argv[1:]:
+ f = open(fn, 'r')
+ tracker.process(f)
+ f.close()
+ tracker.dump(sys.stdout)
More information about the Pypy-commit
mailing list