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

cfbolz at codespeak.net cfbolz at codespeak.net
Sun Feb 6 17:45:52 CET 2005


Author: cfbolz
Date: Sun Feb  6 17:45:51 2005
New Revision: 8927

Added:
   pypy/dist/pypy/translator/llvm/   (props changed)
   pypy/dist/pypy/translator/llvm/__init__.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/autopath.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/build_llvm_module.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/genllvm.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/list_template.ll
   pypy/dist/pypy/translator/llvm/llvm_gc.txt   (contents, props changed)
   pypy/dist/pypy/translator/llvm/llvmbc.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/operations.ll
   pypy/dist/pypy/translator/llvm/string.ll
   pypy/dist/pypy/translator/llvm/test/   (props changed)
   pypy/dist/pypy/translator/llvm/test.html
   pypy/dist/pypy/translator/llvm/test/__init__.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/test/autopath.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/test/llvmsnippet.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/test/test_genllvm.py   (contents, props changed)
Log:
initial chekin of the llvm backend

Added: pypy/dist/pypy/translator/llvm/__init__.py
==============================================================================

Added: pypy/dist/pypy/translator/llvm/autopath.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/autopath.py	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,114 @@
+"""
+self cloning, automatic path configuration 
+
+copy this into any subdirectory of pypy from which scripts need 
+to be run, typically all of the test subdirs. 
+The idea is that any such script simply issues
+
+    import autopath
+
+and this will make sure that the parent directory containing "pypy"
+is in sys.path. 
+
+If you modify the master "autopath.py" version (in pypy/tool/autopath.py) 
+you can directly run it which will copy itself on all autopath.py files
+it finds under the pypy root directory. 
+
+This module always provides these attributes:
+
+    pypydir    pypy root directory path 
+    this_dir   directory where this autopath.py resides 
+
+"""
+
+
+def __dirinfo(part):
+    """ return (partdir, this_dir) and insert parent of partdir
+    into sys.path.  If the parent directories don't have the part
+    an EnvironmentError is raised."""
+
+    import sys, os
+    try:
+        head = this_dir = os.path.realpath(os.path.dirname(__file__))
+    except NameError:
+        head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0]))
+
+    while head:
+        partdir = head
+        head, tail = os.path.split(head)
+        if tail == part:
+            break
+    else:
+        raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir)
+    
+    checkpaths = sys.path[:]
+    pypy_root = os.path.join(head, '')
+    
+    while checkpaths:
+        orig = checkpaths.pop()
+        if os.path.join(os.path.realpath(orig), '').startswith(pypy_root):
+            sys.path.remove(orig)
+    sys.path.insert(0, head)
+
+    munged = {}
+    for name, mod in sys.modules.items():
+        fn = getattr(mod, '__file__', None)
+        if '.' in name or not isinstance(fn, str):
+            continue
+        newname = os.path.splitext(os.path.basename(fn))[0]
+        if not newname.startswith(part + '.'):
+            continue
+        path = os.path.join(os.path.dirname(os.path.realpath(fn)), '')
+        if path.startswith(pypy_root) and newname != part:
+            modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep)
+            if newname != '__init__':
+                modpaths.append(newname)
+            modpath = '.'.join(modpaths)
+            if modpath not in sys.modules:
+                munged[modpath] = mod
+
+    for name, mod in munged.iteritems():
+        if name not in sys.modules:
+            sys.modules[name] = mod
+        if '.' in name:
+            prename = name[:name.rfind('.')]
+            postname = name[len(prename)+1:]
+            if prename not in sys.modules:
+                __import__(prename)
+                if not hasattr(sys.modules[prename], postname):
+                    setattr(sys.modules[prename], postname, mod)
+
+    return partdir, this_dir
+
+def __clone():
+    """ clone master version of autopath.py into all subdirs """
+    from os.path import join, walk
+    if not this_dir.endswith(join('pypy','tool')):
+        raise EnvironmentError("can only clone master version "
+                               "'%s'" % join(pypydir, 'tool',_myname))
+
+
+    def sync_walker(arg, dirname, fnames):
+        if _myname in fnames:
+            fn = join(dirname, _myname)
+            f = open(fn, 'rwb+')
+            try:
+                if f.read() == arg:
+                    print "checkok", fn
+                else:
+                    print "syncing", fn
+                    f = open(fn, 'w')
+                    f.write(arg)
+            finally:
+                f.close()
+    s = open(join(pypydir, 'tool', _myname), 'rb').read()
+    walk(pypydir, sync_walker, s)
+
+_myname = 'autopath.py'
+
+# set guaranteed attributes
+
+pypydir, this_dir = __dirinfo('pypy')
+
+if __name__ == '__main__':
+    __clone()

Added: pypy/dist/pypy/translator/llvm/build_llvm_module.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/build_llvm_module.py	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,73 @@
+"""
+Build a pyrex module out of llvmfile
+"""
+
+import autopath
+
+import os, sys, inspect, re, exceptions
+
+from py.process import cmdexec 
+from py import path 
+
+from pypy.tool.udir import udir
+from pypy.translator.genpyrex import GenPyrex
+from pypy.translator.tool.buildpyxmodule import make_c_from_pyxfile
+from pypy.translator.tool import stdoutcapture
+
+debug = 0
+
+class CompileError(exceptions.Exception):
+    pass
+
+def system_trace(cmd):
+    print cmd
+    return old_system(cmd)
+
+old_system = os.system
+os.system = system_trace
+
+def make_module_from_llvm(llvmfile, pyxfile):
+    include_dir = autopath.this_dir
+    dirpath = llvmfile.dirpath()
+    lastdir = path.local()
+    os.chdir(str(dirpath))
+    modname = pyxfile.purebasename
+    ops1 = ["llvm-as %s -f" % llvmfile,
+           "llvmc -O3 %s.bc -o _%s.o" % (llvmfile.purebasename, modname),
+           "llc _%s.o.bc -f -o _%s.s" % (modname, modname),
+           "as _%s.s -o _%s.o" % (modname, modname)]
+    ops2 = ["gcc -c -fPIC -I/usr/include/python %s.c" % pyxfile.purebasename,
+           "gcc -shared %s.o _%s.o -o %s.so" % (pyxfile.purebasename,
+                                                modname, modname)]
+    try:
+        if debug: print "modname", modname
+        c = stdoutcapture.Capture(mixed_out_err = True)
+        if debug: print "working in", path.local()
+        try:
+            try:
+                for op in ops1:
+                    cmdexec(op)
+                make_c_from_pyxfile(pyxfile)
+                for op in ops2:
+                    cmdexec(op)
+            finally:
+                foutput, foutput = c.done()
+        except:
+            data = foutput.read()
+            fdump = open("%s.errors" % modname, "w")
+            fdump.write(data)
+            fdump.close()
+            print data
+            raise
+        # XXX do we need to do some check on fout/ferr?
+        # XXX not a nice way to import a module
+        if debug: print "inserting path to sys.path", dirpath
+        sys.path.insert(0, '.')
+        if debug: print "import %(modname)s as testmodule" % locals()
+        exec "import %(modname)s as testmodule" % locals()
+        sys.path.pop(0)
+    finally:
+        os.chdir(str(lastdir))
+        #if not debug:
+        #dirpath.rmtree()
+    return testmodule

