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

+
+ +
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 @@
+
+ + + +
+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.

@@ -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= 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.