def representation_type(ty): """ Get the low-level representation type for a high-level (user-defined) type. Returns ======= The pykit type for the object layout. """ from flypy.lib import vectorobject from flypy.lib import arrayobject from flypy.runtime.obj import pointerobject # NOTE: special cases should be kept to an absolute minimum here. They # should probably be introduced only if ctypes cannot represent the # type if ty.impl == vectorobject.Vector: base, count = ty.parameters return ptypes.Vector(representation_type(base), count) elif ty.impl == pointerobject.Pointer: # type pointed to may not be supported by ctypes (base, ) = ty.parameters if base.impl == vectorobject.Vector: return ptypes.Pointer(representation_type(base)) cty = conversion.ctype(ty) result_type = ctypes_support.from_ctypes_type(cty) # struct uses pointer if result_type.is_struct: result_type = ptypes.Pointer(result_type) return result_type
def register_finalizer(caller, builder, env, context, type, gcmod, obj): """ Register a finalizer for the object given as pointer `obj`. """ from flypy.pipeline import phase curphase = env['flypy.state.phase'] #(TODO: (indirect) allocation of a new object in __del__ will recurse # infinitely) if '__del__' in type.fields: # Compile __del__ __del__ = type.fields['__del__'] lfunc, env = phase.apply_phase(phase.codegen, __del__, (type, ), env['flypy.target']) # Retrieve function address of __del__ cfunc = env["codegen.llvm.ctypes"] pointerval = ctypes.cast(cfunc, ctypes.c_void_p).value ptr = ir.Pointer(pointerval, ptypes.Pointer(ptypes.Void)) context[ptr] = Pointer[void] # Cast object to void * obj_p = builder.convert(ptypes.Opaque, obj) context[obj_p] = Pointer[void] # Call gc_add_finalizer with (obj, ptr) result = caller.call(curphase, gcmod.gc_add_finalizer, [obj_p, ptr]) context[result] = void return [obj_p, result]
def implement_from_array(builder, argtypes, parray): base, count = argtypes[0] vector_type = ptypes.Vector(base, count) ptr_type = ptypes.Pointer(vector_type) pv = builder.bitcast(parray, ptr_type) v = builder.ptrload(p) return builder.ret(v)
def run(func, env=None, return_block=None): """ Rewrite 'ret' operations into jumps to a return block and assignments to a return variable. """ b = Builder(func) return_block = return_block or func.new_block("pykit.return") # Allocate return variable if not func.type.restype.is_void: with b.at_front(func.startblock): return_var = b.alloca(types.Pointer(func.type.restype), []) b.store(Undef(func.type.restype), return_var) else: return_var = None # Repace 'ret' instructions with jumps and assignments for op in func.ops: if op.opcode == "ret": b.position_after(op) if return_var: b.store(op.args[0], return_var) b.jump(return_block) op.delete() with b.at_end(return_block): if return_var: result = b.load(return_var.type.base, [return_var]) else: result = None b.ret(result)
def initialize(self): """Initialize pykit untypes structures""" # Setup Function sig = types.Function(types.Opaque, [types.Opaque] * len(self.argnames), False) self.dst = Function(func_name(self.func), self.argnames, sig) # Setup Builder self.builder = Builder(self.dst) # Setup Blocks for offset in self.bytecode.labels: name = blockname(self.func, offset) block = self.dst.new_block(name) self.blocks[offset] = block self.stacks[block] = [] # Setup Variables self.builder.position_at_beginning(self.dst.startblock) for varname in self.varnames: stackvar = self.builder.alloca(types.Pointer(types.Opaque), result=self.dst.temp(varname)) self.allocas[varname] = stackvar # Initialize function arguments if varname in self.argnames: self.builder.store(self.dst.get_arg(varname), stackvar)
def test_type(self): self.assertEqual(from_ctypes_type(ctypes.c_int32), types.Int32) self.assertEqual(from_ctypes_type(ctypes.POINTER(ctypes.c_int32)), types.Pointer(types.Int32)) self.assertEqual( from_ctypes_type(MyStruct), types.Struct(['x', 'y'], [types.Float32, types.Int64]))
def test_value(self): self.assertEqual(from_ctypes_value(ctypes.c_int32(10)), ir.Const(10, types.Int32)) i = ctypes.c_int32(10) p = ctypes.pointer(i) addr = ctypes.cast(p, ctypes.c_void_p).value self.assertEqual(from_ctypes_value(p), ir.Pointer(addr, types.Pointer(types.Int32)))
def test_basic_builder(self): v = self.b.alloca(types.Pointer(types.Float32)) result = self.b.mul(self.a, self.a, result='r') c = self.b.convert(types.Float32, result) self.b.store(c, v) val = self.b.load(v) self.b.ret(val) # print(string(self.f)) assert interp.run(self.f, args=[10]) == 100
def test_basic_builder(self): v = self.b.alloca(types.Pointer(types.Float32), []) result = self.b.mul(types.Int32, [self.a, self.a], result='r') c = self.b.convert(types.Float32, [result]) self.b.store(c, v) val = self.b.load(types.Float32, [v]) self.b.ret(val) # print(string(self.f)) self.assertEqual(str(self.f).strip(), basic_expected)
def alloca(self, varname): if varname not in self.allocas: # Allocate variable with alloca with self.builder.at_front(self.func.startblock): type = types.Pointer(self.local_vars[varname]) result = self.func.temp(varname) self.allocas[varname] = self.builder.alloca(type, [], result) return self.allocas[varname]
def test_unit(self): self.assertEqual(types.Void, types.Void) self.assertEqual(types.Bool, types.Bool) self.assertEqual(types.Int32, types.Int32) self.assertEqual(types.Float32, types.Float32) self.assertEqual(types.Pointer(types.Int32), types.Pointer(types.Int32)) self.assertEqual(types.Vector(types.Int32, 4), types.Vector(types.Int32, 4)) self.assertNotEqual(types.Void, types.Bool) self.assertNotEqual(types.Pointer(types.Void), types.Pointer(types.Bool)) self.assertNotEqual(types.Vector(types.Int32, 4), types.Vector(types.Int32, 5)) self.assertNotEqual(types.Vector(types.Int32, 4), types.Vector(types.Int64, 4))
def from_ctypes_type(ctypes_type, memo=None): """ Convert a ctypes type to a pykit type. Supported are structs, unit types (int/float) """ if memo is None: memo = {} if hashable(ctypes_type) and ctypes_type in memo: return memo[ctypes_type] if hashable(ctypes_type) and ctypes_type in ctypes_map: result = ctypes_map[ctypes_type] elif ctypes_type is ctypes.c_void_p: result = types.Pointer(types.Void) elif is_ctypes_array_type(ctypes_type): result = types.Array(from_ctypes_type(ctypes_type._type_, memo), ctypes_type._length_) elif is_ctypes_pointer_type(ctypes_type): result = types.Pointer(from_ctypes_type(ctypes_type._type_, memo)) elif is_ctypes_struct_type(ctypes_type): # pre-order caching for recursive data structures f_names = [] f_types = [] result = types.Struct(f_names, f_types) memo[ctypes_type] = result fields = [(name, from_ctypes_type(field_type, memo)) for name, field_type in ctypes_type._fields_] fieldnames, fieldtypes = zip(*fields) or (('dummy', ), (types.Int8, )) f_names.extend(fieldnames) f_types.extend(fieldtypes) elif is_ctypes_function_type(ctypes_type): c_restype = from_ctypes_type(ctypes_type._restype_, memo) c_argtypes = [ from_ctypes_type(argty, memo) for argty in ctypes_type._argtypes_ ] result = types.Function(c_restype, c_argtypes, False) else: raise NotImplementedError(ctypes_type) memo[ctypes_type] = result return result
def allocate_object(caller, builder, type, env): """ Allocate object of type `type`. """ if stack_allocate(type): obj = builder.alloca(ptypes.Pointer(ptypes.Opaque)) return [obj], obj else: if env['flypy.target'] != 'cpu': raise errors.CompileError( "Cannot heap allocate object of type %s with target %r" % (type, env['flypy.target'])) return heap_allocate(caller, builder, type, env)
def rewrite_constructors(func, env): """ Rewrite constructor application to object allocation followed by cls.__init__: Rewrite C(x, y) to: obj = allocate() C.__init__(obj, x, y) register_finalizer(obj.__del__) """ phase = env['flypy.state.phase'] context = env['flypy.typing.context'] b = OpBuilder() caller = Caller(b, context, env) for op in func.ops: if op.opcode == 'call': cls, args = op.args if isinstance(cls, Const) and is_flypy_type(cls.const): cls = cls.const f = cls.__init__ type = context[op] # Allocate object obj = ir.Op('allocate_obj', ptypes.Pointer(ptypes.Void), args=[]) register_finalizer = ir.Op('register_finalizer', ptypes.Void, args=[obj]) context[register_finalizer] = void context[obj] = type # Initialize object (call __init__) # TODO: implement this on Type.__call__ when we support *args initialize = caller.call(phase, f, [obj] + op.args[1]) op.replace_uses(obj) op.replace([obj, initialize, register_finalizer])
def generate_copies(func, phis): """ Emit stores to stack variables in predecessor blocks. """ builder = Builder(func) vars = {} loads = {} # Allocate a stack variable for each phi builder.position_at_beginning(func.startblock) for block in phis: for phi in phis[block]: vars[phi] = builder.alloca(types.Pointer(phi.type)) # Generate loads in blocks containing the phis for block in phis: leaders = list(block.leaders) last_leader = leaders[-1] if leaders else block.head builder.position_after(last_leader) for phi in phis[block]: loads[phi] = builder.load(vars[phi]) # Generate copies (store to stack variables) for block in phis: for phi in phis[block]: preds, args = phi.args var = vars[phi] phi_args = [loads.get(arg, arg) for arg in args] for pred, arg in zip(preds, phi_args): builder.position_before(pred.terminator) builder.store(arg, var) # Replace phis for block in phis: for phi in phis[block]: phi.replace_uses(loads[phi]) phi.delete() return vars, loads
def gen_loop(self, start=None, stop=None, step=None): """ Generate a loop given start, stop, step and the index variable type. The builder's position is set to the end of the body block. Returns (condition_block, body_block, exit_block). """ self._assert_position() assert isinstance(stop, Value), "Stop should be a Constant or Operation" ty = stop.type start = start or Const(0, ty) step = step or Const(1, ty) assert start.type == ty == step.type with self.at_front(self.func.blocks[0]): var = self.alloca(types.Pointer(ty), []) prev, exit = self.splitblock('loop.exit') cond = self.func.add_block('loop.cond', after=prev) body = self.func.add_block('loop.body', after=cond) with self.at_end(prev): self.store(start, var) self.jump(cond) # Condition with self.at_front(cond): index = self.load(ty, [var]) self.store(self.add(ty, [index, step]), var) self.cbranch(self.lt(types.Bool, [index, stop]), body, exit) with self.at_end(body): self.jump(cond) self.position_at_beginning(body) return cond, body, exit
def visit_PtrDecl(self, decl): return types.Pointer(self.visit(decl.type.type))
def create(): t = types.Struct([], []) t.names.extend(['spam', 'ham', 'eggs']) t.types.extend([types.Pointer(t), types.Int64, t]) return t
from __future__ import print_function, division, absolute_import import ctypes from flypy import jit, representation, conversion from flypy.types import Pointer, void from flypy.compiler import is_flypy_cc from pykit import types from pykit.ir import OpBuilder, Builder #===------------------------------------------------------------------=== # Return Objects #===------------------------------------------------------------------=== opaque_t = types.Pointer(types.Opaque) @jit('StackVar[a]') class StackVar(object): """ Represent the loaded stack layout of a value. """ layout = [] @classmethod def ctype(cls, ty): cty = conversion.ctype(ty.parameters[0]) # Get the base type if a pointer if hasattr(cty, '_type_'):
def op_addressof(self, op, func): assert func.address addr = const_int(i64, func.address) return self.builder.inttoptr( addr, self.llvm_type(types.Pointer(types.Void)))
def implement_to_array(builder, argtypes, vector, parray): pvector_t = ptypes.Pointer(argtypes[0]) pvector = builder.bitcast(pvector_t, parray) builder.ptrstore(vector, pvector)
def _build_type(type, args): ty, tail = to_type(args[0]), args[1:] for i in range(len(tail)): ty = types.Pointer(ty) return ty