Added: pypy/dist/pypy/translator/llvm/genllvm.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/genllvm.py	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,523 @@
+"""
+Generate a llvm .ll file from an annotated flowgraph.
+"""
+
+import autopath
+import os, sys, exceptions, 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.annotation import model as annmodel
+from pypy.translator import transform
+from pypy.translator.translator import Translator
+from pypy.translator.llvm import llvmbc
+from pypy.translator.llvm import build_llvm_module
+from pypy.translator.test import snippet as test
+
+
+INTRINSIC_OPS = ["lt", "le", "eq", "ne", "gt", "ge", "is", "is_true", "len",
+                 "neg", "pos", "invert", "add", "sub", "mul", "truediv",
+                 "floordiv", "div", "mod", "pow", "lshift", "rshift", "and",
+                 "or", "xor", "inplace_add", "inplace_sub", "inplace_mul",
+                 "inplace_truediv", "inplace_floordiv", "inplace_div",
+                 "inplace_mod", "inplace_pow", "inplace_lshift",
+                 "inplace_rshift", "inplace_and", "inplace_or", "inplace_xor",
+                 "getitem", "setitem", "delitem", "contains", "newlist",
+                 "alloc_and_set"]
+
+C_SIMPLE_TYPES = {annmodel.SomeChar: "char",
+                  annmodel.SomeBool: "unsigned char",
+                  annmodel.SomeInteger: "int"}
+
+debug = 0
+
+
+def llvmcompile(transl):
+    gen = LLVMGenerator(transl)
+    return gen.compile()
+
+
+class CompileError(exceptions.Exception):
+    pass
+
+class LLVMGenerator(object):
+    def __init__(self, transl):
+        self.translator = transl
+        self.annotator = self.translator.annotator
+        self.global_count = 0
+        self.repr_classes = [eval(s)
+                             for s in dir(sys.modules.get(self.__module__))
+                             if "Repr" in s]
+        self.llvm_reprs = {}
+        self.l_entrypoint = self.get_repr(self.translator.functions[0])
+
+    def compile(self):
+        from pypy.tool.udir import udir
+        name = self.l_entrypoint.llvmname()[1:]
+        llvmfile = udir.join('%s.ll' % name)
+        f = llvmfile.open('w')
+        self.write(f)
+        f.close()
+        pyxfile = udir.join('%s_wrap.pyx' % name)
+        f = pyxfile.open('w')
+        f.write(self.l_entrypoint.get_pyrex_source())
+        f.close()
+        mod = build_llvm_module.make_module_from_llvm(llvmfile, pyxfile)
+        return getattr(mod, "wrap_%s" % name)
+
+    def get_global_tmp(self, used_by=None):
+        self.global_count += 1
+        return "%%glb.%s.%i" % ((used_by or "unknown"), self.global_count)
+
+    def get_repr(self, obj):
+        if debug:
+            print "looking for object", obj, type(obj).__name__, obj.__class__,
+        if obj in self.llvm_reprs:
+            if debug:
+                print "->exists already"
+            return self.llvm_reprs[obj]
+        for cl in self.repr_classes:
+            if debug:
+                print "trying", cl
+            g = cl.get(obj, self)
+            if g is not None:
+                self.llvm_reprs[obj] = g
+                return g
+        raise CompileError, "Can't get repr of %s, %s" % (obj, obj.__class__)
+
+    def write(self, f):
+        f.write("\n\n; +-------+\n; |globals|\n; +-------+\n\n")
+        seen_reprs = sets.Set()
+        for l_repr in traverse_dependencies(self.l_entrypoint, seen_reprs):
+            s = l_repr.get_globals()
+            if s != "":
+                f.write(s + "\n")
+        f.write("\n\n; +---------+\n; |space_ops|\n; +---------+\n\n")
+        f1 = file(autopath.this_dir + "/operations.ll", "r")
+        s = f1.read()
+        f.write(s)
+        f1.close()
+        f.write("\n\n; +---------+\n; |functions|\n; +---------+\n\n")
+        seen_reprs = sets.Set()
+        for l_repr in traverse_dependencies(self.l_entrypoint, seen_reprs):
+            s = l_repr.get_functions()
+            if s != "":
+                f.write(s + "\n")
+
+    def __str__(self):
+        f = StringIO.StringIO()
+        self.write(f)
+        return f.getvalue()
+
+def traverse_dependencies(l_repr, seen_reprs):
+    seen_reprs.add(l_repr)
+    for l_dep in l_repr.get_dependencies():
+        if l_dep in seen_reprs:
+            continue
+        seen_reprs.add(l_dep)
+        for l_dep1 in traverse_dependencies(l_dep, seen_reprs):
+            yield l_dep1
+    yield l_repr
+        
+class LLVMRepr(object):
+    def get(obj, gen):
+        return None
+    get = staticmethod(get)
+    
+    def get_globals(self):
+        return ""
+
+    def get_functions(self):
+        return ""
+
+    def llvmname(self):
+        return ""
+
+    def llvmtype(self):
+        return self.type.llvmname()
+
+    def typed_name(self):
+        return self.llvmtype() + " " + self.llvmname()
+
+    def get_dependencies(self):
+        try:
+            return self.dependencies
+        except exceptions.AttributeError:
+            return []
+
+class SimpleRepr(LLVMRepr):
+    """Representation of values that are directly mapped to types in LLVM:
+int, bool, char (string of length 1)"""
+
+    LLVM_SIMPLE_TYPES = {annmodel.SomeInteger: "int",
+                         annmodel.SomeChar: "sbyte",
+                         annmodel.SomeBool: "bool"}
+
+    def get(obj, gen):
+        if not isinstance(obj, Constant):
+            return None
+        type = gen.annotator.binding(obj)
+        if type.__class__ in SimpleRepr.LLVM_SIMPLE_TYPES:
+            llvmtype = SimpleRepr.LLVM_SIMPLE_TYPES[type.__class__]
+            l_repr = SimpleRepr(llvmtype, repr(obj.value), gen)
+            return l_repr
+        return None
+    get = staticmethod(get)
+    
+    def __init__(self, type, llvmname, gen):
+        if debug:
+            print "SimpleRepr: %s, %s" % (type, llvmname)
+        self.type = type
+        if llvmname in ("False", "True"):
+            llvmname = llvmname.lower()
+        self.name = llvmname
+        self.gen = gen
+
+    def llvmname(self):
+        return self.name
+
+    def llvmtype(self):
+        return self.type
+
+
+class VariableRepr(LLVMRepr):
+    def get(obj, gen):
+        if isinstance(obj, Variable):
+            return VariableRepr(obj, gen)
+        return None
+    get = staticmethod(get)
+
+    def __init__(self, var, gen):
+        if debug:
+            print "VariableRepr: %s" % (var.name)
+        self.var = var
+        type = gen.annotator.binding(var)
+        self.type = gen.get_repr(type)
+        self.dependencies = [self.type]
+
+    def llvmname(self):
+        return "%" + self.var.name
+        
+
+class StringRepr(LLVMRepr):
+    def get(obj, gen):
+        if isinstance(obj, Constant):
+            type = gen.annotator.binding(obj)
+            if type.__class__ is annmodel.SomeString:
+                l_repr = StringRepr(obj, gen)
+                return l_repr
+        return None
+    get = staticmethod(get)
+
+    def __init__(self, obj, gen):
+        if debug:
+            print "StringRepr: %s" % obj.value
+        self.s = obj.value
+        self.gen = gen
+        self.glvar1 = gen.get_global_tmp("StringRepr")
+        self.glvar2 = gen.get_global_tmp("StringRepr")
+        self.type = gen.get_repr(gen.annotator.binding(obj))
+        self.dependencies = [self.type]
+
+    def llvmname(self):
+        return self.glvar2
+
+    def get_globals(self):
+        d = {"len": len(self.s), "gv1": self.glvar1, "gv2": self.glvar2,
+             "type": self.type.llvmname_wo_pointer(), "string": self.s}
+        s = """%(gv1)s = internal constant [%(len)i x sbyte] c"%(string)s"
+%(gv2)s = internal constant %(type)s {uint %(len)i,\
+sbyte* getelementptr ([%(len)i x sbyte]* %(gv1)s, uint 0, uint 0)}"""
+        return s % d
+
+class TypeRepr(LLVMRepr):
+    l_stringtype = None
+    def get(obj, gen):
+##         print "TypeRepr", obj
+        if obj.__class__ is annmodel.SomeString or obj is str:
+            if TypeRepr.l_stringtype is None:
+                l_repr = TypeRepr("%std.string",
+                                  "%std.string = type {uint, sbyte*}",
+                                  "string.ll", gen)
+                TypeRepr.l_stringtype = l_repr
+            return TypeRepr.l_stringtype
+    get = staticmethod(get)
+
+    def __init__(self, llvmname, definition, includefile, gen):
+        if debug:
+            print "TypeRepr: %s, %s" % (llvmname, definition)
+        self.name = llvmname
+        self.definition = definition
+        self.gen = gen
+        self.includefile = includefile
+
+    def get_globals(self):
+        try:
+            return self.definition
+        except exceptions.AttributeError:
+            return ""
+
+    def get_functions(self):
+        if self.includefile != "":
+            f = file(autopath.this_dir + "/" + self.includefile, "r")
+            s = f.read()
+            f.close()
+            return s
+        return ""
+
+    def llvmname(self):
+        return self.name + "*"
+
+    def llvmname_wo_pointer(self):
+        return self.name
+
+class ListTypeRepr(TypeRepr):
+    l_listtypes = {}
+    def get(obj, gen):
+        if obj.__class__ is annmodel.SomeList:
+            if obj.s_item.__class__ in ListTypeRepr.l_listtypes:
+                return ListTypeRepr.l_listtypes[obj.s_item.__class__]
+            l_repr = ListTypeRepr(obj, gen)
+            ListTypeRepr.l_listtypes[obj.s_item.__class__] = l_repr
+            return l_repr
+        return None
+    get = staticmethod(get)
+
+    def __init__(self, obj, gen):
+        if debug:
+            print "ListTypeRepr: %s, %s" % (obj, obj.s_item)
+        self.gen = gen
+        self.l_itemtype = gen.get_repr(obj.s_item)
+        self.dependencies = [self.l_itemtype]
+        itemtype = self.l_itemtype.llvmname()
+        self.name = "%%std.list.%s" % itemtype.strip("%")
+        self.definition = self.name + " = type {uint, %s*}" % itemtype
+
+    def get_functions(self):
+        f = file(autopath.this_dir + "/list_template.ll", "r")
+        s = f.read()
+        f.close()
+        s = s.replace("%(item)s", self.l_itemtype.llvmname().strip("%"))
+        #XXX assuming every type consists of 4 bytes
+        s = s.replace("%(sizeof)i", str(4))
+        return s
+
+class SimpleTypeRepr(TypeRepr):
+    def get(obj, gen):
+        if obj.__class__ in [annmodel.SomeInteger, int]:
+            l_repr = SimpleTypeRepr("int", gen)
+            return l_repr            
+        elif obj.__class__ in [annmodel.SomeBool, bool]:
+            l_repr = SimpleTypeRepr("bool", gen)
+            return l_repr            
+        return None
+    get = staticmethod(get)
+
+    def __init__(self, llvmname, gen):
+        if debug:
+            print "SimpleTypeRepr: %s" % llvmname
+        self.name = llvmname
+        self.gen = gen
+        self.definition = ""
+        self.includefile = ""
+
+    def llvmname(self):
+        return self.name
+
+class ImpossibleValueRepr(TypeRepr):
+    def get(obj, gen):
+        if obj.__class__ is annmodel.SomeImpossibleValue:
+            return ImpossibleValueRepr()
+        return None
+    get = staticmethod(get)
+    
+    def __init__(self):
+        self.definition = ""
+        self.dependencies = []
+        self.includefile = ""
+
+    def llvmname(self):
+        return "void"
+
+    def typed_name(self):
+        return self.llvmtype() + " " + self.llvmname()
+
+class BuiltinFunctionRepr(LLVMRepr):
+    def get(obj, gen):
+        if isinstance(obj, Constant) and \
+           type(obj.value).__name__ == 'builtin_function_or_method':
+            l_repr = BuiltinFunctionRepr(obj.value, gen)
+            return l_repr
+        return None
+    get = staticmethod(get)
+
+    def __init__(self, bi, gen):
+        self.name = "%std." + bi.__name__
+        self.gen = gen
+
+    def llvmname(self):
+        return self.name
+
+class FunctionRepr(LLVMRepr):
+    def get(obj, gen):
+        if isinstance(obj, Constant) and \
+               type(obj.value).__name__ == 'function':
+            name = obj.value.__name__
+            l_repr = FunctionRepr(name, obj.value, gen)
+            return l_repr
+        elif type(obj).__name__ == 'function':
+            name = obj.__name__
+            l_repr = FunctionRepr(name, obj, gen)
+            return l_repr
+        return None
+    get = staticmethod(get)
+
+    def __init__(self, name, function, gen):
+        if debug:
+            print "FunctionRepr: %s" % name
+        self.gen = gen
+        self.func = function
+        self.translator = gen.translator
+        self.translator.simplify()
+        self.name = "%" + name
+        self.graph = self.translator.getflowgraph(self.func)
+        self.annotator = gen.translator.annotator
+        transform.transform_allocate(self.annotator)
+        self.blocknum = {}
+        self.allblocks = []
+        self.pyrex_source = ""
+        self.dependencies = sets.Set()
+        self.get_bbs()
+        self.build_bbs()
+
+    def get_bbs(self):
+        def visit(node):
+            if isinstance(node, Block) and node not in self.blocknum:
+                self.allblocks.append(node)
+                self.blocknum[node] = len(self.blocknum)
+        traverse(visit, self.graph)
+        self.same_origin_block = [False] * len(self.allblocks)
+
+    def build_bbs(self):
+        a = self.annotator
+        for number, pyblock in enumerate(self.allblocks):
+            lblock = llvmbc.BasicBlock("block%i" % number)
+            pyblock = self.allblocks[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 node)
+            incoming_links = []
+            def visit(node):
+                if isinstance(node, Link) and node.target == pyblock:
+                    incoming_links.append(node)
+            traverse(visit, self.graph)
+            #special case if the incoming links are from the same block
+            if len(incoming_links) == 2 and \
+               incoming_links[0].prevblock == incoming_links[1].prevblock:
+                for i, arg in enumerate(pyblock.inputargs):
+                    l_select = self.gen.get_repr(
+                        incoming_links[0].prevblock.exitswitch)
+                    l_arg = self.gen.get_repr(arg)
+                    l_v1 = self.gen.get_repr(incoming_links[1].args[i])
+                    l_v2 = self.gen.get_repr(incoming_links[0].args[i])
+                    self.dependencies.update([l_arg, l_switch, l_v1, l_v2])
+                    lblock.select(l_arg, l_select, l_v1, l_v2)
+            elif len(incoming_links) != 0:
+                for i, arg in enumerate(pyblock.inputargs):
+                    l_arg = self.gen.get_repr(arg)
+                    l_values = [self.gen.get_repr(l.args[i])
+                                for l in incoming_links]
+                    self.dependencies.add(l_arg)
+                    self.dependencies.update(l_values)
+                    lblock.phi(l_arg, l_values,
+                               ["%%block%i" % self.blocknum[l.prevblock]
+                                for l in incoming_links])
+            #Create a function call for every operation in the block
+            for op in pyblock.operations:
+                if op.opname == "simple_call" and \
+                       isinstance(op.args[0], Constant) and \
+                       op.args[0].value == self.func:
+                    l_args = [self] + \
+                             [self.gen.get_repr(arg) for arg in op.args[1:]]
+                else:
+                    l_args = [self.gen.get_repr(arg) for arg in op.args]
+                l_target = self.gen.get_repr(op.result)
+                self.dependencies.update(l_args)
+                self.dependencies.add(l_target)
+                if op.opname in INTRINSIC_OPS:
+                    lblock.spaceop(l_target, op.opname, l_args)
+                elif op.opname == "simple_call":
+                    lblock.call(l_target, l_args[0], l_args[1:])
+                else:
+                    self.translator.view()
+                    raise CompileError, "Unhandeled SpaceOp %s" % op.opname
+            #Create branches
+            if pyblock.exitswitch is None:
+                if pyblock.exits == ():
+                    l_returnvalue = self.gen.get_repr(pyblock.inputargs[0])
+                    self.dependencies.add(l_returnvalue)
+                    lblock.ret(l_returnvalue)
+                else:
+                    lblock.uncond_branch(
+                        "%%block%i" % self.blocknum[pyblock.exits[0].target])
+            else:
+                assert isinstance(a.binding(pyblock.exitswitch),
+                                  annmodel.SomeBool)
+                l_switch = self.gen.get_repr(pyblock.exitswitch)
+                self.dependencies.add(l_switch)
+                lblock.cond_branch(
+                    l_switch,
+                    "%%block%i" % self.blocknum[pyblock.exits[1].target],
+                    "%%block%i" % self.blocknum[pyblock.exits[0].target])
+
+    def cfuncdef(self):
+        a = self.translator.annotator
+        retv = self.graph.returnblock.inputargs[0]
+        rettype_c = C_SIMPLE_TYPES[a.binding(retv).__class__]
+        args = self.graph.startblock.inputargs
+        argtypes_c = [C_SIMPLE_TYPES[a.binding(v).__class__] for v in args]
+        fd = "%s %s(%s)" % (rettype_c, self.func.func_name,
+                            ", ".join(argtypes_c))
+        return fd
+
+    def llvmfuncdef(self):
+        a = self.translator.annotator
+        l_retv = self.gen.get_repr(self.graph.returnblock.inputargs[0])
+        l_args = [self.gen.get_repr(ar)
+                  for ar in self.graph.startblock.inputargs]
+        self.dependencies.update(l_args)
+        self.dependencies.add(l_retv)
+        s = "%s %s(" % (l_retv.llvmtype(), self.name)
+        return s + ", ".join([a.typed_name() for a in l_args]) + ")"
+        return llvmbc.function(l_retv, self.name, l_args)
+
+    def get_pyrex_source(self):
+        name = self.func.func_name
+        args = self.graph.startblock.inputargs
+        self.pyrex_source = ["cdef extern %s\n" %
+                             (self.cfuncdef())]
+        self.pyrex_source += ["def wrap_%s(" % name]
+        t = []
+        for i, a in enumerate(args):
+            t += ["%s" % a]
+        t = ", ".join(t)
+        self.pyrex_source += t + "):\n\treturn %s(%s)\n\n" % (name, t)
+        self.pyrex_source += "\ndef test(a):\n\treturn a + 1\n\n"
+        self.pyrex_source = "".join(self.pyrex_source)
+        return self.pyrex_source
+
+
+    def get_functions(self):
+        return str(self.llvm_func)
+
+    def llvmname(self):
+        return self.name
+
+    def llvmtype(self):
+        assert self.llvmfuncdef().count(self.name) == 1
+        return self.llvmfuncdef().replace(self.name + "(", "(")
+

