[pypy-svn] r6010 - in pypy/branch/pypy-genc: . objspace objspace/std translator translator/tool/pygame

arigo at codespeak.net arigo at codespeak.net
Tue Aug 17 21:25:22 CEST 2004


Author: arigo
Date: Tue Aug 17 21:25:17 2004
New Revision: 6010

Added:
   pypy/branch/pypy-genc/
      - copied from r6002, pypy/trunk/src/pypy/
   pypy/branch/pypy-genc/objspace/descroperation.py
      - copied unchanged from r6006, pypy/trunk/src/pypy/objspace/descroperation.py
   pypy/branch/pypy-genc/objspace/std/fake.py
      - copied unchanged from r6005, pypy/trunk/src/pypy/objspace/std/fake.py
   pypy/branch/pypy-genc/translator/autopath.py
      - copied unchanged from r6002, pypy/trunk/src/pypy/translator/test/autopath.py
   pypy/branch/pypy-genc/translator/genc.h   (contents, props changed)
   pypy/branch/pypy-genc/translator/genc.py   (contents, props changed)
   pypy/branch/pypy-genc/translator/genpyrex.py
      - copied unchanged from r6009, pypy/trunk/src/pypy/translator/genpyrex.py
   pypy/branch/pypy-genc/translator/tool/pygame/flowviewer.py
      - copied unchanged from r6007, pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py
   pypy/branch/pypy-genc/translator/tool/pygame/graphdisplay.py
      - copied unchanged from r6008, pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py
   pypy/branch/pypy-genc/translator/translator.py
      - copied, changed from r6009, pypy/trunk/src/pypy/translator/translator.py
Log:
Perhaps generating Pyrex code isn't such a great idea.  The great idea was to 
use CPython as an intermediate target.  But writing C extension modules in C 
instead of in Pyrex is quite possibly much cleaner, because:

* very basic C code is sufficient;

* removing yet another intermediate step might not be a bad idea for clarity;

* reference counting is easy because we know exactly when variables get out of
  scope: when they reach the end of a basic block and are not sent to the next 
  block;

* we don't have to work around various Pyrex restrictions (or hack Pyrex to 
  lift them);

* most importantly, the whole mess with the "class Op" in genpyrex.py can 
  probably be completely omitted, because we can use C macros and generate
  just a succession of OP_XXX(a,b,c) where XXX is the operation name and
  a,b,c are the arguments.  Mapping the operation to actual C code is done
  once and for all in a C header file defining these macros.

The resulting C code looks much like assembler code.  It's quite readable and
easy to map to the original flow graph, too.


Added: pypy/branch/pypy-genc/translator/genc.h
==============================================================================
--- (empty file)
+++ pypy/branch/pypy-genc/translator/genc.h	Tue Aug 17 21:25:17 2004
@@ -0,0 +1,11 @@
+
+/************************************************************/
+ /***  Generic C header section                            ***/
+
+#include <Python.h>
+
+#define FREE(x)  Py_DECREF(x)
+
+
+/************************************************************/
+ /***  The rest is produced by genc.py                     ***/

