[pypy-svn] r18383 - in pypy/dist/pypy/translator/c: . src test

arigo at codespeak.net arigo at codespeak.net
Tue Oct 11 12:35:04 CEST 2005


Author: arigo
Date: Tue Oct 11 12:34:59 2005
New Revision: 18383

Modified:
   pypy/dist/pypy/translator/c/database.py
   pypy/dist/pypy/translator/c/funcgen.py
   pypy/dist/pypy/translator/c/genc.py
   pypy/dist/pypy/translator/c/node.py
   pypy/dist/pypy/translator/c/src/ll_stackless.h
   pypy/dist/pypy/translator/c/stackless.py
   pypy/dist/pypy/translator/c/test/test_standalone.py
Log:
(tismer, valentino, ale, adim, arigo, afa)

Progress on the Stackless-style code generation.
Now all we're left with is a segfault to debug.  Good :-)



Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py	(original)
+++ pypy/dist/pypy/translator/c/database.py	Tue Oct 11 12:34:59 2005
@@ -89,6 +89,8 @@
                 if who_asks is not None:
                     who_asks.dependencies[node] = True
                 return 'struct %s @' % node.name
+            elif T.tag == 'rawmemory':
+                return 'void @'
             else:
                 raise Exception("don't know about opaque type %r" % (T,))
         else:

Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py	(original)
+++ pypy/dist/pypy/translator/c/funcgen.py	Tue Oct 11 12:34:59 2005
@@ -23,13 +23,15 @@
                        more_ll_values
                        vars
                        lltypes