Added: pypy/dist/pypy/translator/llvm/list_template.ll
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/list_template.ll	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,57 @@
+;Template for lists
+
+internal uint %std.len(%std.list.%(item)s* %a) {
+	%p = getelementptr %std.list.%(item)s* %a, int 0, uint 0
+	%length1 = load uint* %p
+	ret uint %length1
+}
+
+internal int %std.len(%std.list.%(item)s* %a) {
+	%length1 = call uint %std.len(%std.list.%(item)s* %a)
+	%length = cast uint %length1 to int
+	ret int %length
+}
+
+
+internal %std.list.%(item)s* %std.make(uint %len, %(item)s* %s) {
+	%ret = malloc %std.list.%(item)s, uint 1
+	%lenp = getelementptr %std.list.%(item)s* %ret, int 0, uint 0
+	%lsp = getelementptr %std.list.%(item)s* %ret, int 0, uint 1
+	store uint %len, uint* %lenp
+	store %(item)s* %s, %(item)s** %lsp
+	ret %std.list.%(item)s* %ret
+}
+
+
+internal %std.list.%(item)s* %std.newlist(%(item)s %init) {
+	%nmem = malloc %(item)s, uint 1
+	%ret = call %std.list.%(item)s* %std.make(uint 1, %(item)s* %nmem)
+	call void %std.setitem(%std.list.%(item)s* %ret, int 0, %(item)s %init)
+	ret %std.list.%(item)s* %ret
+}	
+
+internal %(item)s %std.getitem(%std.list.%(item)s* %s, int %p) {
+	%sp1 = getelementptr %std.list.%(item)s* %s, int 0, uint 1
+	%s1 = load %(item)s** %sp1
+	%len = call uint %std.len(%std.list.%(item)s* %s)
+	%ilen = cast uint %len to int
+	%negpos = add int %ilen, %p
+	%is_negative = setlt int %p, 0
+	%usedpos = select bool %is_negative, int %negpos, int %p
+	%p_item = getelementptr %(item)s* %s1, int %usedpos
+	%value = load %(item)s* %p_item
+	ret %(item)s %value
+}
+
+internal void %std.setitem(%std.list.%(item)s* %s, int %p, %(item)s %n) {
+	%sp1 = getelementptr %std.list.%(item)s* %s, int 0, uint 1
+	%s1 = load %(item)s** %sp1
+	%len = call uint %std.len(%std.list.%(item)s* %s)
+	%ilen = cast uint %len to int
+	%negpos = add int %ilen, %p
+	%is_negative = setlt int %p, 0
+	%usedpos = select bool %is_negative, int %negpos, int %p
+	%itemp = getelementptr %(item)s* %s1, int %usedpos
+	store %(item)s %n, %(item)s* %itemp
+	ret void
+}

