def _test_as_arguments(self, fe_args): """ Test round-tripping types *fe_args* through the default data model's argument conversion and unpacking logic. """ dmm = datamodel.default_manager fi = datamodel.ArgPacker(dmm, fe_args) module = ir.Module() fnty = ir.FunctionType(ir.VoidType(), []) function = ir.Function(module, fnty, name="test_arguments") builder = ir.IRBuilder() builder.position_at_end(function.append_basic_block()) args = [ir.Constant(dmm.lookup(t).get_value_type(), None) for t in fe_args] # Roundtrip values = fi.as_arguments(builder, args) asargs = fi.from_arguments(builder, values) self.assertEqual(len(asargs), len(fe_args)) valtys = tuple([v.type for v in values]) self.assertEqual(valtys, fi.argument_types) expect_types = [a.type for a in args] got_types = [a.type for a in asargs] self.assertEqual(expect_types, got_types) builder.ret_void() ll.parse_assembly(str(module))
def check_parsing(self): mod = ir.Module() # Yield to caller and provide the module for adding # new GV. yield mod # Caller yield back and continue with testing asm = str(mod) llvm.parse_assembly(asm)
def test_encoding_problem(self): c = ir.Constant(ir.ArrayType(ir.IntType(8), 256), bytearray(range(256))) m = self.module() gv = ir.GlobalVariable(m, c.type, "myconstant") gv.global_constant = True gv.initializer = c # With utf-8, the following will cause: # UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 136: invalid continuation byte parsed = llvm.parse_assembly(str(m)) # Make sure the encoding does not modify the IR reparsed = llvm.parse_assembly(str(parsed)) self.assertEqual(str(parsed), str(reparsed))
def compile_module(self, asm, linking_asm=None): library = self.codegen.create_library('compiled_module') ll_module = ll.parse_assembly(asm) ll_module.verify() library.add_llvm_module(ll_module) if linking_asm: linking_library = self.codegen.create_library('linking_module') ll_module = ll.parse_assembly(linking_asm) ll_module.verify() linking_library.add_llvm_module(ll_module) library.add_linking_library(linking_library) return library
def _check_llvm_bugs(self): """ Guard against some well-known LLVM bug(s). """ # Check the locale bug at https://github.com/numba/numba/issues/1569 # Note we can't cache the result as locale settings can change # accross a process's lifetime. Also, for this same reason, # the check here is a mere heuristic (there may be a race condition # between now and actually compiling IR). ir = """ define double @func() { ret double 1.23e+01 } """ mod = ll.parse_assembly(ir) ir_out = str(mod) if "12.3" in ir_out or "1.23" in ir_out: # Everything ok return if "1.0" in ir_out: loc = locale.getlocale() raise RuntimeError( "LLVM will produce incorrect floating-point code " "in the current locale %s.\nPlease read " "http://numba.pydata.org/numba-doc/dev/user/faq.html#llvm-locale-bug " "for more information." % (loc,)) raise AssertionError("Unexpected IR:\n%s\n" % (ir_out,))
def test_as_return(self): """ - Is as_return() and from_return() implemented? - Are they the inverse of each other? """ fnty = ir.FunctionType(ir.VoidType(), []) function = ir.Function(self.module, fnty, name="test_as_return") builder = ir.IRBuilder() builder.position_at_end(function.append_basic_block()) undef_value = ir.Constant(self.datamodel.get_value_type(), None) ret = self.datamodel.as_return(builder, undef_value) self.assertIsNot(ret, NotImplemented, "as_return returned " "NotImplementedError") self.assertEqual(ret.type, self.datamodel.get_return_type()) rev_value = self.datamodel.from_return(builder, ret) self.assertEqual(rev_value.type, self.datamodel.get_value_type()) builder.ret_void() # end function # Ensure valid LLVM generation materialized = ll.parse_assembly(str(self.module)) str(materialized)
def make_add_fn(): global ee int32 = llvm.ir.IntType(32) module = ir.Module() adder_type = ir.FunctionType(int32, (int32, int32)) adder = ir.Function(module, adder_type, 'add') adder.args[0].name = 'a' adder.args[1].name = 'b' bb_entry = adder.append_basic_block('entry') irbuilder = ir.IRBuilder(bb_entry) s = irbuilder.add(adder.args[0], adder.args[1]) irbuilder.ret(s) llvm_module = binding.parse_assembly(str(module)) tm = binding.Target.from_default_triple().create_target_machine() ee = binding.create_mcjit_compiler(llvm_module, tm) ee.finalize_object() cfptr = ee.get_function_address('add') cfunc = CFUNCTYPE(c_int32, c_int32, c_int32)(cfptr) print(cfunc(3, 4)) return cfunc
def __init__(self, module_name): self._libraries = set() self._data_layout = None self._llvm_module = ll.parse_assembly( str(self._create_empty_module(module_name))) self._llvm_module.name = "global_codegen_module" self._init(self._llvm_module)
def evaluate(self, string, optimize=True): ast = self.parser.parse(string) self.generator.generate_llvm(ast) if not (isinstance(ast, FunctionNode) and ast.is_anonymous()): return None # print("-------------- Generated -------------------") # print(str(self.generator.module)) llvm_mod = llvm.parse_assembly(str(self.generator.module)) if optimize: pmb = llvm.create_pass_manager_builder() pmb.opt_level = 2 pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(llvm_mod) # print("-------------- Optimized -------------------") # print(str(llvm_mod)) target_machine = self.target.create_target_machine() with llvm.create_mcjit_compiler(llvm_mod, target_machine) as ee: ee.finalize_object() func = llvm_mod.get_function(ast.prototype.name) fptr = CFUNCTYPE(c_double)(ee.get_pointer_to_function(func)) result = fptr() return result
def _make_cas_function(): """ Generate a compare-and-swap function for portability sake. """ # Generate IR mod = lc.Module.new('generate-cas') llint = lc.Type.int() llintp = lc.Type.pointer(llint) fnty = lc.Type.function(llint, [llintp, llint, llint]) fn = mod.add_function(fnty, name='.numba.parallel.ufunc.cas') ptr, old, repl = fn.args bb = fn.append_basic_block('') builder = lc.Builder.new(bb) outpack = builder.cmpxchg(ptr, old, repl, ordering='monotonic') out = builder.extract_value(outpack, 0) failed = builder.extract_value(outpack, 1) builder.ret(builder.select(failed, old, out)) # Build & Link llmod = ll.parse_assembly(str(mod)) llfn = llmod.get_function(fn.name) target = ll.Target.from_default_triple() tm = target.create_target_machine() engine = ll.create_mcjit_compiler(llmod, tm) ptr = engine.get_pointer_to_function(llfn) return engine, ptr
def __init__(self, codegen, name): self._codegen = codegen self._name = name self._linking_libraries = set() self._final_module = ll.parse_assembly( str(self._codegen._create_empty_module(self._name))) self._shared_module = None
def run(llvm_ir): # Load the runtime ctypes._dlopen(os.path.join(_path, 'gonert.so'), ctypes.RTLD_GLOBAL) # Initialize LLVM llvm.initialize() llvm.initialize_native_target() llvm.initialize_native_asmprinter() target = llvm.Target.from_default_triple() target_machine = target.create_target_machine() mod = llvm.parse_assembly(llvm_ir) mod.verify() engine = llvm.create_mcjit_compiler(mod, target_machine) # Execute the main() function # # !!! Note: Requires modification in Project 8 (see below) # main_ptr = engine.get_function_address('main') # main_func = ctypes.CFUNCTYPE(None)(main_ptr) # main_func() init_ptr = engine.get_function_address('__init') init_func = ctypes.CFUNCTYPE(None)(init_ptr) init_func() main_ptr = engine.get_function_address('_gone_main') main_func = ctypes.CFUNCTYPE(None)(main_ptr) main_func()
def generate_kernel_wrapper(self, func, argtypes): module = func.module arginfo = self.get_arg_packer(argtypes) def sub_gen_with_global(lty): if isinstance(lty, llvmir.PointerType): return (lty.pointee.as_pointer(SPIR_GLOBAL_ADDRSPACE), lty.addrspace) return lty, None if len(arginfo.argument_types) > 0: llargtys, changed = zip(*map(sub_gen_with_global, arginfo.argument_types)) else: llargtys = changed = () wrapperfnty = lc.Type.function(lc.Type.void(), llargtys) wrapper_module = self.create_module("hsa.kernel.wrapper") wrappername = 'hsaPy_{name}'.format(name=func.name) argtys = list(arginfo.argument_types) fnty = lc.Type.function(lc.Type.int(), [self.call_conv.get_return_type( types.pyobject)] + argtys) func = wrapper_module.add_function(fnty, name=func.name) func.calling_convention = CC_SPIR_FUNC wrapper = wrapper_module.add_function(wrapperfnty, name=wrappername) builder = lc.Builder.new(wrapper.append_basic_block('')) # Adjust address space of each kernel argument fixed_args = [] for av, adrsp in zip(wrapper.args, changed): if adrsp is not None: casted = self.addrspacecast(builder, av, adrsp) fixed_args.append(casted) else: fixed_args.append(av) callargs = arginfo.from_arguments(builder, fixed_args) # XXX handle error status status, _ = self.call_conv.call_function(builder, func, types.void, argtypes, callargs) builder.ret_void() set_hsa_kernel(wrapper) # Link module.link_in(ll.parse_assembly(str(wrapper_module))) # To enable inlining which is essential because addrspacecast 1->0 is # illegal. Inlining will optimize the addrspacecast out. func.linkage = 'internal' wrapper = module.get_function(wrapper.name) module.get_function(func.name).linkage = 'internal' return wrapper
def add_ir_module(self, ir_module): """ Add a LLVM IR module's contents to this library. """ self._raise_if_finalized() assert isinstance(ir_module, llvmir.Module) ll_module = ll.parse_assembly(str(ir_module)) ll_module.verify() self.add_llvm_module(ll_module)
def __init__(self, codegen, name): self._codegen = codegen self._name = name self._linking_libraries = set() self._final_module = ll.parse_assembly(str(self._codegen._create_empty_module(self._name))) self._final_module.name = self._name # Remember this on the module, for the object cache hooks self._final_module.__library = weakref.proxy(self) self._shared_module = None
def compile_intermediary_code(engine, intermediary_code): # Create an llvm module object from the intermediary code mod = llvm.parse_assembly(intermediary_code) mod.verify() # Add module to engine and prepair for execution engine.add_module(mod) engine.finalize_object() return mod
def create_run_engine(): global target_machine # Create target machine target = llvm.Target.from_default_triple() target_machine = target.create_target_machine() # Add run engine backing_mod = llvm.parse_assembly("") engine = llvm.create_mcjit_compiler(backing_mod, target_machine) return engine
def __init__(self, codegen, name): self._codegen = codegen self._name = name self._linking_libraries = set() self._final_module = ll.parse_assembly( str(self._codegen._create_empty_module(self._name))) self._final_module.name = cgutils.normalize_ir_text(self._name) self._shared_module = None # Track names of the dynamic globals self._dynamic_globals = []
def compile_ir(engine, llvm_ir): """ Compile the LLVM IR string with the given engine. The compiled module object is returned. """ # Create a LLVM module object from the IR mod = llvm.parse_assembly(llvm_ir) mod.verify() # Now add the module and make sure it is ready for execution engine.add_module(mod) engine.finalize_object() return mod
def __init__(self, codegen, name): self._codegen = codegen self._name = name self._linking_libraries = set() self._final_module = ll.parse_assembly( str(self._codegen._create_empty_module(self._name))) self._final_module.name = cgutils.normalize_ir_text(self._name) # Remember this on the module, for the object cache hooks self._final_module.__library = weakref.proxy(self) self._shared_module = None # Track names of the dynamic globals self._dynamic_globals = []
def __init__(self): self.target = llvm.Target.from_default_triple() machine = self.target.create_target_machine() # machine.set_asm_verbosity(True) module = llvm.parse_assembly( str(ir.Module()) ) self.engine = llvm.create_mcjit_compiler(module, machine) self.symbols = {}
def evaluate(self, codestr, optimize=True, llvmdump=False): """Evaluate code in codestr. Returns None for definitions and externs, and the evaluated expression value for toplevel expressions. """ # Parse the given code and generate code from it ast = Parser().parse_toplevel(codestr) self.codegen.generate_code(ast) if llvmdump: print('======== Unoptimized LLVM IR') print(str(self.codegen.module)) # If we're evaluating a definition or extern declaration, don't do # anything else. If we're evaluating an anonymous wrapper for a toplevel # expression, JIT-compile the module and run the function to get its # result. if not (isinstance(ast, FunctionAST) and ast.is_anonymous()): return None # Convert LLVM IR into in-memory representation llvmmod = llvm.parse_assembly(str(self.codegen.module)) # Optimize the module if optimize: pmb = llvm.create_pass_manager_builder() pmb.opt_level = 2 pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(llvmmod) if llvmdump: print('======== Optimized LLVM IR') print(str(llvmmod)) # Create a MCJIT execution engine to JIT-compile the module. Note that # ee takes ownership of target_machine, so it has to be recreated anew # each time we call create_mcjit_compiler. target_machine = self.target.create_target_machine() with llvm.create_mcjit_compiler(llvmmod, target_machine) as ee: ee.finalize_object() if llvmdump: print('======== Machine code') print(target_machine.emit_assembly(llvmmod)) func = llvmmod.get_function(ast.proto.name) fptr = CFUNCTYPE(c_double)(ee.get_pointer_to_function(func)) result = fptr() return result
def optimize(self, opt_level=2) -> binding.ModuleRef: """Compile and optimize llvm module.""" llvm_module = binding.parse_assembly(str(self.source_module)) llvm_module.verify() # Optimize pass_manager = binding.create_module_pass_manager() pass_manager_builder = binding.create_pass_manager_builder() pass_manager_builder.opt_level = opt_level pass_manager_builder.populate(pass_manager) pass_manager.run(llvm_module) return llvm_module
def compile_ir(engine, llvm_ir): """ Compile the LLVM IR string with the given engine. The compiled module object is returned. Source: http://llvmlite.pydata.org/en/latest/binding/examples.html#compiling-a-trivial-function """ # Create a LLVM module object from the IR mod = llvm.parse_assembly(llvm_ir) mod.verify() # Now add the module and make sure it is ready for execution engine.add_module(mod) engine.finalize_object() return mod
def __init__(self, triple="DEFAULT"): llvm.initialize() llvm.initialize_native_target() llvm.initialize_native_asmprinter() if triple == "DEFAULT": target = llvm.Target.from_default_triple() else: target = llvm.Target.from_triple(triple=triple) self.target_machine = target.create_target_machine() backing_mod = llvm.parse_assembly("") self.engine = llvm.create_mcjit_compiler(module=backing_mod, target_machine=self.target_machine)
def create_execution_engine(): """ Create an ExecutionEngine suitable for JIT code generation on the host CPU. The engine is reusable for an arbitrary number of modules. """ # Create a target machine representing the host target = llvm.Target.from_default_triple() target_machine = target.create_target_machine() # And an execution engine with an empty backing module backing_mod = llvm.parse_assembly("") engine = llvm.create_mcjit_compiler(backing_mod, target_machine) return engine
def create_execution_engine(): """ Create an ExecutionEngine suitable for JIT code generation on the host CPU. The engine is reusable for an arbitrary number of modules. Source: http://llvmlite.pydata.org/en/latest/binding/examples.html#compiling-a-trivial-function """ # Create a target machine representing the host target = llvm.Target.from_default_triple() target_machine = target.create_target_machine() # And an execution engine with an empty backing module backing_mod = llvm.parse_assembly("") engine = llvm.create_mcjit_compiler(backing_mod, target_machine) return engine
def load(self, module_ir, **kwargs): run = kwargs.get('run', None) dump = kwargs.get('dump', None) if dump: print(str(module_ir), file = dump) # TODO declare only needed symbols for name, t in self.symbols.items(): if type(t) is ir.FunctionType: ir.Function(module_ir, t, name) else: ir.GlobalVariable(module_ir, t, name) module = llvm.parse_assembly(str(module_ir)) # TODO optimize module optimize = kwargs.get('optimize', 2) if optimize: pmb = llvm.create_pass_manager_builder() pmb.opt_level = optimize pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(module) # if dump: # print(str(module)) self.engine.add_module(module) module.verify() # get main pointer self.engine.finalize_object() if run: main = self.engine.get_function_address(run) fptr = ctypes.CFUNCTYPE(None)(main) result = fptr() # remember symbols for later modules for g in module_ir.global_values: self.symbols[g.name] = g.type.pointee
def compile_fnclex(context): """ Compile a function that calls fnclex to workround https://support.microsoft.com/en-us/kb/982107 """ codegen = context.codegen() library = codegen.create_library("kb982107") ir_mod = """ define void @fnclex() { call void asm sideeffect "fnclex", ""() ret void } """ ll.initialize_native_asmparser() library.add_llvm_module(ll.parse_assembly(ir_mod)) library.finalize() return library
def exitProgram(self, ctx): print "* Target cpu: " + llvm.get_host_cpu_name() programAst = ProgramAST() for child in ctx.getChildren(): child_ast = self.prop[child] programAst.asts.append(child_ast) mod, cfg_list = programAst.codeGenerate(self.var_ptr_symbolTBL) strmod = str(mod) print "=== Generated IR code ===\n" print strmod with open("output.ll", 'w') as f: f.write(strmod) llmod = llvm.parse_assembly(strmod) answer = raw_input('* Optimizing this code? (y/n): ') if answer.lower() == "y": opt = True else: opt = False if opt: pm = llvm.create_module_pass_manager() pmb = llvm.create_pass_manager_builder() pmb.opt_level = 3 # -O3 pmb.populate(pm) # optimize pm.run(llmod) print "=== Generated optimized IR code ===\n" print llmod with open("output_opt.ll", 'w') as f: f.write(str(llmod)) llmod.verify() with llvm.create_mcjit_compiler(llmod, self.tm) as ee: ee.finalize_object() print "=== Generated assembly code ===\n" print(self.tm.emit_assembly(llmod)) with open("output.asm", 'w') as f: f.write(self.tm.emit_assembly(llmod)) answer = raw_input('Do you want to create CFG Graph? (y/n) : ') if answer.lower() == 'y': for cfg in cfg_list: dot = llvm.get_function_cfg(cfg) llvm.view_dot_graph(dot ,filename=cfg.name,view = True)
def compile_to_object_code(self): """Compile previously evaluated code into an object file. The object file is created for the native target, and its contents are returned as a bytes object. """ # We use the small code model here, rather than the default one # `jitdefault`. # # The reason is that only ELF format is supported under the `jitdefault` # code model on Windows. However, COFF is commonly used by compilers on # Windows. # # Please refer to https://github.com/numba/llvmlite/issues/181 # for more information about this issue. target_machine = self.target.create_target_machine(codemodel='small') # Convert LLVM IR into in-memory representation llvmmod = llvm.parse_assembly(str(self.codegen.module)) return target_machine.emit_object(llvmmod)
def _create_execution_engine(self): """ Create an ExecutionEngine suitable for JIT code generation on the host CPU. The engine is reusable for any number of modules. """ from llvmlite import binding if not self._clang: return None # Initialization... binding.initialize() binding.initialize_native_target() binding.initialize_native_asmprinter() # Create a target machine representing the host target = binding.Target.from_default_triple() target_machine = target.create_target_machine() # And an execution engine with an empty backing module backing_mod = binding.parse_assembly("") engine = binding.create_mcjit_compiler(backing_mod, target_machine) self._binding = binding return engine
def __init__(self): llvm.initialize() llvm.initialize_native_asmprinter() llvm.initialize_native_target() target = llvm.Target.from_default_triple() self.target_machine = target.create_target_machine() self.target_machine.set_asm_verbosity(True) mod = llvm.parse_assembly("") mod.verify() self.ee = llvm.create_mcjit_compiler(mod, self.target_machine) pmb = llvm.create_pass_manager_builder() pmb.opt_level = 3 pmb.loop_vectorize = True pmb.slp_vectorize = True self.pm = llvm.create_module_pass_manager() pmb.populate(self.pm) load_lfortran_runtime_library()
def __init__(self): self.module = ir.Module(name='Kaleidoscope') target = llvm.Target.from_default_triple() target_machine = target.create_target_machine() backing_mod = llvm.parse_assembly('') self.engine = llvm.create_mcjit_compiler(backing_mod, target_machine) self._prototypes = { 'sin': prototype('sin', 'x'), 'cos': prototype('cos', 'x'), 'sqrt': prototype('sqrt', 'x'), } self._runtime = [] for func in runtime.__all__: wrap = runtime.Wrap(getattr(runtime, func)) self._runtime.append(wrap) llvm.add_symbol(str(wrap), wrap.addr) self._prototypes[str(wrap)] = wrap.prototype
def emit_object_file(module, output_file, triple=None): # pragma: nocover """Emit object file from a module. Args: module (Module): Module with an LLVM IR. output_file (str): Where to put emitted object file. triple (str, optional): Platform triple. """ llvm.initialize() llvm.initialize_native_asmprinter() llvm.initialize_native_target() if triple is None: target = llvm.Target.from_default_triple() else: target = llvm.Target.from_triple(triple) machine = target.create_target_machine() mod = llvm.parse_assembly(str(module)) mod.verify() with open(output_file, 'wb') as f: f.write(machine.emit_object(mod))
def test_as_arg(self): """ - Is as_arg() and from_arg() implemented? - Are they the inverse of each other? """ fnty = ir.FunctionType(ir.VoidType(), []) function = ir.Function(self.module, fnty, name="test_as_arg") builder = ir.IRBuilder() builder.position_at_end(function.append_basic_block()) undef_value = ir.Constant(self.datamodel.get_value_type(), None) args = self.datamodel.as_argument(builder, undef_value) self.assertIsNot(args, NotImplemented, "as_argument returned NotImplementedError") if isinstance(args, (tuple, list)): def recur_tuplize(args, func=None): for arg in args: if isinstance(arg, (tuple, list)): yield tuple(recur_tuplize(arg, func=func)) else: if func is None: yield arg else: yield func(arg) argtypes = tuple(recur_tuplize(args, func=lambda x: x.type)) exptypes = tuple(recur_tuplize(self.datamodel.get_argument_type())) self.assertEqual(exptypes, argtypes) else: self.assertEqual(args.type, self.datamodel.get_argument_type()) rev_value = self.datamodel.from_argument(builder, args) self.assertEqual(rev_value.type, self.datamodel.get_value_type()) builder.ret_void() # end function # Ensure valid LLVM generation materialized = ll.parse_assembly(str(self.module)) str(materialized)
def run_jit(module): import llvmlite.binding as llvm llvm.initialize() llvm.initialize_native_target() llvm.initialize_native_asmprinter() target = llvm.Target.from_default_triple() target_machine = target.create_target_machine() compiled_mod = llvm.parse_assembly(str(module)) engine = llvm.create_mcjit_compiler(compiled_mod, target_machine) # Look up the function pointer (a Python int) func_ptr = engine.get_function_address("hello") # Turn into a Python callable using ctypes from ctypes import CFUNCTYPE, c_int hello = CFUNCTYPE(c_int)(func_ptr) res = hello() print('hello() returned', res)
def test_as_data(self): fnty = ir.FunctionType(ir.VoidType(), []) function = ir.Function(self.module, fnty, name="test_as_data") builder = ir.IRBuilder() builder.position_at_end(function.append_basic_block()) undef_value = ir.Constant(self.datamodel.get_value_type(), None) data = self.datamodel.as_data(builder, undef_value) self.assertIsNot(data, NotImplemented, "as_data returned NotImplemented") self.assertEqual(data.type, self.datamodel.get_data_type()) rev_value = self.datamodel.from_data(builder, data) self.assertEqual(rev_value.type, self.datamodel.get_value_type()) builder.ret_void() # end function # Ensure valid LLVM generation materialized = ll.parse_assembly(str(self.module)) str(materialized)
def makeObj(name, mainFunc): target_machine = llvm.Target.from_default_triple().create_target_machine() strmod = str(ast.gLlvmModule) if SHOW_MODULE: print "module:" print "===" print strmod print "===" llmod = llvm.parse_assembly(strmod) if SHOW_ASSEMBLY: print "assembly:" print "===" print target_machine.emit_assembly(llmod) print "===" objdata = target_machine.emit_object(llmod) objFile = open(name, 'wb') objFile.write(objdata) objFile.close()
def module(self, name, show_ir=False): module = ir.Module(name) stdlib = { 'size_t': _size_t, 'malloc': ir.Function(module, ir.FunctionType(_ptr, (_size_t,)), name='malloc') } func = ir.Function(module, llvm_types.PtFunction, '##{}##init'.format(name)) block = func.append_basic_block('entry') bld = ir.IRBuilder(block) yield bld, module, stdlib if show_ir: print(str(module)) refmod = llvm.parse_assembly(str(module)) refmod.verify() self.engine.add_module(refmod) self.engine.finalize_object()
def codegen(ast, specializer, retty, argtys): cgen = LLVMEmitter(specializer, retty, argtys) cgen.visit(ast) mod = llvm.parse_assembly(str(module)) mod.verify() pmb = llvm.PassManagerBuilder() pmb.opt_level=3 pmb.loop_vectorize = True pm = llvm.ModulePassManager() pmb.populate(pm) pm.run(mod) engine.add_module(mod) debug(cgen.function) debug(target_machine.emit_assembly(mod)) return cgen.function
def compile_staged(self): # Parse generated modules and link them mod_bundle = binding.parse_assembly("") while self.staged_modules: m = self.staged_modules.pop() start = time.perf_counter() new_mod = _try_parse_module(m) finish = time.perf_counter() if "time_stat" in debug_env: print("Time to parse LLVM modules '{}': {}".format( m.name, finish - start)) self.__parsed_modules += 1 if new_mod is not None: mod_bundle.link_in(new_mod) mod_bundle.name = m.name # Set the name of the last module self.compiled_modules.add(m) self.opt_and_append_bin_module(mod_bundle)
def compile(self, filename: str, optimize: bool, output: Optional[str], emit_llvm: bool) -> None: compile_time = time() # self.add_debug_info(optimize, filename) program_string = llvm.parse_assembly(str(self.module)) prog_str = str(program_string) if output is None: output = os.path.splitext(filename)[0] with open(output + '.ll', 'w') as out: out.write(prog_str) with open(os.devnull, "w") as tmpout: subprocess.call('clang {0}.ll -O3 -o {0}'.format(output).split(" "), stdout=tmpout, stderr=tmpout) successful("compilation done in: %.3f seconds" % (time() - compile_time)) successful("binary file wrote to " + output) if emit_llvm: successful("llvm assembler wrote to " + output + ".ll") else: os.remove(output + '.ll')
def make_asm(ir_module): # Note: llvmlite does not allow us to do cross-compilation # only native compilation is supported. # therefore, only use default triple for native code generation binding.initialize() binding.initialize_native_target() binding.initialize_native_asmprinter() target = binding.Target.from_triple(binding.get_default_triple()) target_machine = target.create_target_machine() target_machine.set_asm_verbosity(True) # necessary in order to generate code from ir module mod_ref = binding.parse_assembly(ir_module) mod_ref.verify() # generate the native assembly code asm_code = target_machine.emit_assembly(mod_ref) # return asm code as a string return asm_code
def main(verbose=True): llvm.initialize() llvm.initialize_native_asmprinter() llvm.initialize_native_target() target = llvm.Target.from_triple(llvm.get_default_triple()) target_machine = target.create_target_machine() target_machine.set_asm_verbosity(True) # Empty backing module backing_mod = llvm.parse_assembly("") backing_mod.verify() engine = llvm.create_mcjit_compiler(backing_mod, target_machine) print("Interactive Fortran.") print(" * Use Ctrl-D to exit.") print(" * Use Enter to submit.") print(" * Features:") print(" - Multi-line editing (use Alt-Enter)") print(" - History") print(" - Syntax highlighting") print() fortran_evaluator = FortranEvaluator() session = PromptSession('> ', lexer=PygmentsLexer(FortranLexer), multiline=True, key_bindings=kb) try: while True: text = session.prompt() if verbose: print() handle_input(engine, fortran_evaluator, text, verbose) if verbose: print() except EOFError: print("Exiting.")
def add_functions(self, functions): if not functions: return {} module = self.converter.add_functions(functions) try: mod = llvm.parse_assembly(module) mod.verify() except Exception: print("failing: ", module) raise # Now add the module and make sure it is ready for execution self.engine.add_module(mod) if self.optimize: self.module_pass_manager.run(mod) if self.verbose: print(mod) self.engine.finalize_object() # Look up the function pointer (a Python int) result = {} for fname in functions: func_ptr = self.engine.get_function_address(fname) input_types = [x[1] for x in functions[fname].args] output_type = functions[fname].output_type result[fname] = NativeFunctionPointer(fname, func_ptr, input_types, output_type) self.functions_by_name[fname] = result[fname] return result
def create_execution_engine(self): """ Create an ExecutionEngine suitable for JIT code generation on the host CPU. The engine is reusable for an arbitrary number of modules. """ # Create a target machine representing the host target = binding.Target.from_default_triple() self.triple = target.triple # Keep the triple for later # Passing cpu, freatures and opt has not proved to be faster, but do it # anyway, just to show it. cpu = binding.get_host_cpu_name() features = binding.get_host_cpu_features() target_machine = target.create_target_machine( cpu=cpu, features=features.flatten(), opt=3, ) # And an execution engine with an empty backing module backing_mod = binding.parse_assembly("") engine = binding.create_mcjit_compiler(backing_mod, target_machine) return engine
def evaluate(self, optimize=True, ir_dump=False, only_main=False): if ir_dump and not optimize: if only_main: print('define void @"main"(){}'.format(str(self.module).split('define void @"main"()')[1])) else: print(str(self.module)) llvmmod = llvm.parse_assembly(str(self.module)) if optimize: pmb = llvm.create_pass_manager_builder() pmb.opt_level = 2 pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(llvmmod) if ir_dump: print(str(llvmmod)) target_machine = llvm.Target.from_default_triple().create_target_machine() with llvm.create_mcjit_compiler(llvmmod, target_machine) as ee: ee.finalize_object() fptr = CFUNCTYPE(c_void_p)(ee.get_function_address('main')) start_time = time() fptr() end_time = time() print('\n{:f} sec'.format(end_time - start_time))
def bake(self): ir_module = self.irbuild() llvm_module = llvmbinding.parse_assembly(str(ir_module)) #optimizer = llvmbinding.create_pass_manager_builder() #optimizer.opt_level = 3 #optimizer.size_level = 0 #passman = llvm.create_module_pass_manager() #optimizer.populate(passman) #passman.run(module) llvmtarget = llvmbinding.Target.from_default_triple( ).create_target_machine() self.compiler = llvmbinding.create_mcjit_compiler( llvm_module, llvmtarget) self.compiler.finalize_object() krun_pointer = self.compiler.get_function_address("krun") self.krun = self.krun_functype(krun_pointer)
def compile_ir(engine, llvm_ir, opt_level, dump_ir): mod = llvm.parse_assembly(llvm_ir) mod.verify() if dump_ir: print('---------- Initial LLVM IR ---------------') print(llvm_ir) # Optimize the module pmb = llvm.create_pass_manager_builder() pmb.opt_level = opt_level pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(mod) if dump_ir: print('---------- Optimized LLVM IR ---------------') print(str(mod)) engine.add_module(mod) engine.finalize_object() engine.run_static_constructors() return mod
def run_code(code): compiler = Compiler() lexer = PLexer() tokens = lexer.tokenize(code) parser = PParser() parser.parse(tokens) ast = parser.ast ast = ast[1]['body'] #print(pprint.pformat(ast)) compiler.compile(ast) module = compiler.module module.triple = llvm.get_default_triple() llvm.initialize() llvm.initialize_native_target() llvm.initialize_native_asmprinter() llvm_ir_parsed = llvm.parse_assembly(str(module)) llvm_ir_parsed.verify() target_machine = llvm.Target.from_default_triple().create_target_machine() engine = llvm.create_mcjit_compiler(llvm_ir_parsed, target_machine) engine.finalize_object() # Run the function with name func_name. This is why it makes sense to have a 'main' function that calls other functions. entry = engine.get_function_address('main') cfunc = CFUNCTYPE(c_int)(entry) print('The llvm IR generated is:') print(module) print() start_time = time() result = cfunc() end_time = time() print(f'It returns {result}') print('\nExecuted in {:f} sec'.format(end_time - start_time))
def execute(llvm_ir): """ Compile the LLVM IR string with the given engine. The compiled module object is returned. """ llmod = llvm.parse_assembly(str(llvm_ir)) llmod.verify() # print('optimized'.center(80, '-')) pmb = llvm.create_pass_manager_builder() pmb.opt_level = 1 pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(llmod) # print(llmod) target_machine = llvm.Target.from_default_triple().create_target_machine() ee = llvm.create_mcjit_compiler(llmod, target_machine) ee.finalize_object() cfptr = ee.get_function_address("entry_fib") cfunc = CFUNCTYPE(c_int, c_int)(cfptr) return ee, cfunc
def evaluate(self, optimize: bool, ir_dump: bool, timer: bool) -> None: if ir_dump and not optimize: for func in self.module.functions: if func.name == "main": print(func) llvmmod = llvm.parse_assembly(str(self.module)) if optimize: pmb = llvm.create_pass_manager_builder() pmb.opt_level = 3 pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(llvmmod) if ir_dump: print(str(llvmmod)) target_machine = llvm.Target.from_default_triple().create_target_machine() with llvm.create_mcjit_compiler(llvmmod, target_machine) as ee: ee.finalize_object() fptr = CFUNCTYPE(c_void_p)(ee.get_function_address('main')) start_time = time() fptr() end_time = time() if timer: print('\nExecuted in {:f} sec'.format(end_time - start_time))
def main(): llvm.initialize() llvm.initialize_native_target() llvm.initialize_native_asmprinter() i64 = ir.IntType(64) # int func(int, int) ftype_main = ir.FunctionType(i64, []) module = ir.Module(name='sokoide_module') fn_main = ir.Function(module, ftype_main, name="main") block = fn_main.append_basic_block(name='entrypoint') ftype_write = ir.FunctionType(ir.VoidType(), [i64]) fn_write = ir.Function(module, ftype_write, name="write") builder = ir.IRBuilder(block) builder.call(fn_write, (ir.Constant(i64, 42), ), name="write") builder.ret(ir.Constant(i64, 42)) llvm_ir = str(module) llvm_ir_parsed = llvm.parse_assembly(llvm_ir) with open("out.ll", "w") as f: f.write(str(llvm_ir_parsed))
def evaluate(self, codestr, optimize=True, llvmdump=False): ast, _ = Parser().parse_stream(codestr) self.generator.generate_code(ast) if llvmdump: print('========= Unoptimized LLVM IR') print(str(self.generator.module)) if not (isinstance(ast, astree.Function) and ast.is_anonymous()): return None llvmmod = llvm.parse_assembly(str(self.generator.module)) if optimize: pmb = llvm.create_pass_manager_builder() pmb.opt_level = 2 pm = llvm.create_module_pass_manager() pmb.populate(pm) pm.run(llvmmod) if llvmdump: print('========== Optimized LLVM IR') print(str(llvmmod)) target_machine = self.target.create_target_machine() with llvm.create_mcjit_compiler(llvmmod, target_machine) as ee: ee.finalize_object() if llvmdump: print('========== Michine code') print(target_machine.emit_assembly(llvmmod)) fptr = CFUNCTYPE(c_int32)(ee.get_function_address(ast.proto.name)) result = fptr(4, 7) return result
def __init__(self, debugIR=False, debugAST=False, quiet=True, debugLexer=False, debugMemory=False): # Record settings self.debugIR = debugIR self.debugAST = debugAST self.debugLexer = debugLexer self.debugMemory = debugMemory self.quiet = quiet # Setup the execution engine llvm.initialize() llvm.initialize_native_target() llvm.initialize_native_asmprinter() out = ['declare i32 @printf(i8* nocapture readonly, ...)'] out += ['@printFloat = global [4 x i8] c"%f\\0A\\00\"'] out += ['@printInt = global [4 x i8] c"%i\\0A\\00"'] target = llvm.Target.from_default_triple() target_machine = target.create_target_machine() owner = llvm.parse_assembly('\n'.join(out)) self.jit = llvm.create_mcjit_compiler(owner, target_machine) return
def remove_redundant_nrt_refct(ll_module): """ Remove redundant reference count operations from the `llvmlite.binding.ModuleRef`. This parses the ll_module as a string and line by line to remove the unnecessary nrt refct pairs within each block. Decref calls are moved after the last incref call in the block to avoid temporarily decref'ing to zero (which can happen due to hidden decref from alias). Note: non-threadsafe due to usage of global LLVMcontext """ # Early escape if NRT_incref is not used try: ll_module.get_function('NRT_incref') except NameError: return ll_module # the optimisation pass loses the name of module as it operates on # strings, so back it up and reset it on completion name = ll_module.name newll = _remove_redundant_nrt_refct(str(ll_module)) new_mod = ll.parse_assembly(newll) new_mod.name = cgutils.normalize_ir_text(name) return new_mod
def test_DILocation(self): """ Tests that DILocation information is reasonable. """ @njit(debug=True, error_model='numpy') def foo(a): b = a + 1.23 c = a * 2.34 d = b / c print(d) return d # the above produces LLVM like: # define function() { # entry: # alloca # store 0 to alloca # <arithmetic for doing the operations on b, c, d> # setup for print # branch # other_labels: # ... <elided> # } # # The following checks that: # * the alloca and store have no !dbg # * the arithmetic occurs in the order defined and with !dbg # * that the !dbg entries are monotonically increasing in value with # source line number sig = (types.float64, ) metadata = self._get_metadata(foo, sig=sig) full_ir = self._get_llvmir(foo, sig=sig) module = llvm.parse_assembly(full_ir) name = foo.overloads[foo.signatures[0]].fndesc.mangled_name funcs = [x for x in module.functions if x.name == name] self.assertEqual(len(funcs), 1) func = funcs[0] blocks = [x for x in func.blocks] self.assertGreater(len(blocks), 1) block = blocks[0] # Find non-call instr and check the sequence is as expected instrs = [x for x in block.instructions if x.opcode != 'call'] op_seq = [x.opcode for x in instrs] op_expect = ('fadd', 'fmul', 'fdiv') self.assertIn(''.join(op_expect), ''.join(op_seq)) # Parse out metadata from end of each line, check it monotonically # ascends with LLVM source line. Also store all the dbg references, # these will be checked later. line2dbg = set() re_dbg_ref = re.compile(r'.*!dbg (![0-9]+).*$') found = -1 for instr in instrs: inst_as_str = str(instr) matched = re_dbg_ref.match(inst_as_str) if not matched: # if there's no match, ensure it is one of alloca or store, # it's important that the zero init/alloca instructions have # no dbg data accepted = ('alloca ', 'store ') self.assertTrue(any([x in inst_as_str for x in accepted])) continue groups = matched.groups() self.assertEqual(len(groups), 1) dbg_val = groups[0] int_dbg_val = int(dbg_val[1:]) if found >= 0: self.assertTrue(int_dbg_val >= found) found = int_dbg_val # some lines will alias dbg info, this is fine, it's only used to # make sure that the line numbers are correct WRT python line2dbg.add(dbg_val) pysrc, pysrc_line_start = inspect.getsourcelines(foo) # build a map of dbg reference to DI* information metadata_definition_map = self._get_metadata_map(metadata) # Pull out metadata entries referred to by the llvm line end !dbg # check they match the python source, the +2 is for the @njit decorator # and the function definition line. offsets = [ 0, # b = a + 1 1, # a * 2.34 2, # d = b / c 3, # print(d) ] pyln_range = [pysrc_line_start + 2 + x for x in offsets] # do the check for (k, line_no) in zip(sorted(line2dbg, key=lambda x: int(x[1:])), pyln_range): dilocation_info = metadata_definition_map[k] self.assertIn(f'line: {line_no}', dilocation_info) # Check that variable "a" is declared as on the same line as function # definition. expr = r'.*!DILocalVariable\(name: "a",.*line: ([0-9]+),.*' match_local_var_a = re.compile(expr) for entry in metadata_definition_map.values(): matched = match_local_var_a.match(entry) if matched: groups = matched.groups() self.assertEqual(len(groups), 1) dbg_line = int(groups[0]) # +1 for the decorator on Python 3.8+, `inspect` changed, also # recall that Numba's DWARF refers to the "def" line defline = pysrc_line_start + (utils.PYVERSION >= (3, 8)) self.assertEqual(dbg_line, defline) break else: self.fail('Assertion on DILocalVariable not made')
def assert_valid_ir(self, mod): llvm.parse_assembly(str(mod))
block = incr_func.append_basic_block("entry") builder = IRBuilder(block) tmp1 = builder.load(x_var) tmp2 = builder.fadd(tmp1, Constant(ty_double, 1.0)) builder.store(tmp2, x_var) builder.ret_void() # Part (g) - JIT import llvmlite.binding as llvm llvm.initialize() llvm.initialize_native_target() llvm.initialize_native_asmprinter() target = llvm.Target.from_default_triple() target_machine = target.create_target_machine() compiled_mod = llvm.parse_assembly(str(mod)) engine = llvm.create_mcjit_compiler(compiled_mod, target_machine) # Look up the function pointer (a Python int) func_ptr = engine.get_function_address("distance") # Turn into a Python callable using ctypes from ctypes import CFUNCTYPE, c_int, c_double distance = CFUNCTYPE(c_double, c_double, c_double)(func_ptr) res = distance(3, 4) print('distance =', res)