+                       functionname
                        currentblock""".split()
 
-    def __init__(self, graph, db, cpython_exc=False):
+    def __init__(self, graph, db, cpython_exc=False, functionname=None):
         self.graph = graph
         self.db = db
         self.gcpolicy = db.gcpolicy
         self.cpython_exc = cpython_exc
+        self.functionname = functionname
         #
         # collect all variables and constants used in the body,
         # and get their types now

Modified: pypy/dist/pypy/translator/c/genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/genc.py	(original)
+++ pypy/dist/pypy/translator/c/genc.py	Tue Oct 11 12:34:59 2005
@@ -38,6 +38,7 @@
 
         modulename = uniquemodulename('testing')
         targetdir = udir.ensure(modulename, dir=1)
+        self.targetdir = targetdir
         defines = {}
         # defines={'COUNT_OP_MALLOCS': 1}
         if not self.standalone:
@@ -110,7 +111,7 @@
         python_inc = sysconfig.get_python_inc()
         self.executable_name = build_executable(
             [self.c_source_filename] + self.extrafiles,
-            include_dirs = [autopath.this_dir, python_inc],
+            include_dirs = [autopath.this_dir, python_inc, str(self.targetdir)],
             libraries=self.libraries)
         self._compiled = True
         return self.executable_name
@@ -155,9 +156,8 @@
                 funcnodes.append(node)
             else:
                 othernodes.append(node)
-        #if len(funcnodes) >= SPLIT_CRITERIA:
-        # always now
-        self.one_source_file = False
+        if len(funcnodes) >= SPLIT_CRITERIA:
+            self.one_source_file = False
         self.funcnodes = funcnodes
         self.othernodes = othernodes
         self.path = path
@@ -307,9 +307,6 @@
             fc.close()
         print >> f
 
-        if hasattr(self.database, 'stacklessdata'):
-            self.database.stacklessdata.writefiles(self)
-
 # this function acts as the fallback for small sources for now.
 # Maybe we drop this completely if source splitting is the way
 # to go. Currently, I'm quite fine with keeping a working fallback.
@@ -436,6 +433,10 @@
     sg.set_strategy(targetdir)
     sg.gen_readable_parts_of_source(f)
 
+    # 2bis) stackless data
+    if hasattr(database, 'stacklessdata'):
+        database.stacklessdata.writefiles(sg)
+
     # 3) start-up code
     print >> f
     gen_startupcode(f, database)

Modified: pypy/dist/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py	(original)
+++ pypy/dist/pypy/translator/c/node.py	Tue Oct 11 12:34:59 2005
@@ -438,21 +438,21 @@
 
     def __init__(self, db, T, obj):
         self.globalcontainer = True
-        self.funcgen = select_function_code_generator(obj, db)
         self.db = db
         self.T = T
         self.obj = obj
-        #self.dependencies = {}
-        self.typename = db.gettype(T)  #, who_asks=self)
-        if self.funcgen:
-            argnames = self.funcgen.argnames()
-            self.implementationtypename = db.gettype(T, argnames=argnames)
         if hasattr(obj, 'includes'):
             self.includes = obj.includes
             self.name = self.basename()
         else:
             self.includes = ()
             self.name = db.namespace.uniquename('g_' + self.basename())
+        self.funcgen = select_function_code_generator(obj, db, self.name)
+        #self.dependencies = {}
+        self.typename = db.gettype(T)  #, who_asks=self)
+        if self.funcgen:
+            argnames = self.funcgen.argnames()
+            self.implementationtypename = db.gettype(T, argnames=argnames)
         self.ptrname = self.name
 
     def basename(self):
@@ -517,7 +517,7 @@
 
 assert not USESLOTS or '__dict__' not in dir(FuncNode)
 
-def select_function_code_generator(fnobj, db):
+def select_function_code_generator(fnobj, db, functionname):
     if fnobj._callable in extfunc.EXTERNALS:
         # 'fnobj' is one of the ll_xyz() functions with the suggested_primitive
         # flag in pypy.rpython.module.*.  The corresponding C wrappers are
@@ -534,7 +534,7 @@
             gencls = SlpFunctionCodeGenerator
         else:
             gencls = FunctionCodeGenerator
-        return gencls(fnobj.graph, db, cpython_exc)
+        return gencls(fnobj.graph, db, cpython_exc, functionname)
     elif getattr(fnobj, 'external', None) == 'C':
         # deprecated case
         if getattr(fnobj, 'includes', None):

Modified: pypy/dist/pypy/translator/c/src/ll_stackless.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/ll_stackless.h	(original)
+++ pypy/dist/pypy/translator/c/src/ll_stackless.h	Tue Oct 11 12:34:59 2005
@@ -22,10 +22,51 @@
 slp_frame_t* slp_frame_stack_bottom = NULL;
 int slp_restart_substate;
 long slp_retval_long;
-void *slp_retval_ptr;
+double slp_retval_double;
+void *slp_retval_voidptr;
 slp_frame_t* slp_new_frame(int size, int state);
 
 
+slp_frame_t* slp_new_frame(int size, int state)
+{
+  slp_frame_t* f = (slp_frame_t*) malloc(size);
+  f->f_back = NULL;
+  f->state = state;
+  return f;
+}
+
+
+/* example function for testing */
+
+long LL_stackless_stack_frames_depth(void)
+{
+	if (slp_frame_stack_top) goto resume;
+
+	slp_frame_stack_top = slp_frame_stack_bottom =
+		slp_new_frame(sizeof(slp_frame_t), 0);
+	return -1;
+
+ resume:
+    {
+	slp_frame_t* f = slp_frame_stack_top;
+	int result;
+	slp_frame_stack_top = NULL;
+
+	result = 0;
+	while (f) {
+		result++;
+		f = f->f_back;
+	}
+	return result;
+    }
+}
+
+
+#include "slp_defs.h"
+
+#include "slp_state_decoding.h"
+
+
 void slp_main_loop(void)
 {
   int state, signature;
@@ -56,10 +97,6 @@
 
           switch (signature) {
 
-	  case -1:
-		  slp_retval_long = ((long(*)(void)) fn) ();
-		  break;
-
 #include "slp_signatures.h"
 
 	  }
@@ -77,14 +114,6 @@
     }
 }
 
-slp_frame_t* slp_new_frame(int size, int state)
-{
-  slp_frame_t* f = (slp_frame_t*) malloc(size);
-  f->f_back = NULL;
-  f->state = state;
-  return f;
-}
-
 int slp_standalone_entry_point(RPyListOfString *argv)
 {
 	int result = PYPY_STANDALONE(argv);
@@ -95,40 +124,4 @@
 	return result;
 }
 
-
-/* example function for testing */
-
-long LL_stackless_stack_frames_depth(void)
-{
-	if (slp_frame_stack_top) goto resume;
-
-	slp_frame_stack_top = slp_frame_stack_bottom =
-		slp_new_frame(sizeof(slp_frame_t), 0);
-	return -1;
-
- resume:
-    {
-	slp_frame_t* f = slp_frame_stack_top;
-	int result;
-	slp_frame_stack_top = NULL;
-
-	result = 0;
-	while (f) {
-		result++;
-		f = f->f_back;
-	}
-	return result;
-    }
-}
-
-
-struct slp_state_decoding_entry_s slp_state_decoding_table[] = {
-	{ LL_stackless_stack_frames_depth, -1 },    /* 0 */
-	/* XXX WARNING FOR NOW MAKE SURE StacklessData.globalstatecounter
-	   counts the number of manually-inserted lines above !!!!!!!!!! */
-#include "slp_state_decoding.h"
-};
-
-#include "slp_defs.h"
-
 #endif USE_STACKLESS

Modified: pypy/dist/pypy/translator/c/stackless.py
==============================================================================
--- pypy/dist/pypy/translator/c/stackless.py	(original)
+++ pypy/dist/pypy/translator/c/stackless.py	Tue Oct 11 12:34:59 2005
@@ -5,6 +5,8 @@
 """
 
 import py