Added: pypy/dist/pypy/translator/llvm/llvm_gc.txt
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/llvm_gc.txt	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,206 @@
+From sabre at nondot.org  Fri Oct 29 02:19:53 2004
+From: sabre at nondot.org (Chris Lattner)
+Date: Fri Oct 29 02:01:46 2004
+Subject: [LLVMdev] Getting started with GC
+In-Reply-To: <20041028223528.GA31467 at kwai.cs.uiuc.edu>
+Message-ID: <Pine.LNX.4.44.0410290120570.22336-100000 at nondot.org>
+
+On Thu, 28 Oct 2004, Tom Brown wrote:
+
+> We have a few questions about the current state of GC.
+
+Ok. :)
+
+> We decided to start (and finish?) our work by finishing SemiSpace.
+
+Sounds good.
+
+> process_pointer is meant to move objects from CurSpace to OtherSpace.
+> How can it find pointers to a moved object?
+
+This is entirely up to you, as you're basically implementing the semispace
+collector in its entirety.  See below.
+
+> How does it know the size of each object?
+
+I'm a big fan of starting simple.  As such, I'd suggest using this scheme:
+
+When an object is allocated: add a size word on front of it.  This size of
+every object should be rounded up to a multiple of 4.  When it is being
+GC'd, replace the size with the forwarding pointer, but with the low bit
+set.  Because the low bit is set, you should be able to tell if an object
+is forwarded or not.  This allows you to do the simple, standard, in-place
+depth-first traversal of the heap when you are GC'ing from one space to
+the other.
+
+> Assuming we are writing a GC that will only work from llvm assembly our
+> best option seems to be forcing the assembly code to follow a convention
+> that identifies pointers.
+
+There are three issues:
+
+1. Object references from the stack
+2. Object references from globals
+3. Object references from the heap
+
+#1 is the hardest from the code generation standpoint, and it is what LLVM
+provides direct support for.  #2 is really a matter of convention, and
+having the GC export and interface that can be used by langugage front-end
+in question to register global pointers.  #3 requires object descriptors
+of some sort, produces by the front-end and consumed by the GC.  See
+below.
+
+> The SemiSpace code could keep a map from each allocated pointer to its
+> size, similar to how I think malloc works.
+
+For this, I would suggest just putting a header word on the object,
+containing the size.  This is not optimal, but will be a good place to
+start.  Later this can be improved.
+
+> http://llvm.cs.uiuc.edu/docs/GarbageCollection.html (Which seems to be
+> the inverse of out-of-date, whatever that is)
+> Says that there is strong dependency between the frontend and GC
+> implementations.
+
+Yes.  The GC needs information from the front-end, in particular how it
+lays out objects and where to find object references.
+
+> For example, it seems as though the frontend and GC need to agree on a
+> structure for the Meta data and they may call each other during
+> allocation and garbage collection.
+
+Yes.  They don't actually need to 'agree', but there needs to be an API
+provided by the language runtime and consumed by the GC, that is used to
+encode the information.  One way is to standardize maps, a more general
+way is to expose API's to access the maps that the front-end produces
+(allowing the front-end to produce them in any format it wants).
+
+> I imagine it would be good to decouple the frontend and GC as much as
+> possible or one may need to be reimplemented when the other is changed.
+> Do you have any intentions for the use of Meta in SemiSpace?
+
+I'm not sure what you mean by 'meta', but if you mean metadata, yes.
+
+> We could trample around and make something work but it seems as
+> though you have built most of the support structure for GC. We are
+> trying to follow that plan.
+
+Sounds good.  This is what I envision.  :)  The 'vision' encompases many
+langauges and different implementation strategies, but lets start with one
+that you are likely to be familiar with.  Anything you do here can be
+extended to the full vision, if and when you find yourself with tons of
+spare time at the end of your project. :)
+
+Lets imagine that you have a language like Java.  All GC'd objects in Java
+have vtables, and from this vtable a wealth of information about the
+object is accessible (e.g. it's size, whether it's an array, GC map
+information, etc).  The layout of objects in Java might look something
+something like this:
+
+
+obj ptr --\
+          |
+          v
+    [ vtable ptr ] ----> [ rtti info ]  ---->  ...
+    [ obj word 1 ]       [ gc info   ]  ----> [ obj size  ]
+    [ obj word 2 ]       [ vf ptr #1 ]        [ Flags     ]    -> is array, etc
+     ...                  ...                 [ gc map #1 ]
+    [ obj word N ]       [ vf ptr #N ]        [ gc map ...]
+
+In addition, there are some number of "globals" (really statics fields in
+Java) that can contain references.  Given this, it seems like your GC
+needs the front-end to provide the following:
+
+1. A way of identifying/iterating all of the global references.  It seems
+   reasonable for the GC to expose a function like "void gc_add_static_root(void**)"
+   which the front-end would emit calls to.  Java has 'class initializers'
+   which are called to initialize static members of classes (and other
+   stuff), so the language front-end could easily insert calls to this
+   function in the initializer.
+2. A way of getting the size of an object.  Initially you can use a header
+   word on the object, but eventually, it would be nice if the front-end
+   runtime library would provide a function, say
+   "unsigned gc_fe_get_object_size(void *object)", which could be called
+   by the GC implementation to get this information.  With the approach
+   above, if the object was a non-array, it would just get the object size
+   field from the GC info (using several pointer dereferences from
+   'object'.  If it's an array, the FE runtime would do something perhaps
+   more complex to get this info, but you wouldn't really care what it
+   was :).  VM's like Java often specialize a number of other cases (like
+   strings) as well, and obviously the GC doesn't want to know the details
+   of this hackery.
+3. A way of iterating over the (language specific) GC map information for
+   a heap object.  In particular, you need a way to identify the
+   offsets of all of the outgoing pointers from the start of a heap object.
+   I'm not sure what the best way to do this is (or the best way to
+   encode this) but I'm sure you can come up with something. :)  The most
+   naive and inefficient interface (always a good starting place) would be
+   to have the front-end provide a callback:
+     _Bool gc_fe_is_pointer(void *obj, unsigned offset)
+   that the GC can use to probe all of the words in the object to see if
+   they are pointers.  This can obviously be improved. :)
+
+In a naive implementation, the result of these callbacks will be
+extremely inefficient, as all of these functions are very small and will
+be extremely frequently called when a GC happens.  In practice, because
+this is LLVM, we can do things a little bit smarter. :)
+
+In particular, when a source language's runtime library is built, it will
+include two things: all of the GC hooks it is required to implement, and
+an actual GC implementation, chosen from runtime/GC directory.  When this
+is linked together, the link-time optimizer will link all of the little
+helper functions above into the GC, inlining and optimizing the result,
+resulting in a no overhead solution.
+
+
+As far as your class project, the following steps make sense to me:
+
+The first step is to get the alloc_loop testcase fully working, as it
+doesn't require any of the fancy extra interfaces.  This can be done
+directly by adding the object header (I believe), and finishing semispace
+as it stands today.  This should be simple and get you started with the GC
+interfaces.
+
+The next step in this is to flush out the interface between the GC and
+the language runtime.  The GC doesn't want to know anything about how the
+FE lays out vtables and GC info, and the front-end doesn't want to know
+anything about how the GC implements its algorithm.  The
+runtime/GC/GCInterface.h file is a start on this, but the callbacks
+described above will also need to be added.
+
+The next step is to extend alloc_loop to use these interfaces.  It might
+be useful to translate it to C code, to make it easier to deal with.
+>From there, you can add one feature at a time, iterating between adding
+features (like global pointers or pointers in heap objects) to the
+alloc_loop test, and adding features to the GC.  Eventually you will have
+the full set of features listed above.
+
+Note that (by hacking on alloc_loop and other testcases you write), you
+are basically writing a file that would be generated by a garbage
+collected language front-end.  Because of this, you get to write all of
+the vtables/GC info by hand, and can include the "language runtime"
+callbacks directly in the program.
+
+
+This is a somewhat big task, but can be done incrementally.  Let me
+emphasize this point: to do this successfully, it is pretty important that
+you try to add one little step to the testcase, and add the corresponding
+feature to the GC, working a step at a time.  As you find that you need to
+change the interfaces on either side, go ahead and do so.  If you work
+incrementally, you will always have something that *works*, and is better
+than the previous step.  If you add something that is completely horrible
+and you decide is a bad idea, you can always revert to something close by
+that is known good.  For your course project, you obviously want to get
+the most implemented possible (ideally all of the above), but if technical
+difficulties or other unforseen problems come up, at least you will have
+something working and some progress to show.
+
+If you have any questions, please feel free to ask here.  I'm pretty busy
+over these couple of weeks (so my answers may be a little slow), but I
+really want you guys to be successful!
+
+-Chris
+
+-- 
+http://llvm.org/
+http://nondot.org/sabre/
\ No newline at end of file

