[pypy-svn] r10291 - in pypy/dist/pypy/translator/llvm: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Mon Apr 4 17:26:06 CEST 2005


Author: cfbolz
Date: Mon Apr  4 17:26:06 2005
New Revision: 10291

Modified:
   pypy/dist/pypy/translator/llvm/build_llvm_module.py
   pypy/dist/pypy/translator/llvm/class.ll
   pypy/dist/pypy/translator/llvm/classrepr.py
   pypy/dist/pypy/translator/llvm/funcrepr.py
   pypy/dist/pypy/translator/llvm/genllvm.py
   pypy/dist/pypy/translator/llvm/list.c
   pypy/dist/pypy/translator/llvm/list_template.ll
   pypy/dist/pypy/translator/llvm/llvmbc.py
   pypy/dist/pypy/translator/llvm/make_runtime.py
   pypy/dist/pypy/translator/llvm/representation.py
   pypy/dist/pypy/translator/llvm/test/llvmsnippet.py
   pypy/dist/pypy/translator/llvm/test/test_genllvm.py
Log:
Added minimal exception support: All exceptions have to be caught, only
builtin exceptions, raising doesn't work yet, only list.getitem raises
IndexError.


Modified: pypy/dist/pypy/translator/llvm/build_llvm_module.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/build_llvm_module.py	(original)
+++ pypy/dist/pypy/translator/llvm/build_llvm_module.py	Mon Apr  4 17:26:06 2005
@@ -31,13 +31,13 @@
             "opt %s -f %s.bc -o %s_optimized.bc" % (OPTIMIZATION_SWITCHES,
                                                     llvmfile.purebasename,
                                                     llvmfile.purebasename),
-            "llc %s_optimized.bc -f -o %s.s" % (llvmfile.purebasename,
-                                                llvmfile.purebasename),
+            "llc -enable-correct-eh-support %s_optimized.bc -f -o %s.s" % \
+            (llvmfile.purebasename, llvmfile.purebasename),
             "as %s.s -o %s.o" % (llvmfile.purebasename, llvmfile.purebasename)]
     if not optimize:
         ops1 = ["llvm-as %s -f" % llvmfile,
-                "llc %s.bc -f -o %s.s" % (llvmfile.purebasename,
-                                          llvmfile.purebasename),
+                "llc -enable-correct-eh-support %s.bc -f -o %s.s" % \
+                (llvmfile.purebasename, llvmfile.purebasename),
                 "as %s.s -o %s.o" % (llvmfile.purebasename,
                                      llvmfile.purebasename)]
     ops2 = ["gcc -c -fPIC -I/usr/include/python2.3 %s.c" % pyxfile.purebasename,

Modified: pypy/dist/pypy/translator/llvm/class.ll
==============================================================================
--- pypy/dist/pypy/translator/llvm/class.ll	(original)
+++ pypy/dist/pypy/translator/llvm/class.ll	Mon Apr  4 17:26:06 2005
@@ -5,8 +5,8 @@
 
 %std.list.sbyte = type {uint, sbyte*}
 %std.exception = type {%std.class*, %std.list.sbyte*}
-%std.last_exception.type = internal global %std.class {%std.class* null, uint 0}
-%std.last_exception.value = internal global %std.exception {%std.class* null, %std.list.sbyte* null}
+%std.last_exception.type = internal global %std.class* null
+%std.last_exception.value = internal global %std.exception* null
 
 implementation
 
@@ -46,3 +46,8 @@
 	ret bool %result
 }
 
+
+internal sbyte %std.unwind() {
+entry:
+	unwind
+}
\ No newline at end of file

Modified: pypy/dist/pypy/translator/llvm/classrepr.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/classrepr.py	(original)
+++ pypy/dist/pypy/translator/llvm/classrepr.py	Mon Apr  4 17:26:06 2005
@@ -200,6 +200,14 @@
             for l_c in l_cls.iter_subclasses():
                 yield l_c
 
+def create_builtin_exceptions(gen, dependencies):
+    import exceptions
+    for exc in dir(exceptions):
+        print exc, "#############"
+        if "__" not in exc:
+            l_exc = gen.get_repr(getattr(exceptions, exc))
+            dependencies.add(l_exc)
+
 class ExceptionTypeRepr(TypeRepr):
     def get(obj, gen):
         try:

Modified: pypy/dist/pypy/translator/llvm/funcrepr.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/funcrepr.py	(original)
+++ pypy/dist/pypy/translator/llvm/funcrepr.py	Mon Apr  4 17:26:06 2005
@@ -133,27 +133,15 @@
                 exceptblock = "block%i.except" % self.blocknum[pyblock]
                 lblock = llvmbc.TryBasicBlock("block%i" % number,
                                               regularblock, exceptblock)