+from pypy.objspace.flow.model import Variable
+from pypy.rpython import lltype
 from pypy.translator.c.funcgen import FunctionCodeGenerator
 
 
@@ -13,6 +15,24 @@
     def __init__(self):
         self.frame_types = {}
         self.globalstatecounter = 1
+        self.allsignatures = {}
+        self.decode_table = []
+        # start the decoding table with entries for the functions that
+        # are written manually in ll_stackless.h
+        self.registerunwindable('LL_stackless_stack_frames_depth',
+                                lltype.FuncType([], lltype.Signed),
+                                resume_points=1)
+
+    def registerunwindable(self, functionname, FUNC, resume_points):
+        if resume_points >= 1:
+            try:
+                signum = self.allsignatures[FUNC]
+            except KeyError:
+                signum = len(self.allsignatures)
+                self.allsignatures[FUNC] = signum
+            self.decode_table.append((functionname, signum))
+            for n in range(1, resume_points):
+                self.decode_table.append(('NULL', n))
 
     def get_frame_type(self, n_integers, n_floats, n_pointers):
         key = n_integers, n_floats, n_pointers
@@ -24,6 +44,7 @@
             return name
 
     def writefiles(self, sg):
+        # generate slp_defs.h
         f = sg.makefile('slp_defs.h')
         items = self.frame_types.items()
         items.sort()
@@ -31,9 +52,9 @@
             types = (['long']*n_integers +
                      ['double']*n_floats +
                      ['void *']*n_pointers)
-            varnames = (['l%d;' % i for i in range(n_integers)] +
-                        ['d%d;' % i for i in range(n_floats)] +
-                        ['p%d;' % i for i in range(n_pointers)])
+            varnames = (['l%d' % i for i in range(n_integers)] +
+                        ['d%d' % i for i in range(n_floats)] +
+                        ['v%d' % i for i in range(n_pointers)])
             fields = []
             for type, varname in zip(types, varnames):
                 fields.append('%s %s;' % (type, varname))
