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 = llvmts.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 __init__(self, codegen, name): self._codegen = codegen self._name = name self._linking_libraries = set() self._final_module = llvmts.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 __init__(self, module_name): initialize_llvm() self._libraries = set() self._data_layout = None self._llvm_module = llvmts.parse_assembly( str(self._create_empty_module(module_name))) self._llvm_module.name = "global_codegen_module" self._rtlinker = RuntimeLinker() self._init(self._llvm_module)
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) ir = cgutils.normalize_ir_text(str(ir_module)) with llvmts.lock_llvm: ll_module = llvmts.parse_assembly(ir) ll_module.name = ir_module.name 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 = llvmts.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 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(llvmts.parse_assembly(ir_mod)) library.finalize() return library
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 newll = _remove_redundant_nrt_refct(str(ll_module)) return llvmts.parse_assembly(newll)
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 """ # Note: As soon as we have better utility in analyzing materialized LLVM # module in llvmlite, we can redo this without so much string # processing. def _extract_functions(module): cur = [] for line in str(module).splitlines(): if line.startswith('define'): # start of function assert not cur cur.append(line) elif line.startswith('}'): # end of function assert cur cur.append(line) yield True, cur cur = [] elif cur: cur.append(line) else: yield False, [line] def _process_function(func_lines): out = [] for is_bb, bb_lines in _extract_basic_blocks(func_lines): if is_bb and bb_lines: bb_lines = _process_basic_block(bb_lines) out += bb_lines return out def _extract_basic_blocks(func_lines): assert func_lines[0].startswith('define') assert func_lines[-1].startswith('}') yield False, [func_lines[0]] cur = [] for ln in func_lines[1:-1]: m = _regex_bb.match(ln) if m is not None: # line is a basic block separator yield True, cur cur = [] yield False, [ln] elif ln: cur.append(ln) yield True, cur yield False, [func_lines[-1]] def _process_basic_block(bb_lines): bb_lines = _move_and_group_decref_after_all_increfs(bb_lines) bb_lines = _prune_redundant_refct_ops(bb_lines) return bb_lines def _examine_refct_op(bb_lines): for num, ln in enumerate(bb_lines): m = _regex_incref.match(ln) if m is not None: yield num, m.group(1), None continue m = _regex_decref.match(ln) if m is not None: yield num, None, m.group(1) continue yield ln, None, None def _prune_redundant_refct_ops(bb_lines): incref_map = defaultdict(deque) decref_map = defaultdict(deque) for num, incref_var, decref_var in _examine_refct_op(bb_lines): assert not (incref_var and decref_var) if incref_var: incref_map[incref_var].append(num) elif decref_var: decref_map[decref_var].append(num) to_remove = set() for var, decops in decref_map.items(): incops = incref_map[var] ct = min(len(incops), len(decops)) for _ in range(ct): to_remove.add(incops.pop()) to_remove.add(decops.popleft()) return [ln for num, ln in enumerate(bb_lines) if num not in to_remove] def _move_and_group_decref_after_all_increfs(bb_lines): # find last incref last_incref_pos = 0 for pos, ln in enumerate(bb_lines): if _regex_incref.match(ln) is not None: last_incref_pos = pos + 1 # find last decref last_decref_pos = 0 for pos, ln in enumerate(bb_lines): if _regex_decref.match(ln) is not None: last_decref_pos = pos + 1 last_pos = max(last_incref_pos, last_decref_pos) # find decrefs before last_pos decrefs = [] head = [] for ln in bb_lines[:last_pos]: if _regex_decref.match(ln) is not None: decrefs.append(ln) else: head.append(ln) # insert decrefs at last_pos return head + decrefs + bb_lines[last_pos:] # Early escape if NRT_incref is not used try: ll_module.get_function('NRT_incref') except NameError: return ll_module processed = [] for is_func, lines in _extract_functions(ll_module): if is_func: lines = _process_function(lines) processed += lines newll = '\n'.join(processed) return llvmts.parse_assembly(newll)