-                l_excblock = llvmbc.BasicBlock("block%i.except" % number)
-                l_excp = self.gen.get_repr(last_exception)
-                l_uip = self.gen.get_local_tmp(PointerTypeRepr("uint",
-                                                               self.gen), self)
-                l_ui = self.gen.get_local_tmp(
-                    self.gen.get_repr(annmodel.SomeInteger(True, True)), self)
-                self.dependencies.update([l_excp, l_uip, l_ui])
-                l_excblock.load(l_cl, l_excp)
-                l_excblock.getelementptr(l_uip, l_cl, [0, 1])
-                l_excblock.load(l_ui, l_uip)
-                l_excblock.switch(l_ui, "%%block%i.unwind" % number,
-                                  [(str(abs(id(l_c))),
-                                    XXXXXXXXXXXXX)
-                                   for exc in pyblock.exits[1:]])
             else:
                 lblock = llvmbc.BasicBlock("block%i" % number)
             if number == 0:
                 self.llvm_func = llvmbc.Function(self.llvmfuncdef(), lblock)
             else:
                 self.llvm_func.basic_block(lblock)
-            #Create Phi nodes (but not for the first block)
+            if is_tryblock:
+                self.build_exc_blocks(number, pyblock)
+            #Create Phi nodes
             incoming_links = []
             def visit(node):
                 if isinstance(node, Link) and node.target == pyblock:
@@ -177,7 +165,9 @@
                                ["%%block%i" % self.blocknum[l.prevblock]
                                 for l in incoming_links])
             #Handle SpaceOperations
-            for op in pyblock.operations:
+            for opnumber, op in enumerate(pyblock.operations):
+                if opnumber == len(pyblock.operations) - 1 and is_tryblock:
+                    lblock.last_op = True                    
                 l_target = self.gen.get_repr(op.result)
                 self.dependencies.add(l_target)
                 l_arg0 = self.gen.get_repr(op.args[0])
@@ -228,8 +218,8 @@
                         "%%block%i" % self.blocknum[pyblock.exits[0].target])
             elif isinstance(pyblock.exitswitch, Constant) and \
                  pyblock.exitswitch.value == last_exception:
-                lblock.uncond_branch(
-                    "%%block%i" % self.blocknum[pyblock.exits[0].target])
+                #The branch has already be created by the last space op
+                assert lblock.closed
             else:
                 assert isinstance(a.binding(pyblock.exitswitch),
                                   annmodel.SomeBool)
@@ -240,6 +230,30 @@
                     "%%block%i" % self.blocknum[pyblock.exits[1].target],
                     "%%block%i" % self.blocknum[pyblock.exits[0].target])
 
+    def build_exc_blocks(self, number, pyblock):
+        lexcblock = llvmbc.BasicBlock("block%i.except" % number)
+        self.llvm_func.basic_block(lexcblock)
+        l_excp = self.gen.get_repr(last_exception)
+        l_exc = self.gen.get_local_tmp(PointerTypeRepr("%std.class", self.gen),
+                                       self)
+        l_uip = self.gen.get_local_tmp(PointerTypeRepr("uint", self.gen), self)
+        l_ui = self.gen.get_local_tmp(
+            self.gen.get_repr(annmodel.SomeInteger(True, True)), self)
+        self.dependencies.update([l_excp, l_exc, l_uip, l_ui])
+        lexcblock.load(l_exc, l_excp)
+        lexcblock.getelementptr(l_uip, l_exc, [0, 1])
+        lexcblock.load(l_ui, l_uip)
+        exits = pyblock.exits[1:]
+        l_exitcases = [self.gen.get_repr(ex.exitcase) for ex in exits]
+        self.dependencies.update(l_exitcases)
+        sw = [(str(abs(id(ex.exitcase))),
+               "%%block%i" % self.blocknum[ex.target])
+              for ex in exits]
+        lexcblock.switch(l_ui, "%%block%i.unwind" % number, sw)
+        lunwindblock = llvmbc.BasicBlock("block%i.unwind" % number)
+        lunwindblock.unwind()
+        self.llvm_func.basic_block(lunwindblock)
+
     def llvmfuncdef(self):
         s = "internal %s %s(" % (self.retvalue.llvmtype(), self.name)
         return s + ", ".join([a.typed_name() for a in self.l_args]) + ")"
@@ -265,10 +279,6 @@
         lblock.call(l_target, l_args[0], l_args[1:])
 
 class EntryFunctionRepr(LLVMRepr):
-    def get(obj, gen):
-        return None
-    get = staticmethod(get)
-
     def __init__(self, name, function, gen):
         self.gen = gen
         self.function = function
@@ -280,8 +290,11 @@
         self.l_function = self.gen.get_repr(self.function)
         self.dependencies.add(self.l_function)
         lblock = llvmbc.BasicBlock("entry")
+        #XXX clean this up
         lblock.instruction("%tmp = load bool* %Initialized.0__")
         lblock.instruction("br bool %tmp, label %real_entry, label %init")
+        lblock.phi_done = True
+        lblock.closed = True
         self.llvm_func = llvmbc.Function(self.llvmfuncdef(), lblock)
         self.init_block = llvmbc.BasicBlock("init")
         self.init_block.instruction("store bool true, bool* %Initialized.0__")
@@ -457,9 +470,6 @@
         return self.retvalue.llvmtype()
 
 class BoundMethodRepr(LLVMRepr):
