Update llvm_array concepts.
This commit is contained in:
parent
1812cff2d0
commit
009239713e
1 changed files with 187 additions and 74 deletions
|
|
@ -24,19 +24,98 @@
|
||||||
# intp stride;
|
# intp stride;
|
||||||
#} diminfo
|
#} diminfo
|
||||||
#
|
#
|
||||||
|
# These are for low-level array-routines that need to know the number
|
||||||
|
# of dimensions at run-time (not just code-generation time):
|
||||||
|
#
|
||||||
|
# The first two are recommended
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# int32 nd;
|
||||||
|
# intp shape[nd];
|
||||||
|
# } contiguous_array_nd(eltype)
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# int32 nd;
|
||||||
|
# diminfo shape[nd];
|
||||||
|
# } strided_array_nd(eltype)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Backward compatible but deprecated:
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# int32 nd;
|
||||||
|
# intp shape[nd];
|
||||||
|
# intp stride[nd];
|
||||||
|
# } strided_soa_array_nd(eltype)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The most general (where the kind of array is stored as well as number
|
||||||
|
# of dimensions)
|
||||||
|
# Rarely needed.
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# int16 nd;
|
||||||
|
# int16 dimkind;
|
||||||
|
# ???
|
||||||
|
# } array_nd(eltype)
|
||||||
|
#
|
||||||
|
# where ??? is run-time interpreted based on the dimkind to either:
|
||||||
|
# intp shape[nd]; for dimkind = C_CONTIGUOUS or F_CONTIGUOUS
|
||||||
|
#
|
||||||
|
# diminfo shape[nd]; for dimkind = STRIDED
|
||||||
|
#
|
||||||
|
# intp shape[ind];
|
||||||
|
# intp strides[ind]; dimkind = STRIDED_SOA
|
||||||
|
#
|
||||||
|
|
||||||
import llvm.core as lc
|
import llvm.core as lc
|
||||||
from llvm.core import Type
|
from llvm.core import Type
|
||||||
import llvm_cbuilder.shortnames as C
|
import llvm_cbuilder.shortnames as C
|
||||||
|
|
||||||
CONTIGUOUS = 1 << 8
|
# Different Array Types
|
||||||
STRIDED = CONTIGUOUS + 1
|
ARRAYBIT = 1<<4
|
||||||
STRIDED_SOA = CONTIGUOUS + 2
|
C_CONTIGUOUS = ARRAYBIT + 0
|
||||||
|
F_CONTIGUOUS = ARRAYBIT + 1
|
||||||
|
STRIDED = ARRAYBIT + 2
|
||||||
|
STRIDED_SOA = ARRAYBIT + 3
|
||||||
|
|
||||||
array_kinds = (CONTIGUOUS, STRIDED, STRIDED_SOA)
|
HAS_ND = 1<<5
|
||||||
|
C_CONTIGUOUS_ND = C_CONTIGUOUS + HAS_ND
|
||||||
|
F_CONTIGUOUS_ND = F_CONTIGUOUS + HAS_ND
|
||||||
|
STRIDED_ND = STRIDED + HAS_ND
|
||||||
|
STRIDED_SOA_ND = STRIDED_SOA + HAS_ND
|
||||||
|
|
||||||
|
HAS_DIMKIND = 1<<6
|
||||||
|
C_CONTIGUOUS_DK = C_CONTIGUOUS + HAS_DIMKIND
|
||||||
|
F_CONTIGUOUS_DK = F_CONTIGUOUS + HAS_DIMKIND
|
||||||
|
STRIDED_DK = STRIDED + HAS_DIMKIND
|
||||||
|
STRIDED_SOA_DK = STRIDED_SOA + HAS_DIMKIND
|
||||||
|
|
||||||
|
array_kinds = (C_CONTIGUOUS, F_CONTIGUOUS, STRIDED, STRIDED_SOA,
|
||||||
|
C_CONTIGUOUS_ND, F_CONTIGUOUS_ND, STRIDED_ND, STRIDED_SOA_DK,
|
||||||
|
C_CONTIGUOUS_DK, F_CONTIGUOUS_DK, STRIDED_DK, STRIDED_SOA_DK)
|
||||||
|
|
||||||
|
_invmap = {}
|
||||||
|
|
||||||
|
def kind_to_str(kind):
|
||||||
|
global _invmap
|
||||||
|
if not _invmap:
|
||||||
|
for key, value in globals().items():
|
||||||
|
if isinstance(value, int) and value in array_kinds:
|
||||||
|
_invmap[value] = key
|
||||||
|
return _invmap[kind]
|
||||||
|
|
||||||
|
def str_to_kind(str):
|
||||||
|
trial = eval(str)
|
||||||
|
if trial not in array_kinds:
|
||||||
|
raise ValueError("Invalid Array Kind")
|
||||||
|
return trial
|
||||||
|
|
||||||
void_type = C.void
|
void_type = C.void
|
||||||
int_type = C.int
|
int32_type = C.int32
|
||||||
char_type = C.char
|
char_type = C.char
|
||||||
int16_type = C.int16
|
int16_type = C.int16
|
||||||
intp_type = C.intp
|
intp_type = C.intp
|
||||||
|
|
@ -45,99 +124,133 @@ diminfo_type = Type.struct([intp_type, # shape
|
||||||
intp_type # stride
|
intp_type # stride
|
||||||
], name='diminfo')
|
], name='diminfo')
|
||||||
|
|
||||||
# This is the way we define LLVM arrays.
|
_cache = {}
|
||||||
def cont_array_type(nd, el_type=char_type, name=''):
|
# This is the way we define LLVM arrays.
|
||||||
terms = [Type.pointer(el_type), # data
|
# CONTIGUOUS and STRIDED are strongly encouraged...
|
||||||
Type.array(intp_type, nd) # shape
|
def array_type(nd, kind, el_type=char_type):
|
||||||
]
|
key = (kind, nd, el_type)
|
||||||
return Type.struct(terms, name=name)
|
if _cache.has_key(key):
|
||||||
|
return _cache[key]
|
||||||
|
|
||||||
def strided_array_type(nd, el_type=char_type, name=''):
|
base = kind & (~(HAS_ND | HAS_DIMKIND))
|
||||||
terms = [Type.pointer(el_type), # data
|
if base == C_CONTIGUOUS:
|
||||||
Type.array(diminfo_type, nd) # diminfo
|
dimstr = 'Array_C'
|
||||||
]
|
elif base == F_CONTIGUOUS:
|
||||||
return Type.struct(terms, name=name)
|
dimstr = 'Array_F'
|
||||||
|
elif base == STRIDED:
|
||||||
|
dimstr = 'Array_S'
|
||||||
|
elif base == STRIDED_SOA:
|
||||||
|
dimstr = 'Array_A'
|
||||||
|
else:
|
||||||
|
raise TypeError("Do not understand Array kind of %d" % kind)
|
||||||
|
|
||||||
|
terms = [Type.pointer(el_type)] # data
|
||||||
|
|
||||||
|
if (kind & HAS_ND):
|
||||||
|
terms.append(int32_type) # nd
|
||||||
|
dimstr += '_ND'
|
||||||
|
elif (kind & HAS_DIMKIND):
|
||||||
|
terms.extend([int16_type, int16_type]) # nd, dimkind
|
||||||
|
dimstr += '_DK'
|
||||||
|
|
||||||
|
if base in [C_CONTIGUOUS, F_CONTIGUOUS]:
|
||||||
|
terms.append(Type.array(intp_type, nd)) # shape
|
||||||
|
elif base == STRIDED:
|
||||||
|
terms.append(Type.array(diminfo_type, nd)) # diminfo
|
||||||
|
elif base == STRIDED_SOA:
|
||||||
|
terms.extend([Type.array(intp_type, nd), # shape
|
||||||
|
Type.array(intp_type, nd)]) # strides
|
||||||
|
|
||||||
|
ret = Type.struct(terms, name=dimstr)
|
||||||
|
_cache[key] = ret
|
||||||
|
return ret
|
||||||
|
|
||||||
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):
|
def check_array(arrtyp):
|
||||||
if not isinstance(arrtyp, lc.StructType):
|
if not isinstance(arrtyp, lc.StructType):
|
||||||
return None
|
return None
|
||||||
if arrtyp.element_count not in [2, 3]:
|
if arrtyp.element_count not in [2, 3, 4, 5]:
|
||||||
return None
|
|
||||||
if not isinstance(arrtyp.elements[0], lc.PointerType) or \
|
|
||||||
not isinstance(arrtyp.elements[1], lc.ArrayType):
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
data_type = arrtyp.elements[0].pointee
|
# Look through _cache and see if it's there
|
||||||
s1 = arrtyp.elements[1]
|
for key, value in _cache.items():
|
||||||
|
if arrtyp is value:
|
||||||
|
return key
|
||||||
|
|
||||||
|
return _raw_check_array(arrtyp)
|
||||||
|
|
||||||
|
# Manual check
|
||||||
|
def _raw_check_array(arrtyp):
|
||||||
|
a0 = arrtyp.elements[0]
|
||||||
|
a1 = arrtyp.elements[1]
|
||||||
|
if not isinstance(a0, lc.PointerType) or \
|
||||||
|
not (isinstance(a1, lc.ArrayType) or
|
||||||
|
(a1 == int32_type) or (a1 == int16_type)):
|
||||||
|
return None
|
||||||
|
|
||||||
|
data_type = a0.pointee
|
||||||
|
|
||||||
|
if arrtyp.is_literal:
|
||||||
|
c_contig = True
|
||||||
|
else:
|
||||||
|
if arrtyp.name.startswith('Array_F'):
|
||||||
|
c_contig = False
|
||||||
|
else:
|
||||||
|
c_contig = True
|
||||||
|
|
||||||
|
|
||||||
|
if a1 == int32_type:
|
||||||
|
num = 2
|
||||||
|
strided = STRIDED_ND
|
||||||
|
strided_soa = STRIDED_SOA_ND
|
||||||
|
c_contiguous = C_CONTIGUOUS_ND
|
||||||
|
f_contiguous = F_CONTIGUOUS_ND
|
||||||
|
elif a1 == int16_type:
|
||||||
|
if arrtyp.element_count < 3 or arrtyp.elements[2] != int16_type:
|
||||||
|
return None
|
||||||
|
num = 3
|
||||||
|
strided = STRIDED_DK
|
||||||
|
strided_soa = STRIDED_SOA_DK
|
||||||
|
c_contiguous = C_CONTIGUOUS_DK
|
||||||
|
f_contiguous = F_CONTIGUOUS_DK
|
||||||
|
else:
|
||||||
|
num = 1
|
||||||
|
strided = STRIDED
|
||||||
|
strided_soa = STRIDED_SOA
|
||||||
|
c_contiguous = C_CONTIGUOUS
|
||||||
|
f_contiguous = F_CONTIGUOUS
|
||||||
|
|
||||||
|
elcount = num + 2
|
||||||
|
# otherwise we have lc.ArrType as element [1]
|
||||||
|
if arrtyp.element_count not in [num+1,num+2]:
|
||||||
|
return None
|
||||||
|
s1 = arrtyp.elements[num]
|
||||||
nd = s1.count
|
nd = s1.count
|
||||||
|
|
||||||
if arrtyp.element_count == 3:
|
if arrtyp.element_count == elcount:
|
||||||
if not isinstance(arrtyp.elements[2], lc.ArrayType):
|
if not isinstance(arrtyp.elements[num+1], lc.ArrayType):
|
||||||
return None
|
return None
|
||||||
s2 = arrtyp.elements[2]
|
s2 = arrtyp.elements[num+1]
|
||||||
if s1.element != intp_type or s2.element != intp_type:
|
if s1.element != intp_type or s2.element != intp_type:
|
||||||
return None
|
return None
|
||||||
if s1.count != s2.count:
|
if s1.count != s2.count:
|
||||||
return None
|
return None
|
||||||
return STRIDED_SOA, nd, data_type
|
return strided_soa, nd, data_type
|
||||||
|
|
||||||
if s1.element == diminfo_type:
|
if s1.element == diminfo_type:
|
||||||
return STRIDED, nd, data_type
|
return strided, nd, data_type
|
||||||
elif s1.element == intp_type:
|
elif s1.element == intp_type:
|
||||||
return CONTIGUOUS, nd, data_type
|
return c_contiguous if c_contig else f_contiguous, nd, data_type
|
||||||
else:
|
else:
|
||||||
return None
|
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():
|
def test():
|
||||||
arr = cont_array_type(5)
|
arr = array_type(5, C_CONTIGUOUS)
|
||||||
assert check_array(arr) == (CONTIGUOUS, 5, char_type)
|
assert check_array(arr) == (C_CONTIGUOUS, 5, char_type)
|
||||||
arr = strided_array_type(4)
|
arr = array_type(4, STRIDED)
|
||||||
assert check_array(arr) == (STRIDED, 4, char_type)
|
assert check_array(arr) == (STRIDED, 4, char_type)
|
||||||
arr = strided_soa_type(3)
|
arr = array_type(3, STRIDED_SOA)
|
||||||
assert check_array(arr) == (STRIDED_SOA, 3, char_type)
|
assert check_array(arr) == (STRIDED_SOA, 3, char_type)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue