[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