@@ -48,25 +69,51 @@
                     structname, varname, varname))
 
             code = str(py.code.Source('''
-                void *save_%(name)s(%(arguments)s)
-                {
-                    frame_t* f = new_frame(sizeof(struct %(name)s), state);
-                    frame_stack_bottom->f_back = f;
-                    frame_stack_bottom = f;
-                    %(saving_lines)s
-                    return NULL;
-                }
+             void *save_%(name)s(%(arguments)s)
+             {
+                 slp_frame_t* f = slp_new_frame(sizeof(struct %(name)s), state);
+                 slp_frame_stack_bottom->f_back = f;
+                 slp_frame_stack_bottom = f;
+                 %(saving_lines)s
+                 return NULL;
+             }
             '''))
             print >> f, code % {'name': structname,
                                 'arguments': ', '.join(arguments),
-                                'saving_lines': '\n'.join(saving_lines)}
-
+                                'saving_lines': '\n    '.join(saving_lines)}
         f.close()
+
+        # generate slp_signatures.h
         f = sg.makefile('slp_signatures.h')
-        ...
+        items = [(num, FUNC) for (FUNC, num) in self.allsignatures.items()]
+        items.sort()
+        for num, FUNC in items:
+            # 'FUNC' is a lltype.FuncType instance
+            print >> f, 'case %d:' % num
+            # XXX '0' is hopefully fine for a dummy value of any type
+            #     for most compilers
+            dummyargs = ['0'] * len(FUNC.ARGS)
+            callexpr = '((%s) fn) (%s);' % (
+                sg.database.gettype(lltype.Ptr(FUNC)).replace('@', ''),
+                ', '.join(dummyargs))
+            globalretvalvartype = simplified_type(FUNC.RESULT)
+            if globalretvalvartype is not None:
+                globalretvalvarname = RETVALVARS[globalretvalvartype]
+                callexpr = '%s = (%s) %s' % (globalretvalvarname,
+                                             globalretvalvartype,
+                                             callexpr)
+            print >> f, '\t' + callexpr
+            print >> f, '\tbreak;'
+            print >> f
         f.close()
-        f = sg.makefile('slp_XXX.h')
-        ...
+
+        # generate slp_state_decoding.h
+        f = sg.makefile('slp_state_decoding.h')
+        print >> f, 'static struct slp_state_decoding_entry_s',
+        print >> f, 'slp_state_decoding_table[] = {'
+        for i, (functionname, signum) in enumerate(self.decode_table):
+            print >> f, '/* %d */ { %s, %d },' % (i, functionname, signum)
+        print >> f, '};'
         f.close()
 
 
@@ -94,14 +141,27 @@
             yield '\tswitch (slp_restart_substate) {'
             for block in self.resumeblocks:
                 for line in block:
-                    yield line
+                    yield '\t'+line
             yield '\t}'
             yield '\tassert(!"bad restart_substate");'
             yield '}'
+            
+            # record extra data needed to generate the slp_*.h tables:
+            # find the signatures of all functions
+            slpdata = self.db.stacklessdata
+            argtypes = [erase_ptr_type(v.concretetype)
+                        for v in self.graph.getargs()]
+            argtypes = [T for T in argtypes if T is not lltype.Void]
+            rettype = erase_ptr_type(self.graph.getreturnvar().concretetype)
+            FUNC = lltype.FuncType(argtypes, rettype)
+            slpdata.registerunwindable(self.functionname, FUNC,
+                                       resume_points = len(self.resumeblocks))
+
         del self.savelines
         del self.resumeblocks
 
     def check_directcall_result(self, op, err):
+        stacklessdata = self.db.stacklessdata
         block = self.currentblock
         curpos = block.operations.index(op)
 
@@ -114,7 +174,7 @@
             produced[op1.result] = True
         consumed = {}
         for op1 in block.operations[curpos:]:
-            for v in op1:
+            for v in op1.args:
                 if isinstance(v, Variable):
                     consumed[v] = True
         if isinstance(block.exitswitch, Variable):
@@ -129,31 +189,77 @@
         counts = {"long":   [],
                   "double": [],
                   "void*":  []}
+        variables_to_restore = []
         for v in vars:
             st = simplified_type(v.concretetype)
             if st is not None:   # ignore the Voids
