def ctypes_struct_to_lltype(S, name = None): if not name: name = S.__class__.__name__ key = tuple(S._fields_) if key in _struct_cache: return _struct_cache[key] else: llvm_field_types = [ctypes_to_lltype(field_type) for (_, field_type) in S._fields_] llvm_struct = lltype.struct(llvm_field_types, name) _struct_cache[key] = llvm_struct return llvm_struct
def args_to_kernel_data_struct(kinds, argtypes): # Build up the kernel data structure. Currently, this means # adding a shape field for each array argument. First comes # the kernel data prefix with a spot for the 'owner' reference added. input_field_indices = [] kernel_data_fields = [Type.struct([int8_p_type]*3)] kernel_data_ctypes_fields = [('base', JITCKernelData)] for i, (kind, a) in enumerate(izip(kinds, argtypes)): if isinstance(kind, tuple): if kind[0] != lla.C_CONTIGUOUS: raise ValueError('only support C contiguous array presently') input_field_indices.append(len(kernel_data_fields)) kernel_data_fields.append(Type.array( intp_type, len(bek.dshapes[i])-1)) kernel_data_ctypes_fields.append(('operand_%d' % i, c_ssize_t * (len(bek.dshapes[i])-1))) elif kind in [lla.SCALAR, lla.POINTER]: input_field_indices.append(None) else: raise TypeError(("unbound_single_ckernel codegen doesn't " + "support the parameter kind %r yet") % (k,)) # Make an LLVM and ctypes type for the extra data pointer. kernel_data_llvmtype = Type.struct(kernel_data_fields) class kernel_data_ctypestype(ctypes.Structure): _fields_ = kernel_data_ctypes_fields return (kernel_data_llvmtype, kernel_data_ctypestype)
def create_instance(mod, spec, ctx): # Spine # | # # T ... = A .. | B .. | C .. # # | # Values lvals = [] instances = [] # Values # ====== for value in spec.values: tys = [ctx[id] for id in value.params] lvals += [(value.name, Type.struct(tys, value.name))] # Spine # ====== spine = Type.struct([a[1] for a in lvals], 'maybe') for i, (name, value) in enumerate(lvals): fn_spec = Type.function(void, value.elements) F = mod.add_function(fn_spec, value.name) instances += [F] build_constructor(F, value, spine, 1) return spine, instances
def get_data_type(self, ty): """ Get a data representation of the type Returns None if it is an opaque pointer """ if (isinstance(ty, types.Dummy) or isinstance(ty, types.Module) or isinstance(ty, types.Function) or isinstance(ty, types.Dispatcher) or isinstance(ty, types.Object) or isinstance(ty, types.Macro)): return Type.pointer(Type.int(8)) elif isinstance(ty, types.CPointer): dty = self.get_data_type(ty.dtype) return Type.pointer(dty) elif isinstance(ty, types.Optional): return self.get_data_type(ty.type) elif isinstance(ty, types.Array): return self.get_struct_type(self.make_array(ty)) elif isinstance(ty, types.UniTuple): dty = self.get_value_type(ty.dtype) return Type.array(dty, ty.count) elif isinstance(ty, types.Tuple): dtys = [self.get_value_type(t) for t in ty] return Type.struct(dtys) elif isinstance(ty, types.UniTupleIter): stty = self.get_struct_type(self.make_unituple_iter(ty)) return stty elif isinstance(ty, types.Record): # Record are represented as byte array return Type.struct([Type.array(Type.int(8), ty.size)]) elif isinstance(ty, types.UnicodeCharSeq): charty = Type.int(numpy_support.sizeof_unicode_char * 8) return Type.struct([Type.array(charty, ty.count)]) elif isinstance(ty, types.CharSeq): charty = Type.int(8) return Type.struct([Type.array(charty, ty.count)]) elif ty in STRUCT_TYPES: return self.get_struct_type(STRUCT_TYPES[ty]) elif isinstance(ty, types.Pair): pairty = self.make_pair(ty.first_type, ty.second_type) return self.get_struct_type(pairty) else: return LTYPEMAP[ty]
def test_struct_type(self): ta = Type.struct([Type.int(32), Type.float()]) tb = Type.struct([Type.int(32), Type.float()]) tc = Type.struct([Type.int(32), Type.int(32), Type.float()]) ts = set([ta, tb, tc]) self.assertTrue(len(ts) == 2) self.assertTrue(ta in ts) self.assertTrue(tb in ts) self.assertTrue(tc in ts)
def test_struct_extract_value_2d(self): ta = Type.struct([Type.int(32), Type.float()]) tb = Type.struct([ta, Type.float()]) m = Module.new('') f = m.add_function(Type.function(Type.void(), []), "foo") b = Builder.new(f.append_basic_block('')) v = Constant.undef(tb) ins = b.insert_value(v, Constant.real(Type.float(), 1.234), [0, 1]) ext = b.extract_value(ins, [0, 1]) b.ret_void() m.verify() self.assertEqual(str(ext), 'float 0x3FF3BE76C0000000')
def get_data_type(self, ty): """ Get a data representation of the type Returns None if it is an opaque pointer """ if (isinstance(ty, types.Dummy) or isinstance(ty, types.Module) or isinstance(ty, types.Function) or isinstance(ty, types.Dispatcher) or isinstance(ty, types.Object) or isinstance(ty, types.Macro)): return Type.pointer(Type.int(8)) elif isinstance(ty, types.CPointer): dty = self.get_data_type(ty.dtype) return Type.pointer(dty) elif isinstance(ty, types.Optional): return self.get_data_type(ty.type) elif isinstance(ty, types.Array): return self.get_struct_type(self.make_array(ty)) elif isinstance(ty, types.UniTuple): dty = self.get_value_type(ty.dtype) return Type.array(dty, ty.count) elif isinstance(ty, types.Tuple): dtys = [self.get_value_type(t) for t in ty] return Type.struct(dtys) elif isinstance(ty, types.UniTupleIter): stty = self.get_struct_type(self.make_unituple_iter(ty)) return stty elif isinstance(ty, types.Record): # Record are represented as byte array return Type.struct([Type.array(Type.int(8), ty.size)]) elif isinstance(ty, types.UnicodeCharSeq): charty = Type.int(numpy_support.sizeof_unicode_char * 8) return Type.struct([Type.array(charty, ty.count)]) elif isinstance(ty, types.CharSeq): charty = Type.int(8) return Type.struct([Type.array(charty, ty.count)]) elif ty in STRUCT_TYPES: return self.get_struct_type(STRUCT_TYPES[ty]) else: return LTYPEMAP[ty]
def array_type(elt_type): return Type.struct( [ pointer(elt_type), # data int_type, # dimensions pointer(int_type), # shape ], name='ndarray_' + str(elt_type))
def make_anonymous_struct(builder, values): """ Create an anonymous struct constant containing the given LLVM *values*. """ struct_type = Type.struct([v.type for v in values]) struct_val = Constant.undef(struct_type) for i, v in enumerate(values): struct_val = builder.insert_value(struct_val, v, i) return struct_val
def get_value_type(self, ty): if ty == types.boolean: return Type.int(1) dataty = self.get_data_type(ty) if isinstance(ty, types.Record): # Record data are passed by refrence memory = dataty.elements[0] return Type.struct([Type.pointer(memory)]) return dataty
def test_arg_attr(self): m = Module.new('oifjda') vptr = Type.pointer(Type.float()) sptr = Type.pointer(Type.struct([])) fnty = Type.function(Type.void(), [vptr] * 5) func = m.add_function(fnty, 'foo') attrs = [lc.ATTR_STRUCT_RET, lc.ATTR_BY_VAL, lc.ATTR_NEST, lc.ATTR_NO_ALIAS, lc.ATTR_NO_CAPTURE] for i, attr in enumerate(attrs): arg = func.args[i] self.assertEqual(i, arg.arg_no) arg.add_attribute(attr) self.assertTrue(attr in func.args[i])
def ctypes_struct_to_lltype(S, name=None): if not name: name = S.__class__.__name__ key = tuple(S._fields_) if key in _struct_cache: return _struct_cache[key] else: llvm_field_types = [ ctypes_to_lltype(field_type) for (_, field_type) in S._fields_ ] llvm_struct = lltype.struct(llvm_field_types, name) _struct_cache[key] = llvm_struct return llvm_struct
def test_dtype_from_type_complex(): """ Test to-numpy translation of a complex LLVM type. """ from llvm.core import Type from qy import ( type_from_dtype, dtype_from_type, ) dtype = numpy.dtype([("f0", [("f0", numpy.int32), ("f1", numpy.int32)], (4,))]) type_ = Type.struct([Type.array(Type.packed_struct([Type.int(32)] * 2), 4)]) dtype2 = dtype_from_type(type_) assert_equal(dtype2.itemsize, dtype.itemsize) assert_equal(str(dtype2), str(dtype))
def array_type(nd, kind, el_type=char_type, module=None): base = kind & (~(HAS_ND | HAS_DIMKIND)) if base == C_CONTIGUOUS: dimstr = 'Array_C' elif base == F_CONTIGUOUS: dimstr = 'Array_F' elif base == STRIDED: dimstr = 'Array_S' elif base == NEW_STRIDED: dimstr = 'Array_N' else: raise TypeError("Do not understand Array kind of %d" % kind) if (kind & HAS_ND): dimstr += '_ND' elif (kind & HAS_DIMKIND): dimstr += '_DK' key = "%s_%s_%d" % (dimstr, str(el_type), nd) if module is not None: modcache = _cache.setdefault(module.id, {}) if key in modcache: return modcache[key] terms = [Type.pointer(el_type)] # data if (kind & HAS_ND): terms.append(int32_type) # nd elif (kind & HAS_DIMKIND): terms.extend([int16_type, int16_type]) # nd, dimkind if base in [C_CONTIGUOUS, F_CONTIGUOUS]: terms.append(Type.array(intp_type, nd)) # shape elif base == NEW_STRIDED: terms.append(Type.array(diminfo_type, nd)) # diminfo elif base == STRIDED: terms.extend([ Type.array(intp_type, nd), # shape Type.array(intp_type, nd) ]) # strides terms.append(void_p_type) ret = Type.struct(terms, name=key) if module is not None: modcache[key] = ret return ret
def array_type(nd, kind, el_type=char_type, module=None): base = kind & (~(HAS_ND | HAS_DIMKIND)) if base == C_CONTIGUOUS: dimstr = 'Array_C' elif base == F_CONTIGUOUS: dimstr = 'Array_F' elif base == STRIDED: dimstr = 'Array_S' elif base == NEW_STRIDED: dimstr = 'Array_N' else: raise TypeError("Do not understand Array kind of %d" % kind) if (kind & HAS_ND): dimstr += '_ND' elif (kind & HAS_DIMKIND): dimstr += '_DK' key = "%s_%s_%d" % (dimstr, str(el_type), nd) if module is not None: modcache = _cache.setdefault(module.id,{}) if key in modcache: return modcache[key] terms = [Type.pointer(el_type)] # data if (kind & HAS_ND): terms.append(int32_type) # nd elif (kind & HAS_DIMKIND): terms.extend([int16_type, int16_type]) # nd, dimkind if base in [C_CONTIGUOUS, F_CONTIGUOUS]: terms.append(Type.array(intp_type, nd)) # shape elif base == NEW_STRIDED: terms.append(Type.array(diminfo_type, nd)) # diminfo elif base == STRIDED: terms.extend([Type.array(intp_type, nd), # shape Type.array(intp_type, nd)]) # strides terms.append(void_p_type) ret = Type.struct(terms, name=key) if module is not None: modcache[key] = ret return ret
def get_data_type(self, ty): """ Get a data representation of the type Returns None if it is an opaque pointer """ if (isinstance(ty, types.Dummy) or isinstance(ty, types.Module) or isinstance(ty, types.Function) or isinstance(ty, types.Dispatcher) or isinstance(ty, types.Object) or isinstance(ty, types.Macro)): return Type.pointer(Type.int(8)) elif isinstance(ty, types.CPointer): dty = self.get_data_type(ty.dtype) return Type.pointer(dty) elif isinstance(ty, types.Optional): return self.get_data_type(ty.type) elif isinstance(ty, types.Array): return self.get_struct_type(self.make_array(ty)) elif isinstance(ty, types.UniTuple): dty = self.get_value_type(ty.dtype) return Type.array(dty, ty.count) elif isinstance(ty, types.Tuple): dtys = [self.get_value_type(t) for t in ty] return Type.struct(dtys) elif isinstance(ty, types.UniTupleIter): stty = self.get_struct_type(self.make_unituple_iter(ty)) return stty elif ty in STRUCT_TYPES: return self.get_struct_type(STRUCT_TYPES[ty]) else: return LTYPEMAP[ty]
def llvm_type(type): ty = type.__class__ if ty == Boolean: return Type.int(1) elif ty == Integral: return Type.int(type.bits) elif type == Float32: return Type.float() elif type == Float64: return Type.double() elif ty == Struct: return Type.struct([llvm_type(ftype) for ftype in type.types]) elif ty == Pointer: return Type.pointer(llvm_type(type.base)) elif ty == Function: return Type.function(llvm_type(type.restype), [llvm_type(argtype) for argtype in type.argtypes]) elif ty == Void: return Type.void() else: raise TypeError("Cannot convert type %s" % (type,))
def array_type(nd, kind, el_type=char_type): key = (kind, nd, el_type) if _cache.has_key(key): return _cache[key] base = kind & (~(HAS_ND | HAS_DIMKIND)) if base == C_CONTIGUOUS: dimstr = 'Array_C' elif base == F_CONTIGUOUS: 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 handle_struct(type, memo): # Check the cache with a hashable struct type key = type if key in memo: return memo[key] if key in opaque_memo: return opaque_memo[key] # Allocate and pre-order cache dummy struct struct_type = Type.opaque('dummy_struct_type') memo[key] = struct_type opaque_memo[key] = struct_type # Process fields and re-cache fields = [llvm_type(ftype, memo) for ftype in type.types] result = Type.struct(fields) struct_type.set_body([result]) memo[key] = result opaque_memo[key] = result return result
def array_type(nd, kind, el_type=char_type): key = (kind, nd, el_type) if _cache.has_key(key): return _cache[key] base = kind & (~(HAS_ND | HAS_DIMKIND)) if base == C_CONTIGUOUS: dimstr = 'Array_C' elif base == F_CONTIGUOUS: 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
int_type = Type.int() float_type = Type.double() bool_type = Type.int(1) void_type = Type.void() char_type = Type.int(8) pointer = Type.pointer any_type = pointer(Type.int(ptrsize)) string_type = pointer(char_type) # { i32*, i32, i32* } array_type = lambda elt_type: Type.struct( [ pointer(elt_type), # data | (<type>)* int_type, # dimensions | int pointer(int_type), # strides | int* ], name='ndarray_' + str(elt_type)) # opaque for now blaze_type = lambda datashape: Type.opaque(name="blaze") #------------------------------------------------------------------------ # Constants #------------------------------------------------------------------------ false = Constant.int(bool_type, 0) true = Constant.int(bool_type, 1) zero = Constant.int(int_type, 0)
def unbound_single_ckernel(self): """Creates an UnboundCKernelFunction with the ExprSingleOperation prototype. """ import ctypes if self._unbound_single_ckernel is None: i8_p_type = Type.pointer(Type.int(8)) func_type = Type.function(void_type, [i8_p_type, Type.pointer(i8_p_type), i8_p_type]) module = self.module.clone() single_ck_func_name = self.func.name +"_single_ckernel" single_ck_func = Function.new(module, func_type, name=single_ck_func_name) block = single_ck_func.append_basic_block('entry') builder = lc.Builder.new(block) dst_ptr_arg, src_ptr_arr_arg, extra_ptr_arg = single_ck_func.args dst_ptr_arg.name = 'dst_ptr' src_ptr_arr_arg.name = 'src_ptrs' extra_ptr_arg.name = 'extra_ptr' # Build up the kernel data structure. Currently, this means # adding a shape field for each array argument. First comes # the kernel data prefix with a spot for the 'owner' reference added. input_field_indices = [] kernel_data_fields = [Type.struct([i8_p_type]*3)] kernel_data_ctypes_fields = [('base', JITKernelData)] for i, (kind, a) in enumerate(izip(self.kinds, self.argtypes)): if isinstance(kind, tuple): if kind[0] != lla.C_CONTIGUOUS: raise ValueError('only support C contiguous array presently') input_field_indices.append(len(kernel_data_fields)) kernel_data_fields.append(Type.array( intp_type, len(self.dshapes[i])-1)) kernel_data_ctypes_fields.append(('operand_%d' % i, c_ssize_t * (len(self.dshapes[i])-1))) elif kind in [SCALAR, POINTER]: input_field_indices.append(None) else: raise TypeError(("unbound_single_ckernel codegen doesn't " + "support the parameter kind %r yet") % (k,)) # Make an LLVM and ctypes type for the extra data pointer. kernel_data_llvmtype = Type.struct(kernel_data_fields) class kernel_data_ctypestype(ctypes.Structure): _fields_ = kernel_data_ctypes_fields # Cast the extra pointer to the right llvm type extra_struct = builder.bitcast(extra_ptr_arg, Type.pointer(kernel_data_llvmtype)) # Convert the src pointer args to the # appropriate kinds for the llvm call args = [] for i, (kind, atype) in enumerate(izip(self.kinds[:-1], self.argtypes)): if kind == SCALAR: src_ptr = builder.bitcast(builder.load( builder.gep(src_ptr_arr_arg, (lc.Constant.int(intp_type, i),))), Type.pointer(atype)) src_val = builder.load(src_ptr) args.append(src_val) elif kind == POINTER: src_ptr = builder.bitcast(builder.load( builder.gep(src_ptr_arr_arg, (lc.Constant.int(intp_type, i),))), Type.pointer(atype)) args.append(src_ptr) elif isinstance(kind, tuple): src_ptr = builder.bitcast(builder.load( builder.gep(src_ptr_arr_arg, (lc.Constant.int(intp_type, i),))), Type.pointer(kind[2])) # First get the shape of this parameter. This will # be a combination of Fixed and TypeVar (Var unsupported # here for now) shape = self.dshapes[i][:-1] # Get the llvm array arr_var = builder.alloca(atype.pointee) builder.store(src_ptr, builder.gep(arr_var, (lc.Constant.int(int32_type, 0), lc.Constant.int(int32_type, 0)))) for j, sz in enumerate(shape): if isinstance(sz, Fixed): # If the shape is already known at JIT compile time, # insert the constant shape_el_ptr = builder.gep(arr_var, (lc.Constant.int(int32_type, 0), lc.Constant.int(int32_type, 1), lc.Constant.int(intp_type, j))) builder.store(lc.Constant.int(intp_type, operator.index(sz)), shape_el_ptr) elif isinstance(sz, TypeVar): # TypeVar types are only known when the kernel is bound, # so copy it from the extra data pointer sz_from_extra_ptr = builder.gep(extra_struct, (lc.Constant.int(int32_type, 0), lc.Constant.int(int32_type, input_field_indices[i]), lc.Constant.int(intp_type, j))) sz_from_extra = builder.load(sz_from_extra_ptr) shape_el_ptr = builder.gep(arr_var, (lc.Constant.int(int32_type, 0), lc.Constant.int(int32_type, 1), lc.Constant.int(intp_type, j))) builder.store(sz_from_extra, shape_el_ptr) else: raise TypeError(("unbound_single_ckernel codegen doesn't " + "support dimension type %r") % type(sz)) args.append(arr_var) # Call the function and store in the dst kind = self.kinds[-1] func = module.get_function_named(self.func.name) if kind == SCALAR: dst_ptr = builder.bitcast(dst_ptr_arg, Type.pointer(self.return_type)) dst_val = builder.call(func, args) builder.store(dst_val, dst_ptr) elif kind == POINTER: dst_ptr = builder.bitcast(dst_ptr_arg, Type.pointer(self.return_type)) builder.call(func, args + [dst_ptr]) elif isinstance(kind, tuple): dst_ptr = builder.bitcast(dst_ptr_arg, Type.pointer(kind[2])) # First get the shape of the output. This will # be a combination of Fixed and TypeVar (Var unsupported # here for now) shape = self.dshapes[-1][:-1] # Get the llvm array arr_var = builder.alloca(self.argtypes[-1].pointee) builder.store(dst_ptr, builder.gep(arr_var, (lc.Constant.int(int32_type, 0), lc.Constant.int(int32_type, 0)))) for j, sz in enumerate(shape): if isinstance(sz, Fixed): # If the shape is already known at JIT compile time, # insert the constant shape_el_ptr = builder.gep(arr_var, (lc.Constant.int(int32_type, 0), lc.Constant.int(int32_type, 1), lc.Constant.int(intp_type, j))) builder.store(lc.Constant.int(intp_type, operator.index(sz)), shape_el_ptr) elif isinstance(sz, TypeVar): # TypeVar types are only known when the kernel is bound, # so copy it from the extra data pointer sz_from_extra_ptr = builder.gep(extra_struct, (lc.Constant.int(int32_type, 0), lc.Constant.int(int32_type, input_field_indices[-1]), lc.Constant.int(intp_type, j))) sz_from_extra = builder.load(sz_from_extra_ptr) shape_el_ptr = builder.gep(arr_var, (lc.Constant.int(int32_type, 0), lc.Constant.int(int32_type, 1), lc.Constant.int(intp_type, j))) builder.store(sz_from_extra, shape_el_ptr) else: raise TypeError(("unbound_single_ckernel codegen doesn't " + "support dimension type %r") % type(sz)) builder.call(func, args + [arr_var]) else: raise TypeError(("single_ckernel codegen doesn't " + "support kind %r") % kind) builder.ret_void() #print("Function before optimization passes:") #print(single_ck_func) #module.verify() import llvm.ee as le from llvm.passes import build_pass_managers tm = le.TargetMachine.new(opt=3, cm=le.CM_JITDEFAULT, features='') pms = build_pass_managers(tm, opt=3, fpm=False, vectorize=True, loop_vectorize=True) pms.pm.run(module) #print("Function after optimization passes:") #print(single_ck_func) # DEBUGGING: Verify the module. #module.verify() # TODO: Cache the EE - the interplay with the func_ptr # was broken, so just avoiding caching for now # FIXME: Temporarily disabling AVX, because of misdetection # in linux VMs. Some code is in llvmpy's workarounds # submodule related to this. ee = le.EngineBuilder.new(module).mattrs("-avx").create() func_ptr = ee.get_pointer_to_function(single_ck_func) # Create a function which copies the shape from data # descriptors to the extra data struct. if len(kernel_data_ctypes_fields) == 1: def bind_func(estruct, dst_dd, src_dd_list): pass else: def bind_func(estruct, dst_dd, src_dd_list): for i, (ds, dd) in enumerate( izip(self.dshapes, src_dd_list + [dst_dd])): shape = [operator.index(dim) for dim in dd.dshape[-len(ds):-1]] cshape = getattr(estruct, 'operand_%d' % i) for j, dim_size in enumerate(shape): cshape[j] = dim_size self._unbound_single_ckernel = UnboundCKernelFunction( ExprSingleOperation(func_ptr), kernel_data_ctypestype, bind_func, (ee, func_ptr)) return self._unbound_single_ckernel
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 int32_type = C.int32 char_type = C.char int16_type = C.int16 intp_type = C.intp diminfo_type = Type.struct( [ intp_type, # shape intp_type # stride ], name='diminfo') _cache = {} # This is the way we define LLVM arrays. # CONTIGUOUS and STRIDED are strongly encouraged... def array_type(nd, kind, el_type=char_type): key = (kind, nd, el_type) if _cache.has_key(key): return _cache[key] base = kind & (~(HAS_ND | HAS_DIMKIND)) if base == C_CONTIGUOUS:
def get_struct_type(self, struct): """ Get the LLVM struct type for the given Structure class *struct*. """ fields = [self.get_struct_member_type(v) for _, v in struct._fields] return Type.struct(fields)
def get_data_type(self, ty): """ Get a data representation of the type that is safe for storage. Record data are stored as byte array. Returns None if it is an opaque pointer """ try: fac = type_registry.match(ty) except KeyError: pass else: return fac(self, ty) if (isinstance(ty, types.Dummy) or isinstance(ty, types.Module) or isinstance(ty, types.Function) or isinstance(ty, types.Dispatcher) or isinstance(ty, types.Object) or isinstance(ty, types.Macro)): return PYOBJECT elif isinstance(ty, types.CPointer): dty = self.get_data_type(ty.dtype) return Type.pointer(dty) elif isinstance(ty, types.Optional): return self.get_data_type(ty.type) elif isinstance(ty, types.Array): return self.get_struct_type(self.make_array(ty)) elif isinstance(ty, types.UniTuple): dty = self.get_value_type(ty.dtype) return Type.array(dty, ty.count) elif isinstance(ty, types.Tuple): dtys = [self.get_value_type(t) for t in ty] return Type.struct(dtys) elif isinstance(ty, types.Record): # Record are represented as byte array return Type.struct([Type.array(Type.int(8), ty.size)]) elif isinstance(ty, types.UnicodeCharSeq): charty = Type.int(numpy_support.sizeof_unicode_char * 8) return Type.struct([Type.array(charty, ty.count)]) elif isinstance(ty, types.CharSeq): charty = Type.int(8) return Type.struct([Type.array(charty, ty.count)]) elif ty in STRUCT_TYPES: return self.get_struct_type(STRUCT_TYPES[ty]) else: try: impl = struct_registry.match(ty) except KeyError: pass else: return self.get_struct_type(impl(ty)) if isinstance(ty, types.Pair): pairty = self.make_pair(ty.first_type, ty.second_type) return self.get_struct_type(pairty) else: return LTYPEMAP[ty]
trial = eval(str) if trial not in array_kinds: raise ValueError("Invalid Array Kind") return trial void_type = C.void int32_type = C.int32 char_type = C.char int16_type = C.int16 intp_type = C.intp int_type = C.int char_p_type = lc.Type.pointer(C.char) void_p_type = C.void_p diminfo_type = Type.struct([intp_type, # shape intp_type # stride ], name='diminfo') zero_p = lc.Constant.int(intp_type, 0) one_p = lc.Constant.int(intp_type, 1) # We use a per-module cache because the LLVM linker wants a new struct # with the same name in different modules. # The linker does *not* like the *same* struct with the *same* name in # two different modules. _cache = {} # This is the way we define LLVM arrays. # C_CONTIGUOUS, F_CONTIGUOUS, and STRIDED are strongly encouraged... def array_type(nd, kind, el_type=char_type, module=None): base = kind & (~(HAS_ND | HAS_DIMKIND)) if base == C_CONTIGUOUS:
def get_data_type(self, ty): """ Get a data representation of the type that is safe for storage. Record data are stored as byte array. Returns None if it is an opaque pointer """ try: fac = type_registry.match(ty) except KeyError: pass else: return fac(self, ty) if (isinstance(ty, types.Dummy) or isinstance(ty, types.Module) or isinstance(ty, types.Function) or isinstance(ty, types.Dispatcher) or isinstance(ty, types.Object) or isinstance(ty, types.Macro)): return PYOBJECT elif isinstance(ty, types.CPointer): dty = self.get_data_type(ty.dtype) return Type.pointer(dty) elif isinstance(ty, types.Optional): return self.get_struct_type(self.make_optional(ty)) elif isinstance(ty, types.Array): return self.get_struct_type(self.make_array(ty)) elif isinstance(ty, types.UniTuple): dty = self.get_value_type(ty.dtype) return Type.array(dty, ty.count) elif isinstance(ty, types.Tuple): dtys = [self.get_value_type(t) for t in ty] return Type.struct(dtys) elif isinstance(ty, types.Record): # Record are represented as byte array return Type.struct([Type.array(Type.int(8), ty.size)]) elif isinstance(ty, types.UnicodeCharSeq): charty = Type.int(numpy_support.sizeof_unicode_char * 8) return Type.struct([Type.array(charty, ty.count)]) elif isinstance(ty, types.CharSeq): charty = Type.int(8) return Type.struct([Type.array(charty, ty.count)]) elif ty in STRUCT_TYPES: return self.get_struct_type(STRUCT_TYPES[ty]) else: try: impl = struct_registry.match(ty) except KeyError: pass else: return self.get_struct_type(impl(ty)) if isinstance(ty, types.Pair): pairty = self.make_pair(ty.first_type, ty.second_type) return self.get_struct_type(pairty) else: return LTYPEMAP[ty]
def test_struct_identical(self): ta = Type.struct([Type.int(32), Type.float()], name='ta') tb = Type.struct([Type.int(32), Type.float()]) self.assertTrue(ta.is_layout_identical(tb))
def get_struct_type(self, struct): fields = [self.get_data_type(v) for _, v in struct._fields] return Type.struct(fields)
def test_struct_identical(self): m = Module.new("test_struct_identical") ta = Type.struct([Type.int(32), Type.float()], name="ta") tb = Type.struct([Type.int(32), Type.float()]) self.assertTrue(ta.is_layout_identical(tb))
float_type = lc.Type.double() bool_type = lc.Type.int(1) void_type = lc.Type.void() char_type = lc.Type.int(8) vec_type = lambda width, elt_type: Type.vector(elt_type, width) pointer = Type.pointer any_type = pointer(Type.int(ptrsize)) string_type = pointer(char_type) # naive array array_type = lambda elt_type: Type.struct([ pointer(elt_type), # data | (<type>)* int_type, # nd | int pointer(int_type), # strides | int* ], name='ndarray_' + str(elt_type)) intp_type = Type.pointer(int_type) #------------------------------------------------------------------------ # Array Types #------------------------------------------------------------------------ # Contiguous or Fortran # --------------------- # # struct { # eltype *data; # intp shape[nd];
def array_type(elt_type): return Type.struct([ pointer(elt_type), # data int_type, # dimensions pointer(int_type), # shape ], name='ndarray_' + str(elt_type))
def ArrayF_Type(eltype): return Type.struct([ pointer(eltype), # data | (<type>)* intp_type, # shape | intp ], name='Array_F<' + str(eltype) + '>')
#!/usr/bin/env python3 from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT PTR = lambda t: Type.pointer(t) Int8 = Type.int(8) Int32 = Type.int(32) Int64 = Type.int(64) Void = Type.void() STR = PTR(Int8) STRArray = PTR(STR) STRList = Type.struct([Int64, STRArray], "STRList") # class STRList: # type = None # def __init__(self, size): # # assert all(type(v) == type(values[0]) for v in values), \ # # "all elements of list should be of the same type" # self.size = size # def codegen(self): # self.type = STRList def argv(func): global module blk = func.append_basic_block("args") builder = Builder.new(blk) # fn = module.get_function_named("mainargs") fn = LLVMFunction("mainargs", args=[Int32, STRArray], ret=PTR(STRList), m=module) # print(fn.type.pointee.args)
def ArrayS_Type(eltype): return Type.struct([ pointer(eltype), # data | (<type>)* Type.array(diminfo_type, 2), # shape | diminfo ], name='Array_S<' + str(eltype) + '>')
_trace_refs_ = hasattr(sys, 'getobjects') _plat_bits = struct_.calcsize('@P') * 8 _int8 = Type.int(8) _int32 = Type.int(32) _void_star = Type.pointer(_int8) _int8_star = _void_star _sizeof_py_ssize_t = ctypes.sizeof(getattr(ctypes, 'c_size_t')) _llvm_py_ssize_t = Type.int(_sizeof_py_ssize_t * 8) if _trace_refs_: _pyobject_head = Type.struct([_void_star, _void_star, _llvm_py_ssize_t, _void_star]) _pyobject_head_init = Constant.struct([ Constant.null(_void_star), # _ob_next Constant.null(_void_star), # _ob_prev Constant.int(_llvm_py_ssize_t, 1), # ob_refcnt Constant.null(_void_star), # ob_type ]) else: _pyobject_head = Type.struct([_llvm_py_ssize_t, _void_star]) _pyobject_head_init = Constant.struct([ Constant.int(_llvm_py_ssize_t, 1), # ob_refcnt Constant.null(_void_star), # ob_type ]) _pyobject_head_p = Type.pointer(_pyobject_head)
_trace_refs_ = hasattr(sys, 'getobjects') _plat_bits = struct_.calcsize('@P') * 8 _int8 = Type.int(8) _int32 = Type.int(32) _void_star = Type.pointer(_int8) _int8_star = _void_star _sizeof_py_ssize_t = ctypes.sizeof(getattr(ctypes, 'c_size_t')) _llvm_py_ssize_t = Type.int(_sizeof_py_ssize_t * 8) if _trace_refs_: _pyobject_head = Type.struct( [_void_star, _void_star, _llvm_py_ssize_t, _void_star]) _pyobject_head_init = Constant.struct([ Constant.null(_void_star), # _ob_next Constant.null(_void_star), # _ob_prev Constant.int(_llvm_py_ssize_t, 1), # ob_refcnt Constant.null(_void_star), # ob_type ]) else: _pyobject_head = Type.struct([_llvm_py_ssize_t, _void_star]) _pyobject_head_init = Constant.struct([ Constant.int(_llvm_py_ssize_t, 1), # ob_refcnt Constant.null(_void_star), # ob_type ]) _pyobject_head_p = Type.pointer(_pyobject_head)
int_type = Type.int() float_type = Type.double() bool_type = Type.int(1) void_type = Type.void() char_type = Type.int(8) pointer = Type.pointer any_type = pointer(Type.int(ptrsize)) string_type = pointer(char_type) # { i32*, i32, i32* } array_type = lambda elt_type: Type.struct([ pointer(elt_type), # data | (<type>)* int_type, # dimensions | int pointer(int_type), # strides | int* ], name='ndarray_' + str(elt_type)) # opaque for now blaze_type = lambda datashape: Type.opaque(name="blaze") #------------------------------------------------------------------------ # Constants #------------------------------------------------------------------------ false = Constant.int(bool_type, 0) true = Constant.int(bool_type, 1) zero = Constant.int(int_type, 0) #------------------------------------------------------------------------