Added: pypy/branch/pypy-genc/translator/genc.py
==============================================================================
--- (empty file)
+++ pypy/branch/pypy-genc/translator/genc.py	Tue Aug 17 21:25:17 2004
@@ -0,0 +1,193 @@
+"""
+Generate a C source file from the flowmodel.
+
+"""
+import autopath, os
+from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant
+from pypy.objspace.flow.model import Block, traverse
+import inspect
+
+
+class GenC:
+
+    def __init__(self, f, translator, modname=None):
+        self.f = f
+        self.translator = translator
+        self.modname = modname or translator.functions[0].__name__
+        self.annotator = translator.annotator
+        self.namecache = {}
+        self.gen_source()
+
+    def gen_source(self):
+        f = self.f
+        info = {
+            'modname': self.modname,
+            'exported': self.translator.functions[0].__name__,
+            }
+        # header
+        print >> f, C_HEADER % info
+
+        # forward declarations
+        print >> f, '/* forward declarations */'
+        for func in self.translator.functions:
+            print >> f, 'static %s;' % self.cfunction_header(func)
+        print >> f
+
+        # function implementation
+        print >> f, C_SEP
+        print >> f
+        for func in self.translator.functions:
+            self.gen_cfunction(func)
+            print >> f
+
+        # entry point
+        print >> f, C_SEP
+        print >> f, C_ENTRYPOINT_HEADER % info
+        self.gen_entrypoint(self.translator.functions[0])
+        print >> f, C_ENTRYPOINT_FOOTER % info
+
+        # footer
+        print >> f, C_METHOD_TABLE % info
+        print >> f, C_FOOTER % info
+
+
+    def cfunction_name(self, func):
+        # NB. the purpose of the cache is not performance, but to ensure that
+        # two methods that compare equal get the same name.
+        if inspect.ismethod(func) and func.im_self is None:
+            func = func.im_func  # consider unbound methods as plain functions
+        try:
+            return self.namecache[func]
+        except KeyError:
+            assert inspect.isfunction(func) or inspect.ismethod(func)
+            name = '%s__%x' % (func.__name__, id(func))#self._hackname(func)
+            self.namecache[func] = name
+            return name
+
+    def cfunction_header(self, func):
+        graph = self.translator.flowgraphs[func]
+        args = graph.getargs()
+        returntypename = 'PyObject*'
+        l = ['PyObject* %s' % a for a in args]
+        return '%s %s(%s)' % (returntypename,
+                              self.cfunction_name(func),
+                              ', '.join(l))
+
+    def gen_entrypoint(self, func):
+        f = self.f
+        graph = self.translator.flowgraphs[func]
+        args = graph.getargs()
+        l = ['"' + 'O'*len(args) + '"']
+        l2 = []
+        for i in range(len(args)):
+            print >> f, '\tPyObject* a%d;' % i
+            l.append('&a%d' % i)
+            l2.append('a%d' % i)
+        print >> f, '\tif (!PyArg_ParseTuple(args, %s))' % ', '.join(l)
+        print >> f, '\t\treturn NULL;'
+        print >> f, '\treturn %s(%s);' % (self.cfunction_name(func),
+                                          ', '.join(l2))
+
+
+    def gen_cfunction(self, func):
+        f = self.f
+        graph = self.translator.flowgraphs[func]
+        allblocks = []
+        blockname = {}
+        def visit(n):
+            if isinstance(n, Block):
+                allblocks.append(n)
+                blockname[n] = 'block%d' % len(blockname)
+        traverse(visit, graph)
+        
+        # header
+        print >> f, self.cfunction_header(func)
+        print >> f, '{'
+
+        # local variables
+        for block in allblocks:
+            for var in block.getvariables():
+                print >> f, '\tPyObject* %s;' % var
+        print >> f
+
+        # body
+        for block in allblocks:
+            print >> f, '  %s:' % blockname[block]
+            to_release = block.getvariables()
+            
+            # basic block operations
+            for op in block.operations:
+                l = [str(a) for a in op.args]
+                print >> f, '\tOP_%s(%s, %s)' % (op.opname.upper(),
+                                                 ', '.join(l),
+                                                 op.result)
+
+            # exits
+            if block.exits:
+                macros = ['CASE'] * (len(block.exits)-1) + ['ELSE']
+                for macro, exit in zip(macros, block.exits):
+                    if len(block.exits) == 1:
+                        indent = '\t'
+                        close = ''
+                    else:
+                        print >> f, '\t%s(%s, %s) {' % (macro,
+                                                        block.exitswitch,
+                                                        exit.exitcase)
+                        indent = '\t\t'
+                        close = '\t}'
+                    sourceargs = exit.args
+                    targetargs = exit.target.inputargs
+                    assert len(sourceargs) == len(targetargs)
+                    # get rid of assignments of UndefinedConstant
+                    sargs, targs = [], []
+                    for s,t in zip(sourceargs, targetargs):
+                        if not isinstance(s, UndefinedConstant):
+                            sargs.append(s)
+                            targs.append(t)
+                    for var in to_release:
+                        if var not in sargs:
+                            print >> f, '%sFREE(%s)' % (indent, var)
+                    for s,t in zip(sargs, targs):
+                        print >> f, '%s%s = %s;' % (indent, t, s)
+                    print >> f, '%sgoto %s;' % (indent,
+                                                blockname[exit.target])
+                    print >> f, close
+            elif hasattr(block, 'exc_type'):
+                xxx_raise
+            else:
+                print >> f, '\treturn %s;' % block.inputargs[0]
+                print >> f
+
+        print >> f, '}'
+
+
+# ____________________________________________________________
+
+C_HEADER = open(os.path.join(autopath.this_dir, 'genc.h')).read()
+
+C_SEP = "/************************************************************/"
+
+C_ENTRYPOINT_HEADER = '''
+static PyObject* c_%(exported)s(PyObject* self, PyObject* args)
+{
+'''
+
+C_ENTRYPOINT_FOOTER = '''
+}
+'''
+
+C_METHOD_TABLE = '''
+static PyMethodDef %(modname)sMethods[] = {
+\t{"%(exported)s", (PyCFunction)c_%(exported)s, METH_VARARGS},
+\t{NULL, NULL}
+};
+'''
+
+C_FOOTER = '''
+void init%(modname)s(void)
+{
+\tPy_InitModule("%(modname)s", %(modname)sMethods);
+}
+'''
+
+# ____________________________________________________________

Copied: pypy/branch/pypy-genc/translator/translator.py (from r6009, pypy/trunk/src/pypy/translator/translator.py)
==============================================================================
--- pypy/trunk/src/pypy/translator/translator.py	(original)
+++ pypy/branch/pypy-genc/translator/translator.py	Tue Aug 17 21:25:17 2004
@@ -29,7 +29,7 @@
 Try dir(test) for list of current snippets.
 """
 
-import test.autopath
+import autopath
 
 from pypy.objspace.flow.model import *
 from pypy.annotation.model import *



More information about the Pypy-commit mailing list