-                counts[st].append('(%s)%s' % (st, self.expr(v)))
-        structname = self.get_frame_type(len(counts["long"]),
-                                         len(counts["double"]),
-                                         len(counts["void*"]))
+                varname = self.expr(v)
+                # XXX hackish: the name of the field in the structure is
+                # computed from the 1st letter of the 'st' type, counting
+                # from 0 for each of the 'st' types independently
+                variables_to_restore.append((v, '%s%d' % (
+                    st[0], len(counts[st]))))
+                counts[st].append('(%s)%s' % (st, varname))
+        structname = stacklessdata.get_frame_type(len(counts["long"]),
+                                                  len(counts["double"]),
+                                                  len(counts["void*"]))
 
         # reorder the vars according to their type
         vars = counts["long"] + counts["double"] + counts["void*"]
 
-        # generate the 'save:' line
-        label = 'save_%d' % len(self.savelines)
-        arguments = ['%d' % self.globalstatecounter] + vars
+        # generate the 'save:' line, e.g.
+        #      save_0: return (int) save_frame_1(0, (long) n);
+        savelabel = 'save_%d' % len(self.savelines)
+        arguments = ['%d' % stacklessdata.globalstatecounter] + vars
+        stacklessdata.globalstatecounter += 1
         self.savelines.append('%s: return (%s) save_%s(%s);' % (
-            label,
+            savelabel,
             self.lltypename(self.graph.getreturnvar()).replace('@', ''),
             structname,
-            ', '.join(arguments))
-        
-        save_0: return (int) save_frame_1(0, n);
-        
+            ', '.join(arguments)))
+
+        # generate the resume block, e.g.
+        #        case 1:
+        #          n = (long)(((struct frame_1_s*) f)->i1);
+        #          b = (long) retval_long;
+        #          goto resume_1;
+        resumelabel = 'resume_%d' % len(self.resumeblocks)
+        lines = ['case %d:' % len(self.resumeblocks)]
+        for v, fieldname in variables_to_restore:
+            varname = self.expr(v)
+            vartype = self.lltypename(v).replace('@', '')
+            lines.append('\t%s = (%s)(((struct %s*) f)->%s);' % (
+                varname, vartype, structname, fieldname))
+            retvarname = self.expr(op.result)
+            retvartype = self.lltypename(op.result).replace('@', '')
+            retvarst = simplified_type(op.result.concretetype)
+            if retvarst is not None:
+                globalretvalvarname = RETVALVARS[retvarst]
+                lines.append('\t%s = (%s) %s;' % (
+                    retvarname, retvartype, globalretvalvarname))
+            lines.append('\tgoto %s;' % (resumelabel,))
+        self.resumeblocks.append(lines)
+
+        # add the checks for the unwinding case just after the directcall
+        # in the source
+        unwind_check = "if (slp_frame_stack_bottom) goto %s;" % (savelabel,)
+        exception_check = (super(SlpFunctionCodeGenerator, self)
+                           .check_directcall_result(op, err))
+        return '%s\n%s:\n%s' % (unwind_check,
+                                resumelabel,
+                                exception_check)
+
+
+def erase_ptr_type(T):
+    """Return T unless it's a pointer type, in which case we return a general
+    basic pointer type.
+    """
+    if isinstance(T, lltype.Ptr):
+        return ERASED_PTR_TYPE
+    else:
+        return T
 
-        ...
-        ...
+ERASED_PTR_TYPE = lltype.Ptr(lltype.OpaqueType("rawmemory"))
 
 
 def simplified_type(T):
@@ -167,3 +273,9 @@
         return "void*"
     else:
         raise Exception("don't know about %r" % (T,))
+
+RETVALVARS = {
+    "double": "slp_retval_double",
+    "long"  : "slp_retval_long",
+    "void*" : "slp_retval_voidptr",
+    }

Modified: pypy/dist/pypy/translator/c/test/test_standalone.py
==============================================================================



More information about the Pypy-commit mailing list