Fix a lots of bugs in the newbinding to pass all the tests.

NOTE: debug info has not been implemented yet.
This commit is contained in:
Siu Kwan Lam 2013-02-13 15:09:26 -06:00
commit a09394cacd
32 changed files with 2419 additions and 546 deletions

View file

@ -1,3 +1,12 @@
from ._version import get_versions
__version__ = get_versions()['version']
del get_versions
from llvmpy import extra
version = extra.get_llvm_version()
del extra
class Wrapper(object):
def __init__(self, ptr):
assert ptr
@ -9,7 +18,18 @@ class Wrapper(object):
def _extract_ptrs(objs):
return [x._ptr for x in objs]
return [(x._ptr if x is not None else None)
for x in objs]
class LLVMException(Exception):
pass
def test(verbosity=1):
"""test(verbosity=1) -> TextTestResult
Run self-test, and return unittest.runner.TextTestResult object.
"""
from llvm.test_llvmpy import run
return run(verbosity=verbosity)

193
llvm/_version.py Normal file
View file

@ -0,0 +1,193 @@
IN_LONG_VERSION_PY = True
# This file helps to compute a version number in source trees obtained from
# git-archive tarball (such as those provided by github's download-from-tag
# feature). Distribution tarballs (build by setup.py sdist) and build
# directories (produced by setup.py build) will contain a much shorter file
# that just contains the computed version number.
# This file is released into the public domain. Generated by
# versioneer-0.7+ (https://github.com/warner/python-versioneer)
# these strings will be replaced by git during git-archive
git_refnames = "$Format:%d$"
git_full = "$Format:%H$"
GIT = "git"
import subprocess
import sys
def run_command(args, cwd=None, verbose=False):
try:
# remember shell=False, so use git.cmd on windows, not just git
p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd)
except EnvironmentError:
e = sys.exc_info()[1]
if verbose:
print("unable to run %s" % args[0])
print(e)
return None
stdout = p.communicate()[0].strip()
if sys.version >= '3':
stdout = stdout.decode()
if p.returncode != 0:
if verbose:
print("unable to run %s (error)" % args[0])
return None
return stdout
import sys
import re
import os.path
def get_expanded_variables(versionfile_source):
# the code embedded in _version.py can just fetch the value of these
# variables. When used from setup.py, we don't want to import
# _version.py, so we do it with a regexp instead. This function is not
# used from _version.py.
variables = {}
try:
for line in open(versionfile_source,"r").readlines():
if line.strip().startswith("git_refnames ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
variables["refnames"] = mo.group(1)
if line.strip().startswith("git_full ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
variables["full"] = mo.group(1)
except EnvironmentError:
pass
return variables
def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
refnames = variables["refnames"].strip()
if refnames.startswith("$Format"):
if verbose:
print("variables are unexpanded, not using")
return {} # unexpanded, so not in an unpacked git-archive tarball
refs = set([r.strip() for r in refnames.strip("()").split(",")])
for ref in list(refs):
if not re.search(r'\d', ref):
if verbose:
print("discarding '%s', no digits" % ref)
refs.discard(ref)
# Assume all version tags have a digit. git's %d expansion
# behaves like git log --decorate=short and strips out the
# refs/heads/ and refs/tags/ prefixes that would let us
# distinguish between branches and tags. By ignoring refnames
# without digits, we filter out many common branch names like
# "release" and "stabilization", as well as "HEAD" and "master".
if verbose:
print("remaining refs: %s" % ",".join(sorted(refs)))
for ref in sorted(refs):
# sorting will prefer e.g. "2.0" over "2.0rc1"
if ref.startswith(tag_prefix):
r = ref[len(tag_prefix):]
if verbose:
print("picking %s" % r)
return { "version": r,
"full": variables["full"].strip() }
# no suitable tags, so we use the full revision id
if verbose:
print("no suitable tags, using full revision id")
return { "version": variables["full"].strip(),
"full": variables["full"].strip() }
def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
# this runs 'git' from the root of the source tree. That either means
# someone ran a setup.py command (and this code is in versioneer.py, so
# IN_LONG_VERSION_PY=False, thus the containing directory is the root of
# the source tree), or someone ran a project-specific entry point (and
# this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the
# containing directory is somewhere deeper in the source tree). This only
# gets called if the git-archive 'subst' variables were *not* expanded,
# and _version.py hasn't already been rewritten with a short version
# string, meaning we're inside a checked out source tree.
try:
here = os.path.abspath(__file__)
except NameError:
# some py2exe/bbfreeze/non-CPython implementations don't do __file__
return {} # not always correct
# versionfile_source is the relative path from the top of the source tree
# (where the .git directory might live) to this file. Invert this to find
# the root from __file__.
root = here
if IN_LONG_VERSION_PY:
for i in range(len(versionfile_source.split("/"))):
root = os.path.dirname(root)
else:
root = os.path.dirname(here)
if not os.path.exists(os.path.join(root, ".git")):
if verbose:
print("no .git in %s" % root)
return {}
stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"],
cwd=root)
if stdout is None:
return {}
if not stdout.startswith(tag_prefix):
if verbose:
print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix))
return {}
tag = stdout[len(tag_prefix):]
stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root)
if stdout is None:
return {}
full = stdout.strip()
if tag.endswith("-dirty"):
full += "-dirty"
return {"version": tag, "full": full}
def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False):
if IN_LONG_VERSION_PY:
# We're running from _version.py. If it's from a source tree
# (execute-in-place), we can work upwards to find the root of the
# tree, and then check the parent directory for a version string. If
# it's in an installed application, there's no hope.
try:
here = os.path.abspath(__file__)
except NameError:
# py2exe/bbfreeze/non-CPython don't have __file__
return {} # without __file__, we have no hope
# versionfile_source is the relative path from the top of the source
# tree to _version.py. Invert this to find the root from __file__.
root = here
for i in range(len(versionfile_source.split("/"))):
root = os.path.dirname(root)
else:
# we're running from versioneer.py, which means we're running from
# the setup.py in a source tree. sys.argv[0] is setup.py in the root.
here = os.path.abspath(sys.argv[0])
root = os.path.dirname(here)
# Source tarballs conventionally unpack into a directory that includes
# both the project name and a version string.
dirname = os.path.basename(root)
if not dirname.startswith(parentdir_prefix):
if verbose:
print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" %
(root, dirname, parentdir_prefix))
return None
return {"version": dirname[len(parentdir_prefix):], "full": ""}
tag_prefix = ""
parentdir_prefix = "llvmpy-"
versionfile_source = "llvm/_version.py"
def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
variables = { "refnames": git_refnames, "full": git_full }
ver = versions_from_expanded_variables(variables, tag_prefix, verbose)
if not ver:
ver = versions_from_vcs(tag_prefix, versionfile_source, verbose)
if not ver:
ver = versions_from_parentdir(parentdir_prefix, versionfile_source,
verbose)
if not ver:
ver = default
return ver