-    def get(obj, gen):
-        return None
-    get = staticmethod(get)
     def __init__(self, l_func, l_self, l_class, gen):
         self.gen = gen
         self.l_func = l_func

Modified: pypy/dist/pypy/translator/llvm/genllvm.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/genllvm.py	(original)
+++ pypy/dist/pypy/translator/llvm/genllvm.py	Mon Apr  4 17:26:06 2005
@@ -3,12 +3,9 @@
 """
 
 import autopath
-import os, sys, exceptions, sets, StringIO
+import sets, StringIO
 
-from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
-from pypy.objspace.flow.model import FunctionGraph, Block, Link
-from pypy.objspace.flow.model import last_exception, last_exc_value
-from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph
+from pypy.objspace.flow.model import Constant
 from pypy.annotation import model as annmodel
 from pypy.translator import transform
 from pypy.translator.translator import Translator
@@ -22,6 +19,7 @@
 from pypy.translator.llvm import classrepr
 
 from pypy.translator.llvm.representation import LLVMRepr, TmpVariableRepr
+from pypy.translator.llvm.representation import CompileError
 from pypy.translator.llvm.funcrepr import EntryFunctionRepr
 
 debug = True
@@ -51,12 +49,15 @@
         for mod in [representation, funcrepr, typerepr, seqrepr, classrepr]:
             self.repr_classes += [getattr(mod, s)
                                   for s in dir(mod) if "Repr" in s]
+        self.repr_classes = [c for c in self.repr_classes if hasattr(c, "get")]
         self.llvm_reprs = {}
         self.depth = 0
         self.entryname = self.translator.functions[0].__name__
         self.l_entrypoint = EntryFunctionRepr("%__entry__" + self.entryname,
                                               self.translator.functions[0],
                                               self)
+        classrepr.create_builtin_exceptions(self,
+                                            self.l_entrypoint.dependencies)
         self.local_counts[self.l_entrypoint] = 0
         self.l_entrypoint.setup()
 
@@ -91,9 +92,10 @@
 
     def get_repr(self, obj):
         self.depth += 1
+        flag = False
         if debug:
             print "  " * self.depth,
-            print "looking for object", obj, type(obj).__name__, obj.__class__,
+            print "looking for object", obj, type(obj).__name__,
             print id(obj), get_key(obj),
         if isinstance(obj, LLVMRepr):
             self.depth -= 1
@@ -104,6 +106,12 @@
                 print "->exists already:", self.llvm_reprs[get_key(obj)]
             return self.llvm_reprs[get_key(obj)]
         for cl in self.repr_classes:
+            #XXXXXX: Got
+            try:
+                obj.__class__
+            except AttributeError:
+                obj.__class__ = None
+                flag = True
             g = cl.get(obj, self)
             if g is not None:
                 self.llvm_reprs[get_key(obj)] = g
@@ -113,7 +121,11 @@
                     print "calling setup of %s, repr of %s" % (g, obj)
                 g.setup()
                 self.depth -= 1
+                if flag:
+                    del obj.__class__
                 return g
+        if flag:
+            del obj.__class__
         raise CompileError, "Can't get repr of %s, %s" % (obj, obj.__class__)
 
     def write(self, f):
@@ -164,8 +176,3 @@
     yield l_repr
 
 
-t = Translator(test2.two_exceptions)
-a = t.annotate([int])
-a.simplify()
-## t.view()
-f = llvmcompile(t)

Modified: pypy/dist/pypy/translator/llvm/list.c
==============================================================================
--- pypy/dist/pypy/translator/llvm/list.c	(original)
+++ pypy/dist/pypy/translator/llvm/list.c	Mon Apr  4 17:26:06 2005
@@ -1,9 +1,21 @@
 #include <stdio.h>
 
+signed char unwind();
+
 struct item {
     char* dummy;
 };
 
+struct class {
+    char dummy;
+};
+
+
+struct class* LAST_EXCEPTION_TYPE = 0;
+struct class INDEX_ERROR = {0};
+
+
+
 struct list {
     unsigned int length;
     struct item** data;
@@ -21,6 +33,14 @@
     return (int) l->length;
 }
 
+int valid_index(int i, struct list* l) {
+    if (i < 0)
+	return 0;
+    if (i >= len(l))
+	return 0;
+    return 1;
+}
+
 struct list* newlist() {
     struct list* nlist = malloc(sizeof(struct list));
     nlist->length = 0;
@@ -87,6 +107,16 @@
     return l->data[index];
 }
 
+struct item* getitem_EXCEPTION(struct list* l, int index) {
+    if (index < 0)
+	index = l->length + index;
+    if (valid_index(index, l) == 0) {
+	LAST_EXCEPTION_TYPE = &INDEX_ERROR;
+	return unwind();
+    }
+    return l->data[index];
+}
+
 void setitem(struct list* l, int index, struct item* value) {
     if (index < 0)
 	index = l->length + index;

Modified: pypy/dist/pypy/translator/llvm/list_template.ll
==============================================================================
--- pypy/dist/pypy/translator/llvm/list_template.ll	(original)
+++ pypy/dist/pypy/translator/llvm/list_template.ll	Mon Apr  4 17:26:06 2005
@@ -27,6 +27,23 @@
 	ret int %tmp.3
 }
 
+internal int %std.valid_index(int %i, %std.list.%(name)s* %l) {
+entry:
+	%tmp.1 = setlt int %i, 0
+	br bool %tmp.1, label %UnifiedReturnBlock, label %endif.0
+
+endif.0:
+	%tmp.1.i = getelementptr %std.list.%(name)s* %l, int 0, uint 0
+	%tmp.2.i = load uint* %tmp.1.i
+	%tmp.3.i = cast uint %tmp.2.i to int
+	%not.tmp.6 = setgt int %tmp.3.i, %i
+	%retval = cast bool %not.tmp.6 to int
+	ret int %retval
+
+UnifiedReturnBlock:
+	ret int 0
+}
+
 internal %std.list.%(name)s* %std.newlist() {
 entry:
 	%tmp.0 = malloc %std.list.%(name)s
@@ -148,6 +165,39 @@
 	ret %(item)s %tmp.15
 }
 
+internal %(item)s %std.getitem.exc(%std.list.%(name)s* %l, int %index.1) {
+entry:
+	%tmp.1 = setlt int %index.1, 0
+	br bool %tmp.1, label %then.0, label %endif.0.i
+
+then.0:
+	%tmp.4 = getelementptr %std.list.%(name)s* %l, int 0, uint 0
+	%tmp.5 = load uint* %tmp.4
+	%tmp.5 = cast uint %tmp.5 to int
+	%tmp.9 = add int %tmp.5, %index.1
+	%tmp.1.i5 = setlt int %tmp.9, 0
+	br bool %tmp.1.i5, label %then.1, label %endif.0.i
+
+endif.0.i:
+	%index_addr.0.0 = phi int [ %tmp.9, %then.0 ], [ %index.1, %entry ]
+	%tmp.1.i.i = getelementptr %std.list.%(name)s* %l, int 0, uint 0
+	%tmp.2.i.i = load uint* %tmp.1.i.i
+	%tmp.3.i.i = cast uint %tmp.2.i.i to int
+	%tmp.6.i = setgt int %tmp.3.i.i, %index_addr.0.0
+	br bool %tmp.6.i, label %endif.1, label %then.1
+
+then.1:
+	store %std.class* %glb.class.IndexError.object, %std.class** %std.last_exception.type
+	unwind
+endif.1:
+	%tmp.19 = getelementptr %std.list.%(name)s* %l, int 0, uint 1
+	%tmp.20 = load %(item)s** %tmp.19
+	%tmp.22 = getelementptr %(item)s* %tmp.20, int %index_addr.0.0
+	%tmp.23 = load %(item)s* %tmp.22
+	ret %(item)s %tmp.23
+}
+
+
 internal void %std.setitem(%std.list.%(name)s* %l, int %index.1, %(item)s %value) {
 entry:
 	%tmp.1 = setlt int %index.1, 0

Modified: pypy/dist/pypy/translator/llvm/llvmbc.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/llvmbc.py	(original)
+++ pypy/dist/pypy/translator/llvm/llvmbc.py	Mon Apr  4 17:26:06 2005
@@ -8,6 +8,8 @@
 
 from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
 
+class LLVMError(Exception):
+    pass
 
 class Function(object):
     def __init__(self, funcdef, startbb):
@@ -28,63 +30,42 @@
     def __init__(self, label):
         self.label = label
         self.instructions = []
-
+        self.closed = False
+        #True after the first non-phi instruction has been added
+        self.phi_done = False
+        
     def instruction(self, instr): #should not be used
         self.instructions.append(instr)
 
-    def select(self, l_arg, l_select, l_v1, l_v2):
-        s = "%s = select bool %s, %s, %s"
-        s = s % (l_arg.llvmname(), l_select.llvmname(), l_v1.typed_name(),
-                 l_v2.typed_name())
-        self.instructions.append(s)               
-
-    def phi(self, l_arg, l_values, blocks):
-        assert len(l_values) == len(blocks)
-        vars_string = []
-        print "inserting phi node", l_arg, l_values, blocks
-        print l_arg.llvmname(), l_arg.llvmtype()
-        fd = "" + "%s = phi %s " % (l_arg.llvmname(), l_arg.llvmtype())
-        fd += ", ".join(["[%s, %s]" % (v.llvmname(), b)
-               for v, b in zip(l_values, blocks)])
-        self.instructions.append(fd)
-
-    def spaceop(self, l_target, opname, l_args):
-        if l_target.llvmtype() == "void":
-            s = "call void %%std.%s(" % opname
-        else:
-            s = "%s = call %s %%std.%s(" % (l_target.llvmname(),
-                                        l_target.llvmtype(), opname)
-        self.instructions.append(s +
-            ", ".join([a.typed_name() for a in l_args]) + ")")
-        
-    def call(self, l_target, l_func, l_args):
-        if l_target.llvmtype() == "void":
-            s = "call void %s(" % l_func.llvmname()
-        elif  l_target.llvmtype() == "%std.void":
-            s = "call %std.void %s(" % l_func.llvmname()
-        else:
-            s = "%s = call %s %s(" % (l_target.llvmname(), l_target.llvmtype(),
-                                      l_func.llvmname())
-        self.instructions.append(s + 
-            ", ".join([a.typed_name() for a in l_args]) + ")")
-
-    def call_void(self, l_func, l_args):
-        s = "call %s %s(" % (l_func.rettype(), l_func.llvmname())
-        self.instructions.append(s +
-            ", ".join([a.typed_name() for a in l_args]) + ")")
-
+    #Terminator instuctions
     def ret(self, l_value):
+        self.phi_done = True
+        if self.closed:
+            raise LLVMError, "Can't add second terminator instruction."
+        self.closed = True
         self.instructions.append("ret %s" % l_value.typed_name())
 
     def uncond_branch(self, block):
+        if self.closed:
+            raise LLVMError, "Can't add second terminator instruction."
+        self.closed = True
+        self.phi_done = True
         self.instructions.append("br label " + block)
 
     def cond_branch(self, l_switch, blocktrue, blockfalse):
+        if self.closed:
+            raise LLVMError, "Can't add second terminator instruction."
+        self.closed = True
+        self.phi_done = True
         s = "br %s, label %s, label %s" % (l_switch.typed_name(),
                                            blocktrue, blockfalse)
         self.instructions.append(s)
 
     def switch(self, l_switch, default, rest=None):
+        if self.closed:
+            raise LLVMError, "Can't add second terminator instruction."
+        self.closed = True
+        self.phi_done = True
         s = "switch %s, label %s " % (l_switch.typed_name(), default)
         if rest is not None:
             s += "[" + "\n\t".join(["%s %s, label %s" % (l_switch.llvmtype(),
@@ -92,7 +73,27 @@
                                   for c, l in rest]) + "]"
         self.instructions.append(s)
 
+    def unwind(self):
+        if self.closed:
+            raise LLVMError, "Can't add second terminator instruction."
+        self.closed = True
+        self.phi_done = True
+        self.instructions.append("unwind")
+
+    #Memory access instructions
+    def load(self, l_target, l_pter):
+        self.phi_done = True
+        s = "%s = load %s %s" % (l_target.llvmname(), l_pter.llvmtype(),
+                                  l_pter.llvmname())
+        self.instructions.append(s)
+
+    def store(self, l_value, l_pter):
+        self.phi_done = True
+        s = "store %s, %s" % (l_value.typed_name(), l_pter.typed_name())
+        self.instructions.append(s)
+
     def malloc(self, l_target, l_type, num=1):
+        self.phi_done = True
         s = "%s = malloc %s" % (l_target.llvmname(),
                                 l_type.llvmname_wo_pointer())
         if num > 1:
@@ -100,6 +101,7 @@
         self.instructions.append(s)
 
     def getelementptr(self, l_target, l_ptr, adresses):
+        self.phi_done = True
         s = "%s = getelementptr %s %s, " % (l_target.llvmname(),
                                             l_ptr.llvmtype(), l_ptr.llvmname())
         adr = []
@@ -114,31 +116,138 @@
                     adr.append("int %i" % a)
         self.instructions.append(s + ", ".join(adr))
 
-    def load(self, l_target, l_pter):
-        s = "%s = load %s %s" % (l_target.llvmname(), l_pter.llvmtype(),
-                                  l_pter.llvmname())
-        self.instructions.append(s)
+    #Function calls
+    def spaceop(self, l_target, opname, l_args):
+        self.phi_done = True
+        if l_target.llvmtype() == "void":
+            s = "call void %%std.%s(" % opname
+        else:
+            s = "%s = call %s %%std.%s(" % (l_target.llvmname(),
+                                        l_target.llvmtype(), opname)
+        self.instructions.append(s +
+            ", ".join([a.typed_name() for a in l_args]) + ")")
+        
+    def call(self, l_target, l_func, l_args):
+        self.phi_done = True
+        if l_target.llvmtype() == "void":
+            s = "call void %s(" % l_func.llvmname()
+        elif  l_target.llvmtype() == "%std.void":
+            s = "call %std.void %s(" % l_func.llvmname()
+        else:
+            s = "%s = call %s %s(" % (l_target.llvmname(), l_target.llvmtype(),
+                                      l_func.llvmname())
+        self.instructions.append(s + 
+            ", ".join([a.typed_name() for a in l_args]) + ")")
 
-    def store(self, l_value, l_pter):
-        s = "store %s, %s" % (l_value.typed_name(), l_pter.typed_name())
-        self.instructions.append(s)
+    def call_void(self, l_func, l_args):
+        self.phi_done = True
+        s = "call %s %s(" % (l_func.rettype(), l_func.llvmname())
+        self.instructions.append(s +
+            ", ".join([a.typed_name() for a in l_args]) + ")")
+
+    #Other instructions
+    def select(self, l_arg, l_select, l_v1, l_v2):
+        self.phi_done = True
+        s = "%s = select bool %s, %s, %s"
+        s = s % (l_arg.llvmname(), l_select.llvmname(), l_v1.typed_name(),
+                 l_v2.typed_name())
+        self.instructions.append(s)               
+
+    def phi(self, l_arg, l_values, blocks):
+        assert len(l_values) == len(blocks)
+        if self.phi_done:
+            raise LLVMError, "Can't create phi node."
+        vars_string = []
+        print "inserting phi node", l_arg, l_values, blocks
+        print l_arg.llvmname(), l_arg.llvmtype()
+        fd = "" + "%s = phi %s " % (l_arg.llvmname(), l_arg.llvmtype())
+        fd += ", ".join(["[%s, %s]" % (v.llvmname(), b)
+               for v, b in zip(l_values, blocks)])
+        self.instructions.append(fd)
 
     def cast(self, l_target, l_value):
+        self.phi_done = True
         s = "%s = cast %s to %s" % (l_target.llvmname(), l_value.typed_name(),
                                     l_target.llvmtype())
         self.instructions.append(s)
 
-    def unwind(self):
-        self.instructions.append("unwind")
-
+    #Non-instructions methods
     def __str__(self):
         s = [self.label + ":\n"]
         for ins in self.instructions:
             s += ["\t%s\n" % ins]
+        if not self.closed:
+            print "".join(s)
+            raise LLVMError, "Block lacks a terminator instruction."
         return "".join(s)
 
-
 class TryBasicBlock(BasicBlock):
+    """A basic block for which the last operation is turned into an invoke.
+Used for exception handling."""
+    def __init__(self, label, regularblock, exceptblock):
+        BasicBlock.__init__(self, label)
+        self.exceptblock = exceptblock
+        self.regularblock = regularblock
+        self.pending_call = None
+        self.pending_args = None
+        #This is set to True before the last operation
+        #XXX Find a more elegant solution for this
+        self.last_op = False
+
+    def spaceop(self, l_target, opname, l_args):
+        if not self.last_op:
+            return BasicBlock.spaceop(self, l_target, opname, l_args)
+        self.phi_done = True
+        if self.closed:
+            raise LLVMError, "Can't add second terminator instruction."
+        self.closed = True
+        if l_target.llvmtype() == "void":
+            s = "invoke void %%std.%s.exc(" % opname
+        else:
+            s = "%s = invoke %s %%std.%s.exc(" % (l_target.llvmname(),
+                                                  l_target.llvmtype(), opname)
+        s += ", ".join([a.typed_name() for a in l_args]) + ")"
+        s += "\n\t\tto label %%%s\n\t\texcept label %%%s" % \
+             (self.regularblock, self.exceptblock)        
+        self.instructions.append(s)
+
+    def call(self, l_target, l_func, l_args):
+        if not self.last_op:
+            return BasicBlock.call(self, l_target, l_func, l_args)
+        self.phi_done = True
+        if self.closed:
+            raise LLVMError, "Can't add second terminator instruction."
+        self.closed = True
+        if l_target.llvmtype() == "void":
+            s = "invoke void %s(" % l_func.llvmname()
+        elif  l_target.llvmtype() == "%std.void":
+            s = "invoke %std.void %s(" % l_func.llvmname()
+        else:
+            s = "%s = invoke %s %s(" % (l_target.llvmname(),
+                                        l_target.llvmtype(), l_func.llvmname())
+        s += ", ".join([a.typed_name() for a in l_args]) + ")"
+        s += "\n\t\tto label %%%s\n\t\texcept label %%%s" % \
+             (self.regularblock, self.exceptblock)        
+        self.instructions.append(s)
+
+    def call_void(self, l_func, l_args):
+        if not self.last_op:
+            return BasicBlock.call_void(self, l_func, l_args)
+        self.phi_done = True
+        if self.closed:
+            raise LLVMError, "Can't add second terminator instruction."
+        self.closed = True
+        s = "invoke %s %s(" % (l_func.rettype(), l_func.llvmname())
+        s += ", ".join([a.typed_name() for a in l_args]) + ")"
+        s += "\n\t\tto label %%%s\n\t\texcept label %%%s" % \
+             (self.regularblock, self.exceptblock)        
+        self.instructions.append(s)
+
+class TraceBasicBlock(BasicBlock):
+    """A basic block that will make it possible to create a sort of
+'tracebacks' at some point in the future: Every call is turned into an invoke.
+Then the corresponding exceptblock will have to append a string to a global
+traceback object."""
     def __init__(self, label, regularblock, exceptblock):
         self.label = label
         self.exceptblock = exceptblock
@@ -178,7 +287,7 @@
     call = invoke
 
     def invoke_void(self, l_func, l_args):
-        s = "call %s %s(" % (l_func.rettype(), l_func.llvmname())
+        s = "invoke %s %s(" % (l_func.rettype(), l_func.llvmname())
         s += ", ".join([a.typed_name() for a in l_args]) + ")"
         s += "\n\t\tto label %%%s.%i\n\t\texcept label %%%s" % \
              (self.label, len(self.llvmblocks), self.exceptblock)
@@ -190,8 +299,9 @@
 
     def __str__(self):
         if not self.finalized:
-            self.llvmblocks.append(self.instructions)
-            self.instructions = []
+            if len(self.instructions) != 0:
+                self.llvmblocks.append(self.instructions)
+                self.instructions = []
             self.finalized = True
         s = []
         for i, instrs in enumerate(self.llvmblocks):

Modified: pypy/dist/pypy/translator/llvm/make_runtime.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/make_runtime.py	(original)
+++ pypy/dist/pypy/translator/llvm/make_runtime.py	Mon Apr  4 17:26:06 2005
@@ -12,8 +12,8 @@
     print cfile 
     bytecode = udir.join("temp.bc")
     lastdir = path.local()
-    ops = ["llvm-gcc -O3 -c %s -o %s" % (cfile, bytecode),
-           "llvm-dis %s -f" % bytecode]
+    ops = ["llvm-gcc -enable-correct-eh-support-O3 -c %s -o %s" % \
+           (cfile, bytecode), "llvm-dis %s -f" % bytecode]
     for op in ops:
         print op
         cmdexec(op)
@@ -48,7 +48,9 @@
                 if f in line:
                     line = line.replace(f, "std." + f)
                     ret.append(line)
-                    continue
+                    break
+            else:
+                ret.append(line)
         else:
             ret.append(line)
     return "\n".join(ret)
@@ -58,6 +60,15 @@
         code = code.replace("_ALTERNATIVE%i" % i, "")
     return code
 
+def create_exceptions(code):
+    code = code.replace("%LAST_EXCEPTION_TYPE", "%std.last_exception.type")
+    code = code.replace("%INDEX_ERROR", "%glb.class.IndexError.object")
+    return code
+
+def remove_exception(code):
+    code = code.replace("_EXCEPTION", ".exc")
+    return code
+
 def remove_header(code):
     code = code.split("implementation")
     return code[1]
@@ -71,12 +82,37 @@
             ret.append(line)
     return "\n".join(ret)
 
+def create_unwind(code):
+    ret = []
+    remove = False
+    for line in code.split("\n"):
+        if "call" in line and "%unwind(" in line:
+            ret.append("\tunwind")
+            remove = True
+        elif "declare" in line and "unwind" in line:
+            pass
+        elif remove:
+            if not line.startswith("\t") and ":" in line:
+                remove = False
+                ret.append(line)
+        else:
+            ret.append(line)
+    return "\n".join(ret)
+
+def remove_structs(code):
+    code = code.replace("struct.class", "std.class")
+    return code
+
 def cleanup_code(code):
     code = remove_comments(code)
     code = add_std(code)
     code = remove_header(code)
     code = internal_functions(code)
     code = remove_alternatives(code)
+    code = create_exceptions(code)
+    code = remove_exception(code)
+    code = remove_structs(code)
+    code = create_unwind(code)
     return code
 
 def make_list_template():

Modified: pypy/dist/pypy/translator/llvm/representation.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/representation.py	(original)
+++ pypy/dist/pypy/translator/llvm/representation.py	Mon Apr  4 17:26:06 2005
@@ -2,6 +2,7 @@
 import sets
 
 from pypy.objspace.flow.model import Variable, Constant
+from pypy.objspace.flow.model import last_exception, last_exc_value
 from pypy.annotation import model as annmodel
 
 LLVM_SIMPLE_TYPES = {annmodel.SomeChar: "sbyte",
@@ -51,24 +52,27 @@
 
 
 class SimpleRepr(LLVMRepr):
-    """Representation of values that are directly mapped to types in LLVM:
-bool, char (string of length 1)"""
+    """Representation of values that only need simple representation:
+bool, char (string of length 1), last_exception, last_exc_value"""
 
     def get(obj, gen):
-        if not isinstance(obj, Constant):
-            return None
-        type = gen.annotator.binding(obj)
-        if type.__class__ in LLVM_SIMPLE_TYPES:
-            llvmtype = LLVM_SIMPLE_TYPES[type.__class__]
-            l_repr = SimpleRepr(llvmtype, repr(obj.value), gen)
-            return l_repr
+        if isinstance(obj, Constant):
+            type_ = gen.annotator.binding(obj)
+            if type_.__class__ in LLVM_SIMPLE_TYPES:
+                llvmtype = LLVM_SIMPLE_TYPES[type_.__class__]
+                return SimpleRepr(llvmtype, repr(obj.value), gen)
+        if obj == last_exception:
+            return SimpleRepr("%std.class**", "%std.last_exception.type", gen)
+        if obj == last_exc_value:
+            return SimpleRepr("%std.exception**", "%std.last_exception.value",
+                              gen)
         return None
     get = staticmethod(get)
     
-    def __init__(self, type, llvmname, gen):
+    def __init__(self, type_, llvmname, gen):
         if debug:
             print "SimpleRepr: %s, %s" % (type, llvmname)
-        self.type = type
+        self.type = type_
         if llvmname in ("False", "True"):
             llvmname = llvmname.lower()
         self.name = llvmname
@@ -84,13 +88,13 @@
 class IntRepr(LLVMRepr):
     def get(obj, gen):
         if obj.__class__ is int:
-            type = gen.annotator.binding(Constant(obj))
-            return IntRepr(type, obj, gen)
+            type_ = gen.annotator.binding(Constant(obj))
+            return IntRepr(type_, obj, gen)
         if not isinstance(obj, Constant):
             return None
-        type = gen.annotator.binding(obj)
-        if type.__class__ == annmodel.SomeInteger:
-            return IntRepr(type, obj.value, gen)
+        type_ = gen.annotator.binding(obj)
+        if type_.__class__ == annmodel.SomeInteger:
+            return IntRepr(type_, obj.value, gen)
     get = staticmethod(get)
 
     def __init__(self, annotation, value, gen):
@@ -129,8 +133,8 @@
         if debug:
             print "VariableRepr: %s" % (var.name)
         self.var = var
-        type = gen.annotator.binding(var)
-        self.type = gen.get_repr(type)
+        type_ = gen.annotator.binding(var)
+        self.type = gen.get_repr(type_)
         self.dependencies = sets.Set([self.type])
 
     def llvmname(self):
@@ -146,11 +150,11 @@
                                    % repr(name))
 
 class TmpVariableRepr(LLVMRepr):
-    def __init__(self, name, type, gen):
+    def __init__(self, name, type_, gen):
         if debug:
-            print "TmpVariableRepr: %s %s" % (type, name)
+            print "TmpVariableRepr: %s %s" % (type_, name)
         self.name = name
-        self.type = type
+        self.type = type_
         self.dependencies = sets.Set()
 
     def llvmname(self):
@@ -178,8 +182,8 @@
 class StringRepr(LLVMRepr):
     def get(obj, gen):
         if isinstance(obj, Constant):
-            type = gen.annotator.binding(obj)
-            if isinstance(type, annmodel.SomeString):
+            type_ = gen.annotator.binding(obj)
+            if isinstance(type_, annmodel.SomeString):
                 return StringRepr(obj.value, gen)
         elif isinstance(obj, str):
             return StringRepr(obj, gen)
@@ -217,8 +221,8 @@
 class TupleRepr(LLVMRepr):
     def get(obj, gen):
         if isinstance(obj, Constant):
-            type = gen.annotator.binding(obj)
-            if isinstance(type, annmodel.SomeTuple):
+            type_ = gen.annotator.binding(obj)
+            if isinstance(type_, annmodel.SomeTuple):
                 return TupleRepr(obj, gen)
         return None
     get = staticmethod(get)
@@ -253,4 +257,3 @@
             raise AttributeError, ("TupleRepr instance has no attribute %s"
                                    % repr(name))
 
-

Modified: pypy/dist/pypy/translator/llvm/test/llvmsnippet.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/test/llvmsnippet.py	(original)
+++ pypy/dist/pypy/translator/llvm/test/llvmsnippet.py	Mon Apr  4 17:26:06 2005
@@ -272,7 +272,6 @@
 def two_exceptions(n):
     lst = range(10)
     try:
-        lst[n] += 1
         lst[n]
     except IndexError:
         return 2
@@ -280,3 +279,11 @@
         return 3
     return 4
 
+def catch_base_exception(n):
+    lst = range(10)
+    try:
+        lst[n]
+    except LookupError:
+        return 2
+    return 4
+

Modified: pypy/dist/pypy/translator/llvm/test/test_genllvm.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/test/test_genllvm.py	(original)
+++ pypy/dist/pypy/translator/llvm/test/test_genllvm.py	Mon Apr  4 17:26:06 2005
@@ -17,7 +17,7 @@
     a = t.annotate(annotate)
     a.simplify()
     gen = LLVMGenerator(t)
-    return gen.compile()
+    return gen.compile(True)
 
 def is_on_path(name):
     try:
@@ -27,6 +27,7 @@
     else: 
         return True
 
+
 class TestLLVMRepr(object):
     def setup_method(self,method):
         if not llvm_found:
@@ -249,6 +250,21 @@
         assert f(15) == 15
         assert f(30) == 30
 
+class TestException(object):
+    def test_two_exception(self):
+        f = compile_function(llvmsnippet.two_exceptions, [int])
+        for i in range(10):
+            assert f(i) == 4
+        for i in range(10, 20):
+            assert f(i) == 2
+
+    def test_catch_base_exception(self):
+        f = compile_function(llvmsnippet.catch_base_exception, [int])
+        for i in range(10):
+            assert f(i) == 4
+        for i in range(10, 20):
+            assert f(i) == 2
+
 
 class TestSnippet(object):
     def setup_method(self, method):
@@ -328,7 +344,7 @@
         with_init = compile_function(test.with_init, [int])
         assert with_init(42) == 42
 
-    def DONOTtest_with_more_init(self):
+    def DONOT_test_with_more_init(self):
         with_more_init = compile_function(test.with_more_init, [int, bool])
         assert with_more_init(42, True) == 42
         assert with_more_init(42, False) == -42



More information about the Pypy-commit mailing list