Added: pypy/dist/pypy/translator/llvm/llvmbc.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/llvmbc.py	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,81 @@
+"""
+Some simple classes that output LLVM-assembler.
+"""
+
+import autopath
+
+import exceptions
+
+from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
+
+
+class Function(object):
+    def __init__(self, funcdef, startbb):
+        self.funcdef = funcdef
+        self.startbb = startbb
+        self.blocks = {}
+
+    def basic_block(self, block):
+        assert block.label != self.startbb.label, "Block has same label as startblock!"
+        self.blocks[block.label] = block
+
+    def __str__(self):
+        r = [self.funcdef, " {\n", str(self.startbb)]
+        r += [str(bb) for bb in self.blocks.values()] + ["}\n\n"]
+        return "".join(r)
+
+class BasicBlock(object):
+    def __init__(self, label):
+        self.label = label
+        self.instructions = []
+
+    def instructions(self, instruction): #should not be used
+        self.instructions.append(instruction)
+
+    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 = []
+        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):
+        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 ret(self, l_value):
+        self.instructions.append("ret %s" % l_value.typed_name())
+
+    def uncond_branch(self, block):
+        self.instructions.append("br label " + block)
+
+    def cond_branch(self, l_switch, blocktrue, blockfalse):
+        s = "br %s, label %s, label %s" % (l_switch.typed_name(),
+                                           blocktrue, blockfalse)
+        self.instructions.append(s)
+
+
+    def __str__(self):
+        s = [self.label + ":\n"]
+        for ins in self.instructions:
+            s += ["\t%s\n" % ins]
+        return "".join(s)
+

