[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