diff --git a/llvm_array/__init__.py b/llvm_array/__init__.py new file mode 100644 index 0000000..f6a0f3f --- /dev/null +++ b/llvm_array/__init__.py @@ -0,0 +1,2 @@ +from __future__ import absolute_imports +from .array.py import * diff --git a/llvm_array/array.py b/llvm_array/array.py new file mode 100644 index 0000000..12df60e --- /dev/null +++ b/llvm_array/array.py @@ -0,0 +1,144 @@ +# This should be moved to llvmpy +# +# There are different array kinds parameterized by eltype and nd +# +# Contiguous or Fortran +# struct { +# eltype *data; +# intp shape[nd]; +# } contiguous_array(eltype, nd) +# +# struct { +# eltype *data; +# diminfo shape[nd]; +# } strided_array(eltype, nd) +# +# struct { +# eltype *data; +# intp shape[nd]; +# intp stride[nd]; +# } strided_soa_array(eltype, nd) +# +# struct { +# intp dim; +# intp stride; +#} diminfo +# + +import llvm.core as lc +from llvm.core import Type +import llvm_cbuilder.shortnames as C + +CONTIGUOUS = 1 << 8 +STRIDED = CONTIGUOUS + 1 +STRIDED_SOA = CONTIGUOUS + 2 + +array_kinds = (CONTIGUOUS, STRIDED, STRIDED_SOA) + +void_type = C.void +int_type = C.int +char_type = C.char +int16_type = C.int16 +intp_type = C.intp + +diminfo_type = Type.struct([intp_type, # shape + intp_type # stride + ], name='diminfo') + +# This is the way we define LLVM arrays. +def cont_array_type(nd, el_type=char_type, name=''): + terms = [Type.pointer(el_type), # data + Type.array(intp_type, nd) # shape + ] + return Type.struct(terms, name=name) + +def strided_array_type(nd, el_type=char_type, name=''): + terms = [Type.pointer(el_type), # data + Type.array(diminfo_type, nd) # diminfo + ] + return Type.struct(terms, name=name) + +def strided_soa_type(nd, el_type=char_type, name=''): + terms = [Type.pointer(el_type), # data + Type.array(intp_type, nd), # shape[nd] + Type.array(intp_type, nd) # strides[nd] + ] + return Type.struct(terms, name=name) + +def check_array(arrtyp): + if not isinstance(arrtyp, lc.StructType): + return None + if arrtyp.element_count not in [2, 3]: + return None + if not isinstance(arrtyp.elements[0], lc.PointerType) or \ + not isinstance(arrtyp.elements[1], lc.ArrayType): + return None + + data_type = arrtyp.elements[0].pointee + s1 = arrtyp.elements[1] + nd = s1.count + + if arrtyp.element_count == 3: + if not isinstance(arrtyp.elements[2], lc.ArrayType): + return None + s2 = arrtyp.elements[2] + if s1.element != intp_type or s2.element != intp_type: + return None + if s1.count != s2.count: + return None + return STRIDED_SOA, nd, data_type + + if s1.element == diminfo_type: + return STRIDED, nd, data_type + elif s1.element == intp_type: + return CONTIGUOUS, nd, data_type + else: + return None + +def is_cont_array(arrtyp): + if not isinstance(arrtyp, lc.StructType): + return False + if arrtyp.element_count != 2 or \ + not isinstance(arrtyp.elements[0], lc.PointerType) or \ + not isinstance(arrtyp.elements[1], lc.ArrayType): + return False + if arrtyp.elements[1].element != intp_type: + return False + return True + +def is_strided_array(arrtyp, kind=diminfo_type): + if not isinstance(arrtyp, lc.StructType): + return False + if arrtyp.element_count != 2 or \ + not isinstance(arrtyp.elements[0], lc.PointerType) or \ + not isinstance(arrtyp.elements[1], lc.ArrayType): + return False + if arrtyp.elements[1].element != kind: + return False + return True + +def is_strided_soa_array(arrtyp): + if not isinstance(arrtyp, lc.StructType): + return False + if arrtyp.element_count != 3 or \ + not isinstance(arrtyp.elements[0], lc.PointerType) or \ + not isinstance(arrtyp.elements[1], lc.ArrayType) or \ + not isinstance(arrtyp.elements[2], lc.ArrayType): + return False + s1, s2 = arrtyp.elements[1:] + if s1.element != intp_type or s2.element != intp_type: + return False + if s1.count != s2.count: + return False + return True + +def test(): + arr = cont_array_type(5) + assert check_array(arr) == (CONTIGUOUS, 5, char_type) + arr = strided_array_type(4) + assert check_array(arr) == (STRIDED, 4, char_type) + arr = strided_soa_type(3) + assert check_array(arr) == (STRIDED_SOA, 3, char_type) + +if __name__ == '__main__': + test() \ No newline at end of file diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index 9c1e86a..f66836f 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -3,6 +3,15 @@ from collections import defaultdict import logging logger = logging.getLogger(__name__) +def silent_logger(): + ''' + Silent logger for unless we have a error message. + ''' + logger.setLevel(logging.ERROR) + +# comment out the line below to re-enable logging at DEBUG level. +silent_logger() + def set_debug(enabled): ''' Side-effect: configure logger with it is not configured. diff --git a/llvmpy/src/Function.py b/llvmpy/src/Function.py index 55a50d9..c453fd1 100644 --- a/llvmpy/src/Function.py +++ b/llvmpy/src/Function.py @@ -2,6 +2,7 @@ from binding import * from .namespace import llvm from .Value import GlobalValue, Constant, Function, Argument, Value from .BasicBlock import BasicBlock +from .ValueSymbolTable import ValueSymbolTable from .Attributes import Attributes from .Type import Type from .DerivedTypes import FunctionType @@ -23,7 +24,7 @@ class Function: getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) - hasGC = Method(cast(bool, Bool)) + hasGC = Method(cast(Bool, bool)) getGC = Method(cast(ConstCharPtr, str)) setGC = Method(Void, cast(str, ConstCharPtr)) @@ -31,6 +32,7 @@ class Function: getArgumentList = CustomMethod('Function_getArgumentList', PyObjectPtr) getBasicBlockList = CustomMethod('Function_getBasicBlockList', PyObjectPtr) getEntryBlock = Method(ref(BasicBlock)) + getValueSymbolTable = Method(ref(ValueSymbolTable)) copyAttributesFrom = Method(Void, ptr(GlobalValue)) @@ -49,6 +51,9 @@ class Function: addFnAttr = Method(Void, Attributes.AttrVal) removeFnAttr = Method(Void, ref(Attributes)) + #hasFnAttribute = Method(cast(Bool, bool), Attributes.AttrVal) + + Create = Method(ptr(Function)) eraseFromParent = Method() eraseFromParent.disowning = True diff --git a/llvmpy/src/Value.py b/llvmpy/src/Value.py index fb9c3cc..922850f 100644 --- a/llvmpy/src/Value.py +++ b/llvmpy/src/Value.py @@ -8,6 +8,7 @@ MDNode = llvm.Class(Value) MDString = llvm.Class(Value) User = llvm.Class(Value) BasicBlock = llvm.Class(Value) +ValueSymbolTable = llvm.Class() Constant = llvm.Class(User) GlobalValue = llvm.Class(Constant) Function = llvm.Class(GlobalValue) diff --git a/llvmpy/src/ValueSymbolTable.py b/llvmpy/src/ValueSymbolTable.py new file mode 100644 index 0000000..862febc --- /dev/null +++ b/llvmpy/src/ValueSymbolTable.py @@ -0,0 +1,13 @@ +from binding import * +from .Value import ValueSymbolTable, Value +from .ADT.StringRef import StringRef + +@ValueSymbolTable +class ValueSymbolTable: + new = Constructor() + delete = Destructor() + lookup = Method(ptr(Value), cast(str, StringRef)) + empty = Method(cast(Bool, bool)) + size = Method(cast(Unsigned, int)) + dump = Method(Void) + diff --git a/setup.py b/setup.py index b74ec71..1dc8af8 100644 --- a/setup.py +++ b/setup.py @@ -180,6 +180,7 @@ setup( packages = ['llvm', 'llvm.workaround', 'llvm_cbuilder', 'llpython', + 'llvm_array', 'llvmpy.api', 'llvmpy.api.llvm'], py_modules = ['llvmpy', 'llvmpy._capsule',