Added: pypy/dist/pypy/translator/llvm/operations.ll
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/operations.ll	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,172 @@
+;implementation of space operations for simple types
+implementation
+
+declare void %llvm.memmove(sbyte*, sbyte*, uint, uint)
+declare void %llvm.memcpy(sbyte*, sbyte*, uint, uint)
+declare void %llvm.memset(sbyte*, ubyte, uint, uint)
+
+
+;Basic operations for ints
+internal int %std.add(int %a, int %b) {
+	%r = add int %a, %b
+	ret int %r
+}
+
+internal int %std.inplace_add(int %a, int %b) {
+	%r = add int %a, %b	
+	ret int %r
+}
+
+internal int %std.sub(int %a, int %b) {
+	%r = sub int %a, %b
+	ret int %r
+}
+
+internal int %std.inplace_sub(int %a, int %b) {
+	%r = sub int %a, %b
+	ret int %r
+}
+
+internal int %std.mul(int %a, int %b) {
+	%r = mul int %a, %b	
+	ret int %r
+}
+
+internal int %std.inplace_mul(int %a, int %b) {
+	%r = mul int %a, %b
+	ret int %r
+}
+
+internal int %std.div(int %a, int %b) {
+	%r = div int %a, %b
+	ret int %r
+}
+
+internal int %std.inplace_div(int %a, int %b) {
+	%r = div int %a, %b
+	ret int %r
+}
+
+internal int %std.floordiv(int %a, int %b) {
+	%r = div int %a, %b
+	ret int %r
+}
+
+internal int %std.inplace_floordiv(int %a, int %b) {
+	%r = div int %a, %b
+	ret int %r
+}
+
+internal int %std.mod(int %a, int %b) {
+	%r = rem int %a, %b	
+	ret int %r
+}
+
+internal int %std.inplace_mod(int %a, int %b) {
+	%r = rem int %a, %b	
+	ret int %r
+}
+
+
+;Basic comparisons for ints
+
+internal bool %std.is(int %a, int %b) {
+	%r = seteq int %a, %b
+	ret bool %r
+}
+
+internal bool %std.is_true(int %a) {
+	%b = cast int %a to bool
+	ret bool %b
+}
+
+internal bool %std.eq(int %a, int %b) {
+	%r = seteq int %a, %b	
+	ret bool %r
+}
+
+internal bool %std.neq(int %a, int %b) {
+	%r = seteq int %a, %b	
+	%r1 = xor bool %r, true
+	ret bool %r1
+}
+
+internal bool %std.lt(int %a, int %b) {
+	%r = setlt int %a, %b	
+	ret bool %r
+}
+
+internal bool %std.gt(int %a, int %b) {
+	%r = setgt int %a, %b	
+	ret bool %r
+}
+
+internal bool %std.le(int %a, int %b) {
+	%r = setle int %a, %b	
+	ret bool %r
+}
+
+internal bool %std.ge(int %a, int %b) {
+	%r = setge int %a, %b	
+	ret bool %r
+}
+
+;Logical operations for ints
+internal int %std.and(int %a, int %b) {
+	%r = and int %a, %b
+	ret int %r
+}
+
+internal int %std.inplace_and(int %a, int %b) {
+	%r = and int %a, %b
+	ret int %r
+}
+
+internal int %std.or(int %a, int %b) {
+	%r = or int %a, %b
+	ret int %r
+}
+
+internal int %std.inplace_or(int %a, int %b) {
+	%r = or int %a, %b
+	ret int %r
+}
+
+internal int %std.xor(int %a, int %b) {
+	%r = xor int %a, %b
+	ret int %r
+}
+
+internal int %std.inplace_xor(int %a, int %b) {
+	%r = xor int %a, %b
+	ret int %r
+}
+
+internal int %std.lshift(int %a, int %b) {
+	%shift = cast int %b to ubyte
+	%r = shl int %a, ubyte %shift
+	ret int %r
+}
+
+internal int %std.rshift(int %a, int %b) {
+	%shift = cast int %b to ubyte
+	%r = shr int %a, ubyte %shift
+	ret int %r
+}
+
+
+;bools
+internal bool %std.is_true(bool %a) {
+	ret bool %a
+}
+
+internal bool %std.and(bool %a, bool %b) {
+	%r = and bool %a, %b	
+	ret bool %r
+}
+
+internal bool %std.or(bool %a, bool %b) {
+	%r = or bool %a, %b	
+	ret bool %r
+}
+

