[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 ("genllvm") 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> python -i genllvm.py
+>>> t = Translator(test.my_gcd)
+>>> a = t.annotate([int, int])
+>>> f = llvmcompile(t)
+>>> f(10, 2)
+2
+>>> 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