[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