Added: pypy/dist/pypy/translator/llvm/string.ll
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/string.ll	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,49 @@
+internal uint %std.len(%std.string* %a) {
+	%p = getelementptr %std.string* %a, int 0, uint 0
+	%length1 = load uint* %p
+	ret uint %length1
+}
+
+internal %std.string* %std.make(uint %len, sbyte* %s) {
+	%ret = malloc %std.string, uint 1
+	%lenp = getelementptr %std.string* %ret, int 0, uint 0
+	%lsp = getelementptr %std.string* %ret, int 0, uint 1
+	store uint %len, uint* %lenp
+	store sbyte* %s, sbyte** %lsp
+	ret %std.string* %ret
+}
+
+
+internal %std.string* %std.add(%std.string* %a, %std.string* %b) {
+	%lena = call uint %std.len(%std.string* %a)
+	%lenb = call uint %std.len(%std.string* %b)
+	%totlen = add uint %lena, %lenb
+	%nmem1 = malloc sbyte, uint %totlen
+	%oldsp1 = getelementptr %std.string* %a, int 0, uint 1
+	%oldsp2 = getelementptr %std.string* %b, int 0, uint 1
+	%olds1 =  load sbyte** %oldsp1
+	%olds2 =  load sbyte** %oldsp2
+	%nposp = getelementptr sbyte* %nmem1, uint %lena
+	call void %llvm.memcpy(sbyte* %nmem1, sbyte* %olds1, uint %lena, uint 0)
+	call void %llvm.memcpy(sbyte* %nposp, sbyte* %olds2, uint %lenb, uint 0)
+	%ret = call %std.string* %std.make(uint %totlen, sbyte* %nmem1)
+	ret %std.string* %ret
+}
+
+
+internal sbyte %std.getitem(%std.string* %s, int %p) {
+	%sp1 = getelementptr %std.string* %s, int 0, uint 1
+	%s1 = load sbyte** %sp1
+	%len = call uint %std.len(%std.string* %s)
+	%ilen = cast uint %len to int
+	%negpos = add int %ilen, %p
+	%is_negative = setlt int %p, 0
+	%usedpos = select bool %is_negative, int %negpos, int %p
+	%negusedpos = setlt int %usedpos, 0
+	%posbig = setgt int %usedpos, %ilen
+	%wrongindex = or bool %negusedpos, %posbig
+	%charp = getelementptr sbyte* %s1, int %usedpos
+	%value = load sbyte* %charp
+	%ret = select bool %wrongindex, sbyte 33, sbyte %value
+	ret sbyte %value
+}

Added: pypy/dist/pypy/translator/llvm/test.html
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/test.html	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.3.7: http://docutils.sourceforge.net/" />
+<title>Description of the llvm backend</title>
+<link rel="stylesheet" href="default.css" type="text/css" />
+</head>
+<body>
+<div class="document" id="description-of-the-llvm-backend">
+<h1 class="title">Description of the llvm backend</h1>
+<p>The llvm backend (&quot;genllvm&quot;) tries to generate llvm-assembly out of an
+annotated flowgraph. The annotation has to be complete for genllvm to
+work. The produced assembly can then be optimized and converted to native code
+by llvm. A simple Pyrex wrapper for the entry function is then generated to be
+able to use the llvm-compiled functions from Python.</p>
+<div class="section" id="how-to-use-genllvm">
+<h1><a name="how-to-use-genllvm">How to use genllvm</a></h1>
+<p>To try it out use the function 'llvmcompile' in the module
+pypy.translator.llvm.genllvm on an annotated flowgraph:</p>
+<pre class="literal-block">
+%pypy/translator/llvm&gt; python -i genllvm.py
+&gt;&gt;&gt; t = Translator(test.my_gcd) 
+&gt;&gt;&gt; a = t.annotate([int, int])
+&gt;&gt;&gt; f = llvmcompile(t)
+&gt;&gt;&gt; f(10, 2)
+2
+&gt;&gt;&gt; f(14, 7)
+7
+</pre>
+</div>
+<div class="section" id="structure">
+<h1><a name="structure">Structure</a></h1>
+<p>The llvm backend consists of several parts:</p>
+<blockquote>
+<ol class="arabic simple">
+<li></li>
+</ol>
+</blockquote>
+<div class="section" id="things-that-work">
+<h2><a name="things-that-work">Things that work:</a></h2>
+<blockquote>
+<ul class="simple">
+<li>ints, bools, function calls</li>
+</ul>
+</blockquote>
+</div>
+</div>
+</div>
+</body>
+</html>

Added: pypy/dist/pypy/translator/llvm/test/__init__.py
==============================================================================

Added: pypy/dist/pypy/translator/llvm/test/autopath.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/test/autopath.py	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,114 @@
+"""
+self cloning, automatic path configuration 
+
+copy this into any subdirectory of pypy from which scripts need 
+to be run, typically all of the test subdirs. 
+The idea is that any such script simply issues
+
+    import autopath
+
+and this will make sure that the parent directory containing "pypy"
+is in sys.path. 
+
+If you modify the master "autopath.py" version (in pypy/tool/autopath.py) 
+you can directly run it which will copy itself on all autopath.py files
+it finds under the pypy root directory. 
+
+This module always provides these attributes:
+
+    pypydir    pypy root directory path 
+    this_dir   directory where this autopath.py resides 
+
+"""
+
+
+def __dirinfo(part):
+    """ return (partdir, this_dir) and insert parent of partdir
+    into sys.path.  If the parent directories don't have the part
+    an EnvironmentError is raised."""
+
+    import sys, os
+    try:
+        head = this_dir = os.path.realpath(os.path.dirname(__file__))
+    except NameError:
+        head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0]))
+
+    while head:
+        partdir = head
+        head, tail = os.path.split(head)
+        if tail == part:
+            break
+    else:
+        raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir)
+    
+    checkpaths = sys.path[:]
+    pypy_root = os.path.join(head, '')
+    
+    while checkpaths:
+        orig = checkpaths.pop()
+        if os.path.join(os.path.realpath(orig), '').startswith(pypy_root):
+            sys.path.remove(orig)
+    sys.path.insert(0, head)
+
+    munged = {}
+    for name, mod in sys.modules.items():
+        fn = getattr(mod, '__file__', None)
+        if '.' in name or not isinstance(fn, str):
+            continue
+        newname = os.path.splitext(os.path.basename(fn))[0]
+        if not newname.startswith(part + '.'):
+            continue
+        path = os.path.join(os.path.dirname(os.path.realpath(fn)), '')
+        if path.startswith(pypy_root) and newname != part:
+            modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep)
+            if newname != '__init__':
+                modpaths.append(newname)
+            modpath = '.'.join(modpaths)
+            if modpath not in sys.modules:
+                munged[modpath] = mod
+
+    for name, mod in munged.iteritems():
+        if name not in sys.modules:
+            sys.modules[name] = mod
+        if '.' in name:
+            prename = name[:name.rfind('.')]
+            postname = name[len(prename)+1:]
+            if prename not in sys.modules:
+                __import__(prename)
+                if not hasattr(sys.modules[prename], postname):
+                    setattr(sys.modules[prename], postname, mod)
+
+    return partdir, this_dir
+
+def __clone():
+    """ clone master version of autopath.py into all subdirs """
+    from os.path import join, walk
+    if not this_dir.endswith(join('pypy','tool')):
+        raise EnvironmentError("can only clone master version "
+                               "'%s'" % join(pypydir, 'tool',_myname))
+
+
+    def sync_walker(arg, dirname, fnames):
+        if _myname in fnames:
+            fn = join(dirname, _myname)
+            f = open(fn, 'rwb+')
+            try:
+                if f.read() == arg:
+                    print "checkok", fn
+                else:
+                    print "syncing", fn
+                    f = open(fn, 'w')
+                    f.write(arg)
+            finally:
+                f.close()
+    s = open(join(pypydir, 'tool', _myname), 'rb').read()
+    walk(pypydir, sync_walker, s)
+
+_myname = 'autopath.py'
+
+# set guaranteed attributes
+
+pypydir, this_dir = __dirinfo('pypy')
+
+if __name__ == '__main__':
+    __clone()

