From 274f0f9ec4dd61223200ef3ecf8a870826635515 Mon Sep 17 00:00:00 2001
From: "mdevan.foobar"
Date: Sat, 14 Jun 2008 19:05:45 +0000
Subject: [PATCH] New tests. Code cleanup.
git-svn-id: http://llvm-py.googlecode.com/svn/trunk@11 8d1e9007-1d4e-0410-b67e-1979fd6579aa
---
CHANGELOG | 1 +
README | 15 +-
llvm/_core.c | 37 ++--
llvm/_util.py | 5 +-
llvm/core.py | 193 ++++++++++++++------
llvm/ee.py | 3 -
llvm/passes.py | 3 -
setup.py | 2 +-
test/testall.py | 381 ++++++++++++++++++++++++++++++++++++++++
www/makeweb.py | 2 +-
www/src/contribute.txt | 10 +-
www/src/index.txt | 6 +-
www/src/userguide.txt | 23 ++-
www/web/contribute.html | 37 +++-
www/web/index.html | 8 +-
www/web/userguide.html | 25 ++-
16 files changed, 638 insertions(+), 113 deletions(-)
create mode 100644 test/testall.py
diff --git a/CHANGELOG b/CHANGELOG
index 7c6034b..9e8dff6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,7 @@
* Python doc string documentation added (still incomplete)
* Many minor style/cosmetic changes and bug fixes
* Added documentation as on website into SVN
+ * Lots of cleanup
0.1, 10-May-2008:
diff --git a/README b/README
index d81f459..42b79d2 100644
--- a/README
+++ b/README
@@ -2,28 +2,23 @@
llvm-py: Python Bindings for LLVM
---------------------------------
+llvm-py provides Python bindings for LLVM.
+
Home page:
----------
- http://mdevan.nfshost.com/llvm-py.html
- http://code.google.com/p/llvm-py/
+ http://mdevan.nfshost.com/llvm-py/
Quickstart:
----------
- 1. Get 2.3svn version of LLVM, build it. 2.2 or earlier will *not* work.
- LLVM need not be installed.
+ 1. Get 2.3 version of LLVM, build it. 2.2 or earlier will *not* work.
2. Unpack llvm-py, build and install:
$ tar jxvf llvm-py-0.2.tar.bz2
$ cd llvm-py-0.2
-
- # if you've installed LLVM, and llvm-config is in the path
- $ sudo python setup.py install
-
- # if you've just built LLVM and not installed it, locate llvm-config,
- # usually under ../llvm/Release/bin
+ # Locate llvm-config, usually under /Release/bin
$ sudo python setup.py install --llvm-config=/path/to/llvm-config
3. See examples under 'test' directory.
diff --git a/llvm/_core.c b/llvm/_core.c
index 2b0748a..bb6ddba 100644
--- a/llvm/_core.c
+++ b/llvm/_core.c
@@ -355,7 +355,20 @@ _wrap_obj2obj(LLVMGetFunctionCallConv, LLVMValueRef, int)
_wrap_objint2none(LLVMSetFunctionCallConv, LLVMValueRef)
_wrap_obj2str(LLVMGetCollector, LLVMValueRef)
_wrap_objstr2none(LLVMSetCollector, LLVMValueRef)
-_wrap_objint2obj(LLVMVerifyFunction, LLVMValueRef, int)
+
+static PyObject *
+_wLLVMVerifyFunction(PyObject *self, PyObject *args)
+{
+ PyObject *obj;
+ LLVMValueRef fn;
+
+ if (!PyArg_ParseTuple(args, "O", &obj))
+ return NULL;
+
+ fn = (LLVMValueRef) PyCObject_AsVoidPtr(obj);
+ return ctor_int(LLVMVerifyFunction(fn, LLVMReturnStatusAction));
+}
+
/*===-- Arguments --------------------------------------------------------===*/
@@ -407,27 +420,6 @@ _wrap_objint2obj(LLVMGetIncomingBlock, LLVMValueRef, LLVMBasicBlockRef)
/*===-- Instruction builders ----------------------------------------------===*/
_wrap_none2obj(LLVMCreateBuilder, LLVMBuilderRef)
-
-static PyObject *
-_wLLVMPositionBuilder(PyObject *self, PyObject *args)
-{
- PyObject *obj1, *obj2, *obj3 = 0;
- LLVMBuilderRef builder;
- LLVMBasicBlockRef block;
- LLVMValueRef instr = NULL;
-
- if (!PyArg_ParseTuple(args, "OO|O", &obj1, &obj2, &obj3))
- return NULL;
-
- builder = (LLVMBuilderRef) (PyCObject_AsVoidPtr(obj1));
- block = (LLVMBasicBlockRef)(PyCObject_AsVoidPtr(obj2));
- if (obj3) /* optional */
- instr = (LLVMValueRef)(PyCObject_AsVoidPtr(obj3));
-
- LLVMPositionBuilder(builder, block, instr);
- Py_RETURN_NONE;
-}
-
_wrap_objobj2none(LLVMPositionBuilderBefore, LLVMBuilderRef, LLVMValueRef)
_wrap_objobj2none(LLVMPositionBuilderAtEnd, LLVMBuilderRef, LLVMBasicBlockRef)
_wrap_obj2obj(LLVMGetInsertBlock, LLVMBuilderRef, LLVMBasicBlockRef)
@@ -946,7 +938,6 @@ static PyMethodDef core_methods[] = {
/* Instruction builders */
_method( LLVMCreateBuilder )
- _method( LLVMPositionBuilder )
_method( LLVMPositionBuilderBefore )
_method( LLVMPositionBuilderAtEnd )
_method( LLVMGetInsertBlock )
diff --git a/llvm/_util.py b/llvm/_util.py
index bbbc23d..db6576e 100644
--- a/llvm/_util.py
+++ b/llvm/_util.py
@@ -13,6 +13,7 @@ import llvm
def _check_gen(obj, type):
if not isinstance(obj, type):
+ type_str = type.__name__
msg = "argument not an instance of llvm.core.%s" % type_str
raise TypeError, msg
@@ -51,7 +52,7 @@ def unpack_constants(objlist): return _unpack_gen(objlist, check_is_constant)
# we now return a list.
#===----------------------------------------------------------------------===
-def wrapiter(first, next, container, wrapper):
+def wrapiter(first, next, container, wrapper, extra=[]):
# ptr = first(container)
# while ptr:
# yield wrapper(ptr)
@@ -59,7 +60,7 @@ def wrapiter(first, next, container, wrapper):
ret = []
ptr = first(container)
while ptr:
- ret.append(wrapper(ptr))
+ ret.append(wrapper(ptr, *extra))
ptr = next(ptr)
return ret
diff --git a/llvm/core.py b/llvm/core.py
index ed979c0..15c8678 100644
--- a/llvm/core.py
+++ b/llvm/core.py
@@ -132,9 +132,6 @@ class Module(llvm.Ownable):
"""
llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeModule)
- def __del__(self):
- llvm.Ownable.__del__(self)
-
def __str__(self):
"""Text representation of a module.
@@ -212,7 +209,7 @@ class Module(llvm.Ownable):
# do stuff with gv
"""
return wrapiter(_core.LLVMGetFirstGlobal, _core.LLVMGetNextGlobal,
- self.ptr, GlobalVariable)
+ self.ptr, GlobalVariable, [self])
def add_function(self, ty, name):
"""Add a function of given type with given name."""
@@ -233,9 +230,13 @@ class Module(llvm.Ownable):
# do stuff with f
"""
return wrapiter(_core.LLVMGetFirstFunction,
- _core.LLVMGetNextFunction, self.ptr, Function)
+ _core.LLVMGetNextFunction, self.ptr, Function, [self])
def verify(self):
+ """Verify module.
+
+ Checks module for errors. Raises `llvm.LLVMException' on any
+ error."""
ret = _core.LLVMVerifyModule(self.ptr)
if ret != "":
raise llvm.LLVMException, ret
@@ -267,6 +268,7 @@ class Type(object):
elif bits == 64:
return _make_type(_core.LLVMInt64Type(), TYPE_INTEGER)
else:
+ bits = int(bits) # bits must be an int
return _make_type(_core.LLVMIntType(bits), TYPE_INTEGER)
@staticmethod
@@ -306,7 +308,8 @@ class Type(object):
check_is_type(return_ty)
var_arg = 1 if var_arg else 0 # convert to int
params = unpack_types(param_tys)
- return _make_type(_core.LLVMFunctionType(return_ty.ptr, params, var_arg), TYPE_FUNCTION)
+ return _make_type(_core.LLVMFunctionType(return_ty.ptr, params,
+ var_arg), TYPE_FUNCTION)
@staticmethod
def struct(element_tys): # not packed
@@ -314,7 +317,7 @@ class Type(object):
Creates a structure type with elements of types as given in the
iterable `element_tys'. This method creates a unpacked
- structure. For a packed one, use packed_struct() method."""
+ structure. For a packed one, use the packed_struct() method."""
elems = unpack_types(element_tys)
return _make_type(_core.LLVMStructType(elems, 0), TYPE_STRUCT)
@@ -324,42 +327,77 @@ class Type(object):
Creates a structure type with elements of types as given in the
iterable `element_tys'. This method creates a packed
- structure. For an unpacked one, use struct() method."""
+ structure. For an unpacked one, use the struct() method."""
elems = unpack_types(element_tys)
return _make_type(_core.LLVMStructType(elems, 1), TYPE_STRUCT)
@staticmethod
def array(element_ty, count):
+ """Create an array type.
+
+ Creates a type for an array of elements of type `element_ty',
+ having 'count' elements."""
check_is_type(element_ty)
- return _make_type(_core.LLVMArrayType(element_ty.ptr, count), TYPE_ARRAY)
+ count = int(count) # must be an int
+ return _make_type(_core.LLVMArrayType(element_ty.ptr, count),
+ TYPE_ARRAY)
@staticmethod
def pointer(pointee_ty, addr_space=0):
+ """Create a pointer type.
+
+ Creates a pointer type, which can point to values of type
+ `pointee_ty', in the address space `addr_space'."""
check_is_type(pointee_ty)
- return _make_type(_core.LLVMPointerType(pointee_ty.ptr, addr_space), TYPE_POINTER)
+ addr_space = int(addr_space) # must be an int
+ return _make_type(_core.LLVMPointerType(pointee_ty.ptr,
+ addr_space), TYPE_POINTER)
@staticmethod
def vector(element_ty, count):
+ """Create a vector type.
+
+ Creates a type for a vector of elements of type `element_ty',
+ having `count' elements."""
check_is_type(element_ty)
- return _make_type(_core.LLVMVectorType(element_ty.ptr, count), TYPE_VECTOR)
+ count = int(count) # must be an int
+ return _make_type(_core.LLVMVectorType(element_ty.ptr, count),
+ TYPE_VECTOR)
@staticmethod
def void():
+ """Create a void type.
+
+ Represents the `void' type."""
return _make_type(_core.LLVMVoidType(), TYPE_VOID)
@staticmethod
def label():
+ """Create a label type."""
return _make_type(_core.LLVMLabelType(), TYPE_LABEL)
@staticmethod
def opaque():
+ """Create an opaque type.
+
+ Opaque types are used to create self-referencing types."""
return _make_type(_core.LLVMOpaqueType(), TYPE_OPAQUE)
def __init__(self, ptr, kind):
+ """DO NOT CALL DIRECTLY.
+
+ Use one of the static methods instead."""
self.ptr = ptr
self.kind = kind
+ """An enum (int) value denoting which type this is.
+
+ Use the symbolic constants TYPE_* defined in llvm.core
+ module."""
def __str__(self):
+ """Text representation of a type.
+
+ Returns the textual representation (`llvm assembly') of the type."""
return _core.LLVMDumpTypeToString(self.ptr)
def __eq__(self, rhs):
@@ -369,10 +407,10 @@ class Type(object):
return False
def refine(self, dest):
- """Refine the abstract type represented by self to a concrete class.
+ """Refine the abstract type represented by self into a concrete class.
This object is no longer valid after refining, so do not hold references
- to it after calling."""
+ to it after calling. See the user guide for examples on how to use this."""
check_is_type(dest)
_core.LLVMRefineType(self.ptr, dest.ptr)
@@ -380,43 +418,62 @@ class Type(object):
class IntegerType(Type):
+ """Represents an integer type."""
def __init__(self, ptr, kind):
+ """DO NOT CALL DIRECTLY.
+
+ Use one of the static methods of the *base* class (Type) instead."""
Type.__init__(self, ptr, kind)
@property
def width(self):
+ """The width of the integer type, in bits."""
return _core.LLVMGetIntTypeWidth(self.ptr)
class FunctionType(Type):
+ """Represents a function type."""
def __init__(self, ptr, kind):
+ """DO NOT CALL DIRECTLY.
+
+ Use one of the static methods of the *base* class (Type) instead."""
Type.__init__(self, ptr, kind)
@property
def return_type(self):
+ """The type of the value returned by this function."""
ptr = _core.LLVMGetReturnType(self.ptr)
kind = _core.LLVMGetTypeKind(ptr)
return _make_type(ptr, kind)
@property
def vararg(self):
+ """True if this function is variadic."""
return _core.LLVMIsFunctionVarArg(self.ptr) != 0
@property
def args(self):
+ """An iterable that yields Type objects, representing the types of the
+ arguments accepted by this function, in order."""
pp = _core.LLVMGetFunctionTypeParams(self.ptr)
return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ]
@property
def arg_count(self):
+ """Number of arguments accepted by this function.
+
+ Same as len(obj.args), but faster."""
return _core.LLVMCountParamTypes(self.ptr)
class StructType(Type):
def __init__(self, ptr, kind):
+ """DO NOT CALL DIRECTLY.
+
+ Use one of the static methods of the *base* class (Type) instead."""
Type.__init__(self, ptr, kind)
@property
@@ -436,6 +493,9 @@ class StructType(Type):
class ArrayType(Type):
def __init__(self, ptr, kind):
+ """DO NOT CALL DIRECTLY.
+
+ Use one of the static methods of the *base* class (Type) instead."""
Type.__init__(self, ptr, kind)
@property
@@ -452,6 +512,9 @@ class ArrayType(Type):
class PointerType(Type):
def __init__(self, ptr, kind):
+ """DO NOT CALL DIRECTLY.
+
+ Use one of the static methods of the *base* class (Type) instead."""
Type.__init__(self, ptr, kind)
@property
@@ -462,6 +525,9 @@ class PointerType(Type):
class VectorType(Type):
def __init__(self, ptr, kind):
+ """DO NOT CALL DIRECTLY.
+
+ Use one of the static methods of the *base* class (Type) instead."""
Type.__init__(self, ptr, kind)
@property
@@ -602,12 +668,12 @@ class Constant(Value):
@staticmethod
def struct(consts): # not packed
const_ptrs = unpack_constants(consts)
- return Constant(_core.LLVMConstStruct(consts, 0))
+ return Constant(_core.LLVMConstStruct(const_ptrs, 0))
@staticmethod
def packed_struct(consts):
const_ptrs = unpack_constants(consts)
- return Constant(_core.LLVMConstStruct(consts, 1))
+ return Constant(_core.LLVMConstStruct(const_ptrs, 1))
@staticmethod
def vector(consts):
@@ -770,7 +836,7 @@ class Constant(Value):
check_is_constant(index)
return Constant(_core.LLVMConstInsertElement(self.ptr, value.ptr, index.ptr))
- def shuffle_element(self, vector_b, mask): # note: self must be a _vector_ constant
+ def shuffle_vector(self, vector_b, mask): # note: self must be a _vector_ constant
check_is_constant(vector_b) # note: vector_b must be a _vector_ constant
check_is_constant(mask)
return Constant(_core.LLVMConstShuffleVector(self.ptr, vector_b.ptr, mask.ptr))
@@ -778,8 +844,13 @@ class Constant(Value):
class GlobalValue(Constant):
- def __init__(self, ptr):
+ def __init__(self, ptr, module):
Constant.__init__(self, ptr)
+ self._module = module # hang on to the module
+
+ def _delete(self):
+ self._module = None # set it free
+ self.ptr = None
def get_linkage(self): return _core.LLVMGetLinkage(self.ptr)
def set_linkage(self, value): _core.LLVMSetLinkage(self.ptr, value)
@@ -799,13 +870,11 @@ class GlobalValue(Constant):
@property
def is_declaration(self):
- return _core.LLVMIsDeclaration(self.ptr)
+ return _core.LLVMIsDeclaration(self.ptr) != 0
@property
def module(self):
- mod = Module(_core.LLVMGetGlobalParent(self.ptr))
- owner = dummy_owner(mod)
- return mod
+ return self._module
class GlobalVariable(GlobalValue):
@@ -813,18 +882,18 @@ class GlobalVariable(GlobalValue):
@staticmethod
def new(module, ty, name):
check_is_type(ty)
- return GlobalVariable(_core.LLVMAddGlobal(module.ptr, ty.ptr, name))
+ return GlobalVariable(_core.LLVMAddGlobal(module.ptr, ty.ptr, name), module)
@staticmethod
def get(module, name):
- return GlobalVariable(_core.LLVMGetNamedGlobal(module.ptr, name))
+ return GlobalVariable(_core.LLVMGetNamedGlobal(module.ptr, name), module)
- def __init__(self, ptr):
- GlobalValue.__init__(self, ptr)
+ def __init__(self, ptr, module):
+ GlobalValue.__init__(self, ptr, module)
def delete(self):
_core.LLVMDeleteGlobal(self.ptr)
- self.ptr = None
+ self._delete()
def get_initializer(self):
if _core.LLVMHasInitializer(self.ptr):
@@ -862,27 +931,23 @@ class Argument(Value):
def set_alignment(self, align):
_core.LLVMSetParamAlignment(self.ptr, align)
- @property
- def function(self):
- return Function(_core.LLVMGetParamParent(self.ptr))
-
class Function(GlobalValue):
@staticmethod
def new(module, func_ty, name):
- return Function(_core.LLVMAddFunction(module.ptr, name, func_ty.ptr))
+ return Function(_core.LLVMAddFunction(module.ptr, name, func_ty.ptr), module)
@staticmethod
def get(module, name):
- return Function(_core.LLVMGetNamedFunction(module.ptr, name))
+ return Function(_core.LLVMGetNamedFunction(module.ptr, name), module)
- def __init__(self, ptr):
- GlobalValue.__init__(self, ptr)
+ def __init__(self, ptr, module):
+ GlobalValue.__init__(self, ptr, module)
def delete(self):
_core.LLVMDeleteFunction(self.ptr)
- self.ptr = None
+ self._delete()
@property
def intrinsic_id(self):
@@ -906,6 +971,8 @@ class Function(GlobalValue):
return _core.LLVMCountBasicBlocks(self.ptr)
def get_entry_basic_block(self):
+ if self.basic_block_count == 0:
+ return None
return BasicBlock(_core.LLVMGetEntryBasicBlock(self.ptr))
def append_basic_block(self, name):
@@ -917,6 +984,8 @@ class Function(GlobalValue):
_core.LLVMGetNextBasicBlock, self.ptr, BasicBlock)
def verify(self):
+ # Although we're just asking LLVM to return the success or
+ # failure, it appears to print result to stderr and abort.
return _core.LLVMVerifyFunction(self.ptr) != 0
@@ -939,8 +1008,8 @@ class CallOrInvokeInstruction(Instruction):
def __init__(self, ptr):
Instruction.__init__(self, ptr)
- def get_calling_convention(self): return _core.LLVMGetFunctionCallConv(self.ptr)
- def set_calling_convention(self, value): _core.LLVMSetFunctionCallConv(self.ptr, value)
+ def get_calling_convention(self): return _core.LLVMGetInstructionCallConv(self.ptr)
+ def set_calling_convention(self, value): _core.LLVMSetInstructionCallConv(self.ptr, value)
calling_convention = property(get_calling_convention, set_calling_convention)
def add_parameter_attribute(self, idx, attr):
@@ -1020,8 +1089,11 @@ class BasicBlock(Value):
class Builder(object):
@staticmethod
- def new():
- return Builder(_core.LLVMCreateBuilder())
+ def new(basic_block):
+ check_is_basic_block(basic_block)
+ b = Builder(_core.LLVMCreateBuilder())
+ b.position_at_end(basic_block)
+ return b
def __init__(self, ptr):
self.ptr = ptr
@@ -1029,22 +1101,34 @@ class Builder(object):
def __del__(self):
_core.LLVMDisposeBuilder(self.ptr)
- def position(self, block, instr=None):
- if instr:
- _core.LLVMPositionBuilder(self.ptr, block.ptr, instr.ptr)
- else:
- _core.LLVMPositionBuilder(self.ptr, block.ptr)
-
- def position_before(self, instr):
- _core.LLVMPositionBuilderBefore(self.ptr, instr.ptr)
+ def position_at_beginning(self, bblk):
+ """Position the builder at the beginning of the given block.
+ Next instruction inserted will be first one in the block."""
+ # Avoids using "blk.instructions", which will fetch all the
+ # instructions into a list. Don't try this at home, though.
+ first_inst = Instruction(_core.LLVMGetFirstInstruction(self.block.ptr))
+ self.position_before(first_inst)
+
def position_at_end(self, bblk):
+ """Position the builder at the end of the given block.
+
+ Next instruction inserted will be last one in the block."""
_core.LLVMPositionBuilderAtEnd(self.ptr, bblk.ptr)
+ def position_before(self, instr):
+ """Position the builder before the given instruction.
+
+ The instruction can belong to a basic block other than the
+ current one."""
+ _core.LLVMPositionBuilderBefore(self.ptr, instr.ptr)
+
@property
- def insert_block(self):
+ def block(self):
return BasicBlock(_core.LLVMGetInsertBlock(self.ptr))
+ # terminator instructions
+
def ret_void(self):
return Instruction(_core.LLVMBuildRetVoid(self.ptr))
@@ -1084,7 +1168,7 @@ class Builder(object):
def unreachable(self):
return Instruction(_core.LLVMBuildUnreachable(self.ptr))
- # arithmethic-related
+ # arithmethic, bitwise and logical
def add(self, lhs, rhs, name=""):
check_is_value(lhs)
@@ -1207,7 +1291,7 @@ class Builder(object):
index_ptrs = unpack_values(indices)
return Value(_core.LLVMBuildGEP(self.ptr, ptr.ptr, index_ptrs, name))
- # casts
+ # casts and extensions
def trunc(self, value, dest_ty, name=""):
check_is_value(value)
@@ -1306,11 +1390,11 @@ class Builder(object):
arg_ptrs = unpack_values(args)
return CallOrInvokeInstruction(_core.LLVMBuildCall(self.ptr, fn.ptr, arg_ptrs, name))
- def select(self, if_blk, then_blk, else_blk, name=""):
- check_is_basic_block(if_blk)
+ def select(self, cond, then_blk, else_blk, name=""):
+ check_is_value(cond)
check_is_basic_block(then_blk)
check_is_basic_block(else_blk)
- return Value(_core.LLVMBuildSelect(self.ptr, if_blk.ptr, then_blk.ptr, else_blk.ptr, name))
+ return Value(_core.LLVMBuildSelect(self.ptr, cond.ptr, then_blk.ptr, else_blk.ptr, name))
def vaarg(self, list_val, ty, name=""):
check_is_value(list_val)
@@ -1356,9 +1440,6 @@ class ModuleProvider(llvm.Ownable):
# a module provider is both a owner (of modules) and an ownable
# (can be owned by execution engines)
- def __del__(self):
- llvm.Ownable.__del__(self)
-
#===----------------------------------------------------------------------===
# Memory buffer
diff --git a/llvm/ee.py b/llvm/ee.py
index 2dafb8c..dc56077 100644
--- a/llvm/ee.py
+++ b/llvm/ee.py
@@ -21,9 +21,6 @@ class TargetData(llvm.Ownable):
def __init__(self, ptr):
llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeTargetData)
- def __del__(self):
- llvm.Ownable.__del__(self)
-
def __str__(self):
return _core.LLVMTargetDataAsString(self.ptr)
diff --git a/llvm/passes.py b/llvm/passes.py
index fff381b..b976926 100644
--- a/llvm/passes.py
+++ b/llvm/passes.py
@@ -78,9 +78,6 @@ class FunctionPassManager(PassManager):
def __init__(self, ptr):
PassManager.__init__(self, ptr)
- def __del__(self):
- PassManager.__del__(self)
-
def initialize(self):
_core.LLVMInitializeFunctionPassManager(self.ptr)
diff --git a/setup.py b/setup.py
index a376d82..74a3dbe 100644
--- a/setup.py
+++ b/setup.py
@@ -68,7 +68,7 @@ def call_setup(llvm_config):
description='Python Bindings for LLVM',
author='Mahadevan R',
author_email='mdevan.foobar@gmail.com',
- url='http://code.google.com/p/llvm-py/',
+ url='http://mdevan.nfshost.com/llvm-py/',
packages=['llvm'],
py_modules = [ 'llvm.core' ],
ext_modules = [ ext_core ],)
diff --git a/test/testall.py b/test/testall.py
new file mode 100644
index 0000000..f9e21de
--- /dev/null
+++ b/test/testall.py
@@ -0,0 +1,381 @@
+#!/usr/bin/env python
+
+#
+# This script attempts to achieve 100% function and branch coverage for
+# all APIs in the llvm package. It only exercises the APIs, doesn't test
+# them for correctness.
+#
+
+from llvm import *
+from llvm.core import *
+
+ti = Type.int()
+
+def do_module():
+ print " Testing class Module"
+ m = Module.new('test')
+ m.target = 'a'
+ a = m.target
+ m.data_layout = 'a'
+ a = m.data_layout
+ m.add_type_name('a', ti)
+ m.delete_type_name('a')
+ s = str(m)
+ s = m == Module.new('a')
+ m.add_global_variable(ti, 'b')
+ m.get_global_variable_named('b')
+ gvs = list(m.global_variables)
+ ft = Type.function(ti, [ti])
+ m.add_function(ft, "func")
+ m.get_function_named("func")
+ fns = list(m.functions)
+ try:
+ m.verify()
+ except LLVMException:
+ pass
+
+
+def do_type():
+ print " Testing class Type"
+ for i in range(1,100):
+ Type.int(i)
+ Type.float()
+ Type.double()
+ Type.x86_fp80()
+ Type.fp128()
+ Type.ppc_fp128()
+ Type.function(ti, [ti]*100, True)
+ Type.function(ti, [ti]*100, False)
+ Type.struct([ti]*100)
+ Type.packed_struct([ti]*100)
+ Type.array(ti, 100)
+ Type.pointer(ti, 4)
+ Type.vector(ti, 100)
+ Type.void()
+ Type.label()
+ Type.opaque()
+ s = str(ti)
+ s = ti == Type.float()
+ Type.opaque().refine(Type.int())
+ s = ti.width
+ ft = Type.function(ti, [ti]*10)
+ ft.return_type
+ ft.vararg
+ s = list(ft.args)
+ ft.arg_count
+ st = Type.struct([ti]*10)
+ s = st.element_count
+ s = list(st.elements)
+ s = st.packed
+ st = Type.packed_struct([ti]*10)
+ s = st.element_count
+ s = list(st.elements)
+ s = st.packed
+ at = Type.array(ti, 100)
+ s = at.element
+ s = at.count
+ pt = Type.pointer(ti, 10)
+ pt.address_space
+ vt = Type.vector(ti, 100)
+ s = vt.element
+ s = vt.count
+
+
+def do_typehandle():
+ print " Testing class TypeHandle"
+ th = TypeHandle.new(Type.opaque())
+ ts = Type.struct([ Type.int(), Type.pointer(th.type) ])
+ th.type.refine(ts)
+
+
+def do_value():
+ print " Testing class Value"
+ k = Constant.int(ti, 42)
+ k.name = 'a'
+ s = k.name
+ t = s.type
+ s = str(k)
+ s = k == Constant.int(ti, 43)
+
+
+def do_constant():
+ print " Testing class Constant"
+ Constant.null(ti)
+ Constant.all_ones(ti)
+ Constant.undef(ti)
+ Constant.int(ti, 10)
+ Constant.int_signextend(ti, 10)
+ Constant.real(Type.float(), "10.0")
+ Constant.real(Type.float(), 3.14)
+ Constant.string("test")
+ Constant.stringz("test2")
+ Constant.array(ti, [Constant.int(ti,42)]*10)
+ Constant.struct([Constant.int(ti,42)]*10)
+ Constant.packed_struct([Constant.int(ti,42)]*10)
+ Constant.vector([Constant.int(ti,42)]*10)
+ Constant.sizeof(ti)
+ k = Constant.int(ti, 10)
+ f = Constant.real(Type.float(), 3.1415)
+ k.neg().not_().add(k).sub(k).mul(k).udiv(k).sdiv(k).urem(k)
+ k.srem(k).and_(k).or_(k).icmp(IPRED_ULT, k)
+ f.fdiv(f).frem(f).fcmp(RPRED_ULT, f)
+ vi = Constant.vector([Constant.int(ti,42)]*10)
+ vi.vicmp(IPRED_ULT, vi)
+ vf = Constant.vector([Constant.real(Type.float(), 3.14)]*10)
+ vf.vfcmp(RPRED_ULT, vf)
+ k.shl(k).lshr(k).ashr(k)
+ # TODO gep
+ k.trunc(Type.int(1))
+ k.sext(Type.int(64))
+ k.zext(Type.int(64))
+ Constant.real(Type.double(), 1.0).fptrunc(Type.float())
+ Constant.real(Type.float(), 1.0).fpext(Type.double())
+ k.uitofp(Type.float())
+ k.sitofp(Type.float())
+ f.fptoui(ti)
+ f.fptosi(ti)
+ p = Type.pointer(ti)
+ # TODO ptrtoint
+ k.inttoptr(p)
+ f.bitcast(Type.int(32))
+ k.trunc(Type.int(1)).select(k, k)
+ vi.extract_element( Constant.int(ti,0) )
+ vi.insert_element( k, k )
+ vi.shuffle_vector( vi, vi )
+
+
+def do_global_value():
+ print " Testing class GlobalValue"
+ m = Module.new('a')
+ gv = GlobalVariable.new(m, Type.int(), 'b')
+ s = gv.is_declaration
+ m = gv.module
+ s = gv.is_declaration
+ gv.linkage = LINKAGE_EXTERNAL
+ s = gv.linkage
+ gv.section = '.text'
+ s = gv.section
+ gv.visibility = VISIBILITY_HIDDEN
+ s = gv.visibility
+ gv.alignment = 8
+ s = gv.alignment
+
+
+def do_global_variable():
+ print " Testing class GlobalVariable"
+ m = Module.new('a')
+ gv = GlobalVariable.new(m, Type.int(), 'b')
+ gv = GlobalVariable.get(m, 'b')
+ gv.delete()
+ gv = GlobalVariable.new(m, Type.int(), 'c')
+ gv.initializer = Constant.int( ti, 10 )
+ s = gv.initializer
+ gv.global_constant = True
+ s = gv.global_constant
+
+
+def do_argument():
+ print " Testing class Argument"
+ m = Module.new('a')
+ ft = Type.function(ti, [ti])
+ f = Function.new(m, ft, 'func')
+ a = f.args[0]
+ a.add_attribute(ATTR_ZEXT)
+ a.remove_attribute(ATTR_ZEXT)
+ a.set_alignment(4)
+
+
+def do_function():
+ print " Testing class Function"
+ ft = Type.function(ti, [ti]*20)
+ zz = Function.new(Module.new('z'), ft, 'foobar')
+ del zz
+ Function.new(Module.new('zz'), ft, 'foobar')
+ m = Module.new('a')
+ f = Function.new(m, ft, 'func')
+ f.delete()
+ ft = Type.function(ti, [ti]*20)
+ f = Function.new(m, ft, 'func2')
+ g = f.intrinsic_id
+ f.calling_convenion = CC_FASTCALL
+ g = f.calling_convenion
+ f.collector = 'a'
+ c = f.collector
+ a = list(f.args)
+ g = f.basic_block_count
+ g = f.get_entry_basic_block()
+ g = f.append_basic_block('a')
+ g = f.get_entry_basic_block()
+ g = list(f.basic_blocks)
+ # LLVM misbehaves:
+ #try:
+ # f.verify()
+ #except LLVMException:
+ # pass
+
+
+def do_instruction():
+ print " Testing class Instruction"
+ m = Module.new('a')
+ ft = Type.function(ti, [ti]*20)
+ f = Function.new(m, ft, 'func')
+ b = f.append_basic_block('a')
+ bb = Builder.new(b)
+ i = bb.ret_void()
+ bb2 = i.basic_block
+
+
+def do_callorinvokeinstruction():
+ print " Testing class CallOrInvokeInstruction"
+ m = Module.new('a')
+ ft = Type.function(ti, [ti])
+ f = Function.new(m, ft, 'func')
+ b = f.append_basic_block('a')
+ bb = Builder.new(b)
+ i = bb.invoke(f, [Constant.int(ti, 10)], b, b)
+ a = i.calling_convention
+ i.calling_convention = CC_FASTCALL
+ i.add_parameter_attribute(0, ATTR_SEXT)
+ i.remove_parameter_attribute(0, ATTR_SEXT)
+ i.set_parameter_alignment(0, 8)
+
+
+def do_phinode():
+ print " Testing class PhiNode"
+ m = Module.new('a')
+ ft = Type.function(ti, [ti])
+ f = Function.new(m, ft, 'func')
+ b = f.append_basic_block('b')
+ c = f.append_basic_block('c')
+ d = f.append_basic_block('d')
+ bb = Builder.new(d)
+ p = bb.phi(ti)
+ v = p.incoming_count
+ p.add_incoming( Constant.int(ti, 10), b )
+ p.add_incoming( Constant.int(ti, 10), c )
+ p.get_incoming_value(0)
+ p.get_incoming_block(0)
+
+
+def do_switchinstruction():
+ print " Testing class SwitchInstruction"
+ m = Module.new('a')
+ ft = Type.function(ti, [ti])
+ f = Function.new(m, ft, 'func')
+ b = f.append_basic_block('b')
+ bb = Builder.new(b)
+ s = bb.switch(f.args[0], b)
+ s.add_case(Constant.int(ti, 10), b)
+
+
+def do_builder():
+ print " Testing class Builder"
+ m = Module.new('a')
+ ft = Type.function(ti, [ti])
+ f = Function.new(m, ft, 'func')
+ blk = f.append_basic_block('b')
+ b = Builder.new(blk)
+ b.ret(Constant.int(ti, 10))
+ b.position_at_beginning(blk)
+ b.position_at_end(blk)
+ b.position_before(blk.instructions[0])
+ blk2 = b.block
+ b.ret_void()
+ b.ret(Constant.int(ti, 10))
+ b.ret_many([Constant.int(ti, 10)]*10)
+ b.branch(blk)
+ b.cbranch(Constant.int(Type.int(1), 1), blk, blk)
+ b.switch(f.args[0], blk)
+ b.invoke(f, [Constant.int(ti,10)], blk, blk)
+ b.unwind()
+ b.unreachable()
+ v = f.args[0]
+ fv = Constant.real(Type.float(), "1.0")
+ k = Constant.int(ti, 10)
+ b.add(v, v)
+ b.sub(v, v)
+ b.mul(v, v)
+ b.udiv(v, v)
+ b.sdiv(v, v)
+ b.fdiv(fv, fv)
+ b.urem(v, v)
+ b.srem(v, v)
+ b.frem(fv, fv)
+ b.shl(v, k)
+ b.lshr(v, k)
+ b.ashr(v, k)
+ b.and_(v, v)
+ b.or_(v, v)
+ b.xor(v, v)
+ b.neg(v)
+ b.not_(v)
+ p = b.malloc(Type.int())
+ b.malloc_array(Type.int(), k)
+ b.alloca(Type.int())
+ b.alloca_array(Type.int(), k)
+ b.free(p)
+ b.load(p)
+ b.store(k, p)
+ # TODO gep
+ b.trunc(v, Type.int(1))
+ b.zext(v, Type.int(64))
+ b.sext(v, Type.int(64))
+ b.fptoui(fv, ti)
+ b.fptosi(fv, ti)
+ b.uitofp(k, Type.float())
+ b.sitofp(k, Type.float())
+ b.fptrunc(Constant.real(Type.double(), "1.0"), Type.float())
+ b.fpext(Constant.real(Type.float(), "1.0"), Type.double())
+ b.ptrtoint(p, ti)
+ b.inttoptr(k, Type.pointer(Type.int()))
+ b.bitcast(v, Type.float())
+ b.icmp(IPRED_ULT, v, v)
+ b.fcmp(RPRED_ULT, fv, fv)
+ vi = Constant.vector([Constant.int(ti,42)]*10)
+ b.vicmp(IPRED_ULT, vi, vi)
+ vf = Constant.vector([Constant.real(Type.float(), 3.14)]*10)
+ b.vfcmp(RPRED_ULT, vf, vf)
+ # TODO b.getresult(v, 0)
+ b.call(f, [v])
+ b.select(Constant.int(Type.int(1), 1), blk, blk)
+ b.vaarg(v, Type.int())
+ b.extract_element(vi, v)
+ b.insert_element(vi, v, v)
+ b.shuffle_vector(vi, vi, vi)
+ # NOTE: phi nodes without incoming values segfaults in LLVM during
+ # destruction.
+ i = b.phi(Type.int())
+ i.add_incoming(v, blk)
+
+
+def do_moduleprovider():
+ print " Testing class ModuleProvider"
+ m = Module.new('a')
+ mp = ModuleProvider.new(m)
+
+
+def do_llvm_core():
+ print " Testing module llvm.core"
+ do_module()
+ do_type()
+ do_typehandle()
+ do_constant()
+ do_global_value()
+ do_global_variable()
+ do_argument()
+ do_function()
+ do_instruction()
+ do_callorinvokeinstruction()
+ do_phinode()
+ do_switchinstruction()
+ do_builder()
+ do_moduleprovider()
+
+
+def do_llvm():
+ print "Testing package llvm"
+ do_llvm_core()
+
+
+do_llvm()
+
diff --git a/www/makeweb.py b/www/makeweb.py
index 2ff59c8..7dc334e 100755
--- a/www/makeweb.py
+++ b/www/makeweb.py
@@ -6,7 +6,7 @@ from string import Template
from optparse import OptionParser
# files in src dir that should not be copied to web dir
-SKIP_FILES = [ 'layout.conf', '.svn' ]
+SKIP_FILES = [ 'layout.conf', '.svn', 'instrset.inc' ]
# asciidoc command line
ASCIIDOC = 'asciidoc --unsafe --conf-file=${srcdir}/layout.conf -a icons -o ${outfile} ${infile}'
diff --git a/www/src/contribute.txt b/www/src/contribute.txt
index 06de8c7..01cbe9b 100644
--- a/www/src/contribute.txt
+++ b/www/src/contribute.txt
@@ -11,7 +11,6 @@ Browse SVN, http://code.google.com/p/llvm-py/source/browse/[http://code.google.c
Issues tracker, http://code.google.com/p/llvm-py/issues/list[http://code.google.com/p/llvm-py/issues/list]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
SVN HEAD can be checked out like so:
----
@@ -21,3 +20,12 @@ $ svn checkout http://llvm-py.googlecode.com/svn/trunk/ llvm-py
Mahadevan R (mdevan.foobar@gmail.com) is available to answer your
queries.
+Current Next Steps
+------------------
+
+- Wrap GenericValue, function call args for execution engine.
+- Add APIs to read/write `.bc` and `.ll` files.
+- Wrap `lto`.
+- Add examples.
+- Update documentation.
+- Improve tests.
diff --git a/www/src/index.txt b/www/src/index.txt
index 4dc1761..173280e 100644
--- a/www/src/index.txt
+++ b/www/src/index.txt
@@ -6,9 +6,11 @@ http://llvm.org/[LLVM]. It's goal is to expose enough of LLVM APIs to
implement a compiler or VM in pure Python. Currently, llvm-py is
available for LLVM 2.3 and Python 2.5, on Linux/x86. It is expected to
be usable on various unices, as well as with Python 2.4, with minimal
-changes, if any. It should be stable enough for you to play with.
+changes, if any.
-llvm-py is just hatching, and your contributions would be most welcome.
+llvm-py is just hatching. It should be stable enough to start hacking
+away, though. Be sure to send in a patch (or shout at the author) if you
+miss any specific LLVM API.
News
----
diff --git a/www/src/userguide.txt b/www/src/userguide.txt
index a22a2fb..11cd455 100644
--- a/www/src/userguide.txt
+++ b/www/src/userguide.txt
@@ -1,6 +1,8 @@
llvm-py User Guide
===================
+NOTE: This document is updated constantly. Check back often.
+
llvm-py provides Python bindings for LLVM. This document explains how
you can setup and use it. A working knowledge of Python and a basic idea
of LLVM is assumed.
@@ -46,7 +48,7 @@ llvm-py is distributed as a source tarball. You'll need to build and
install it before it can be used. At least the following will be
required for this:
-- compilers, both gcc and g++
+- C and C\+\+ compilers (gcc/g\+\+)
- Python itself
- Python development files (headers and libraries)
- LLVM, either installed or built
@@ -56,7 +58,11 @@ command `sudo apt-get install gcc g++ python python-dev'. Note that
ubuntu repository has an old version of llvm (1.8) which will not work
with llvm-py.
-Tip: If LLVM 2.3 does not install cleanly, try installing 'ocamldoc'
+It does not matter which compiler LLVM itself was built with (g\+\+,
+llvm-g\+\+ or any other); llvm-py can be built with any compiler. It has
+been tried only with gcc/g\+\+ though.
+
+Tip: If LLVM 2.3 does not install cleanly, try installing ``ocamldoc''
first.
@@ -108,11 +114,16 @@ libraries of LLVM, use this:
$ tar jxvf llvm-py-0.2.tar.bz2
$ cd llvm-py-0.2
$ python setup.py build -g --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config
-$ sudo python setup.py install -g --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config
+$ sudo python setup.py install --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config
-----------------------------------------------------------------------
Be warned that debug binaries will be huge (65MB+) !
+`setup.py` is a standard Python distutils script. See the Python
+documentation regarding http://docs.python.org/inst/inst.html[Installing
+Python Modules] and http://docs.python.org/dist/dist.html[Distributing
+Python Modules] for more information on such scripts.
+
[[uninstall]]
Uninstall
@@ -891,6 +902,12 @@ r3 = Constant.undef() # an `undefined' value
source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TypeHandle (llvm.core)
+~~~~~~~~~~~~~~~~~~~~~~
+
+TODO
+
+
Instructions (llvm.core)
~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/www/web/contribute.html b/www/web/contribute.html
index a8ecef7..dede335 100644
--- a/www/web/contribute.html
+++ b/www/web/contribute.html
@@ -81,10 +81,45 @@ cellspacing="0" cellpadding="4">
queries.
+Current Next Steps
+
+
+-
+
+Wrap GenericValue, function call args for execution engine.
+
+
+-
+
+Add APIs to read/write .bc and .ll files.
+
+
+-
+
+Wrap lto.
+
+
+-
+
+Add examples.
+
+
+-
+
+Update documentation.
+
+
+-
+
+Improve tests.
+
+
+
+
diff --git a/www/web/index.html b/www/web/index.html
index 80126bc..5cfe28c 100644
--- a/www/web/index.html
+++ b/www/web/index.html
@@ -40,8 +40,10 @@
implement a compiler or VM in pure Python. Currently, llvm-py is
available for LLVM 2.3 and Python 2.5, on Linux/x86. It is expected to
be usable on various unices, as well as with Python 2.4, with minimal
-changes, if any. It should be stable enough for you to play with.
-llvm-py is just hatching, and your contributions would be most welcome.
+changes, if any.
+llvm-py is just hatching. It should be stable enough to start hacking
+away, though. Be sure to send in a patch (or shout at the author) if you
+miss any specific LLVM API.
News
@@ -60,7 +62,7 @@ changes, if any. It should be stable enough for you to play with.
diff --git a/www/web/userguide.html b/www/web/userguide.html
index 421d378..3ad4794 100644
--- a/www/web/userguide.html
+++ b/www/web/userguide.html
@@ -35,6 +35,14 @@
+
+
+
+
+ |
+This document is updated constantly. Check back often. |
+
+
llvm-py provides Python bindings for LLVM. This document explains how
you can setup and use it. A working knowledge of Python and a basic idea
of LLVM is assumed.
@@ -73,7 +81,7 @@ required for this:
-
-compilers, both gcc and g++
+C and C++ compilers (gcc/g++)
-
@@ -96,7 +104,10 @@ LLVM, either installed or built
command `sudo apt-get install gcc g++ python python-dev'. Note that
ubuntu repository has an old version of llvm (1.8) which will not work
with llvm-py.
-
Tip: If LLVM 2.3 does not install cleanly, try installing ocamldoc
+
It does not matter which compiler LLVM itself was built with (g++,
+llvm-g++ or any other); llvm-py can be built with any compiler. It has
+been tried only with gcc/g++ though.
+Tip: If LLVM 2.3 does not install cleanly, try installing “ocamldoc”
first.
llvm-config
Inorder to build llvm-py, it's build script needs to know from where to
@@ -136,9 +147,13 @@ libraries of LLVM, use this:
$ tar jxvf llvm-py-0.2.tar.bz2
$ cd llvm-py-0.2
$ python setup.py build -g --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config
-$ sudo python setup.py install -g --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config
+$ sudo python setup.py install --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config
Be warned that debug binaries will be huge (65MB+) !
+setup.py is a standard Python distutils script. See the Python
+documentation regarding Installing
+Python Modules and Distributing
+Python Modules for more information on such scripts.
Uninstall
To get rid of llvm-py completely, if you wish to do so:
@@ -1659,6 +1674,8 @@ r2 = Constant
r3 = Constant.undef() # an `undefined' value
+TypeHandle (llvm.core)
+TODO
Instructions (llvm.core)
TODO
Basic Block (llvm.core)
@@ -1702,7 +1719,7 @@ reached at mdevan.foobar@gmail.com.