[pypy-svn] r17713 - pypy/dist/pypy/translator/llvm
ericvrp at codespeak.net
ericvrp at codespeak.net
Wed Sep 21 12:20:22 CEST 2005
Author: ericvrp
Date: Wed Sep 21 12:20:21 2005
New Revision: 17713
Modified:
pypy/dist/pypy/translator/llvm/codewriter.py
pypy/dist/pypy/translator/llvm/exception.py
pypy/dist/pypy/translator/llvm/opwriter.py
Log:
* Moved more code to exceptionpolicy.
* Added 'fast' exceptionpolicy, which does not realy on setjmp/longjmp.
Modified: pypy/dist/pypy/translator/llvm/codewriter.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/codewriter.py (original)
+++ pypy/dist/pypy/translator/llvm/codewriter.py Wed Sep 21 12:20:21 2005
@@ -86,9 +86,6 @@
else:
self.indent("ret %s %s" % (type_, ref))
- def unwind(self):
- self.indent("unwind")
-
def phi(self, targetvar, type_, refs, blocknames):
assert targetvar.startswith('%')
assert refs and len(refs) == len(blocknames), "phi node requires blocks"
@@ -118,17 +115,12 @@
tail_ += ' '
args = ", ".join(["%s %s" % item for item in zip(argtypes, argrefs)])
if except_label:
- assert label
- instruction = 'invoke'
- optional = ' to label %%%s except label %%%s' % (label, except_label)
- else:
- assert not label
- instruction = 'call'
- optional = ''
- if returntype == 'void':
- self.indent("%s%s %s void %s(%s)%s" % (tail_, instruction, cconv, functionref, args, optional))
+ self.genllvm.exceptionpolicy.invoke(self, targetvar, tail_, cconv, returntype, functionref, args, label, except_label)
else:
- self.indent("%s = %s%s %s %s %s(%s)%s" % (targetvar, tail_, instruction, cconv, returntype, functionref, args, optional))
+ if returntype == 'void':
+ self.indent("%scall %s void %s(%s)" % (tail_, cconv, functionref, args))
+ else:
+ self.indent("%s = %scall %s %s %s(%s)" % (targetvar, tail_, cconv, returntype, functionref, args))
def cast(self, targetvar, fromtype, fromvar, targettype):
if fromtype == 'void' and targettype == 'void':
Modified: pypy/dist/pypy/translator/llvm/exception.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/exception.py (original)
+++ pypy/dist/pypy/translator/llvm/exception.py Wed Sep 21 12:20:21 2005
@@ -5,14 +5,32 @@
def __init__(self):
raise Exception, 'ExceptionPolicy should not be used directly'
- def pyrex_entrypoint_code(self, entrynode):
- return ''
+ def transform(self, translator):
+ return
- def llc_options(self):
- return ''
+ def _noresult(self, returntype):
+ r = returntype.strip()
+ if r == 'void':
+ return 'void'
+ elif r == 'bool':
+ return 'bool false'
+ elif r in 'float double'.split():
+ return r + ' 0.0'
+ elif r in 'ubyte sbyte ushort short uint int ulong long'.split():
+ return r + ' 0'
+ return r + ' null'
+
+ def _nonoderesult(self, node):
+ decl = node.getdecl()
+ returntype, name = decl.split(' ', 1)
+ noresult = self._noresult(returntype)
+ #print 'XXX decl=%s -> returntype=%s -> noresult=ret %s' % (decl, returntype, noresult)
+ return noresult
def new(exceptionpolicy=None): #factory
- if exceptionpolicy is None or exceptionpolicy == 'cpython':
+ if exceptionpolicy is None:
+ exceptionpolicy = 'cpython'
+ if exceptionpolicy == 'cpython':
from pypy.translator.llvm.exception import CPythonExceptionPolicy
exceptionpolicy = CPythonExceptionPolicy()
elif exceptionpolicy == 'fast':
@@ -27,23 +45,18 @@
new = staticmethod(new)
-class NoneExceptionPolicy(ExceptionPolicy):
+class NoneExceptionPolicy(ExceptionPolicy): #XXX untested
def __init__(self):
pass
-class CPythonExceptionPolicy(ExceptionPolicy): #uses issubclass()
+class CPythonExceptionPolicy(ExceptionPolicy): #uses issubclass() and llvm invoke&unwind
def __init__(self):
pass
def pyrex_entrypoint_code(self, entrynode):
returntype, entrypointname = entrynode.getdecl().split('%', 1)
- if returntype == 'double ':
- noresult = '0.0'
- elif returntype == 'bool ':
- noresult = 'false'
- else:
- noresult = '0'
+ noresult = self._noresult(returntype)
cconv = DEFAULT_CCONV
return '''
ccc %(returntype)s%%__entrypoint__%(entrypointname)s {
@@ -54,7 +67,7 @@
ret %(returntype)s %%result
exception:
- ret %(returntype)s %(noresult)s
+ ret %(noresult)s
}
ccc int %%__entrypoint__raised_LLVMException() {
@@ -64,13 +77,141 @@
}
''' % locals()
+ def invoke(self, codewriter, targetvar, tail_, cconv, returntype, functionref, args, label, except_label):
+ labels = 'to label %%%s except label %%%s' % (label, except_label)
+ if returntype == 'void':
+ codewriter.indent('%sinvoke %s void %s(%s) %s' % (tail_, cconv, functionref, args, labels))
+ else:
+ codewriter.indent('%s = %sinvoke %s %s %s(%s) %s' % (targetvar, tail_, cconv, returntype, functionref, args, labels))
+
+ def _is_raise_new_exception(self, db, graph, block):
+ from pypy.objspace.flow.model import mkentrymap
+ is_raise_new = False
+ entrylinks = mkentrymap(graph)[block]
+ entrylinks = [x for x in entrylinks if x.prevblock is not None]
+ inputargs = db.repr_arg_multi(block.inputargs)
+ for i, arg in enumerate(inputargs):
+ names = db.repr_arg_multi([link.args[i] for link in entrylinks])
+ for name in names: #These tests-by-name are a bit yikes, but I don't see a better way right now
+ if not name.startswith('%last_exception_') and not name.startswith('%last_exc_value_'):
+ is_raise_new = True
+ return is_raise_new
+
+ def write_exceptblock(self, funcnode, codewriter, block):
+ assert len(block.inputargs) == 2
+
+ db = funcnode.db
+ graph = funcnode.graph
+
+ if self._is_raise_new_exception(db, graph, block):
+ funcnode.write_block_phi_nodes(codewriter, block)
+
+ inputargs = db.repr_arg_multi(block.inputargs)
+ inputargtypes = db.repr_arg_type_multi(block.inputargs)
+
+ codewriter.store(inputargtypes[0], inputargs[0], '%last_exception_type')
+ codewriter.store(inputargtypes[1], inputargs[1], '%last_exception_value')
+ else:
+ codewriter.comment('reraise last exception')
+ #Reraising last_exception.
+ #Which is already stored in the global variables.
+ #So nothing needs to happen here!
+
+ codewriter.indent('unwind')
+
+ def fetch_exceptions(self, codewriter, exc_found_labels, lltype_of_exception_type, lltype_of_exception_value):
+ for label, target, last_exc_type_var, last_exc_value_var in exc_found_labels:
+ codewriter.label(label)
+ if last_exc_type_var:
+ codewriter.load(last_exc_type_var, lltype_of_exception_type, '%last_exception_type')
+ if last_exc_value_var:
+ codewriter.load(last_exc_value_var, lltype_of_exception_value, '%last_exception_value')
+ codewriter.br_uncond(target)
+
+ def reraise(self, funcnode, codewriter):
+ codewriter.comment('reraise when exception is not caught')
+ codewriter.indent('unwind')
+
def llc_options(self):
return '-enable-correct-eh-support'
-class FastExceptionPolicy(ExceptionPolicy): #uses only 'direct' exception class comparision
+class FastExceptionPolicy(ExceptionPolicy): #uses issubclass() and last_exception tests after each call
def __init__(self):
- pass
+ self.invoke_count = 0
- pyrex_entrypoint_code = CPythonExceptionPolicy.pyrex_entrypoint_code
- llc_options = CPythonExceptionPolicy.llc_options
+ def pyrex_entrypoint_code(self, entrynode):
+ returntype, entrypointname = entrynode.getdecl().split('%', 1)
+ noresult = self._noresult(returntype)
+ cconv = DEFAULT_CCONV
+ return '''
+ccc %(returntype)s%%__entrypoint__%(entrypointname)s {
+ store %%RPYTHON_EXCEPTION_VTABLE* null, %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type
+ %%result = call %(cconv)s %(returntype)s%%%(entrypointname)s
+ %%tmp = load %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type
+ %%exc = seteq %%RPYTHON_EXCEPTION_VTABLE* %%tmp, null
+ br bool %%exc, label %%no_exception, label %%exception
+
+no_exception:
+ ret %(returntype)s %%result
+
+exception:
+ ret %(noresult)s
+}
+
+ccc int %%__entrypoint__raised_LLVMException() {
+ %%tmp = load %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type
+ %%result = cast %%RPYTHON_EXCEPTION_VTABLE* %%tmp to int
+ ret int %%result
+}
+''' % locals()
+
+ def transform(self, translator):
+ from pypy.translator.backendopt.exception import create_exception_handling
+ for graph in translator.flowgraphs.itervalues():
+ create_exception_handling(translator, graph)
+ #translator.view()
+
+ def invoke(self, codewriter, targetvar, tail_, cconv, returntype, functionref, args, label, except_label):
+ if returntype == 'void':
+ codewriter.indent('%scall %s void %s(%s)' % (tail_, cconv, functionref, args))
+ else:
+ codewriter.indent('%s = %scall %s %s %s(%s)' % (targetvar, tail_, cconv, returntype, functionref, args))
+ tmp = '%%invoke.tmp.%d' % self.invoke_count
+ exc = '%%invoke.exc.%d' % self.invoke_count
+ self.invoke_count += 1
+ codewriter.indent('%(tmp)s = load %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type' % locals())
+ codewriter.indent('%(exc)s = seteq %%RPYTHON_EXCEPTION_VTABLE* %(tmp)s, null' % locals())
+ codewriter.indent('br bool %(exc)s, label %%%(label)s, label %%%(except_label)s' % locals())
+
+ def write_exceptblock(self, funcnode, codewriter, block):
+ assert len(block.inputargs) == 2
+
+ noresult = self._nonoderesult(funcnode)
+
+ funcnode.write_block_phi_nodes(codewriter, block)
+
+ inputargs = funcnode.db.repr_arg_multi(block.inputargs)
+ inputargtypes = funcnode.db.repr_arg_type_multi(block.inputargs)
+
+ codewriter.store(inputargtypes[0], inputargs[0], '%last_exception_type')
+ codewriter.store(inputargtypes[1], inputargs[1], '%last_exception_value')
+ codewriter.indent('ret ' + noresult)
+
+ def fetch_exceptions(self, codewriter, exc_found_labels, lltype_of_exception_type, lltype_of_exception_value):
+ for label, target, last_exc_type_var, last_exc_value_var in exc_found_labels:
+ codewriter.label(label)
+ if last_exc_type_var:
+ codewriter.load(last_exc_type_var, lltype_of_exception_type, '%last_exception_type')
+ if last_exc_value_var:
+ codewriter.load(last_exc_value_var, lltype_of_exception_value, '%last_exception_value')
+ codewriter.store(lltype_of_exception_type , 'null', '%last_exception_type')
+ codewriter.store(lltype_of_exception_value, 'null', '%last_exception_value')
+ codewriter.br_uncond(target)
+
+ def reraise(self, funcnode, codewriter):
+ noresult = self._nonoderesult(funcnode)
+ codewriter.indent('ret ' + noresult)
+
+ def llc_options(self):
+ return ''
Modified: pypy/dist/pypy/translator/llvm/opwriter.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/opwriter.py (original)
+++ pypy/dist/pypy/translator/llvm/opwriter.py Wed Sep 21 12:20:21 2005
@@ -100,10 +100,7 @@
else:
meth = getattr(self, op.opname, None)
if not meth:
- msg = "operation %s not found" %(op.opname,)
- self.codewriter.comment('XXX: Error: ' + msg)
- # XXX commented out for testing
- #assert meth is not None, msg
+ raise Exception, "operation %s not found" % op.opname
return
meth(op)
@@ -164,7 +161,7 @@
#this is really generated, don't know why
# XXX rxe: Surely that cant be right?
- uint_neg = int_neg
+ uint_neg = int_neg
def float_neg(self, op):
self._generic_neg(op, "0.0")
@@ -275,10 +272,8 @@
"null")
def direct_call(self, op):
-
op_args = [arg for arg in op.args
if arg.concretetype is not lltype.Void]
-
assert len(op_args) >= 1
targetvar = self.db.repr_arg(op.result)
returntype = self.db.repr_arg_type(op.result)
@@ -289,6 +284,11 @@
returntype = "%s (%s)*" % (returntype, ", ".join(argtypes))
self.codewriter.call(targetvar,returntype,functionref,argrefs,argtypes)
+ def last_exception_type_ptr(self, op):
+ e = self.db.translator.rtyper.getexceptiondata()
+ lltype_of_exception_type = ('%structtype.' + e.lltype_of_exception_type.TO.__name__ + '*')
+ self.codewriter.load('%'+str(op.result), lltype_of_exception_type, '%last_exception_type')
+
def invoke(self, op):
op_args = [arg for arg in op.args
if arg.concretetype is not lltype.Void]
@@ -314,20 +314,15 @@
link = self.block.exits[0]
assert link.exitcase is None
- targetvar = self.db.repr_arg(op.result)
- returntype = self.db.repr_arg_type(op.result)
- argrefs = self.db.repr_arg_multi(op_args[1:])
- argtypes = self.db.repr_arg_type_multi(op_args[1:])
+ targetvar = self.db.repr_arg(op.result)
+ returntype = self.db.repr_arg_type(op.result)
+ argrefs = self.db.repr_arg_multi(op_args[1:])
+ argtypes = self.db.repr_arg_type_multi(op_args[1:])
none_label = self.node.block_to_name[link.target]
block_label = self.node.block_to_name[self.block]
exc_label = block_label + '_exception_handling'
-
-
-
-
-
if self.db.is_function_ptr(op.result): #use longhand form
returntype = "%s (%s)*" % (returntype, ", ".join(argtypes))
self.codewriter.call(targetvar, returntype, functionref, argrefs,
@@ -360,7 +355,6 @@
for name, blockname in zip(names, blocknames):
if blockname != exc_found_label:
continue
- #XXX might want to refactor the next few lines
if name.startswith('%last_exception_'):
last_exc_type_var = name
if name.startswith('%last_exc_value_'):
@@ -371,11 +365,11 @@
not_this_exception_label = block_label + '_not_exception_' + etype.ref[1:]
- if current_exception_type.find('getelementptr') == -1: #XXX catch all (except:)
+ if current_exception_type.find('getelementptr') == -1: #catch all (except:)
catch_all = True
self.codewriter.br_uncond(exc_found_label)
- else:
- if not last_exception_type:
+ else: #catch specific exception (class) type
+ if not last_exception_type: #load pointer only once
last_exception_type = self.db.repr_tmpvar()
self.codewriter.load(last_exception_type, lltype_of_exception_type, '%last_exception_type')
self.codewriter.newline()
@@ -388,25 +382,10 @@
self.codewriter.br(ll_issubclass_cond, not_this_exception_label, exc_found_label)
self.codewriter.label(not_this_exception_label)
+ ep = self.codewriter.genllvm.exceptionpolicy
if not catch_all:
- self.codewriter.comment('reraise when exception is not caught')
- self.codewriter.unwind()
-
- for label, target, last_exc_type_var, last_exc_value_var in exc_found_labels:
- self.codewriter.label(label)
- if last_exc_type_var:
- self.codewriter.load(last_exc_type_var, lltype_of_exception_type, '%last_exception_type')
- if last_exc_value_var:
- self.codewriter.load(last_exc_value_var, lltype_of_exception_value, '%last_exception_value')
-
- self.codewriter.br_uncond(target)
-
-
-
-
-
-
-
+ ep.reraise(self.node, self.codewriter)
+ ep.fetch_exceptions(self.codewriter, exc_found_labels, lltype_of_exception_type, lltype_of_exception_value)
def malloc(self, op):
arg_type = op.args[0].value
@@ -452,8 +431,6 @@
("uint", index))
self.codewriter.load(targetvar, targettype, tmpvar)
else:
- #XXX what if this the last operation of the exception block?
- # XXX rxe: would a getfield() ever raise anyway???
self.codewriter.comment("***Skipping operation getfield()***")
def getsubstruct(self, op):
More information about the Pypy-commit
mailing list