[pypy-svn] r6232 - pypy/branch/pypy-genc/translator

arigo at codespeak.net arigo at codespeak.net
Mon Aug 30 17:22:47 CEST 2004


Author: arigo
Date: Mon Aug 30 17:22:46 2004
New Revision: 6232

Modified:
   pypy/branch/pypy-genc/translator/genc.h
   pypy/branch/pypy-genc/translator/genc.py
   pypy/branch/pypy-genc/translator/typer.py
Log:
Progress.


Modified: pypy/branch/pypy-genc/translator/genc.h
==============================================================================
--- pypy/branch/pypy-genc/translator/genc.h	(original)
+++ pypy/branch/pypy-genc/translator/genc.h	Mon Aug 30 17:22:46 2004
@@ -74,6 +74,8 @@
 
 #define return_i(n)             return n;
 #define return_o(o)             return o;
+#define returnerr_i()           return -1;
+#define returnerr_o()           return NULL;
 #define incref_o(o)             Py_INCREF(o);
 #define decref_o(o)             Py_DECREF(o);
 

Modified: pypy/branch/pypy-genc/translator/genc.py
==============================================================================
--- pypy/branch/pypy-genc/translator/genc.py	(original)
+++ pypy/branch/pypy-genc/translator/genc.py	Mon Aug 30 17:22:46 2004
@@ -12,9 +12,9 @@
 class CRepr:
     "A possible representation of a flow-graph variable as C-level variables."
 
-    def __init__(self, impl, error_retval, parse_code=None):
+    def __init__(self, impl, err_check=None, parse_code=None):
         self.impl = impl   # list [(C type, prefix for variable name)]
-        self.error_retval = error_retval  # return value signalling an error
+        self.err_check = err_check  # condition to check for error return value
         self.parse_code = parse_code  # character(s) for PyArg_ParseTuple()
 
     def __repr__(self):
@@ -31,9 +31,9 @@
 class CTypeSet:
     "A (small) set of C types that typer.LLFunction can manipulate."
 
-    R_VOID   = CRepr([],             error_retval='-1')
-    R_INT    = CRepr(['int'],        error_retval='-1',   parse_code='i')
-    R_OBJECT = CRepr(['PyObject*'],  error_retval='NULL', parse_code='O')
+    R_VOID   = CRepr([])
+    R_INT    = CRepr(['int'],       err_check='< 0',     parse_code='i')
+    R_OBJECT = CRepr(['PyObject*'], err_check='== NULL', parse_code='O')
 
     REPR_BY_CODE = {
         'v': R_VOID,
@@ -41,7 +41,8 @@
         'o': R_OBJECT,
         }
 
-    def __init__(self, bindings):
+    def __init__(self, genc, bindings):
+        self.genc = genc
         self.bindings = bindings
         self.r_constants = {}
         self.lloperations = {'convert': {}, 'release': {}}
@@ -73,7 +74,17 @@
         if opname == 'OP_NEWLIST':
             opnewlist = self.lloperations.setdefault('OP_NEWLIST', {})
             sig = (self.R_OBJECT,) * len(hltypes)
-            opnewlist[sig] = 'newlist', True
+            def writer(*stuff):
+                content = stuff[:-2]
+                result = stuff[-2]
+                err = stuff[-1]
+                ls = ['if (!(%s = PyList_New(%d))) goto %s;' % (
+                    result, len(content), err)]
+                for i in range(len(content)):
+                    ls.append('PyList_SET_ITEM(%s, %d, %s); Py_INCREF(%s);' % (
+                        result, i, content[i], content[i]))
+                return '\n'.join(ls)
+            opnewlist[sig] = writer, True
             return   # retry
         raise TypingError((opname,) + hltypes)
 
@@ -85,7 +96,15 @@
             return self.r_constants[key]
         except KeyError:
             # a constant doesn't need any C variable to be encoded
-            r = self.r_constants[key] = CRepr([], '-1')
+            r = self.r_constants[key] = CRepr([])
+            # returning a constant
+            def writer():
+                return 'return 0;'
+            self.lloperations['return'][r,] = writer, False
+            def writer():
+                return 'return -1;'
+            self.lloperations['returnerr'][r,] = writer, False
+            
             # but to convert it to something more general like an int or
             # a PyObject* we need to revive its value, which is done by
             # new conversion operations that we define now
@@ -93,21 +112,51 @@
             if isinstance(value, int):
                 # can convert the constant to a C int
                 r.const = str(int(value))