Added: pypy/dist/pypy/translator/llvm/test/llvmsnippet.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/test/llvmsnippet.py	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,47 @@
+import autopath
+
+def simple1():
+    return 1
+
+def simple2():
+    return False
+
+def simple3():
+    c = "Hello, Stars!"
+    return c
+
+def simple4():
+    return 3 + simple1()
+
+def simple5(b):
+    if b:
+        x = 12
+    else:
+        x = 13
+    return x
+
+def simple6():
+    simple4()
+    return 1
+
+def ackermann(n, m):
+    if n == 0:
+        return m + 1
+    if m == 0:
+        return ackermann(n - 1, 1)
+    return ackermann(n - 1, ackermann(n, m - 1))
+
+
+def arraytestsimple():
+    a = [42]
+    return a[0]
+
+def arraytestsimple1():
+    a = [43]
+    return a[-1]
+
+def arraytestsetitem(i):
+    a = [43]
+    a[0] = i * 2
+    return a[-1]
+

Added: pypy/dist/pypy/translator/llvm/test/test_genllvm.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/test/test_genllvm.py	Sun Feb  6 17:45:51 2005
@@ -0,0 +1,164 @@
+import autopath
+import py
+
+import StringIO
+
+from pypy.translator.translator import Translator
+from pypy.translator.llvm.genllvm import LLVMGenerator
+from pypy.translator.test import snippet as test
+from pypy.objspace.flow.model import Constant, Variable
+
+from pypy.translator.llvm.test import llvmsnippet
+
+def setup_module(mod): 
+    mod.llvm_found = is_on_path("llvm-as")
+
+def compile_function(function, annotate):
+    t = Translator(function)
+    a = t.annotate(annotate)
+    gen = LLVMGenerator(t)
+    return gen.compile()
+
+def is_on_path(name):
+    try:
+        py.path.local.sysfind(name) 
+    except py.error.ENOENT: 
+        return False 
+    else: 
+        return True
+
+class TestLLVMRepr(object):
+    def DONOT_test_simple1(self):
+        t = Translator(llvmsnippet.simple1)
+        a = t.annotate([])
+        gen = LLVMGenerator(t)
+        l_repr = gen.get_repr(t.getflowgraph().startblock.exits[0].args[0])
+        assert l_repr.llvmname() == "1"
+        assert l_repr.typed_name() == "int 1"
+        print gen.l_entrypoint.get_functions()
+        assert gen.l_entrypoint.get_functions() == """\
+int %simple1() {
+block0:
+\tbr label %block1
+block1:
+\t%v0 = phi int [1, %block0]
+\tret int %v0
+}
+
+"""
+
+    def test_simple2(self):
+        t = Translator(llvmsnippet.simple2)
+        a = t.annotate([])
+        gen = LLVMGenerator(t)
+        print gen
+        print t.getflowgraph().startblock.exits[0].args[0]
+        l_repr = gen.get_repr(t.getflowgraph().startblock.exits[0].args[0])
+        assert l_repr.llvmname() == "false"
+        assert l_repr.typed_name() == "bool false"
+
+    def test_typerepr(self):
+        t = Translator(llvmsnippet.simple1)
+        a = t.annotate([])
+        gen = LLVMGenerator(t)
+        l_repr = gen.get_repr(str)
+        assert l_repr.llvmname() == "%std.string*"
+
+    def test_stringrepr(self):
+        t = Translator(llvmsnippet.simple3)
+        a = t.annotate([])
+        gen = LLVMGenerator(t)
+        l_repr1 = gen.get_repr(t.getflowgraph().startblock.exits[0].args[0])
+        l_repr2 = gen.get_repr(t.getflowgraph().startblock.exits[0].args[0])
+        assert l_repr1 is l_repr2
+        assert l_repr1.typed_name() == "%std.string* %glb.StringRepr.2"
+        assert l_repr2.get_globals() == """%glb.StringRepr.1 = \
+internal constant [13 x sbyte] c"Hello, Stars!"
+%glb.StringRepr.2 = internal constant %std.string {uint 13,\
+sbyte* getelementptr ([13 x sbyte]* %glb.StringRepr.1, uint 0, uint 0)}"""
+
+class TestGenLLVM(object):
+    def setup_method(self,method):
+        if not llvm_found:
+            py.test.skip("llvm-as not found on path")
+
+    def test_simple1(self):
+        f = compile_function(llvmsnippet.simple1, [])
+        assert f() == 1
+
+    def test_simple2(self):
+        f = compile_function(llvmsnippet.simple2, [])
+        assert f() == 0
+
+    def test_simple4(self):
+        f = compile_function(llvmsnippet.simple4, [])
+        assert f() == 4
+
+    def test_simple5(self):
+        f = compile_function(llvmsnippet.simple5, [int])
+        assert f(1) == 12
+        assert f(0) == 13
+
+    def test_ackermann(self):
+        f = compile_function(llvmsnippet.ackermann, [int, int])
+        for i in range(10):
+            assert f(0, i) == i + 1
+            assert f(1, i) == i + 2
+            assert f(2, i) == 2 * i + 3
+            assert f(3, i) == 2 ** (i + 3) - 3
+
+class TestLLVMArray(object):
+    def setup_method(self, method):
+        if not llvm_found:
+            py.test.skip("llvm-as not found on path.")
+
+    def test_simplearray(self):
+        f = compile_function(llvmsnippet.arraytestsimple, [])
+        assert f() == 42
+
+    def test_simplearray1(self):
+        f = compile_function(llvmsnippet.arraytestsimple1, [])
+        assert f() == 43
+
+    def test_simplearray_setitem(self):
+        f = compile_function(llvmsnippet.arraytestsetitem, [int])
+        assert f(32) == 64
+
+class TestSnippet(object):
+    def setup_method(self, method):
+        if not llvm_found:
+            py.test.skip("llvm-as not found on path.")
+        
+    def test_if_then_else(self):
+        f = compile_function(test.if_then_else, [int, int, int])
+        assert f(0, 12, 13) == 13
+        assert f(13, 12, 13) == 12
+        
+    def test_my_gcd(self):
+        f = compile_function(test.my_gcd, [int, int])
+        assert f(15, 5) == 5
+        assert f(18, 42) == 6
+
+    def test_is_perfect_number(self):
+        f = compile_function(test.is_perfect_number, [int])
+        assert f(28) == 1
+        assert f(123) == 0
+        assert f(496) == 1
+
+    def test_my_bool(self):
+        f = compile_function(test.my_bool, [int])
+        assert f(10) == 1
+        assert f(1) == 1
+        assert f(0) == 0
+        
+    def test_while_func(self):
+        while_func = compile_function(test.while_func, [int])
+        assert while_func(10) == 55
+
+    def test_factorial2(self):
+        factorial2 = compile_function(test.factorial2, [int])
+        assert factorial2(5) == 120
+
+    def test_factorial(self):
+        factorial = compile_function(test.factorial, [int])
+        assert factorial(5) == 120



More information about the Pypy-commit mailing list