[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