-                llname = '%s = ' + r.const + ';'
-                conv[r, self.R_INT] = llname, False
+                def writer(z):
+                    return '%s = %s;' % (z, r.const)
+                conv[r, self.R_INT] = writer, False
                 # can convert the constant to a PyObject*
-                llname = 'convert_io(' + r.const + ', %s, %s)'
-                conv[r, self.R_OBJECT] = llname, True
+                def writer(z, err):
+                    return 'convert_io(%s, %s, %s)' % (r.const, z, err)
+                conv[r, self.R_OBJECT] = writer, True
             elif isinstance(value, str):
                 # can convert the constant to a PyObject*
-                llname = ('convert_so(' + c_str(value) + ', ' +
-                          str(len(value)) + ', %s, %s)')
-                conv[r, self.R_OBJECT] = llname, True
+                def writer(z, err):
+                    return 'convert_so(%s, %d, %s, %s)' % (
+                        (c_str(value), len(value), z, err))
+                conv[r, self.R_OBJECT] = writer, True
             elif value is None:
                 # can convert the constant to Py_None
                 r.const = 'Py_None'
-                llname = 'convert_vo(%s)'
-                conv[r, self.R_OBJECT] = llname, False
+                def writer(z):
+                    return 'convert_vo(%s)' % (z,)
+                conv[r, self.R_OBJECT] = writer, False
+            elif callable(value) and value in self.genc.llfunctions:
+                # another Python function: can be called with OP_SIMPLE_CALL
+                llfunc = self.genc.llfunctions[value]
+                ops = self.lloperations.setdefault('OP_SIMPLE_CALL', {})
+                sig = [r]
+                for v in llfunc.graph.getargs():
+                    sig.append(self.gethltype(v))
+                hltype = self.gethltype(llfunc.graph.getreturnvar())
+                sig.append(hltype)
+                if len(hltype.impl) == 0:   # no return value
+                    def writer(*stuff):
+                        args = stuff[:-1]
+                        err = stuff[-1]
+                        return 'if (%s(%s) < 0) goto %s;' % (
+                            llfunc.name, ', '.join(args), err)
+                elif len(hltype.impl) == 1:  # one LLVar for the return value
+                    def writer(*stuff):
+                        args = stuff[:-2]
+                        result = stuff[-2]
+                        err = stuff[-1]
+                        return ('if ((%s = %s(%s)) %s) goto %s;' % (
+                            result, llfunc.name, ', '.join(args),
+                            hltype.err_check, err))
+                else:
+                    XXX("to do")
+                ops[tuple(sig)] = writer, True
             else:
                 print "// XXX not implemented: constant", key
             return r
@@ -120,18 +169,19 @@
         for line in C_HEADER.split('\n'):
             match = rexp.match(line)
             if match:
-                opname, typecodes, formalargs = match.groups()
-                llname = '%s_%s' % (opname, typecodes)
-                sig = tuple([self.REPR_BY_CODE[code] for code in typecodes])
-                can_fail = formalargs.replace(' ','').endswith(',err')
-                ops = self.lloperations.setdefault(opname, {})
-                assert sig not in ops, llname
-                siglen = 0
-                for hltype in sig:
-                    siglen += len(hltype.impl)
-                l = ['%s'] * (siglen + can_fail)
-                llname = llname + '(' + ', '.join(l) + ')'
-                ops.setdefault(sig, (llname, can_fail))
+                self.register_operation_template(*match.groups())
+
+    def register_operation_template(self, opname, typecodes, formalargs):
+        llname = '%s_%s' % (opname, typecodes)
+        sig = tuple([self.REPR_BY_CODE[code] for code in typecodes])
+        can_fail = formalargs.replace(' ','').endswith(',err')
+        ops = self.lloperations.setdefault(opname, {})
+        assert sig not in ops, llname
+        # the operation's low-level name is a callable that will
+        # produce the correct macro call
+        def writer(*args):
+            return llname + '(' + ', '.join(args) + ')'
+        ops.setdefault(sig, (writer, can_fail))
 
 def c_str(s):
     "Return the C expression for the string 's'."
@@ -151,7 +201,8 @@
         self.modname = modname or translator.functions[0].__name__
         if translator.annotator:
             bindings = translator.annotator.bindings.copy()
-            # force the entry point's return type to be 'PyObject*'
+            # for simplicity, force the entry point's return type to be
+            # 'PyObject*'
             try:
                 entrypoint = translator.functions[0]
                 del bindings[translator.flowgraphs[entrypoint].getreturnvar()]
