def codegen_compile(func, datatype: str): """ :param func: :param datatype: either 'float', 'double' or 'int' :return: """ func_name = func.__name__ sig = signature(func) if datatype.startswith('int'): llvm_type = ll.IntType(64) type_dummy_instance = LLVMInt64 c_type = c_int64 elif datatype.startswith('uint'): llvm_type = ll.IntType(64) type_dummy_instance = LLVMUInt64 c_type = c_uint64 elif datatype in ['float', 'double']: llvm_type = ll.DoubleType() type_dummy_instance = LLVMDouble c_type = c_double else: return None llvm_param_types = [llvm_type for c in param_names[:len(sig.parameters)]] fntype = ll.FunctionType(llvm_type, llvm_param_types) module = ll.Module() llvm_func = ll.Function(module, fntype, name=func_name) bb_entry = llvm_func.append_basic_block() builder = ll.IRBuilder() builder.position_at_end(bb_entry) context = Context(builder) params = [type_dummy_instance(context, arg) for arg in llvm_func.args] ret = func(*params) context.builder.ret(ret.instruction) code = str(module) llmod = llvm.parse_assembly(code) pmb = llvm.create_pass_manager_builder() pmb.opt_level = 2 pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(llmod) ee = llvm.create_mcjit_compiler(llmod, target_machine) ee.finalize_object() cfptr = ee.get_function_address(func_name) cfunc = CFUNCTYPE(c_type, *[c_type for c in llvm_param_types])(cfptr) # keep the reference alive # (this is probably an ugly hack? but whatever) cfunc.execution_engine = ee cfunc.target_asm = target_machine.emit_assembly(llmod) cfunc.llvm_code = code return cfunc