def gv_from_python(x, llvm_type = None): if isinstance(x, GenericValue): return x elif isinstance(x, (int,long)): llvm_type = ty_int64 if llvm_type is None else llvm_type assert is_llvm_int_type(llvm_type), \ "Expected LLVM integer type, not %s" % (llvm_type,) return GenericValue.int(llvm_type, x) elif isinstance(x, float): llvm_type = ty_float64 if llvm_type is None else llvm_type assert is_llvm_float_type(llvm_type), \ "Expected LLVM float type, not %s" % (llvm_type,) return GenericValue.real(llvm_type, x) elif isinstance(x, bool): llvm_type = ty_int8 if llvm_type is None else llvm_type assert is_llvm_int_type(llvm_type), \ "Expected LLVM integer type, not %s" % (llvm_type,) return GenericValue.int(llvm_type, x) else: assert isinstance(x, np.ndarray) assert llvm_type is not None assert is_llvm_ptr_type(llvm_type), \ "Native argument receiving numpy array must be a pointer, not %s" % (llvm_type,) elt_type = llvm_type.pointee assert is_llvm_float_type(elt_type) or is_llvm_int_type(elt_type) assert elt_type == python_to_lltype(x.dtype), \ "Can't pass array with %s* data pointer to function that expects %s*" % (x.dtype, elt_type) return GenericValue.pointer(x.ctypes.data)
def ctypes_to_generic_value(cval, t): if isinstance(t, core_types.FloatT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.real(llvm_t, cval.value) elif isinstance(t, core_types.SignedT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.int_signed(llvm_t, cval.value) elif isinstance(t, core_types.IntT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.int(llvm_t, cval.value) elif isinstance(t, core_types.PtrT): return GenericValue.pointer(ctypes.addressof(cval.contents)) else: return GenericValue.pointer(ctypes.addressof(cval))
def python_to_generic_value(x, t): if isinstance(t, core_types.FloatT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.real(llvm_t, x) elif isinstance(t, core_types.SignedT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.int_signed(llvm_t, x) elif isinstance(t, core_types.IntT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.int(llvm_t, x) elif isinstance(t, core_types.PtrT): return GenericValue.pointer(x) else: ctypes_obj = type_conv.from_python(x) return GenericValue.pointer(ctypes.addressof(ctypes_obj))
def python_to_generic_value(x, t): if isinstance(t, FloatT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.real(llvm_t, x) elif isinstance(t, SignedT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.int_signed(llvm_t, x) elif isinstance(t, IntT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.int(llvm_t, x) elif isinstance(t, PtrT): return GenericValue.pointer(x) else: ctypes_obj = type_conv.from_python(x) return GenericValue.pointer(ctypes.addressof(ctypes_obj))
def parfor(fn, niters, fixed_args = (), ee = shared_exec_engine): """ Given a function from index integers to void, run it in parallel over the index range specified by the tuple 'niters' """ assert isinstance(fn, Function), \ "Can only run LLVM functions, not %s" % type(fn) # in case fixed arguments aren't yet GenericValues, convert them fixed_args = tuple(gv_from_python(v, arg.type) for (v,arg) in zip(fixed_args, fn.args)) iter_ranges, steps, shape = parse_iters(niters) result_lltype = return_type(fn) if result_lltype == ty_void: work_fn = parfor_wrapper(fn, steps) launch(work_fn, iter_ranges, fixed_args, ee) return else: assert is_llvm_float_type(result_lltype) or is_llvm_int_type(result_lltype) dtype = lltype_to_dtype(result_lltype) result_array = np.empty(shape = shape, dtype = dtype) fixed_args = (GenericValue.pointer(result_array.ctypes.data),) + fixed_args work_fn = parfor_wrapper(fn, steps, shape) n_given = len(fixed_args) + 2*len(steps) n_expected = len(work_fn.args) assert n_given == n_expected, \ "Work function expects %d arguments but got %d" % (n_expected, n_given) launch(work_fn, iter_ranges, fixed_args, ee) return result_array assert False, "Collecting results not yet implemented"
def ctypes_to_generic_value(cval, t): if isinstance(t, FloatT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.real(llvm_t, cval.value) elif isinstance(t, SignedT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.int_signed(llvm_t, cval.value) elif isinstance(t, IntT): llvm_t = llvm_types.llvm_value_type(t) return GenericValue.int(llvm_t, cval.value) elif isinstance(t, NoneT): return GenericValue.int(llvm_types.int64_t, 0) elif isinstance(t, PtrT): return GenericValue.pointer(ctypes.addressof(cval.contents)) else: return GenericValue.pointer(ctypes.addressof(cval))
def run( py_main_func, *call_args ): from rpy.rtypes import ConstantTypeRegistry registry = ConstantTypeRegistry() # Annotates call graph types (local var, functions param/return...) print( '\nAnalysing call graph...\n%s' % ('='*70) ) annotator = CallableGraphAnnotator( registry ) annotator.set_entry_point( py_main_func, call_args ) annotator.annotate_dependencies() # Generate LLVM code from rpy.codegenerator import ModuleGenerator, FunctionCodeGenerator, L_INT_TYPE, L_BOOL_TYPE module = ModuleGenerator( registry ) l_func_entry, l_func_type = None, None # Declares all function in modules fn_code_generators = [] for r_func_type, type_annotator in annotator.annotator_by_callable.items(): py_func = r_func_type.get_function_object() print( '\nDeclaring function:\n%s\nPython: %s\nRType: %s' % ('-'*70, py_func, r_func_type) ) func_generator = FunctionCodeGenerator( py_func, module, annotator ) fn_code_generators.append( (r_func_type, func_generator) ) # Makes sure that all class type have their struct/attribute index dict initialized for r_func_type, _ in fn_code_generators: if r_func_type.is_constructor(): module.llvm_type_from_rtype( r_func_type ) # Generates function's code, possibly referencing previously declared functions for r_func_type, func_generator in fn_code_generators: print( '\nGenerating code for function:\n%s\n%s\nSouce:\n' % ('-'*70, r_func_type) ) print( func_generator.annotation.get_function_source() ) func_generator.generate_llvm_code() func_generator.report() if r_func_type.get_function_object() is py_main_func: l_func_entry = func_generator.l_func l_func_type = func_generator.l_func_type print( 'Generated module code:' ) print( '----------------------\n%s', module.l_module ) optimize( module ) print( 'Generated module code after optimization:' ) print( '-----------------------------------------\n', module.l_module ) # Execute generate code # 1) Convert call args into generic value print( 'Invoking function with %r' % (call_args,) ) from llvm.core import ModuleProvider, TYPE_VOID from llvm.ee import ExecutionEngine, GenericValue module_provider = ModuleProvider.new( module.l_module ) engine = ExecutionEngine.new( module_provider ) l_call_args = [] for py_call_arg, l_arg in zip( call_args, l_func_entry.args ): if l_arg.type == L_INT_TYPE: l_call_args.append( GenericValue.int_signed( L_INT_TYPE, py_call_arg ) ) elif l_arg.type == L_BOOL_TYPE: l_call_args.append( GenericValue.int( L_BOOL_TYPE, py_call_arg ) ) else: raise ValueError( 'Unsupported parameter "%s" of type: %r' % (py_call_arg, l_arg_type) ) # 2) run the functions l_return_value = engine.run_function( l_func_entry, l_call_args ) # 3) convert LLVM return value into python type if l_func_type.return_type == L_INT_TYPE: return l_return_value.as_int_signed() elif l_func_type.return_type == L_BOOL_TYPE: return l_return_value.as_int() and True or False elif l_func_type.return_type.kind == TYPE_VOID: return None print( 'Return:', l_return_value ) raise ValueError( 'Unsupported return type "%s"' % l_func_entry.return_type )
dsquared_func = Function.new(mod, Type.function(Type.double(), [Type.double(), Type.double()], False), "dsquared") block = dsquared_func.append_basic_block("entry") builder = Builder.new(block) x = dsquared_func.args[0] xsquared = builder.fmul(x, x) y = dsquared_func.args[1] ysquared = builder.fmul(y, y) d2 = builder.fadd(xsquared, ysquared) builder.ret(d2) #print(mod) a = GenericValue.real(Type.double(), 3.0) b = GenericValue.real(Type.double(), 4.0) result = engine.run_function(dsquared_func, [a, b]) #print(result.as_real(Type.double())) sqrt_func = Function.new(mod, Type.function(Type.double(), [Type.double()], False), "sqrt") r = engine.run_function(sqrt_func, [result]) #print(r.as_real(Type.double())) # define a function that calls a function distance_func = Function.new(mod, Type.function(Type.double(), [Type.double(), Type.double()], False), "distance") block = distance_func.append_basic_block("entry") builder = Builder.new(block) x = distance_func.args[0]
def run(py_main_func, *call_args): from rpy.rtypes import ConstantTypeRegistry registry = ConstantTypeRegistry() # Annotates call graph types (local var, functions param/return...) print('\nAnalysing call graph...\n%s' % ('=' * 70)) annotator = CallableGraphAnnotator(registry) annotator.set_entry_point(py_main_func, call_args) annotator.annotate_dependencies() # Generate LLVM code from rpy.codegenerator import ModuleGenerator, FunctionCodeGenerator, L_INT_TYPE, L_BOOL_TYPE module = ModuleGenerator(registry) l_func_entry, l_func_type = None, None # Declares all function in modules fn_code_generators = [] for r_func_type, type_annotator in annotator.annotator_by_callable.items(): py_func = r_func_type.get_function_object() print('\nDeclaring function:\n%s\nPython: %s\nRType: %s' % ('-' * 70, py_func, r_func_type)) func_generator = FunctionCodeGenerator(py_func, module, annotator) fn_code_generators.append((r_func_type, func_generator)) # Makes sure that all class type have their struct/attribute index dict initialized for r_func_type, _ in fn_code_generators: if r_func_type.is_constructor(): module.llvm_type_from_rtype(r_func_type) # Generates function's code, possibly referencing previously declared functions for r_func_type, func_generator in fn_code_generators: print('\nGenerating code for function:\n%s\n%s\nSouce:\n' % ('-' * 70, r_func_type)) print(func_generator.annotation.get_function_source()) func_generator.generate_llvm_code() func_generator.report() if r_func_type.get_function_object() is py_main_func: l_func_entry = func_generator.l_func l_func_type = func_generator.l_func_type print('Generated module code:') print('----------------------\n%s', module.l_module) optimize(module) print('Generated module code after optimization:') print('-----------------------------------------\n', module.l_module) # Execute generate code # 1) Convert call args into generic value print('Invoking function with %r' % (call_args, )) from llvm.core import ModuleProvider, TYPE_VOID from llvm.ee import ExecutionEngine, GenericValue module_provider = ModuleProvider.new(module.l_module) engine = ExecutionEngine.new(module_provider) l_call_args = [] for py_call_arg, l_arg in zip(call_args, l_func_entry.args): if l_arg.type == L_INT_TYPE: l_call_args.append(GenericValue.int_signed(L_INT_TYPE, py_call_arg)) elif l_arg.type == L_BOOL_TYPE: l_call_args.append(GenericValue.int(L_BOOL_TYPE, py_call_arg)) else: raise ValueError('Unsupported parameter "%s" of type: %r' % (py_call_arg, l_arg_type)) # 2) run the functions l_return_value = engine.run_function(l_func_entry, l_call_args) # 3) convert LLVM return value into python type if l_func_type.return_type == L_INT_TYPE: return l_return_value.as_int_signed() elif l_func_type.return_type == L_BOOL_TYPE: return l_return_value.as_int() and True or False elif l_func_type.return_type.kind == TYPE_VOID: return None print('Return:', l_return_value) raise ValueError('Unsupported return type "%s"' % l_func_entry.return_type)