@@ -159,7 +210,7 @@
                 pass
         else:
             bindings = {}
-        self.typeset = CTypeSet(bindings)
+        self.typeset = CTypeSet(self, bindings)
         self.llfunctions = {}
         self.build_llfunctions()
         self.gen_source()
@@ -212,7 +263,7 @@
         llargs, rettype = llfunc.ll_header()
         l = ['%s %s' % (a.type, a.name) for a in llargs]
         l = l or ['void']
-        return '%s %s(%s)' % (rettype,
+        return '%s %s(%s)' % (rettype or 'int',
                               llfunc.name,
                               ', '.join(l))
 
@@ -264,40 +315,22 @@
                 seen[a] = True
         print >> f
 
-        # define special cases for some operations
-        def print_move(x, y):
-            print >> f, '\t%s = %s;' % (y, x)
-
-        def print_goto(lbl):
-            print >> f, '\tgoto %s;' % lbl
-
-        def print_returnerror():
-            v = llfunc.graph.getreturnvar()
-            hltype = self.typeset.gethltype(v)
-            print >> f, '\treturn %s;' % hltype.error_retval
-
-        def print_newlist(*args):
-            content = args[:-2]
-            result = args[-2]
-            err = args[-1]
-            print >> f, '\t%s = PyList_New(%d);' % (result, len(content))
-            print >> f, '\tif (!%s) goto %s;' % (result, err)
-            for i in range(len(content)):
-                print >> f, '\tPyList_SET_ITEM(%s, %d, %s); Py_INCREF(%s);' % (
-                    result, i, content[i], content[i])
-
         # print the body
         for line in body:
             if isinstance(line, LLOp):
                 args = [a.name for a in line.args]
                 if line.errtarget:
                     args.append(line.errtarget)
-                try:
-                    fn = locals()['print_' + line.name]
-                except KeyError:        # common case operations
-                    print >> f, '\t' + line.name % tuple(args)
-                else:                   # special case operations
-                    fn(*args)
+                # line.name is actually not a string, but a callable that
+                # generates the C code -- unless it is a special low-level-only
+                # operation that comes from typer.py.
+                writer = line.name   
+                if isinstance(writer, str):
+                    writer = LL_ONLY_OPERATIONS[writer]
+                code = writer(*args)
+                for codeline in code.split('\n'):
+                    print >> f, '\t' + codeline
+
             elif line:  # label
                 print >> f, '   %s:' % line
             else:  # empty line
@@ -305,6 +338,11 @@
         print >> f, '}'
 
 
+LL_ONLY_OPERATIONS = {
+    'move': lambda x,y: '%s = %s;' % (y,x),
+    'goto': lambda err: 'goto %s;' % err,
+    }
+
 # ____________________________________________________________
 
 C_HEADER = open(os.path.join(autopath.this_dir, 'genc.h')).read()

Modified: pypy/branch/pypy-genc/translator/typer.py
==============================================================================
--- pypy/branch/pypy-genc/translator/typer.py	(original)
+++ pypy/branch/pypy-genc/translator/typer.py	Mon Aug 30 17:22:46 2004
@@ -43,11 +43,11 @@
 #         'decref'    z : release (or decref) the object z
 #         'caseXXX'   z : fails (i.e. jump to errlabel) if z is not XXX
 #         'return'    z : z is the return value of the function
+#         'returnerr' z : same, but return an error code instead of z's content
 #
 #       Low-level-only operation names:
 #         'goto'        : fails unconditionally (i.e. jump to errlabel)
 #         'move'    x y : raw copy of the LLVar x to the LLVar y
-#         'returnerror' : return an error code from the function
 #
 #   def typingerror(self, opname, hltypes):
 #       Called when no match is found in lloperations.  This function must
@@ -95,7 +95,12 @@
         Enumerates low-level operations: LLOps with labels inbetween (strings).
         """
         self.blockname = {}
-        self.release_root = ReleaseNode(None, LLOp('returnerror', []), None)
+        v = self.graph.getreturnvar()
+        self.makevar(v)
+        sig = (self.hltypes[v],)
+        llname, can_fail = self.lloperations['returnerr'][sig]
+        assert not can_fail
+        self.release_root = ReleaseNode(None, LLOp(llname, []), None)
         allblocks = []
         
         # collect all blocks



More information about the Pypy-commit mailing list