File diff suppressed because it is too large Load diff

View file

@ -38,8 +38,8 @@ import contextlib
import llvm
from llvm import core
from llvmpy import api
from llvm.passes import TargetData, TargetTransformInfo
from llvmpy import api, extra
#===----------------------------------------------------------------------===
# Enumerations
#===----------------------------------------------------------------------===
@ -63,20 +63,20 @@ class GenericValue(llvm.Wrapper):
@staticmethod
def int(ty, intval):
ptr = api.llvm.CreateInt(ty._ptr, intval, False)
ptr = api.llvm.GenericValue.CreateInt(ty._ptr, int(intval), False)
return GenericValue(ptr)
@staticmethod
def int_signed(ty, intval):
ptr = api.llvm.CreateInt(ty._ptr, intval, True)
ptr = api.llvm.GenericValue.CreateInt(ty._ptr, int(intval), True)
return GenericValue(ptr)
@staticmethod
def real(ty, floatval):
if str(ty) == 'float':
ptr = api.llvm.CreateFloat(floatval)
ptr = api.llvm.GenericValue.CreateFloat(float(floatval))
elif str(ty) == 'double':
ptr = api.llvm.CreateDouble(floatval)
ptr = api.llvm.GenericValue.CreateDouble(float(floatval))
else:
raise Exception('Unreachable')
return GenericValue(ptr)
@ -91,7 +91,7 @@ class GenericValue(llvm.Wrapper):
`addr` is an integer representing an address.
'''
ptr = api.llvm.CreatePointer(addr)
ptr = api.llvm.GenericValue.CreatePointer(int(addr))
return GenericValue(ptr)
def as_int(self):
@ -101,7 +101,7 @@ class GenericValue(llvm.Wrapper):
return self._ptr.toSignedInt()
def as_real(self, ty):
return self._ptr.toFloat()
return self._ptr.toFloat(ty._ptr)
def as_pointer(self):
return self._ptr.toPointer()
@ -113,7 +113,7 @@ class GenericValue(llvm.Wrapper):
class EngineBuilder(llvm.Wrapper):
@staticmethod
def new(module):
ptr = api.llvm.EngineBuilder.new(module)
ptr = api.llvm.EngineBuilder.new(module._ptr)
return EngineBuilder(ptr)
def force_jit(self):
@ -158,10 +158,10 @@ class EngineBuilder(llvm.Wrapper):
'''
if args:
triple, march, mcpu, mattrs = args
ptr = self._ptr.select_target(triple, march, mcpu,
ptr = self._ptr.selectTarget(triple, march, mcpu,
mattrs.split(','))
else:
ptr = self._ptr.select_target()
ptr = self._ptr.selectTarget()
return TargetMachine(ptr)
@ -182,7 +182,8 @@ class ExecutionEngine(llvm.Wrapper):
self._ptr.DisableLazyCompilation(disabled)
def run_function(self, fn, args):
return self._ptr.runFunction(fn._ptr, map(lambda x: x._ptr, args))
ptr = self._ptr.runFunction(fn._ptr, map(lambda x: x._ptr, args))
return GenericValue(ptr)
def get_pointer_to_function(self, fn):
return self._ptr.getPointerToFunction(fn._ptr)
@ -195,13 +196,13 @@ class ExecutionEngine(llvm.Wrapper):
self._ptr.addGlobalMapping(gvar._ptr, addr)
def run_static_ctors(self):
self._ptr.runStaticConstructorDestructors(False)
self._ptr.runStaticConstructorsDestructors(False)
def run_static_dtors(self):
self._ptr.runStaticConstructorDestructors(True)
self._ptr.runStaticConstructorsDestructors(True)
def free_machine_code_for(self, fn):
self.freeMachineCodeForFunction(fn._ptr)
self._ptr.freeMachineCodeForFunction(fn._ptr)
def add_module(self, module):
self._ptr.addModule(module._ptr)
@ -222,17 +223,17 @@ def print_registered_targets():
'''
Note: print directly to stdout
'''
llvm.TargetRegistry.printRegisteredTargetsForVersion()
api.llvm.TargetRegistry.printRegisteredTargetsForVersion()
def get_host_cpu_name():
'''return the string name of the host CPU
'''
return llvm.sys.getHostCPUName()
return api.llvm.sys.getHostCPUName()
def get_default_triple():
'''return the target triple of the host in str-rep
'''
return llvm.sys.getDefaultTargetTriple()
return api.llvm.sys.getDefaultTargetTriple()
class TargetMachine(llvm.Wrapper):
@ -243,20 +244,20 @@ class TargetMachine(llvm.Wrapper):
triple = get_default_triple()
if not cpu:
cpu = get_host_cpu_name()
with contextlib.closing(StringIO) as error:
with contextlib.closing(StringIO()) as error:
target = api.llvm.TargetRegistry.lookupTarget(triple, error)
if not target:
raise llvm.LLVMException(error)
if not target.hasTargetMachine():
raise llvm.LLVMException(target, "No target machine.")
target_options = api.llvm.TargetOptions()
target_options = api.llvm.TargetOptions.new()
tm = target.createTargetMachine(triple, cpu, features,
target_options,
api.llvm.Reloc.Model.Default,
cm, opt)
if not tm:
raise llvm.LLVMException("Cannot create target machine")
return TargetMachine(ptr)
return TargetMachine(tm)
@staticmethod
def lookup(arch, cpu='', features='', opt=2, cm=CM_DEFAULT):
@ -272,24 +273,25 @@ class TargetMachine(llvm.Wrapper):
use: `llvm-as < /dev/null | llc -march=xyz -mattr=help`
'''
triple = api.llvm.Triple.new()
with contextlib.closing(StringIO) as error:
target = api.llvm.TargetMachine.lookupTarget(arch, triple, error)
with contextlib.closing(StringIO()) as error:
target = api.llvm.TargetRegistry.lookupTarget(arch, triple, error)
if not target:
raise llvm.LLVMException(error)
if not target.hasTargetMachine():
raise llvm.LLVMException(target, "No target machine.")
target_options = api.llvm.TargetOptions()
target_options = api.llvm.TargetOptions.new()
tm = target.createTargetMachine(str(triple), cpu, features,
target_options,
api.llvm.Reloc.Model.Default,
cm, opt)
if not tm:
raise llvm.LLVMException("Cannot create target machine")
return TargetMachine(ptr)
return TargetMachine(tm)
def _emit_file(self, module, cgft):
pm = api.llvm.PassManager.new()
os = api.extra.make_raw_ostream_for_printing()
os = extra.make_raw_ostream_for_printing()
pm.add(api.llvm.DataLayout.new(str(self.target_data)))
failed = self._ptr.addPassesToEmitFile(pm, os, cgft)
pm.run(module)
return os.str()
@ -298,19 +300,19 @@ class TargetMachine(llvm.Wrapper):
'''returns byte string of the module as assembly code of the target machine
'''
CGFT = api.llvm.TargetMachine.CodeGenFileType
return self._emit_file(module, CGFT.CGFT_AssemblyFile)
return self._emit_file(module._ptr, CGFT.CGFT_AssemblyFile)
def emit_object(self, module):
'''returns byte string of the module as native code of the target machine
'''
CGFT = api.llvm.TargetMachine.CodeGenFileType
return self._emit_file(module, CGFT.CGFT_ObjectFile)
return self._emit_file(module._ptr, CGFT.CGFT_ObjectFile)
@property
def target_data(self):
'''get target data of this machine
'''
return TargetData(self._ptr.getDataLayout)
return TargetData(self._ptr.getDataLayout())
@property
def target_name(self):

View file

@ -46,7 +46,7 @@ from llvmpy import api
class PassManagerBuilder(llvm.Wrapper):
@staticmethod
def new():
return PassManagerBuilder(api.llvm.PassManagerBuilder())
return PassManagerBuilder(api.llvm.PassManagerBuilder.new())
def populate(self, pm):
if isinstance(pm, FunctionPassManager):
@ -59,7 +59,7 @@ class PassManagerBuilder(llvm.Wrapper):
return self._ptr.OptLevel
@opt_level.setter
def _set_opt_level(self, optlevel):
def opt_level(self, optlevel):
self._ptr.OptLevel = optlevel
@property
@ -67,7 +67,7 @@ class PassManagerBuilder(llvm.Wrapper):
return self._ptr.SizeLevel
@size_level.setter
def _set_size_level(self, sizelevel):
def size_level(self, sizelevel):
self._ptr.SizeLevel = sizelevel
@property
@ -75,8 +75,9 @@ class PassManagerBuilder(llvm.Wrapper):
return self._ptr.Vectorize
@vectorize.setter
def _set_vectorize(self, enable):
self._ptr.Vectroize = enable
def vectorize(self, enable):
self._ptr.Vectorize = enable
@property
def loop_vectorize(self):
@ -142,10 +143,11 @@ class PassManager(llvm.Wrapper):
def _add_pass(self, pass_name):
passreg = api.llvm.PassRegistry.getPassRegistry()
a_pass = passreg.getPassInfo(pass_name)
a_pass = passreg.getPassInfo(pass_name).createPass()
if not a_pass:
assert pass_name not in PASSES, "Registered but not found?"
raise llvm.LLVMException('Invalid pass name "%s"' % pass_name)
print a_pass
self._ptr.add(a_pass)
def run(self, module):
@ -155,17 +157,17 @@ class FunctionPassManager(PassManager):
@staticmethod
def new(module):
ptr = api.llvm.FunctionPassManager.new(module)
ptr = api.llvm.FunctionPassManager.new(module._ptr)
return FunctionPassManager(ptr)
def __init__(self, ptr):
PassManager.__init__(self, ptr)
def initialize(self):
self._ptr.doInitization()
self._ptr.doInitialization()
def run(self, fn):
return self._ptr.run(fn)
return self._ptr.run(fn._ptr)
def finalize(self):
self._ptr.doFinalization()
@ -187,7 +189,7 @@ class Pass(llvm.Wrapper):
The error cannot be caught.
'''
passreg = api.llvm.PassRegistry.getPassRegistry()
a_pass = passreg.getPassInfo(pass_name)
a_pass = passreg.getPassInfo(name).createPass()
p = Pass(a_pass)
p.__name = name
return p
@ -196,7 +198,10 @@ class Pass(llvm.Wrapper):
def name(self):
'''The name used in PassRegistry.
'''
return p.__name
try:
return self.__name
except AttributeError:
return
@property
def description(self):
@ -235,7 +240,8 @@ class TargetData(Pass):
@property
def target_integer_type(self):
return self._ptr.core.IntegerType(core.Type.getInt32Ty())
context = api.llvm.getGlobalContext()
return api.llvm.IntegerType(api.llvm.Type.getInt32Ty(context))
def size(self, ty):
return self._ptr.getTypeSizeInBits(ty._ptr)
@ -256,15 +262,15 @@ class TargetData(Pass):
if isinstance(ty_or_gv, core.Type):
return self._ptr.getPrefTypeAlignment(ty_or_gv._ptr)
elif isinstance(ty_or_gv, core.GlobalVariable):
return self._ptr._core.getPreferredAlignment(ty_or_gv._ptr)
return self._ptr.getPreferredAlignment(ty_or_gv._ptr)
else:
raise core.LLVMException("argument is neither a type nor a global variable")
def element_at_offset(self, ty, ofs):
return self._ptr.getStructLayout(ty).getElementContainingOffset(ofs)
return self._ptr.getStructLayout(ty._ptr).getElementContainingOffset(ofs)
def offset_of_element(self, ty, el):
return self._ptr.getStructLayout(ty).getElementOffset(el)
return self._ptr.getStructLayout(ty._ptr).getElementOffset(el)
#===----------------------------------------------------------------------===
# Target Library Info
@ -277,6 +283,19 @@ class TargetLibraryInfo(Pass):
ptr = api.llvm.TargetLibraryInfo.new(triple)
return TargetLibraryInfo(ptr)
#===----------------------------------------------------------------------===
# Target Transformation Info
#===----------------------------------------------------------------------===
class TargetTransformInfo(Pass):
@staticmethod
def new(targetmachine):
scalartti = targetmachine._ptr.getScalarTargetTransformInfo()
vectortti = targetmachine._ptr.getVectorTargetTransformInfo()
ptr = api.llvm.TargetTransformInfo.new(scalartti, vectortti)
return TargetTransformInfo(ptr)
#===----------------------------------------------------------------------===
# Helpers
#===----------------------------------------------------------------------===

51
llvm/tbaa.py Normal file
View file

@ -0,0 +1,51 @@
from llvm.core import *
class TBAABuilder(object):
'''Simplify creation of TBAA metadata.
Each TBAABuidler object operates on a module.
User can create multiple TBAABuilder on a module
'''
def __init__(self, module, rootid):
'''
module --- the module to use.
root --- string name to identify the TBAA root.
'''
self.__module = module
self.__rootid = rootid
self.__rootmd = self.__new_md(rootid)
@classmethod
def new(cls, module, rootid):
return cls(module, rootid)
def get_node(self, name, parent=None, const=False):
'''Returns a MetaData object representing a TBAA node.
Use loadstore_instruction.set_metadata('tbaa', node) to
bind a type to a memory.
'''
parent = parent or self.root
const = Constant.int(Type.int(), int(bool(const)))
return self.__new_md(name, parent, const)
@property
def module(self):
return self.__module
@property
def root(self):
return self.__rootmd
@property
def root_name(self):
return self.__rootid
def __new_md(self, *args):
contents = list(args)
for i, v in enumerate(contents):
if isinstance(v, str):
contents[i] = MetaDataString.get(self.module, v)
return MetaData.get(self.module, contents)

1243
llvm/test_llvmpy.py Normal file

File diff suppressed because it is too large Load diff