diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..8966ad8ea2c84f792a1965b189a3605bdd14a866 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +lib/python3.11/site-packages/llvmlite/binding/libllvmlite.dylib filter=lfs diff=lfs merge=lfs -text diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/ffi.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/ffi.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd9a7c675e36ab7e03f22f81b00db5af0695dd27 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/ffi.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/initfini.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/initfini.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a113433df3d0be377d325ac187fd5ad4c452a1ee Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/initfini.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/linker.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/linker.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa7e511fa3b49625618428e1ce58093f77eb7aef Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/linker.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/module.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/module.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c4bfae6799162a7b5e32ac1d6aed2884998eea2 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/module.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/object_file.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/object_file.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5221b05ec7907da483beb4cee0ae9b0cae7c6f47 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/object_file.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/options.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/options.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58d28c133d2c436ace42513aaf44d76eef4d5cbb Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/options.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/orcjit.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/orcjit.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce04594c657a65ae0da70ae3400de838d43a11e3 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/orcjit.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/passmanagers.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/passmanagers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2bf2902d04302ba5d661486f540b8f621fd77b9 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/passmanagers.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/targets.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/targets.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed85f58c32befac6f354ce6f284dde95660100e1 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/targets.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/transforms.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/transforms.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..840da6d23e9111302107e93be7519a1f03fd0fe9 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/transforms.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/__pycache__/value.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/value.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70cb0ca90c022e21bfe7abad5308b38c4d09c243 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/binding/__pycache__/value.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/binding/analysis.py b/lib/python3.11/site-packages/llvmlite/binding/analysis.py new file mode 100644 index 0000000000000000000000000000000000000000..fe2692bf9c58478972ba4d2ce7f4a9c55bc0a068 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/analysis.py @@ -0,0 +1,69 @@ +""" +A collection of analysis utilities +""" + +from ctypes import POINTER, c_char_p, c_int + +from llvmlite.binding import ffi +from llvmlite.binding.module import parse_assembly + + +def get_function_cfg(func, show_inst=True): + """Return a string of the control-flow graph of the function in DOT + format. If the input `func` is not a materialized function, the module + containing the function is parsed to create an actual LLVM module. + The `show_inst` flag controls whether the instructions of each block + are printed. + """ + assert func is not None + from llvmlite import ir + if isinstance(func, ir.Function): + mod = parse_assembly(str(func.module)) + func = mod.get_function(func.name) + + # Assume func is a materialized function + with ffi.OutputString() as dotstr: + ffi.lib.LLVMPY_WriteCFG(func, dotstr, show_inst) + return str(dotstr) + + +def view_dot_graph(graph, filename=None, view=False): + """ + View the given DOT source. If view is True, the image is rendered + and viewed by the default application in the system. The file path of + the output is returned. If view is False, a graphviz.Source object is + returned. If view is False and the environment is in a IPython session, + an IPython image object is returned and can be displayed inline in the + notebook. + + This function requires the graphviz package. + + Args + ---- + - graph [str]: a DOT source code + - filename [str]: optional. if given and view is True, this specifies + the file path for the rendered output to write to. + - view [bool]: if True, opens the rendered output file. + + """ + # Optionally depends on graphviz package + import graphviz as gv + + src = gv.Source(graph) + if view: + # Returns the output file path + return src.render(filename, view=view) + else: + # Attempts to show the graph in IPython notebook + try: + __IPYTHON__ + except NameError: + return src + else: + import IPython.display as display + format = 'svg' + return display.SVG(data=src.pipe(format)) + + +# Ctypes binding +ffi.lib.LLVMPY_WriteCFG.argtypes = [ffi.LLVMValueRef, POINTER(c_char_p), c_int] diff --git a/lib/python3.11/site-packages/llvmlite/binding/common.py b/lib/python3.11/site-packages/llvmlite/binding/common.py new file mode 100644 index 0000000000000000000000000000000000000000..3f5746a5b057e76b1bf7b33c2892de1640919519 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/common.py @@ -0,0 +1,34 @@ +import atexit + + +def _encode_string(s): + encoded = s.encode('utf-8') + return encoded + + +def _decode_string(b): + return b.decode('utf-8') + + +_encode_string.__doc__ = """Encode a string for use by LLVM.""" +_decode_string.__doc__ = """Decode a LLVM character (byte)string.""" + + +_shutting_down = [False] + + +def _at_shutdown(): + _shutting_down[0] = True + + +atexit.register(_at_shutdown) + + +def _is_shutting_down(_shutting_down=_shutting_down): + """ + Whether the interpreter is currently shutting down. + For use in finalizers, __del__ methods, and similar; it is advised + to early bind this function rather than look it up when calling it, + since at shutdown module globals may be cleared. + """ + return _shutting_down[0] diff --git a/lib/python3.11/site-packages/llvmlite/binding/context.py b/lib/python3.11/site-packages/llvmlite/binding/context.py new file mode 100644 index 0000000000000000000000000000000000000000..7dffb82a71c1096490e80fb0031010a088cbcf0c --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/context.py @@ -0,0 +1,29 @@ +from llvmlite.binding import ffi + + +def create_context(): + return ContextRef(ffi.lib.LLVMPY_ContextCreate()) + + +def get_global_context(): + return GlobalContextRef(ffi.lib.LLVMPY_GetGlobalContext()) + + +class ContextRef(ffi.ObjectRef): + def __init__(self, context_ptr): + super(ContextRef, self).__init__(context_ptr) + + def _dispose(self): + ffi.lib.LLVMPY_ContextDispose(self) + + +class GlobalContextRef(ContextRef): + def _dispose(self): + pass + + +ffi.lib.LLVMPY_GetGlobalContext.restype = ffi.LLVMContextRef + +ffi.lib.LLVMPY_ContextCreate.restype = ffi.LLVMContextRef + +ffi.lib.LLVMPY_ContextDispose.argtypes = [ffi.LLVMContextRef] diff --git a/lib/python3.11/site-packages/llvmlite/binding/dylib.py b/lib/python3.11/site-packages/llvmlite/binding/dylib.py new file mode 100644 index 0000000000000000000000000000000000000000..e22542c496b7baadc002333f28e14a91e63a359a --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/dylib.py @@ -0,0 +1,45 @@ +from ctypes import c_void_p, c_char_p, c_bool, POINTER + +from llvmlite.binding import ffi +from llvmlite.binding.common import _encode_string + + +def address_of_symbol(name): + """ + Get the in-process address of symbol named *name*. + An integer is returned, or None if the symbol isn't found. + """ + return ffi.lib.LLVMPY_SearchAddressOfSymbol(_encode_string(name)) + + +def add_symbol(name, address): + """ + Register the *address* of global symbol *name*. This will make + it usable (e.g. callable) from LLVM-compiled functions. + """ + ffi.lib.LLVMPY_AddSymbol(_encode_string(name), c_void_p(address)) + + +def load_library_permanently(filename): + """ + Load an external library + """ + with ffi.OutputString() as outerr: + if ffi.lib.LLVMPY_LoadLibraryPermanently( + _encode_string(filename), outerr): + raise RuntimeError(str(outerr)) + +# ============================================================================ +# FFI + + +ffi.lib.LLVMPY_AddSymbol.argtypes = [ + c_char_p, + c_void_p, +] + +ffi.lib.LLVMPY_SearchAddressOfSymbol.argtypes = [c_char_p] +ffi.lib.LLVMPY_SearchAddressOfSymbol.restype = c_void_p + +ffi.lib.LLVMPY_LoadLibraryPermanently.argtypes = [c_char_p, POINTER(c_char_p)] +ffi.lib.LLVMPY_LoadLibraryPermanently.restype = c_bool diff --git a/lib/python3.11/site-packages/llvmlite/binding/executionengine.py b/lib/python3.11/site-packages/llvmlite/binding/executionengine.py new file mode 100644 index 0000000000000000000000000000000000000000..07cb8dab02056ea4d48b7a29ef20b6c8c0887b7a --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/executionengine.py @@ -0,0 +1,322 @@ +from ctypes import (POINTER, c_char_p, c_bool, c_void_p, + c_int, c_uint64, c_size_t, CFUNCTYPE, string_at, cast, + py_object, Structure) + +from llvmlite.binding import ffi, targets, object_file + + +# Just check these weren't optimized out of the DLL. +ffi.lib.LLVMPY_LinkInMCJIT + + +def create_mcjit_compiler(module, target_machine): + """ + Create a MCJIT ExecutionEngine from the given *module* and + *target_machine*. + """ + with ffi.OutputString() as outerr: + engine = ffi.lib.LLVMPY_CreateMCJITCompiler( + module, target_machine, outerr) + if not engine: + raise RuntimeError(str(outerr)) + + target_machine._owned = True + return ExecutionEngine(engine, module=module) + + +def check_jit_execution(): + """ + Check the system allows execution of in-memory JITted functions. + An exception is raised otherwise. + """ + errno = ffi.lib.LLVMPY_TryAllocateExecutableMemory() + if errno != 0: + raise OSError(errno, + "cannot allocate executable memory. " + "This may be due to security restrictions on your " + "system, such as SELinux or similar mechanisms." + ) + + +class ExecutionEngine(ffi.ObjectRef): + """An ExecutionEngine owns all Modules associated with it. + Deleting the engine will remove all associated modules. + It is an error to delete the associated modules. + """ + _object_cache = None + + def __init__(self, ptr, module): + """ + Module ownership is transferred to the EE + """ + self._modules = set([module]) + self._td = None + module._owned = True + ffi.ObjectRef.__init__(self, ptr) + + def get_function_address(self, name): + """ + Return the address of the function named *name* as an integer. + + It's a fatal error in LLVM if the symbol of *name* doesn't exist. + """ + return ffi.lib.LLVMPY_GetFunctionAddress(self, name.encode("ascii")) + + def get_global_value_address(self, name): + """ + Return the address of the global value named *name* as an integer. + + It's a fatal error in LLVM if the symbol of *name* doesn't exist. + """ + return ffi.lib.LLVMPY_GetGlobalValueAddress(self, name.encode("ascii")) + + def add_global_mapping(self, gv, addr): + # XXX unused? + ffi.lib.LLVMPY_AddGlobalMapping(self, gv, addr) + + def add_module(self, module): + """ + Ownership of module is transferred to the execution engine + """ + if module in self._modules: + raise KeyError("module already added to this engine") + ffi.lib.LLVMPY_AddModule(self, module) + module._owned = True + self._modules.add(module) + + def finalize_object(self): + """ + Make sure all modules owned by the execution engine are fully processed + and "usable" for execution. + """ + ffi.lib.LLVMPY_FinalizeObject(self) + + def run_static_constructors(self): + """ + Run static constructors which initialize module-level static objects. + """ + ffi.lib.LLVMPY_RunStaticConstructors(self) + + def run_static_destructors(self): + """ + Run static destructors which perform module-level cleanup of static + resources. + """ + ffi.lib.LLVMPY_RunStaticDestructors(self) + + def remove_module(self, module): + """ + Ownership of module is returned + """ + with ffi.OutputString() as outerr: + if ffi.lib.LLVMPY_RemoveModule(self, module, outerr): + raise RuntimeError(str(outerr)) + self._modules.remove(module) + module._owned = False + + @property + def target_data(self): + """ + The TargetData for this execution engine. + """ + if self._td is not None: + return self._td + ptr = ffi.lib.LLVMPY_GetExecutionEngineTargetData(self) + self._td = targets.TargetData(ptr) + self._td._owned = True + return self._td + + def enable_jit_events(self): + """ + Enable JIT events for profiling of generated code. + Return value indicates whether connection to profiling tool + was successful. + """ + ret = ffi.lib.LLVMPY_EnableJITEvents(self) + return ret + + def _find_module_ptr(self, module_ptr): + """ + Find the ModuleRef corresponding to the given pointer. + """ + ptr = cast(module_ptr, c_void_p).value + for module in self._modules: + if cast(module._ptr, c_void_p).value == ptr: + return module + return None + + def add_object_file(self, obj_file): + """ + Add object file to the jit. object_file can be instance of + :class:ObjectFile or a string representing file system path + """ + if isinstance(obj_file, str): + obj_file = object_file.ObjectFileRef.from_path(obj_file) + + ffi.lib.LLVMPY_MCJITAddObjectFile(self, obj_file) + + def set_object_cache(self, notify_func=None, getbuffer_func=None): + """ + Set the object cache "notifyObjectCompiled" and "getBuffer" + callbacks to the given Python functions. + """ + self._object_cache_notify = notify_func + self._object_cache_getbuffer = getbuffer_func + # Lifetime of the object cache is managed by us. + self._object_cache = _ObjectCacheRef(self) + # Note this doesn't keep a reference to self, to avoid reference + # cycles. + ffi.lib.LLVMPY_SetObjectCache(self, self._object_cache) + + def _raw_object_cache_notify(self, data): + """ + Low-level notify hook. + """ + if self._object_cache_notify is None: + return + module_ptr = data.contents.module_ptr + buf_ptr = data.contents.buf_ptr + buf_len = data.contents.buf_len + buf = string_at(buf_ptr, buf_len) + module = self._find_module_ptr(module_ptr) + if module is None: + # The LLVM EE should only give notifications for modules + # known by us. + raise RuntimeError("object compilation notification " + "for unknown module %s" % (module_ptr,)) + self._object_cache_notify(module, buf) + + def _raw_object_cache_getbuffer(self, data): + """ + Low-level getbuffer hook. + """ + if self._object_cache_getbuffer is None: + return + module_ptr = data.contents.module_ptr + module = self._find_module_ptr(module_ptr) + if module is None: + # The LLVM EE should only give notifications for modules + # known by us. + raise RuntimeError("object compilation notification " + "for unknown module %s" % (module_ptr,)) + + buf = self._object_cache_getbuffer(module) + if buf is not None: + # Create a copy, which will be freed by the caller + data[0].buf_ptr = ffi.lib.LLVMPY_CreateByteString(buf, len(buf)) + data[0].buf_len = len(buf) + + def _dispose(self): + # The modules will be cleaned up by the EE + for mod in self._modules: + mod.detach() + if self._td is not None: + self._td.detach() + self._modules.clear() + self._object_cache = None + self._capi.LLVMPY_DisposeExecutionEngine(self) + + +class _ObjectCacheRef(ffi.ObjectRef): + """ + Internal: an ObjectCache instance for use within an ExecutionEngine. + """ + + def __init__(self, obj): + ptr = ffi.lib.LLVMPY_CreateObjectCache(_notify_c_hook, + _getbuffer_c_hook, + obj) + ffi.ObjectRef.__init__(self, ptr) + + def _dispose(self): + self._capi.LLVMPY_DisposeObjectCache(self) + + +# ============================================================================ +# FFI + + +ffi.lib.LLVMPY_CreateMCJITCompiler.argtypes = [ + ffi.LLVMModuleRef, + ffi.LLVMTargetMachineRef, + POINTER(c_char_p), +] +ffi.lib.LLVMPY_CreateMCJITCompiler.restype = ffi.LLVMExecutionEngineRef + +ffi.lib.LLVMPY_RemoveModule.argtypes = [ + ffi.LLVMExecutionEngineRef, + ffi.LLVMModuleRef, + POINTER(c_char_p), +] +ffi.lib.LLVMPY_RemoveModule.restype = c_bool + +ffi.lib.LLVMPY_AddModule.argtypes = [ + ffi.LLVMExecutionEngineRef, + ffi.LLVMModuleRef +] + +ffi.lib.LLVMPY_AddGlobalMapping.argtypes = [ffi.LLVMExecutionEngineRef, + ffi.LLVMValueRef, + c_void_p] + +ffi.lib.LLVMPY_FinalizeObject.argtypes = [ffi.LLVMExecutionEngineRef] + +ffi.lib.LLVMPY_GetExecutionEngineTargetData.argtypes = [ + ffi.LLVMExecutionEngineRef +] +ffi.lib.LLVMPY_GetExecutionEngineTargetData.restype = ffi.LLVMTargetDataRef + +ffi.lib.LLVMPY_TryAllocateExecutableMemory.argtypes = [] +ffi.lib.LLVMPY_TryAllocateExecutableMemory.restype = c_int + +ffi.lib.LLVMPY_GetFunctionAddress.argtypes = [ + ffi.LLVMExecutionEngineRef, + c_char_p +] +ffi.lib.LLVMPY_GetFunctionAddress.restype = c_uint64 + +ffi.lib.LLVMPY_GetGlobalValueAddress.argtypes = [ + ffi.LLVMExecutionEngineRef, + c_char_p +] +ffi.lib.LLVMPY_GetGlobalValueAddress.restype = c_uint64 + +ffi.lib.LLVMPY_MCJITAddObjectFile.argtypes = [ + ffi.LLVMExecutionEngineRef, + ffi.LLVMObjectFileRef +] + + +class _ObjectCacheData(Structure): + _fields_ = [ + ('module_ptr', ffi.LLVMModuleRef), + ('buf_ptr', c_void_p), + ('buf_len', c_size_t), + ] + + +_ObjectCacheNotifyFunc = CFUNCTYPE(None, py_object, + POINTER(_ObjectCacheData)) +_ObjectCacheGetBufferFunc = CFUNCTYPE(None, py_object, + POINTER(_ObjectCacheData)) + +# XXX The ctypes function wrappers are created at the top-level, otherwise +# there are issues when creating CFUNCTYPEs in child processes on CentOS 5 +# 32 bits. +_notify_c_hook = _ObjectCacheNotifyFunc( + ExecutionEngine._raw_object_cache_notify) +_getbuffer_c_hook = _ObjectCacheGetBufferFunc( + ExecutionEngine._raw_object_cache_getbuffer) + +ffi.lib.LLVMPY_CreateObjectCache.argtypes = [_ObjectCacheNotifyFunc, + _ObjectCacheGetBufferFunc, + py_object] +ffi.lib.LLVMPY_CreateObjectCache.restype = ffi.LLVMObjectCacheRef + +ffi.lib.LLVMPY_DisposeObjectCache.argtypes = [ffi.LLVMObjectCacheRef] + +ffi.lib.LLVMPY_SetObjectCache.argtypes = [ffi.LLVMExecutionEngineRef, + ffi.LLVMObjectCacheRef] + +ffi.lib.LLVMPY_CreateByteString.restype = c_void_p +ffi.lib.LLVMPY_CreateByteString.argtypes = [c_void_p, c_size_t] diff --git a/lib/python3.11/site-packages/llvmlite/binding/ffi.py b/lib/python3.11/site-packages/llvmlite/binding/ffi.py new file mode 100644 index 0000000000000000000000000000000000000000..58ab4efbcee9ace11ef5b37662c9c2bb8d542b81 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/ffi.py @@ -0,0 +1,388 @@ +import sys +import ctypes +import threading +import importlib.resources as _impres + +from llvmlite.binding.common import _decode_string, _is_shutting_down +from llvmlite.utils import get_library_name + + +def _make_opaque_ref(name): + newcls = type(name, (ctypes.Structure,), {}) + return ctypes.POINTER(newcls) + + +LLVMContextRef = _make_opaque_ref("LLVMContext") +LLVMModuleRef = _make_opaque_ref("LLVMModule") +LLVMValueRef = _make_opaque_ref("LLVMValue") +LLVMTypeRef = _make_opaque_ref("LLVMType") +LLVMExecutionEngineRef = _make_opaque_ref("LLVMExecutionEngine") +LLVMPassManagerBuilderRef = _make_opaque_ref("LLVMPassManagerBuilder") +LLVMPassManagerRef = _make_opaque_ref("LLVMPassManager") +LLVMTargetDataRef = _make_opaque_ref("LLVMTargetData") +LLVMTargetLibraryInfoRef = _make_opaque_ref("LLVMTargetLibraryInfo") +LLVMTargetRef = _make_opaque_ref("LLVMTarget") +LLVMTargetMachineRef = _make_opaque_ref("LLVMTargetMachine") +LLVMMemoryBufferRef = _make_opaque_ref("LLVMMemoryBuffer") +LLVMAttributeListIterator = _make_opaque_ref("LLVMAttributeListIterator") +LLVMAttributeSetIterator = _make_opaque_ref("LLVMAttributeSetIterator") +LLVMGlobalsIterator = _make_opaque_ref("LLVMGlobalsIterator") +LLVMFunctionsIterator = _make_opaque_ref("LLVMFunctionsIterator") +LLVMBlocksIterator = _make_opaque_ref("LLVMBlocksIterator") +LLVMArgumentsIterator = _make_opaque_ref("LLVMArgumentsIterator") +LLVMInstructionsIterator = _make_opaque_ref("LLVMInstructionsIterator") +LLVMOperandsIterator = _make_opaque_ref("LLVMOperandsIterator") +LLVMTypesIterator = _make_opaque_ref("LLVMTypesIterator") +LLVMObjectCacheRef = _make_opaque_ref("LLVMObjectCache") +LLVMObjectFileRef = _make_opaque_ref("LLVMObjectFile") +LLVMSectionIteratorRef = _make_opaque_ref("LLVMSectionIterator") +LLVMOrcLLJITRef = _make_opaque_ref("LLVMOrcLLJITRef") +LLVMOrcDylibTrackerRef = _make_opaque_ref("LLVMOrcDylibTrackerRef") + + +class _LLVMLock: + """A Lock to guarantee thread-safety for the LLVM C-API. + + This class implements __enter__ and __exit__ for acquiring and releasing + the lock as a context manager. + + Also, callbacks can be attached so that every time the lock is acquired + and released the corresponding callbacks will be invoked. + """ + def __init__(self): + # The reentrant lock is needed for callbacks that re-enter + # the Python interpreter. + self._lock = threading.RLock() + self._cblist = [] + + def register(self, acq_fn, rel_fn): + """Register callbacks that are invoked immediately after the lock is + acquired (``acq_fn()``) and immediately before the lock is released + (``rel_fn()``). + """ + self._cblist.append((acq_fn, rel_fn)) + + def unregister(self, acq_fn, rel_fn): + """Remove the registered callbacks. + """ + self._cblist.remove((acq_fn, rel_fn)) + + def __enter__(self): + self._lock.acquire() + # Invoke all callbacks + for acq_fn, rel_fn in self._cblist: + acq_fn() + + def __exit__(self, *exc_details): + # Invoke all callbacks + for acq_fn, rel_fn in self._cblist: + rel_fn() + self._lock.release() + + +class _suppress_cleanup_errors: + def __init__(self, context): + self._context = context + + def __enter__(self): + return self._context.__enter__() + + def __exit__(self, exc_type, exc_value, traceback): + try: + return self._context.__exit__(exc_type, exc_value, traceback) + except PermissionError: + pass # Resource dylibs can't be deleted on Windows. + + +class _lib_wrapper(object): + """Wrap libllvmlite with a lock such that only one thread may access it at + a time. + + This class duck-types a CDLL. + """ + __slots__ = ['_lib_handle', '_fntab', '_lock'] + + def __init__(self): + self._lib_handle = None + self._fntab = {} + self._lock = _LLVMLock() + + def _load_lib(self): + try: + with _suppress_cleanup_errors(_importlib_resources_path( + __name__.rpartition(".")[0], + get_library_name())) as lib_path: + self._lib_handle = ctypes.CDLL(str(lib_path)) + # Check that we can look up expected symbols. + _ = self._lib_handle.LLVMPY_GetVersionInfo() + except (OSError, AttributeError) as e: + # OSError may be raised if the file cannot be opened, or is not + # a shared library. + # AttributeError is raised if LLVMPY_GetVersionInfo does not + # exist. + raise OSError("Could not find/load shared object file") from e + + @property + def _lib(self): + # Not threadsafe. + if not self._lib_handle: + self._load_lib() + return self._lib_handle + + def __getattr__(self, name): + try: + return self._fntab[name] + except KeyError: + # Lazily wraps new functions as they are requested + cfn = getattr(self._lib, name) + wrapped = _lib_fn_wrapper(self._lock, cfn) + self._fntab[name] = wrapped + return wrapped + + @property + def _name(self): + """The name of the library passed in the CDLL constructor. + + For duck-typing a ctypes.CDLL + """ + return self._lib._name + + @property + def _handle(self): + """The system handle used to access the library. + + For duck-typing a ctypes.CDLL + """ + return self._lib._handle + + +class _lib_fn_wrapper(object): + """Wraps and duck-types a ctypes.CFUNCTYPE to provide + automatic locking when the wrapped function is called. + + TODO: we can add methods to mark the function as threadsafe + and remove the locking-step on call when marked. + """ + __slots__ = ['_lock', '_cfn'] + + def __init__(self, lock, cfn): + self._lock = lock + self._cfn = cfn + + @property + def argtypes(self): + return self._cfn.argtypes + + @argtypes.setter + def argtypes(self, argtypes): + self._cfn.argtypes = argtypes + + @property + def restype(self): + return self._cfn.restype + + @restype.setter + def restype(self, restype): + self._cfn.restype = restype + + def __call__(self, *args, **kwargs): + with self._lock: + return self._cfn(*args, **kwargs) + + +def _importlib_resources_path_repl(package, resource): + """Replacement implementation of `import.resources.path` to avoid + deprecation warning following code at importlib_resources/_legacy.py + as suggested by https://importlib-resources.readthedocs.io/en/latest/using.html#migrating-from-legacy + + Notes on differences from importlib.resources implementation: + + The `_common.normalize_path(resource)` call is skipped because it is an + internal API and it is unnecessary for the use here. What it does is + ensuring `resource` is a str and that it does not contain path separators. + """ # noqa E501 + return _impres.as_file(_impres.files(package) / resource) + + +_importlib_resources_path = (_importlib_resources_path_repl + if sys.version_info[:2] >= (3, 9) + else _impres.path) + + +lib = _lib_wrapper() + + +def register_lock_callback(acq_fn, rel_fn): + """Register callback functions for lock acquire and release. + *acq_fn* and *rel_fn* are callables that take no arguments. + """ + lib._lock.register(acq_fn, rel_fn) + + +def unregister_lock_callback(acq_fn, rel_fn): + """Remove the registered callback functions for lock acquire and release. + The arguments are the same as used in `register_lock_callback()`. + """ + lib._lock.unregister(acq_fn, rel_fn) + + +class _DeadPointer(object): + """ + Dummy class to make error messages more helpful. + """ + + +class OutputString(object): + """ + Object for managing the char* output of LLVM APIs. + """ + _as_parameter_ = _DeadPointer() + + @classmethod + def from_return(cls, ptr): + """Constructing from a pointer returned from the C-API. + The pointer must be allocated with LLVMPY_CreateString. + + Note + ---- + Because ctypes auto-converts *restype* of *c_char_p* into a python + string, we must use *c_void_p* to obtain the raw pointer. + """ + return cls(init=ctypes.cast(ptr, ctypes.c_char_p)) + + def __init__(self, owned=True, init=None): + self._ptr = init if init is not None else ctypes.c_char_p(None) + self._as_parameter_ = ctypes.byref(self._ptr) + self._owned = owned + + def close(self): + if self._ptr is not None: + if self._owned: + lib.LLVMPY_DisposeString(self._ptr) + self._ptr = None + del self._as_parameter_ + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + + def __del__(self, _is_shutting_down=_is_shutting_down): + # Avoid errors trying to rely on globals and modules at interpreter + # shutdown. + if not _is_shutting_down(): + if self.close is not None: + self.close() + + def __str__(self): + if self._ptr is None: + return "" + s = self._ptr.value + assert s is not None + return _decode_string(s) + + def __bool__(self): + return bool(self._ptr) + + __nonzero__ = __bool__ + + @property + def bytes(self): + """Get the raw bytes of content of the char pointer. + """ + return self._ptr.value + + +def ret_string(ptr): + """To wrap string return-value from C-API. + """ + if ptr is not None: + return str(OutputString.from_return(ptr)) + + +def ret_bytes(ptr): + """To wrap bytes return-value from C-API. + """ + if ptr is not None: + return OutputString.from_return(ptr).bytes + + +class ObjectRef(object): + """ + A wrapper around a ctypes pointer to a LLVM object ("resource"). + """ + _closed = False + _as_parameter_ = _DeadPointer() + # Whether this object pointer is owned by another one. + _owned = False + + def __init__(self, ptr): + if ptr is None: + raise ValueError("NULL pointer") + self._ptr = ptr + self._as_parameter_ = ptr + self._capi = lib + + def close(self): + """ + Close this object and do any required clean-up actions. + """ + try: + if not self._closed and not self._owned: + self._dispose() + finally: + self.detach() + + def detach(self): + """ + Detach the underlying LLVM resource without disposing of it. + """ + if not self._closed: + del self._as_parameter_ + self._closed = True + self._ptr = None + + def _dispose(self): + """ + Dispose of the underlying LLVM resource. Should be overriden + by subclasses. Automatically called by close(), __del__() and + __exit__() (unless the resource has been detached). + """ + + @property + def closed(self): + """ + Whether this object has been closed. A closed object can't + be used anymore. + """ + return self._closed + + def __enter__(self): + assert hasattr(self, "close") + if self._closed: + raise RuntimeError("%s instance already closed" % (self.__class__,)) + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + + def __del__(self, _is_shutting_down=_is_shutting_down): + if not _is_shutting_down(): + if self.close is not None: + self.close() + + def __bool__(self): + return bool(self._ptr) + + def __eq__(self, other): + if not hasattr(other, "_ptr"): + return False + return ctypes.addressof(self._ptr[0]) == \ + ctypes.addressof(other._ptr[0]) + + __nonzero__ = __bool__ + + # XXX useful? + def __hash__(self): + return hash(ctypes.cast(self._ptr, ctypes.c_void_p).value) diff --git a/lib/python3.11/site-packages/llvmlite/binding/initfini.py b/lib/python3.11/site-packages/llvmlite/binding/initfini.py new file mode 100644 index 0000000000000000000000000000000000000000..4466d9da2f2c131b750a2a8ff61ed7381acb7363 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/initfini.py @@ -0,0 +1,73 @@ +from ctypes import c_uint + +from llvmlite.binding import ffi + + +def initialize(): + """ + Initialize the LLVM core. + """ + ffi.lib.LLVMPY_InitializeCore() + + +def initialize_all_targets(): + """ + Initialize all targets. Necessary before targets can be looked up + via the :class:`Target` class. + """ + ffi.lib.LLVMPY_InitializeAllTargetInfos() + ffi.lib.LLVMPY_InitializeAllTargets() + ffi.lib.LLVMPY_InitializeAllTargetMCs() + + +def initialize_all_asmprinters(): + """ + Initialize all code generators. Necessary before generating + any assembly or machine code via the :meth:`TargetMachine.emit_object` + and :meth:`TargetMachine.emit_assembly` methods. + """ + ffi.lib.LLVMPY_InitializeAllAsmPrinters() + + +def initialize_native_target(): + """ + Initialize the native (host) target. Necessary before doing any + code generation. + """ + ffi.lib.LLVMPY_InitializeNativeTarget() + + +def initialize_native_asmprinter(): + """ + Initialize the native ASM printer. + """ + ffi.lib.LLVMPY_InitializeNativeAsmPrinter() + + +def initialize_native_asmparser(): + """ + Initialize the native ASM parser. + """ + ffi.lib.LLVMPY_InitializeNativeAsmParser() + + +def shutdown(): + ffi.lib.LLVMPY_Shutdown() + + +# ============================================================================= +# Set function FFI + +ffi.lib.LLVMPY_GetVersionInfo.restype = c_uint + + +def _version_info(): + v = [] + x = ffi.lib.LLVMPY_GetVersionInfo() + while x: + v.append(x & 0xff) + x >>= 8 + return tuple(reversed(v)) + + +llvm_version_info = _version_info() diff --git a/lib/python3.11/site-packages/llvmlite/binding/libllvmlite.dylib b/lib/python3.11/site-packages/llvmlite/binding/libllvmlite.dylib new file mode 100644 index 0000000000000000000000000000000000000000..9b78261765c88dc8dc590fcedf3e5ee9cfb54696 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/libllvmlite.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3357cc66e6582cf25850ce9b1f710cbe4160f871a90c8bbe96cfd87fe857ea30 +size 91363294 diff --git a/lib/python3.11/site-packages/llvmlite/binding/linker.py b/lib/python3.11/site-packages/llvmlite/binding/linker.py new file mode 100644 index 0000000000000000000000000000000000000000..31d1e26ffb99763af367d07c30fd77770103dc79 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/linker.py @@ -0,0 +1,20 @@ +from ctypes import c_int, c_char_p, POINTER +from llvmlite.binding import ffi + + +def link_modules(dst, src): + with ffi.OutputString() as outerr: + err = ffi.lib.LLVMPY_LinkModules(dst, src, outerr) + # The underlying module was destroyed + src.detach() + if err: + raise RuntimeError(str(outerr)) + + +ffi.lib.LLVMPY_LinkModules.argtypes = [ + ffi.LLVMModuleRef, + ffi.LLVMModuleRef, + POINTER(c_char_p), +] + +ffi.lib.LLVMPY_LinkModules.restype = c_int diff --git a/lib/python3.11/site-packages/llvmlite/binding/module.py b/lib/python3.11/site-packages/llvmlite/binding/module.py new file mode 100644 index 0000000000000000000000000000000000000000..dcbb1faa6545718f9226133ccef42b03a098fd37 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/module.py @@ -0,0 +1,349 @@ +from ctypes import (c_char_p, byref, POINTER, c_bool, create_string_buffer, + c_size_t, string_at) + +from llvmlite.binding import ffi +from llvmlite.binding.linker import link_modules +from llvmlite.binding.common import _decode_string, _encode_string +from llvmlite.binding.value import ValueRef, TypeRef +from llvmlite.binding.context import get_global_context + + +def parse_assembly(llvmir, context=None): + """ + Create Module from a LLVM IR string + """ + if context is None: + context = get_global_context() + llvmir = _encode_string(llvmir) + strbuf = c_char_p(llvmir) + with ffi.OutputString() as errmsg: + mod = ModuleRef( + ffi.lib.LLVMPY_ParseAssembly(context, strbuf, errmsg), + context) + if errmsg: + mod.close() + raise RuntimeError("LLVM IR parsing error\n{0}".format(errmsg)) + return mod + + +def parse_bitcode(bitcode, context=None): + """ + Create Module from a LLVM *bitcode* (a bytes object). + """ + if context is None: + context = get_global_context() + buf = c_char_p(bitcode) + bufsize = len(bitcode) + with ffi.OutputString() as errmsg: + mod = ModuleRef(ffi.lib.LLVMPY_ParseBitcode( + context, buf, bufsize, errmsg), context) + if errmsg: + mod.close() + raise RuntimeError( + "LLVM bitcode parsing error\n{0}".format(errmsg)) + return mod + + +class ModuleRef(ffi.ObjectRef): + """ + A reference to a LLVM module. + """ + + def __init__(self, module_ptr, context): + super(ModuleRef, self).__init__(module_ptr) + self._context = context + + def __str__(self): + with ffi.OutputString() as outstr: + ffi.lib.LLVMPY_PrintModuleToString(self, outstr) + return str(outstr) + + def as_bitcode(self): + """ + Return the module's LLVM bitcode, as a bytes object. + """ + ptr = c_char_p(None) + size = c_size_t(-1) + ffi.lib.LLVMPY_WriteBitcodeToString(self, byref(ptr), byref(size)) + if not ptr: + raise MemoryError + try: + assert size.value >= 0 + return string_at(ptr, size.value) + finally: + ffi.lib.LLVMPY_DisposeString(ptr) + + def _dispose(self): + self._capi.LLVMPY_DisposeModule(self) + + def get_function(self, name): + """ + Get a ValueRef pointing to the function named *name*. + NameError is raised if the symbol isn't found. + """ + p = ffi.lib.LLVMPY_GetNamedFunction(self, _encode_string(name)) + if not p: + raise NameError(name) + return ValueRef(p, 'function', dict(module=self)) + + def get_global_variable(self, name): + """ + Get a ValueRef pointing to the global variable named *name*. + NameError is raised if the symbol isn't found. + """ + p = ffi.lib.LLVMPY_GetNamedGlobalVariable(self, _encode_string(name)) + if not p: + raise NameError(name) + return ValueRef(p, 'global', dict(module=self)) + + def get_struct_type(self, name): + """ + Get a TypeRef pointing to a structure type named *name*. + NameError is raised if the struct type isn't found. + """ + p = ffi.lib.LLVMPY_GetNamedStructType(self, _encode_string(name)) + if not p: + raise NameError(name) + return TypeRef(p) + + def verify(self): + """ + Verify the module IR's correctness. RuntimeError is raised on error. + """ + with ffi.OutputString() as outmsg: + if ffi.lib.LLVMPY_VerifyModule(self, outmsg): + raise RuntimeError(str(outmsg)) + + @property + def name(self): + """ + The module's identifier. + """ + return _decode_string(ffi.lib.LLVMPY_GetModuleName(self)) + + @name.setter + def name(self, value): + ffi.lib.LLVMPY_SetModuleName(self, _encode_string(value)) + + @property + def source_file(self): + """ + The module's original source file name + """ + return _decode_string(ffi.lib.LLVMPY_GetModuleSourceFileName(self)) + + @property + def data_layout(self): + """ + This module's data layout specification, as a string. + """ + # LLVMGetDataLayout() points inside a std::string managed by LLVM. + with ffi.OutputString(owned=False) as outmsg: + ffi.lib.LLVMPY_GetDataLayout(self, outmsg) + return str(outmsg) + + @data_layout.setter + def data_layout(self, strrep): + ffi.lib.LLVMPY_SetDataLayout(self, + create_string_buffer( + strrep.encode('utf8'))) + + @property + def triple(self): + """ + This module's target "triple" specification, as a string. + """ + # LLVMGetTarget() points inside a std::string managed by LLVM. + with ffi.OutputString(owned=False) as outmsg: + ffi.lib.LLVMPY_GetTarget(self, outmsg) + return str(outmsg) + + @triple.setter + def triple(self, strrep): + ffi.lib.LLVMPY_SetTarget(self, + create_string_buffer( + strrep.encode('utf8'))) + + def link_in(self, other, preserve=False): + """ + Link the *other* module into this one. The *other* module will + be destroyed unless *preserve* is true. + """ + if preserve: + other = other.clone() + link_modules(self, other) + + @property + def global_variables(self): + """ + Return an iterator over this module's global variables. + The iterator will yield a ValueRef for each global variable. + + Note that global variables don't include functions + (a function is a "global value" but not a "global variable" in + LLVM parlance) + """ + it = ffi.lib.LLVMPY_ModuleGlobalsIter(self) + return _GlobalsIterator(it, dict(module=self)) + + @property + def functions(self): + """ + Return an iterator over this module's functions. + The iterator will yield a ValueRef for each function. + """ + it = ffi.lib.LLVMPY_ModuleFunctionsIter(self) + return _FunctionsIterator(it, dict(module=self)) + + @property + def struct_types(self): + """ + Return an iterator over the struct types defined in + the module. The iterator will yield a TypeRef. + """ + it = ffi.lib.LLVMPY_ModuleTypesIter(self) + return _TypesIterator(it, dict(module=self)) + + def clone(self): + return ModuleRef(ffi.lib.LLVMPY_CloneModule(self), self._context) + + +class _Iterator(ffi.ObjectRef): + + kind = None + + def __init__(self, ptr, parents): + ffi.ObjectRef.__init__(self, ptr) + self._parents = parents + assert self.kind is not None + + def __next__(self): + vp = self._next() + if vp: + return ValueRef(vp, self.kind, self._parents) + else: + raise StopIteration + + next = __next__ + + def __iter__(self): + return self + + +class _GlobalsIterator(_Iterator): + + kind = 'global' + + def _dispose(self): + self._capi.LLVMPY_DisposeGlobalsIter(self) + + def _next(self): + return ffi.lib.LLVMPY_GlobalsIterNext(self) + + +class _FunctionsIterator(_Iterator): + + kind = 'function' + + def _dispose(self): + self._capi.LLVMPY_DisposeFunctionsIter(self) + + def _next(self): + return ffi.lib.LLVMPY_FunctionsIterNext(self) + + +class _TypesIterator(_Iterator): + + kind = 'type' + + def _dispose(self): + self._capi.LLVMPY_DisposeTypesIter(self) + + def __next__(self): + vp = self._next() + if vp: + return TypeRef(vp) + else: + raise StopIteration + + def _next(self): + return ffi.lib.LLVMPY_TypesIterNext(self) + + next = __next__ + + +# ============================================================================= +# Set function FFI + +ffi.lib.LLVMPY_ParseAssembly.argtypes = [ffi.LLVMContextRef, + c_char_p, + POINTER(c_char_p)] +ffi.lib.LLVMPY_ParseAssembly.restype = ffi.LLVMModuleRef + +ffi.lib.LLVMPY_ParseBitcode.argtypes = [ffi.LLVMContextRef, + c_char_p, c_size_t, + POINTER(c_char_p)] +ffi.lib.LLVMPY_ParseBitcode.restype = ffi.LLVMModuleRef + +ffi.lib.LLVMPY_DisposeModule.argtypes = [ffi.LLVMModuleRef] + +ffi.lib.LLVMPY_PrintModuleToString.argtypes = [ffi.LLVMModuleRef, + POINTER(c_char_p)] +ffi.lib.LLVMPY_WriteBitcodeToString.argtypes = [ffi.LLVMModuleRef, + POINTER(c_char_p), + POINTER(c_size_t)] + +ffi.lib.LLVMPY_GetNamedFunction.argtypes = [ffi.LLVMModuleRef, + c_char_p] +ffi.lib.LLVMPY_GetNamedFunction.restype = ffi.LLVMValueRef + +ffi.lib.LLVMPY_VerifyModule.argtypes = [ffi.LLVMModuleRef, + POINTER(c_char_p)] +ffi.lib.LLVMPY_VerifyModule.restype = c_bool + +ffi.lib.LLVMPY_GetDataLayout.argtypes = [ffi.LLVMModuleRef, POINTER(c_char_p)] +ffi.lib.LLVMPY_SetDataLayout.argtypes = [ffi.LLVMModuleRef, c_char_p] + +ffi.lib.LLVMPY_GetTarget.argtypes = [ffi.LLVMModuleRef, POINTER(c_char_p)] +ffi.lib.LLVMPY_SetTarget.argtypes = [ffi.LLVMModuleRef, c_char_p] + +ffi.lib.LLVMPY_GetNamedGlobalVariable.argtypes = [ffi.LLVMModuleRef, c_char_p] +ffi.lib.LLVMPY_GetNamedGlobalVariable.restype = ffi.LLVMValueRef + +ffi.lib.LLVMPY_GetNamedStructType.argtypes = [ffi.LLVMModuleRef, c_char_p] +ffi.lib.LLVMPY_GetNamedStructType.restype = ffi.LLVMTypeRef + +ffi.lib.LLVMPY_ModuleGlobalsIter.argtypes = [ffi.LLVMModuleRef] +ffi.lib.LLVMPY_ModuleGlobalsIter.restype = ffi.LLVMGlobalsIterator + +ffi.lib.LLVMPY_DisposeGlobalsIter.argtypes = [ffi.LLVMGlobalsIterator] + +ffi.lib.LLVMPY_GlobalsIterNext.argtypes = [ffi.LLVMGlobalsIterator] +ffi.lib.LLVMPY_GlobalsIterNext.restype = ffi.LLVMValueRef + +ffi.lib.LLVMPY_ModuleFunctionsIter.argtypes = [ffi.LLVMModuleRef] +ffi.lib.LLVMPY_ModuleFunctionsIter.restype = ffi.LLVMFunctionsIterator + +ffi.lib.LLVMPY_ModuleTypesIter.argtypes = [ffi.LLVMModuleRef] +ffi.lib.LLVMPY_ModuleTypesIter.restype = ffi.LLVMTypesIterator + +ffi.lib.LLVMPY_DisposeFunctionsIter.argtypes = [ffi.LLVMFunctionsIterator] + +ffi.lib.LLVMPY_DisposeTypesIter.argtypes = [ffi.LLVMTypesIterator] + +ffi.lib.LLVMPY_FunctionsIterNext.argtypes = [ffi.LLVMFunctionsIterator] +ffi.lib.LLVMPY_FunctionsIterNext.restype = ffi.LLVMValueRef + +ffi.lib.LLVMPY_TypesIterNext.argtypes = [ffi.LLVMTypesIterator] +ffi.lib.LLVMPY_TypesIterNext.restype = ffi.LLVMTypeRef + +ffi.lib.LLVMPY_CloneModule.argtypes = [ffi.LLVMModuleRef] +ffi.lib.LLVMPY_CloneModule.restype = ffi.LLVMModuleRef + +ffi.lib.LLVMPY_GetModuleName.argtypes = [ffi.LLVMModuleRef] +ffi.lib.LLVMPY_GetModuleName.restype = c_char_p + +ffi.lib.LLVMPY_SetModuleName.argtypes = [ffi.LLVMModuleRef, c_char_p] + +ffi.lib.LLVMPY_GetModuleSourceFileName.argtypes = [ffi.LLVMModuleRef] +ffi.lib.LLVMPY_GetModuleSourceFileName.restype = c_char_p diff --git a/lib/python3.11/site-packages/llvmlite/binding/object_file.py b/lib/python3.11/site-packages/llvmlite/binding/object_file.py new file mode 100644 index 0000000000000000000000000000000000000000..e5961b079ef87393347436a8fd8e70fb0525b39d --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/object_file.py @@ -0,0 +1,82 @@ +from llvmlite.binding import ffi +from ctypes import (c_bool, c_char_p, c_char, c_size_t, string_at, c_uint64, + POINTER) + + +class SectionIteratorRef(ffi.ObjectRef): + def name(self): + return ffi.lib.LLVMPY_GetSectionName(self) + + def is_text(self): + return ffi.lib.LLVMPY_IsSectionText(self) + + def size(self): + return ffi.lib.LLVMPY_GetSectionSize(self) + + def address(self): + return ffi.lib.LLVMPY_GetSectionAddress(self) + + def data(self): + return string_at(ffi.lib.LLVMPY_GetSectionContents(self), self.size()) + + def is_end(self, object_file): + return ffi.lib.LLVMPY_IsSectionIteratorAtEnd(object_file, self) + + def next(self): + ffi.lib.LLVMPY_MoveToNextSection(self) + + def _dispose(self): + ffi.lib.LLVMPY_DisposeSectionIterator(self) + + +class ObjectFileRef(ffi.ObjectRef): + @classmethod + def from_data(cls, data): + return cls(ffi.lib.LLVMPY_CreateObjectFile(data, len(data))) + + @classmethod + def from_path(cls, path): + with open(path, 'rb') as f: + data = f.read() + return cls(ffi.lib.LLVMPY_CreateObjectFile(data, len(data))) + + def sections(self): + it = SectionIteratorRef(ffi.lib.LLVMPY_GetSections(self)) + while not it.is_end(self): + yield it + it.next() + + def _dispose(self): + ffi.lib.LLVMPY_DisposeObjectFile(self) + + +ffi.lib.LLVMPY_CreateObjectFile.argtypes = [c_char_p, c_size_t] +ffi.lib.LLVMPY_CreateObjectFile.restype = ffi.LLVMObjectFileRef + +ffi.lib.LLVMPY_DisposeObjectFile.argtypes = [ffi.LLVMObjectFileRef] + +ffi.lib.LLVMPY_GetSections.argtypes = [ffi.LLVMObjectFileRef] +ffi.lib.LLVMPY_GetSections.restype = ffi.LLVMSectionIteratorRef + +ffi.lib.LLVMPY_DisposeSectionIterator.argtypes = [ffi.LLVMSectionIteratorRef] + +ffi.lib.LLVMPY_MoveToNextSection.argtypes = [ffi.LLVMSectionIteratorRef] + +ffi.lib.LLVMPY_IsSectionIteratorAtEnd.argtypes = [ + ffi.LLVMObjectFileRef, ffi.LLVMSectionIteratorRef] +ffi.lib.LLVMPY_IsSectionIteratorAtEnd.restype = c_bool + +ffi.lib.LLVMPY_GetSectionName.argtypes = [ffi.LLVMSectionIteratorRef] +ffi.lib.LLVMPY_GetSectionName.restype = c_char_p + +ffi.lib.LLVMPY_GetSectionSize.argtypes = [ffi.LLVMSectionIteratorRef] +ffi.lib.LLVMPY_GetSectionSize.restype = c_uint64 + +ffi.lib.LLVMPY_GetSectionAddress.argtypes = [ffi.LLVMSectionIteratorRef] +ffi.lib.LLVMPY_GetSectionAddress.restype = c_uint64 + +ffi.lib.LLVMPY_GetSectionContents.argtypes = [ffi.LLVMSectionIteratorRef] +ffi.lib.LLVMPY_GetSectionContents.restype = POINTER(c_char) + +ffi.lib.LLVMPY_IsSectionText.argtypes = [ffi.LLVMSectionIteratorRef] +ffi.lib.LLVMPY_IsSectionText.restype = c_bool diff --git a/lib/python3.11/site-packages/llvmlite/binding/options.py b/lib/python3.11/site-packages/llvmlite/binding/options.py new file mode 100644 index 0000000000000000000000000000000000000000..15eedfaaf476938c97abcd7e75131e9590f34203 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/options.py @@ -0,0 +1,17 @@ +from llvmlite.binding import ffi +from llvmlite.binding.common import _encode_string +from ctypes import c_char_p + + +def set_option(name, option): + """ + Set the given LLVM "command-line" option. + + For example set_option("test", "-debug-pass=Structure") would display + all optimization passes when generating code. + """ + ffi.lib.LLVMPY_SetCommandLine(_encode_string(name), + _encode_string(option)) + + +ffi.lib.LLVMPY_SetCommandLine.argtypes = [c_char_p, c_char_p] diff --git a/lib/python3.11/site-packages/llvmlite/binding/orcjit.py b/lib/python3.11/site-packages/llvmlite/binding/orcjit.py new file mode 100644 index 0000000000000000000000000000000000000000..82996f586bf688bce389db15d29b0c294f5cba67 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/orcjit.py @@ -0,0 +1,342 @@ +import ctypes +from ctypes import POINTER, c_bool, c_char_p, c_uint8, c_uint64, c_size_t + +from llvmlite.binding import ffi, targets + + +class _LinkElement(ctypes.Structure): + _fields_ = [("element_kind", c_uint8), + ("value", c_char_p), + ("value_len", c_size_t)] + + +class _SymbolAddress(ctypes.Structure): + _fields_ = [("name", c_char_p), ("address", c_uint64)] + + +class JITLibraryBuilder: + """ + Create a library for linking by OrcJIT + + OrcJIT operates like a linker: a number of compilation units and + dependencies are collected together and linked into a single dynamic library + that can export functions to other libraries or to be consumed directly as + entry points into JITted code. The native OrcJIT has a lot of memory + management complications so this API is designed to work well with Python's + garbage collection. + + The creation of a new library is a bit like a linker command line where + compilation units, mostly as LLVM IR, and previously constructed libraries + are linked together, then loaded into memory, and the addresses of exported + symbols are extracted. Any static initializers are run and the exported + addresses and a resource tracker is produced. As long as the resource + tracker is referenced somewhere in Python, the exported addresses will be + valid. Once the resource tracker is garbage collected, the static + destructors will run and library will be unloaded from memory. + """ + def __init__(self): + self.__entries = [] + self.__exports = set() + self.__imports = {} + + def add_ir(self, llvmir): + """ + Adds a compilation unit to the library using LLVM IR as the input + format. + + This takes a string or an object that can be converted to a string, + including IRBuilder, that contains LLVM IR. + """ + self.__entries.append((0, str(llvmir).encode('utf-8'))) + return self + + def add_native_assembly(self, asm): + """ + Adds a compilation unit to the library using native assembly as the + input format. + + This takes a string or an object that can be converted to a string that + contains native assembly, which will be + parsed by LLVM. + """ + self.__entries.append((1, str(asm).encode('utf-8'))) + return self + + def add_object_img(self, data): + """ + Adds a compilation unit to the library using pre-compiled object code. + + This takes the bytes of the contents of an object artifact which will be + loaded by LLVM. + """ + self.__entries.append((2, bytes(data))) + return self + + def add_object_file(self, file_path): + """ + Adds a compilation unit to the library using pre-compiled object file. + + This takes a string or path-like object that references an object file + which will be loaded by LLVM. + """ + with open(file_path, "rb") as f: + self.__entries.append((2, f.read())) + return self + + def add_jit_library(self, name): + """ + Adds an existing JIT library as prerequisite. + + The name of the library must match the one provided in a previous link + command. + """ + self.__entries.append((3, str(name).encode('utf-8'))) + return self + + def add_current_process(self): + """ + Allows the JITted library to access symbols in the current binary. + + That is, it allows exporting the current binary's symbols, including + loaded libraries, as imports to the JITted + library. + """ + self.__entries.append((3, b'')) + return self + + def import_symbol(self, name, address): + """ + Register the *address* of global symbol *name*. This will make + it usable (e.g. callable) from LLVM-compiled functions. + """ + self.__imports[str(name)] = c_uint64(address) + return self + + def export_symbol(self, name): + """ + During linking, extract the address of a symbol that was defined in one + of the compilation units. + + This allows getting symbols, functions or global variables, out of the + JIT linked library. The addresses will be + available when the link method is called. + """ + self.__exports.add(str(name)) + return self + + def link(self, lljit, library_name): + """ + Link all the current compilation units into a JITted library and extract + the address of exported symbols. + + An instance of the OrcJIT instance must be provided and this will be the + scope that is used to find other JITted libraries that are dependencies + and also be the place where this library will be defined. + + After linking, the method will return a resource tracker that keeps the + library alive. This tracker also knows the addresses of any exported + symbols that were requested. + + The addresses will be valid as long as the resource tracker is + referenced. + + When the resource tracker is destroyed, the library will be cleaned up, + however, the name of the library cannot be reused. + """ + assert not lljit.closed, "Cannot add to closed JIT" + encoded_library_name = str(library_name).encode('utf-8') + assert len(encoded_library_name) > 0, "Library cannot be empty" + elements = (_LinkElement * len(self.__entries))() + for idx, (kind, value) in enumerate(self.__entries): + elements[idx].element_kind = c_uint8(kind) + elements[idx].value = c_char_p(value) + elements[idx].value_len = c_size_t(len(value)) + exports = (_SymbolAddress * len(self.__exports))() + for idx, name in enumerate(self.__exports): + exports[idx].name = name.encode('utf-8') + + imports = (_SymbolAddress * len(self.__imports))() + for idx, (name, addr) in enumerate(self.__imports.items()): + imports[idx].name = name.encode('utf-8') + imports[idx].address = addr + + with ffi.OutputString() as outerr: + tracker = lljit._capi.LLVMPY_LLJIT_Link( + lljit._ptr, + encoded_library_name, + elements, + len(self.__entries), + imports, + len(self.__imports), + exports, + len(self.__exports), + outerr) + if not tracker: + raise RuntimeError(str(outerr)) + return ResourceTracker(tracker, + library_name, + {name: exports[idx].address + for idx, name in enumerate(self.__exports)}) + + +class ResourceTracker(ffi.ObjectRef): + """ + A resource tracker is created for each loaded JIT library and keeps the + module alive. + + OrcJIT supports unloading libraries that are no longer used. This resource + tracker should be stored in any object that reference functions or constants + for a JITted library. When all references to the resource tracker are + dropped, this will trigger LLVM to unload the library and destroy any + functions. + + Failure to keep resource trackers while calling a function or accessing a + symbol can result in crashes or memory corruption. + + LLVM internally tracks references between different libraries, so only + "leaf" libraries need to be tracked. + """ + def __init__(self, ptr, name, addresses): + self.__addresses = addresses + self.__name = name + ffi.ObjectRef.__init__(self, ptr) + + def __getitem__(self, item): + """ + Get the address of an exported symbol as an integer + """ + return self.__addresses[item] + + @property + def name(self): + return self.__name + + def _dispose(self): + with ffi.OutputString() as outerr: + if self._capi.LLVMPY_LLJIT_Dylib_Tracker_Dispose(self, outerr): + raise RuntimeError(str(outerr)) + + +class LLJIT(ffi.ObjectRef): + """ + A OrcJIT-based LLVM JIT engine that can compile and run LLVM IR as a + collection of JITted dynamic libraries + + The C++ OrcJIT API has a lot of memory ownership patterns that do not work + with Python. This API attempts to provide ones that are safe at the expense + of some features. Each LLJIT instance is a collection of JIT-compiled + libraries. In the C++ API, there is a "main" library; this API does not + provide access to the main library. Use the JITLibraryBuilder to create a + new named library instead. + """ + def __init__(self, ptr): + self._td = None + ffi.ObjectRef.__init__(self, ptr) + + def lookup(self, dylib, fn): + """ + Find a function in this dynamic library and construct a new tracking + object for it + + If the library or function do not exist, an exception will occur. + + Parameters + ---------- + dylib : str or None + the name of the library containing the symbol + fn : str + the name of the function to get + """ + assert not self.closed, "Cannot lookup in closed JIT" + address = ctypes.c_uint64() + with ffi.OutputString() as outerr: + tracker = ffi.lib.LLVMPY_LLJITLookup(self, + dylib.encode("utf-8"), + fn.encode("utf-8"), + ctypes.byref(address), + outerr) + if not tracker: + raise RuntimeError(str(outerr)) + + return ResourceTracker(tracker, dylib, {fn: address.value}) + + @property + def target_data(self): + """ + The TargetData for this LLJIT instance. + """ + if self._td is not None: + return self._td + ptr = ffi.lib.LLVMPY_LLJITGetDataLayout(self) + self._td = targets.TargetData(ptr) + self._td._owned = True + return self._td + + def _dispose(self): + if self._td is not None: + self._td.detach() + self._capi.LLVMPY_LLJITDispose(self) + + +def create_lljit_compiler(target_machine=None, *, + use_jit_link=False, + suppress_errors=False): + """ + Create an LLJIT instance + """ + with ffi.OutputString() as outerr: + lljit = ffi.lib.LLVMPY_CreateLLJITCompiler(target_machine, + suppress_errors, + use_jit_link, + outerr) + if not lljit: + raise RuntimeError(str(outerr)) + + return LLJIT(lljit) + + +ffi.lib.LLVMPY_LLJITLookup.argtypes = [ + ffi.LLVMOrcLLJITRef, + c_char_p, + c_char_p, + POINTER(c_uint64), + POINTER(c_char_p), +] +ffi.lib.LLVMPY_LLJITLookup.restype = ffi.LLVMOrcDylibTrackerRef + +ffi.lib.LLVMPY_LLJITGetDataLayout.argtypes = [ + ffi.LLVMOrcLLJITRef, +] +ffi.lib.LLVMPY_LLJITGetDataLayout.restype = ffi.LLVMTargetDataRef + +ffi.lib.LLVMPY_CreateLLJITCompiler.argtypes = [ + ffi.LLVMTargetMachineRef, + c_bool, + c_bool, + POINTER(c_char_p), +] +ffi.lib.LLVMPY_CreateLLJITCompiler.restype = ffi.LLVMOrcLLJITRef + +ffi.lib.LLVMPY_LLJITDispose.argtypes = [ + ffi.LLVMOrcLLJITRef, +] + + +ffi.lib.LLVMPY_LLJIT_Link.argtypes = [ + ffi.LLVMOrcLLJITRef, + c_char_p, + POINTER(_LinkElement), + c_size_t, + POINTER(_SymbolAddress), + c_size_t, + POINTER(_SymbolAddress), + c_size_t, + POINTER(c_char_p) +] +ffi.lib.LLVMPY_LLJIT_Link.restype = ffi.LLVMOrcDylibTrackerRef + +ffi.lib.LLVMPY_LLJIT_Dylib_Tracker_Dispose.argtypes = [ + ffi.LLVMOrcDylibTrackerRef, + POINTER(c_char_p) +] +ffi.lib.LLVMPY_LLJIT_Dylib_Tracker_Dispose.restype = c_bool diff --git a/lib/python3.11/site-packages/llvmlite/binding/passmanagers.py b/lib/python3.11/site-packages/llvmlite/binding/passmanagers.py new file mode 100644 index 0000000000000000000000000000000000000000..dc9c07e1381c02f6b1b1b0131d54d0ad4e246b82 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/passmanagers.py @@ -0,0 +1,923 @@ +from ctypes import (c_bool, c_char_p, c_int, c_size_t, c_uint, Structure, byref, + POINTER) +from collections import namedtuple +from enum import IntFlag +from llvmlite.binding import ffi +import os +from tempfile import mkstemp +from llvmlite.binding.common import _encode_string + +_prunestats = namedtuple('PruneStats', + ('basicblock diamond fanout fanout_raise')) + + +class PruneStats(_prunestats): + """ Holds statistics from reference count pruning. + """ + + def __add__(self, other): + if not isinstance(other, PruneStats): + msg = 'PruneStats can only be added to another PruneStats, got {}.' + raise TypeError(msg.format(type(other))) + return PruneStats(self.basicblock + other.basicblock, + self.diamond + other.diamond, + self.fanout + other.fanout, + self.fanout_raise + other.fanout_raise) + + def __sub__(self, other): + if not isinstance(other, PruneStats): + msg = ('PruneStats can only be subtracted from another PruneStats, ' + 'got {}.') + raise TypeError(msg.format(type(other))) + return PruneStats(self.basicblock - other.basicblock, + self.diamond - other.diamond, + self.fanout - other.fanout, + self.fanout_raise - other.fanout_raise) + + +class _c_PruneStats(Structure): + _fields_ = [ + ('basicblock', c_size_t), + ('diamond', c_size_t), + ('fanout', c_size_t), + ('fanout_raise', c_size_t)] + + +def dump_refprune_stats(printout=False): + """ Returns a namedtuple containing the current values for the refop pruning + statistics. If kwarg `printout` is True the stats are printed to stderr, + default is False. + """ + + stats = _c_PruneStats(0, 0, 0, 0) + do_print = c_bool(printout) + + ffi.lib.LLVMPY_DumpRefPruneStats(byref(stats), do_print) + return PruneStats(stats.basicblock, stats.diamond, stats.fanout, + stats.fanout_raise) + + +def set_time_passes(enable): + """Enable or disable the pass timers. + + Parameters + ---------- + enable : bool + Set to True to enable the pass timers. + Set to False to disable the pass timers. + """ + ffi.lib.LLVMPY_SetTimePasses(c_bool(enable)) + + +def report_and_reset_timings(): + """Returns the pass timings report and resets the LLVM internal timers. + + Pass timers are enabled by ``set_time_passes()``. If the timers are not + enabled, this function will return an empty string. + + Returns + ------- + res : str + LLVM generated timing report. + """ + with ffi.OutputString() as buf: + ffi.lib.LLVMPY_ReportAndResetTimings(buf) + return str(buf) + + +def create_module_pass_manager(): + return ModulePassManager() + + +def create_function_pass_manager(module): + return FunctionPassManager(module) + + +class RefPruneSubpasses(IntFlag): + PER_BB = 0b0001 # noqa: E221 + DIAMOND = 0b0010 # noqa: E221 + FANOUT = 0b0100 # noqa: E221 + FANOUT_RAISE = 0b1000 + ALL = PER_BB | DIAMOND | FANOUT | FANOUT_RAISE + + +class PassManager(ffi.ObjectRef): + """PassManager + """ + + def _dispose(self): + self._capi.LLVMPY_DisposePassManager(self) + + def add_aa_eval_pass(self): + """ + See https://llvm.org/docs/Passes.html#aa-eval-exhaustive-alias-analysis-precision-evaluator + + LLVM 14: `llvm::createAAEvalPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddAAEvalPass(self) + + def add_basic_aa_pass(self): + """ + See https://llvm.org/docs/Passes.html#basic-aa-basic-alias-analysis-stateless-aa-impl + + LLVM 14: `llvm::createBasicAAWrapperPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddBasicAAWrapperPass(self) + + def add_constant_merge_pass(self): + """ + See http://llvm.org/docs/Passes.html#constmerge-merge-duplicate-global-constants + + LLVM 14: `LLVMAddConstantMergePass` + """ # noqa E501 + ffi.lib.LLVMPY_AddConstantMergePass(self) + + def add_dead_arg_elimination_pass(self): + """ + See http://llvm.org/docs/Passes.html#deadargelim-dead-argument-elimination + + LLVM 14: `LLVMAddDeadArgEliminationPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddDeadArgEliminationPass(self) + + def add_dependence_analysis_pass(self): + """ + See https://llvm.org/docs/Passes.html#da-dependence-analysis + + LLVM 14: `llvm::createDependenceAnalysisWrapperPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddDependenceAnalysisPass(self) + + def add_dot_call_graph_pass(self): + """ + See https://llvm.org/docs/Passes.html#dot-callgraph-print-call-graph-to-dot-file + + LLVM 14: `llvm::createCallGraphDOTPrinterPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddCallGraphDOTPrinterPass(self) + + def add_dot_cfg_printer_pass(self): + """ + See https://llvm.org/docs/Passes.html#dot-cfg-print-cfg-of-function-to-dot-file + + LLVM 14: `llvm::createCFGPrinterLegacyPassPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddCFGPrinterPass(self) + + def add_dot_dom_printer_pass(self, show_body=False): + """ + See https://llvm.org/docs/Passes.html#dot-dom-print-dominance-tree-of-function-to-dot-file + + LLVM 14: `llvm::createDomPrinterPass` and `llvm::createDomOnlyPrinterPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddDotDomPrinterPass(self, show_body) + + def add_dot_postdom_printer_pass(self, show_body=False): + """ + See https://llvm.org/docs/Passes.html#dot-postdom-print-postdominance-tree-of-function-to-dot-file + + LLVM 14: `llvm::createPostDomPrinterPass` and `llvm::createPostDomOnlyPrinterPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddDotPostDomPrinterPass(self, show_body) + + def add_globals_mod_ref_aa_pass(self): + """ + See https://llvm.org/docs/Passes.html#globalsmodref-aa-simple-mod-ref-analysis-for-globals + + LLVM 14: `llvm::createGlobalsAAWrapperPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddGlobalsModRefAAPass(self) + + def add_iv_users_pass(self): + """ + See https://llvm.org/docs/Passes.html#iv-users-induction-variable-users + + LLVM 14: `llvm::createIVUsersPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddIVUsersPass(self) + + def add_lint_pass(self): + """ + See https://llvm.org/docs/Passes.html#lint-statically-lint-checks-llvm-ir + + LLVM 14: `llvm::createLintLegacyPassPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLintPass(self) + + def add_lazy_value_info_pass(self): + """ + See https://llvm.org/docs/Passes.html#lazy-value-info-lazy-value-information-analysis + + LLVM 14: `llvm::createLazyValueInfoPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLazyValueInfoPass(self) + + def add_module_debug_info_pass(self): + """ + See https://llvm.org/docs/Passes.html#module-debuginfo-decodes-module-level-debug-info + + LLVM 14: `llvm::createModuleDebugInfoPrinterPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddModuleDebugInfoPrinterPass(self) + + def add_region_info_pass(self): + """ + See https://llvm.org/docs/Passes.html#regions-detect-single-entry-single-exit-regions + + LLVM 14: `llvm::createRegionInfoPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddRegionInfoPass(self) + + def add_scalar_evolution_aa_pass(self): + """ + See https://llvm.org/docs/Passes.html#scev-aa-scalarevolution-based-alias-analysis + + LLVM 14: `llvm::createSCEVAAWrapperPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddScalarEvolutionAAPass(self) + + def add_aggressive_dead_code_elimination_pass(self): + """ + See https://llvm.org/docs/Passes.html#adce-aggressive-dead-code-elimination + + LLVM 14: `llvm::createAggressiveDCEPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddAggressiveDCEPass(self) + + def add_always_inliner_pass(self, insert_lifetime=True): + """ + See https://llvm.org/docs/Passes.html#always-inline-inliner-for-always-inline-functions + + LLVM 14: `llvm::createAlwaysInlinerLegacyPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddAlwaysInlinerPass(self, insert_lifetime) + + def add_arg_promotion_pass(self, max_elements=3): + """ + See https://llvm.org/docs/Passes.html#argpromotion-promote-by-reference-arguments-to-scalars + + LLVM 14: `llvm::createArgumentPromotionPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddArgPromotionPass(self, max_elements) + + def add_break_critical_edges_pass(self): + """ + See https://llvm.org/docs/Passes.html#break-crit-edges-break-critical-edges-in-cfg + + LLVM 14: `llvm::createBreakCriticalEdgesPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddBreakCriticalEdgesPass(self) + + def add_dead_store_elimination_pass(self): + """ + See https://llvm.org/docs/Passes.html#dse-dead-store-elimination + + LLVM 14: `llvm::createDeadStoreEliminationPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddDeadStoreEliminationPass(self) + + def add_reverse_post_order_function_attrs_pass(self): + """ + See https://llvm.org/docs/Passes.html#function-attrs-deduce-function-attributes + + LLVM 14: `llvm::createReversePostOrderFunctionAttrsPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddReversePostOrderFunctionAttrsPass(self) + + def add_function_attrs_pass(self): + """ + See http://llvm.org/docs/Passes.html#functionattrs-deduce-function-attributes + + LLVM 14: `LLVMAddFunctionAttrsPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddFunctionAttrsPass(self) + + def add_function_inlining_pass(self, threshold): + """ + See http://llvm.org/docs/Passes.html#inline-function-integration-inlining + + LLVM 14: `createFunctionInliningPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddFunctionInliningPass(self, threshold) + + def add_global_dce_pass(self): + """ + See http://llvm.org/docs/Passes.html#globaldce-dead-global-elimination + + LLVM 14: `LLVMAddGlobalDCEPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddGlobalDCEPass(self) + + def add_global_optimizer_pass(self): + """ + See http://llvm.org/docs/Passes.html#globalopt-global-variable-optimizer + + LLVM 14: `LLVMAddGlobalOptimizerPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddGlobalOptimizerPass(self) + + def add_ipsccp_pass(self): + """ + See http://llvm.org/docs/Passes.html#ipsccp-interprocedural-sparse-conditional-constant-propagation + + LLVM 14: `LLVMAddIPSCCPPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddIPSCCPPass(self) + + def add_dead_code_elimination_pass(self): + """ + See http://llvm.org/docs/Passes.html#dce-dead-code-elimination + LLVM 14: `llvm::createDeadCodeEliminationPass` + """ + ffi.lib.LLVMPY_AddDeadCodeEliminationPass(self) + + def add_aggressive_instruction_combining_pass(self): + """ + See https://llvm.org/docs/Passes.html#aggressive-instcombine-combine-expression-patterns + + LLVM 14: `llvm::createAggressiveInstCombinerPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddAggressiveInstructionCombiningPass(self) + + def add_internalize_pass(self): + """ + See https://llvm.org/docs/Passes.html#internalize-internalize-global-symbols + + LLVM 14: `llvm::createInternalizePass` + """ # noqa E501 + ffi.lib.LLVMPY_AddInternalizePass(self) + + def add_cfg_simplification_pass(self): + """ + See http://llvm.org/docs/Passes.html#simplifycfg-simplify-the-cfg + + LLVM 14: `LLVMAddCFGSimplificationPass` + """ + ffi.lib.LLVMPY_AddCFGSimplificationPass(self) + + def add_jump_threading_pass(self, threshold=-1): + """ + See https://llvm.org/docs/Passes.html#jump-threading-jump-threading + + LLVM 14: `llvm::createJumpThreadingPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddJumpThreadingPass(self, threshold) + + def add_lcssa_pass(self): + """ + See https://llvm.org/docs/Passes.html#lcssa-loop-closed-ssa-form-pass + + LLVM 14: `llvm::createLCSSAPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLCSSAPass(self) + + def add_gvn_pass(self): + """ + See http://llvm.org/docs/Passes.html#gvn-global-value-numbering + + LLVM 14: `LLVMAddGVNPass` + """ + ffi.lib.LLVMPY_AddGVNPass(self) + + def add_instruction_combining_pass(self): + """ + See http://llvm.org/docs/Passes.html#passes-instcombine + + LLVM 14: `LLVMAddInstructionCombiningPass` + """ + ffi.lib.LLVMPY_AddInstructionCombiningPass(self) + + def add_licm_pass(self): + """ + See http://llvm.org/docs/Passes.html#licm-loop-invariant-code-motion + + LLVM 14: `LLVMAddLICMPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLICMPass(self) + + def add_loop_deletion_pass(self): + """ + See https://llvm.org/docs/Passes.html#loop-deletion-delete-dead-loops + + LLVM 14: `llvm::createLoopDeletionPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLoopDeletionPass(self) + + def add_loop_extractor_pass(self): + """ + See https://llvm.org/docs/Passes.html#loop-extract-extract-loops-into-new-functions + + LLVM 14: `llvm::createLoopExtractorPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLoopExtractorPass(self) + + def add_single_loop_extractor_pass(self): + """ + See https://llvm.org/docs/Passes.html#loop-extract-single-extract-at-most-one-loop-into-a-new-function + + LLVM 14: `llvm::createSingleLoopExtractorPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddSingleLoopExtractorPass(self) + + def add_sccp_pass(self): + """ + See http://llvm.org/docs/Passes.html#sccp-sparse-conditional-constant-propagation + + LLVM 14: `LLVMAddSCCPPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddSCCPPass(self) + + def add_loop_strength_reduce_pass(self): + """ + See https://llvm.org/docs/Passes.html#loop-reduce-loop-strength-reduction + + LLVM 14: `llvm::createLoopStrengthReducePass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLoopStrengthReducePass(self) + + def add_loop_simplification_pass(self): + """ + See https://llvm.org/docs/Passes.html#loop-simplify-canonicalize-natural-loops + + LLVM 14: `llvm::createLoopSimplifyPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLoopSimplificationPass(self) + + def add_loop_unroll_pass(self): + """ + See https://llvm.org/docs/Passes.html#loop-unroll-unroll-loops + + LLVM 14: `LLVMAddLoopUnrollPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLoopUnrollPass(self) + + def add_loop_unroll_and_jam_pass(self): + """ + See https://llvm.org/docs/Passes.html#loop-unroll-and-jam-unroll-and-jam-loops + + LLVM 14: `LLVMAddLoopUnrollAndJamPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLoopUnrollAndJamPass(self) + + def add_loop_unswitch_pass(self, + optimize_for_size=False, + has_branch_divergence=False): + """ + See https://llvm.org/docs/Passes.html#loop-unswitch-unswitch-loops + + LLVM 14: `llvm::createLoopUnswitchPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLoopUnswitchPass(self, + optimize_for_size, + has_branch_divergence) + + def add_lower_atomic_pass(self): + """ + See https://llvm.org/docs/Passes.html#loweratomic-lower-atomic-intrinsics-to-non-atomic-form + + LLVM 14: `llvm::createLowerAtomicPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLowerAtomicPass(self) + + def add_lower_invoke_pass(self): + """ + See https://llvm.org/docs/Passes.html#lowerinvoke-lower-invokes-to-calls-for-unwindless-code-generators + + LLVM 14: `llvm::createLowerInvokePass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLowerInvokePass(self) + + def add_lower_switch_pass(self): + """ + See https://llvm.org/docs/Passes.html#lowerswitch-lower-switchinsts-to-branches + + LLVM 14: `llvm::createLowerSwitchPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddLowerSwitchPass(self) + + def add_memcpy_optimization_pass(self): + """ + See https://llvm.org/docs/Passes.html#memcpyopt-memcpy-optimization + + LLVM 14: `llvm::createMemCpyOptPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddMemCpyOptimizationPass(self) + + def add_merge_functions_pass(self): + """ + See https://llvm.org/docs/Passes.html#mergefunc-merge-functions + + LLVM 14: `llvm::createMergeFunctionsPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddMergeFunctionsPass(self) + + def add_merge_returns_pass(self): + """ + See https://llvm.org/docs/Passes.html#mergereturn-unify-function-exit-nodes + + LLVM 14: `llvm::createUnifyFunctionExitNodesPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddMergeReturnsPass(self) + + def add_partial_inlining_pass(self): + """ + See https://llvm.org/docs/Passes.html#partial-inliner-partial-inliner + + LLVM 14: `llvm::createPartialInliningPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddPartialInliningPass(self) + + def add_prune_exception_handling_pass(self): + """ + See https://llvm.org/docs/Passes.html#prune-eh-remove-unused-exception-handling-info + + LLVM 14: `llvm::createPruneEHPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddPruneExceptionHandlingPass(self) + + def add_reassociate_expressions_pass(self): + """ + See https://llvm.org/docs/Passes.html#reassociate-reassociate-expressions + + LLVM 14: `llvm::createReassociatePass` + """ # noqa E501 + ffi.lib.LLVMPY_AddReassociatePass(self) + + def add_demote_register_to_memory_pass(self): + """ + See https://llvm.org/docs/Passes.html#rel-lookup-table-converter-relative-lookup-table-converter + + LLVM 14: `llvm::createDemoteRegisterToMemoryPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddDemoteRegisterToMemoryPass(self) + + def add_sroa_pass(self): + """ + See http://llvm.org/docs/Passes.html#scalarrepl-scalar-replacement-of-aggregates-dt + Note that this pass corresponds to the ``opt -sroa`` command-line option, + despite the link above. + + LLVM 14: `llvm::createSROAPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddSROAPass(self) + + def add_sink_pass(self): + """ + See https://llvm.org/docs/Passes.html#sink-code-sinking + + LLVM 14: `llvm::createSinkingPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddSinkPass(self) + + def add_strip_symbols_pass(self, only_debug=False): + """ + See https://llvm.org/docs/Passes.html#strip-strip-all-symbols-from-a-module + + LLVM 14: `llvm::createStripSymbolsPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddStripSymbolsPass(self, only_debug) + + def add_strip_dead_debug_info_pass(self): + """ + See https://llvm.org/docs/Passes.html#strip-dead-debug-info-strip-debug-info-for-unused-symbols + + LLVM 14: `llvm::createStripDeadDebugInfoPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddStripDeadDebugInfoPass(self) + + def add_strip_dead_prototypes_pass(self): + """ + See https://llvm.org/docs/Passes.html#strip-dead-prototypes-strip-unused-function-prototypes + + LLVM 14: `llvm::createStripDeadPrototypesPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddStripDeadPrototypesPass(self) + + def add_strip_debug_declare_pass(self): + """ + See https://llvm.org/docs/Passes.html#strip-debug-declare-strip-all-llvm-dbg-declare-intrinsics + + LLVM 14: `llvm::createStripDebugDeclarePass` + """ # noqa E501 + ffi.lib.LLVMPY_AddStripDebugDeclarePrototypesPass(self) + + def add_strip_nondebug_symbols_pass(self): + """ + See https://llvm.org/docs/Passes.html#strip-nondebug-strip-all-symbols-except-dbg-symbols-from-a-module + + LLVM 14: `llvm::createStripNonDebugSymbolsPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddStripNondebugSymbolsPass(self) + + def add_tail_call_elimination_pass(self): + """ + See https://llvm.org/docs/Passes.html#tailcallelim-tail-call-elimination + + LLVM 14: `llvm::createTailCallEliminationPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddTailCallEliminationPass(self) + + def add_type_based_alias_analysis_pass(self): + """ + LLVM 14: `LLVMAddTypeBasedAliasAnalysisPass` + """ # noqa E501 + ffi.lib.LLVMPY_AddTypeBasedAliasAnalysisPass(self) + + def add_basic_alias_analysis_pass(self): + """ + See http://llvm.org/docs/AliasAnalysis.html#the-basicaa-pass + + LLVM 14: `LLVMAddBasicAliasAnalysisPass` + """ + ffi.lib.LLVMPY_AddBasicAliasAnalysisPass(self) + + def add_loop_rotate_pass(self): + """http://llvm.org/docs/Passes.html#loop-rotate-rotate-loops.""" + ffi.lib.LLVMPY_LLVMAddLoopRotatePass(self) + + def add_target_library_info(self, triple): + ffi.lib.LLVMPY_AddTargetLibraryInfoPass(self, _encode_string(triple)) + + # Non-standard LLVM passes + + def add_refprune_pass(self, subpasses_flags=RefPruneSubpasses.ALL, + subgraph_limit=1000): + """Add Numba specific Reference count pruning pass. + + Parameters + ---------- + subpasses_flags : RefPruneSubpasses + A bitmask to control the subpasses to be enabled. + subgraph_limit : int + Limit the fanout pruners to working on a subgraph no bigger than + this number of basic-blocks to avoid spending too much time in very + large graphs. Default is 1000. Subject to change in future + versions. + """ + iflags = RefPruneSubpasses(subpasses_flags) + ffi.lib.LLVMPY_AddRefPrunePass(self, iflags, subgraph_limit) + + +class ModulePassManager(PassManager): + + def __init__(self, ptr=None): + if ptr is None: + ptr = ffi.lib.LLVMPY_CreatePassManager() + PassManager.__init__(self, ptr) + + def run(self, module, remarks_file=None, remarks_format='yaml', + remarks_filter=''): + """ + Run optimization passes on the given module. + + Parameters + ---------- + module : llvmlite.binding.ModuleRef + The module to be optimized inplace + remarks_file : str; optional + If not `None`, it is the file to store the optimization remarks. + remarks_format : str; optional + The format to write; YAML is default + remarks_filter : str; optional + The filter that should be applied to the remarks output. + """ + if remarks_file is None: + return ffi.lib.LLVMPY_RunPassManager(self, module) + else: + r = ffi.lib.LLVMPY_RunPassManagerWithRemarks( + self, module, _encode_string(remarks_format), + _encode_string(remarks_filter), + _encode_string(remarks_file)) + if r == -1: + raise IOError("Failed to initialize remarks file.") + return r > 0 + + def run_with_remarks(self, module, remarks_format='yaml', + remarks_filter=''): + """ + Run optimization passes on the given module and returns the result and + the remarks data. + + Parameters + ---------- + module : llvmlite.binding.ModuleRef + The module to be optimized + remarks_format : str + The remarks output; YAML is the default + remarks_filter : str; optional + The filter that should be applied to the remarks output. + """ + remarkdesc, remarkfile = mkstemp() + try: + with os.fdopen(remarkdesc, 'r'): + pass + r = self.run(module, remarkfile, remarks_format, remarks_filter) + if r == -1: + raise IOError("Failed to initialize remarks file.") + with open(remarkfile) as f: + return bool(r), f.read() + finally: + os.unlink(remarkfile) + + +class FunctionPassManager(PassManager): + + def __init__(self, module): + ptr = ffi.lib.LLVMPY_CreateFunctionPassManager(module) + self._module = module + module._owned = True + PassManager.__init__(self, ptr) + + def initialize(self): + """ + Initialize the FunctionPassManager. Returns True if it produced + any changes (?). + """ + return ffi.lib.LLVMPY_InitializeFunctionPassManager(self) + + def finalize(self): + """ + Finalize the FunctionPassManager. Returns True if it produced + any changes (?). + """ + return ffi.lib.LLVMPY_FinalizeFunctionPassManager(self) + + def run(self, function, remarks_file=None, remarks_format='yaml', + remarks_filter=''): + """ + Run optimization passes on the given function. + + Parameters + ---------- + function : llvmlite.binding.FunctionRef + The function to be optimized inplace + remarks_file : str; optional + If not `None`, it is the file to store the optimization remarks. + remarks_format : str; optional + The format of the remarks file; the default is YAML + remarks_filter : str; optional + The filter that should be applied to the remarks output. + """ + if remarks_file is None: + return ffi.lib.LLVMPY_RunFunctionPassManager(self, function) + else: + r = ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks( + self, function, _encode_string(remarks_format), + _encode_string(remarks_filter), + _encode_string(remarks_file)) + if r == -1: + raise IOError("Failed to initialize remarks file.") + return bool(r) + + def run_with_remarks(self, function, remarks_format='yaml', + remarks_filter=''): + """ + Run optimization passes on the given function and returns the result + and the remarks data. + + Parameters + ---------- + function : llvmlite.binding.FunctionRef + The function to be optimized inplace + remarks_format : str; optional + The format of the remarks file; the default is YAML + remarks_filter : str; optional + The filter that should be applied to the remarks output. + """ + # LLVM is going to need to close this file and then reopen it, so we + # can't use an unlinked temporary file. + remarkdesc, remarkfile = mkstemp() + try: + # We get an open handle, but we need LLVM to write first, so close + # it. + with os.fdopen(remarkdesc, 'r'): + pass + r = self.run(function, remarkfile, remarks_format, remarks_filter) + if r == -1: + raise IOError("Failed to initialize remarks file.") + with open(remarkfile) as f: + return bool(r), f.read() + finally: + os.unlink(remarkfile) + + +# ============================================================================ +# FFI + +ffi.lib.LLVMPY_CreatePassManager.restype = ffi.LLVMPassManagerRef + +ffi.lib.LLVMPY_CreateFunctionPassManager.argtypes = [ffi.LLVMModuleRef] +ffi.lib.LLVMPY_CreateFunctionPassManager.restype = ffi.LLVMPassManagerRef + +ffi.lib.LLVMPY_DisposePassManager.argtypes = [ffi.LLVMPassManagerRef] + +ffi.lib.LLVMPY_RunPassManager.argtypes = [ffi.LLVMPassManagerRef, + ffi.LLVMModuleRef] +ffi.lib.LLVMPY_RunPassManager.restype = c_bool + +ffi.lib.LLVMPY_RunPassManagerWithRemarks.argtypes = [ffi.LLVMPassManagerRef, + ffi.LLVMModuleRef, + c_char_p, + c_char_p, + c_char_p] +ffi.lib.LLVMPY_RunPassManagerWithRemarks.restype = c_int + +ffi.lib.LLVMPY_InitializeFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_InitializeFunctionPassManager.restype = c_bool + +ffi.lib.LLVMPY_FinalizeFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_FinalizeFunctionPassManager.restype = c_bool + +ffi.lib.LLVMPY_RunFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef, + ffi.LLVMValueRef] +ffi.lib.LLVMPY_RunFunctionPassManager.restype = c_bool + +ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks.argtypes = [ + ffi.LLVMPassManagerRef, ffi.LLVMValueRef, c_char_p, c_char_p, c_char_p +] +ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks.restype = c_int + +ffi.lib.LLVMPY_AddAAEvalPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddBasicAAWrapperPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddConstantMergePass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddDeadArgEliminationPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddDependenceAnalysisPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddCallGraphDOTPrinterPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddCFGPrinterPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddDotDomPrinterPass.argtypes = [ffi.LLVMPassManagerRef, c_bool] +ffi.lib.LLVMPY_AddDotPostDomPrinterPass.argtypes = [ + ffi.LLVMPassManagerRef, + c_bool] +ffi.lib.LLVMPY_AddGlobalsModRefAAPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddInstructionCountPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddIVUsersPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLazyValueInfoPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLintPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddModuleDebugInfoPrinterPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddRegionInfoPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddScalarEvolutionAAPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddAggressiveDCEPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddAlwaysInlinerPass.argtypes = [ffi.LLVMPassManagerRef, c_bool] +ffi.lib.LLVMPY_AddArgPromotionPass.argtypes = [ffi.LLVMPassManagerRef, c_uint] +ffi.lib.LLVMPY_AddBreakCriticalEdgesPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddDeadStoreEliminationPass.argtypes = [ + ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddReversePostOrderFunctionAttrsPass.argtypes = [ + ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddAggressiveInstructionCombiningPass.argtypes = [ + ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddInternalizePass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLCSSAPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLoopDeletionPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLoopExtractorPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddSingleLoopExtractorPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLoopStrengthReducePass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLoopSimplificationPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLoopUnrollPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLoopUnrollAndJamPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLoopUnswitchPass.argtypes = [ + ffi.LLVMPassManagerRef, + c_bool, + c_bool] +ffi.lib.LLVMPY_AddLowerAtomicPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLowerInvokePass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLowerSwitchPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddMemCpyOptimizationPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddMergeFunctionsPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddMergeReturnsPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddPartialInliningPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddPruneExceptionHandlingPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddReassociatePass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddDemoteRegisterToMemoryPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddSinkPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddStripSymbolsPass.argtypes = [ffi.LLVMPassManagerRef, c_bool] +ffi.lib.LLVMPY_AddStripDeadDebugInfoPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddStripDeadPrototypesPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddStripDebugDeclarePrototypesPass.argtypes = [ + ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddStripNondebugSymbolsPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddTailCallEliminationPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddJumpThreadingPass.argtypes = [ffi.LLVMPassManagerRef, c_int] +ffi.lib.LLVMPY_AddFunctionAttrsPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddFunctionInliningPass.argtypes = [ + ffi.LLVMPassManagerRef, c_int] +ffi.lib.LLVMPY_AddGlobalDCEPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddGlobalOptimizerPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddIPSCCPPass.argtypes = [ffi.LLVMPassManagerRef] + +ffi.lib.LLVMPY_AddDeadCodeEliminationPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddCFGSimplificationPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddGVNPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddInstructionCombiningPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddLICMPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddSCCPPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddSROAPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddTypeBasedAliasAnalysisPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddBasicAliasAnalysisPass.argtypes = [ffi.LLVMPassManagerRef] +ffi.lib.LLVMPY_AddTargetLibraryInfoPass.argtypes = [ffi.LLVMPassManagerRef, + c_char_p] + +ffi.lib.LLVMPY_AddRefPrunePass.argtypes = [ffi.LLVMPassManagerRef, c_int, + c_size_t] + +ffi.lib.LLVMPY_DumpRefPruneStats.argtypes = [POINTER(_c_PruneStats), c_bool] diff --git a/lib/python3.11/site-packages/llvmlite/binding/targets.py b/lib/python3.11/site-packages/llvmlite/binding/targets.py new file mode 100644 index 0000000000000000000000000000000000000000..a7e6ffdc3e51e2d668f944ff6ca4f75fc5c6c612 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/targets.py @@ -0,0 +1,450 @@ +import os +from ctypes import (POINTER, c_char_p, c_longlong, c_int, c_size_t, + c_void_p, string_at) + +from llvmlite.binding import ffi +from llvmlite.binding.common import _decode_string, _encode_string + + +def get_process_triple(): + """ + Return a target triple suitable for generating code for the current process. + An example when the default triple from ``get_default_triple()`` is not be + suitable is when LLVM is compiled for 32-bit but the process is executing + in 64-bit mode. + """ + with ffi.OutputString() as out: + ffi.lib.LLVMPY_GetProcessTriple(out) + return str(out) + + +class FeatureMap(dict): + """ + Maps feature name to a boolean indicating the availability of the feature. + Extends ``dict`` to add `.flatten()` method. + """ + + def flatten(self, sort=True): + """ + Args + ---- + sort: bool + Optional. If True, the features are sorted by name; otherwise, + the ordering is unstable between python session due to hash + randomization. Defaults to True. + + Returns a string suitable for use as the ``features`` argument to + ``Target.create_target_machine()``. + + """ + iterator = sorted(self.items()) if sort else iter(self.items()) + flag_map = {True: '+', False: '-'} + return ','.join('{0}{1}'.format(flag_map[v], k) + for k, v in iterator) + + +def get_host_cpu_features(): + """ + Returns a dictionary-like object indicating the CPU features for current + architecture and whether they are enabled for this CPU. The key-value pairs + are the feature name as string and a boolean indicating whether the feature + is available. The returned value is an instance of ``FeatureMap`` class, + which adds a new method ``.flatten()`` for returning a string suitable for + use as the "features" argument to ``Target.create_target_machine()``. + + If LLVM has not implemented this feature or it fails to get the information, + this function will raise a RuntimeError exception. + """ + with ffi.OutputString() as out: + outdict = FeatureMap() + if not ffi.lib.LLVMPY_GetHostCPUFeatures(out): + return outdict + flag_map = {'+': True, '-': False} + content = str(out) + if content: # protect against empty string + for feat in content.split(','): + if feat: # protect against empty feature + outdict[feat[1:]] = flag_map[feat[0]] + return outdict + + +def get_default_triple(): + """ + Return the default target triple LLVM is configured to produce code for. + """ + with ffi.OutputString() as out: + ffi.lib.LLVMPY_GetDefaultTargetTriple(out) + return str(out) + + +def get_host_cpu_name(): + """ + Get the name of the host's CPU, suitable for using with + :meth:`Target.create_target_machine()`. + """ + with ffi.OutputString() as out: + ffi.lib.LLVMPY_GetHostCPUName(out) + return str(out) + + +_object_formats = { + 1: "COFF", + 2: "ELF", + 3: "MachO", +} + + +def get_object_format(triple=None): + """ + Get the object format for the given *triple* string (or the default + triple if omitted). + A string is returned + """ + if triple is None: + triple = get_default_triple() + res = ffi.lib.LLVMPY_GetTripleObjectFormat(_encode_string(triple)) + return _object_formats[res] + + +def create_target_data(layout): + """ + Create a TargetData instance for the given *layout* string. + """ + return TargetData(ffi.lib.LLVMPY_CreateTargetData(_encode_string(layout))) + + +class TargetData(ffi.ObjectRef): + """ + A TargetData provides structured access to a data layout. + Use :func:`create_target_data` to create instances. + """ + + def __str__(self): + if self._closed: + return "" + with ffi.OutputString() as out: + ffi.lib.LLVMPY_CopyStringRepOfTargetData(self, out) + return str(out) + + def _dispose(self): + self._capi.LLVMPY_DisposeTargetData(self) + + def get_abi_size(self, ty): + """ + Get ABI size of LLVM type *ty*. + """ + return ffi.lib.LLVMPY_ABISizeOfType(self, ty) + + def get_element_offset(self, ty, position): + """ + Get byte offset of type's ty element at the given position + """ + + offset = ffi.lib.LLVMPY_OffsetOfElement(self, ty, position) + if offset == -1: + raise ValueError("Could not determined offset of {}th " + "element of the type '{}'. Is it a struct" + "type?".format(position, str(ty))) + return offset + + def get_pointee_abi_size(self, ty): + """ + Get ABI size of pointee type of LLVM pointer type *ty*. + """ + size = ffi.lib.LLVMPY_ABISizeOfElementType(self, ty) + if size == -1: + raise RuntimeError("Not a pointer type: %s" % (ty,)) + return size + + def get_pointee_abi_alignment(self, ty): + """ + Get minimum ABI alignment of pointee type of LLVM pointer type *ty*. + """ + size = ffi.lib.LLVMPY_ABIAlignmentOfElementType(self, ty) + if size == -1: + raise RuntimeError("Not a pointer type: %s" % (ty,)) + return size + + +RELOC = frozenset(['default', 'static', 'pic', 'dynamicnopic']) +CODEMODEL = frozenset(['default', 'jitdefault', 'small', 'kernel', 'medium', + 'large']) + + +class Target(ffi.ObjectRef): + _triple = '' + + # No _dispose() method since LLVMGetTargetFromTriple() returns a + # persistent object. + + @classmethod + def from_default_triple(cls): + """ + Create a Target instance for the default triple. + """ + triple = get_default_triple() + return cls.from_triple(triple) + + @classmethod + def from_triple(cls, triple): + """ + Create a Target instance for the given triple (a string). + """ + with ffi.OutputString() as outerr: + target = ffi.lib.LLVMPY_GetTargetFromTriple(triple.encode('utf8'), + outerr) + if not target: + raise RuntimeError(str(outerr)) + target = cls(target) + target._triple = triple + return target + + @property + def name(self): + s = ffi.lib.LLVMPY_GetTargetName(self) + return _decode_string(s) + + @property + def description(self): + s = ffi.lib.LLVMPY_GetTargetDescription(self) + return _decode_string(s) + + @property + def triple(self): + return self._triple + + def __str__(self): + return "".format(self.name, self.description) + + def create_target_machine(self, cpu='', features='', + opt=2, reloc='default', codemodel='jitdefault', + printmc=False, jit=False, abiname=''): + """ + Create a new TargetMachine for this target and the given options. + + Specifying codemodel='default' will result in the use of the "small" + code model. Specifying codemodel='jitdefault' will result in the code + model being picked based on platform bitness (32="small", 64="large"). + + The `printmc` option corresponds to llvm's `-print-machineinstrs`. + + The `jit` option should be set when the target-machine is to be used + in a JIT engine. + + The `abiname` option specifies the ABI. RISC-V targets with hard-float + needs to pass the ABI name to LLVM. + """ + assert 0 <= opt <= 3 + assert reloc in RELOC + assert codemodel in CODEMODEL + triple = self._triple + # MCJIT under Windows only supports ELF objects, see + # http://lists.llvm.org/pipermail/llvm-dev/2013-December/068341.html + # Note we still want to produce regular COFF files in AOT mode. + if os.name == 'nt' and codemodel == 'jitdefault': + triple += '-elf' + tm = ffi.lib.LLVMPY_CreateTargetMachine(self, + _encode_string(triple), + _encode_string(cpu), + _encode_string(features), + opt, + _encode_string(reloc), + _encode_string(codemodel), + int(printmc), + int(jit), + _encode_string(abiname), + ) + if tm: + return TargetMachine(tm) + else: + raise RuntimeError("Cannot create target machine") + + +class TargetMachine(ffi.ObjectRef): + + def _dispose(self): + self._capi.LLVMPY_DisposeTargetMachine(self) + + def add_analysis_passes(self, pm): + """ + Register analysis passes for this target machine with a pass manager. + """ + ffi.lib.LLVMPY_AddAnalysisPasses(self, pm) + + def set_asm_verbosity(self, verbose): + """ + Set whether this target machine will emit assembly with human-readable + comments describing control flow, debug information, and so on. + """ + ffi.lib.LLVMPY_SetTargetMachineAsmVerbosity(self, verbose) + + def emit_object(self, module): + """ + Represent the module as a code object, suitable for use with + the platform's linker. Returns a byte string. + """ + return self._emit_to_memory(module, use_object=True) + + def emit_assembly(self, module): + """ + Return the raw assembler of the module, as a string. + + llvm.initialize_native_asmprinter() must have been called first. + """ + return _decode_string(self._emit_to_memory(module, use_object=False)) + + def _emit_to_memory(self, module, use_object=False): + """Returns bytes of object code of the module. + + Args + ---- + use_object : bool + Emit object code or (if False) emit assembly code. + """ + with ffi.OutputString() as outerr: + mb = ffi.lib.LLVMPY_TargetMachineEmitToMemory(self, module, + int(use_object), + outerr) + if not mb: + raise RuntimeError(str(outerr)) + + bufptr = ffi.lib.LLVMPY_GetBufferStart(mb) + bufsz = ffi.lib.LLVMPY_GetBufferSize(mb) + try: + return string_at(bufptr, bufsz) + finally: + ffi.lib.LLVMPY_DisposeMemoryBuffer(mb) + + @property + def target_data(self): + return TargetData(ffi.lib.LLVMPY_CreateTargetMachineData(self)) + + @property + def triple(self): + with ffi.OutputString() as out: + ffi.lib.LLVMPY_GetTargetMachineTriple(self, out) + return str(out) + + +def has_svml(): + """ + Returns True if SVML was enabled at FFI support compile time. + """ + if ffi.lib.LLVMPY_HasSVMLSupport() == 0: + return False + else: + return True + + +# ============================================================================ +# FFI + +ffi.lib.LLVMPY_GetProcessTriple.argtypes = [POINTER(c_char_p)] + +ffi.lib.LLVMPY_GetHostCPUFeatures.argtypes = [POINTER(c_char_p)] +ffi.lib.LLVMPY_GetHostCPUFeatures.restype = c_int + +ffi.lib.LLVMPY_GetDefaultTargetTriple.argtypes = [POINTER(c_char_p)] + +ffi.lib.LLVMPY_GetHostCPUName.argtypes = [POINTER(c_char_p)] + +ffi.lib.LLVMPY_GetTripleObjectFormat.argtypes = [c_char_p] +ffi.lib.LLVMPY_GetTripleObjectFormat.restype = c_int + +ffi.lib.LLVMPY_CreateTargetData.argtypes = [c_char_p] +ffi.lib.LLVMPY_CreateTargetData.restype = ffi.LLVMTargetDataRef + +ffi.lib.LLVMPY_CopyStringRepOfTargetData.argtypes = [ + ffi.LLVMTargetDataRef, + POINTER(c_char_p), +] + +ffi.lib.LLVMPY_DisposeTargetData.argtypes = [ + ffi.LLVMTargetDataRef, +] + +ffi.lib.LLVMPY_ABISizeOfType.argtypes = [ffi.LLVMTargetDataRef, + ffi.LLVMTypeRef] +ffi.lib.LLVMPY_ABISizeOfType.restype = c_longlong + +ffi.lib.LLVMPY_OffsetOfElement.argtypes = [ffi.LLVMTargetDataRef, + ffi.LLVMTypeRef, + c_int] +ffi.lib.LLVMPY_OffsetOfElement.restype = c_longlong + +ffi.lib.LLVMPY_ABISizeOfElementType.argtypes = [ffi.LLVMTargetDataRef, + ffi.LLVMTypeRef] +ffi.lib.LLVMPY_ABISizeOfElementType.restype = c_longlong + +ffi.lib.LLVMPY_ABIAlignmentOfElementType.argtypes = [ffi.LLVMTargetDataRef, + ffi.LLVMTypeRef] +ffi.lib.LLVMPY_ABIAlignmentOfElementType.restype = c_longlong + +ffi.lib.LLVMPY_GetTargetFromTriple.argtypes = [c_char_p, POINTER(c_char_p)] +ffi.lib.LLVMPY_GetTargetFromTriple.restype = ffi.LLVMTargetRef + +ffi.lib.LLVMPY_GetTargetName.argtypes = [ffi.LLVMTargetRef] +ffi.lib.LLVMPY_GetTargetName.restype = c_char_p + +ffi.lib.LLVMPY_GetTargetDescription.argtypes = [ffi.LLVMTargetRef] +ffi.lib.LLVMPY_GetTargetDescription.restype = c_char_p + +ffi.lib.LLVMPY_CreateTargetMachine.argtypes = [ + ffi.LLVMTargetRef, + # Triple + c_char_p, + # CPU + c_char_p, + # Features + c_char_p, + # OptLevel + c_int, + # Reloc + c_char_p, + # CodeModel + c_char_p, + # PrintMC + c_int, + # JIT + c_int, + # ABIName + c_char_p, +] +ffi.lib.LLVMPY_CreateTargetMachine.restype = ffi.LLVMTargetMachineRef + +ffi.lib.LLVMPY_DisposeTargetMachine.argtypes = [ffi.LLVMTargetMachineRef] + +ffi.lib.LLVMPY_GetTargetMachineTriple.argtypes = [ffi.LLVMTargetMachineRef, + POINTER(c_char_p)] + +ffi.lib.LLVMPY_SetTargetMachineAsmVerbosity.argtypes = [ + ffi.LLVMTargetMachineRef, c_int] + +ffi.lib.LLVMPY_AddAnalysisPasses.argtypes = [ + ffi.LLVMTargetMachineRef, + ffi.LLVMPassManagerRef, +] + +ffi.lib.LLVMPY_TargetMachineEmitToMemory.argtypes = [ + ffi.LLVMTargetMachineRef, + ffi.LLVMModuleRef, + c_int, + POINTER(c_char_p), +] +ffi.lib.LLVMPY_TargetMachineEmitToMemory.restype = ffi.LLVMMemoryBufferRef + +ffi.lib.LLVMPY_GetBufferStart.argtypes = [ffi.LLVMMemoryBufferRef] +ffi.lib.LLVMPY_GetBufferStart.restype = c_void_p + +ffi.lib.LLVMPY_GetBufferSize.argtypes = [ffi.LLVMMemoryBufferRef] +ffi.lib.LLVMPY_GetBufferSize.restype = c_size_t + +ffi.lib.LLVMPY_DisposeMemoryBuffer.argtypes = [ffi.LLVMMemoryBufferRef] + +ffi.lib.LLVMPY_CreateTargetMachineData.argtypes = [ + ffi.LLVMTargetMachineRef, +] +ffi.lib.LLVMPY_CreateTargetMachineData.restype = ffi.LLVMTargetDataRef + +ffi.lib.LLVMPY_HasSVMLSupport.argtypes = [] +ffi.lib.LLVMPY_HasSVMLSupport.restype = c_int diff --git a/lib/python3.11/site-packages/llvmlite/binding/transforms.py b/lib/python3.11/site-packages/llvmlite/binding/transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..82c5dc157a54d7cb1730dadb9b453cc684640cbf --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/transforms.py @@ -0,0 +1,151 @@ +from ctypes import c_uint, c_bool +from llvmlite.binding import ffi +from llvmlite.binding import passmanagers + + +def create_pass_manager_builder(): + return PassManagerBuilder() + + +class PassManagerBuilder(ffi.ObjectRef): + __slots__ = () + + def __init__(self, ptr=None): + if ptr is None: + ptr = ffi.lib.LLVMPY_PassManagerBuilderCreate() + ffi.ObjectRef.__init__(self, ptr) + + @property + def opt_level(self): + """ + The general optimization level as an integer between 0 and 3. + """ + return ffi.lib.LLVMPY_PassManagerBuilderGetOptLevel(self) + + @opt_level.setter + def opt_level(self, level): + ffi.lib.LLVMPY_PassManagerBuilderSetOptLevel(self, level) + + @property + def size_level(self): + """ + Whether and how much to optimize for size. An integer between 0 and 2. + """ + return ffi.lib.LLVMPY_PassManagerBuilderGetSizeLevel(self) + + @size_level.setter + def size_level(self, size): + ffi.lib.LLVMPY_PassManagerBuilderSetSizeLevel(self, size) + + @property + def inlining_threshold(self): + """ + The integer threshold for inlining a function into another. The higher, + the more likely inlining a function is. This attribute is write-only. + """ + raise NotImplementedError("inlining_threshold is write-only") + + @inlining_threshold.setter + def inlining_threshold(self, threshold): + ffi.lib.LLVMPY_PassManagerBuilderUseInlinerWithThreshold( + self, threshold) + + @property + def disable_unroll_loops(self): + """ + If true, disable loop unrolling. + """ + return ffi.lib.LLVMPY_PassManagerBuilderGetDisableUnrollLoops(self) + + @disable_unroll_loops.setter + def disable_unroll_loops(self, disable=True): + ffi.lib.LLVMPY_PassManagerBuilderSetDisableUnrollLoops(self, disable) + + @property + def loop_vectorize(self): + """ + If true, allow vectorizing loops. + """ + return ffi.lib.LLVMPY_PassManagerBuilderGetLoopVectorize(self) + + @loop_vectorize.setter + def loop_vectorize(self, enable=True): + return ffi.lib.LLVMPY_PassManagerBuilderSetLoopVectorize(self, enable) + + @property + def slp_vectorize(self): + """ + If true, enable the "SLP vectorizer", which uses a different algorithm + from the loop vectorizer. Both may be enabled at the same time. + """ + return ffi.lib.LLVMPY_PassManagerBuilderGetSLPVectorize(self) + + @slp_vectorize.setter + def slp_vectorize(self, enable=True): + return ffi.lib.LLVMPY_PassManagerBuilderSetSLPVectorize(self, enable) + + def _populate_module_pm(self, pm): + ffi.lib.LLVMPY_PassManagerBuilderPopulateModulePassManager(self, pm) + + def _populate_function_pm(self, pm): + ffi.lib.LLVMPY_PassManagerBuilderPopulateFunctionPassManager(self, pm) + + def populate(self, pm): + if isinstance(pm, passmanagers.ModulePassManager): + self._populate_module_pm(pm) + elif isinstance(pm, passmanagers.FunctionPassManager): + self._populate_function_pm(pm) + else: + raise TypeError(pm) + + def _dispose(self): + self._capi.LLVMPY_PassManagerBuilderDispose(self) + + +# ============================================================================ +# FFI + +ffi.lib.LLVMPY_PassManagerBuilderCreate.restype = ffi.LLVMPassManagerBuilderRef + +ffi.lib.LLVMPY_PassManagerBuilderDispose.argtypes = [ + ffi.LLVMPassManagerBuilderRef, +] + +ffi.lib.LLVMPY_PassManagerBuilderPopulateModulePassManager.argtypes = [ + ffi.LLVMPassManagerBuilderRef, + ffi.LLVMPassManagerRef, +] + +ffi.lib.LLVMPY_PassManagerBuilderPopulateFunctionPassManager.argtypes = [ + ffi.LLVMPassManagerBuilderRef, + ffi.LLVMPassManagerRef, +] + +# Unsigned int PassManagerBuilder properties + +for _func in (ffi.lib.LLVMPY_PassManagerBuilderSetOptLevel, + ffi.lib.LLVMPY_PassManagerBuilderSetSizeLevel, + ffi.lib.LLVMPY_PassManagerBuilderUseInlinerWithThreshold, + ): + _func.argtypes = [ffi.LLVMPassManagerBuilderRef, c_uint] + +for _func in (ffi.lib.LLVMPY_PassManagerBuilderGetOptLevel, + ffi.lib.LLVMPY_PassManagerBuilderGetSizeLevel, + ): + _func.argtypes = [ffi.LLVMPassManagerBuilderRef] + _func.restype = c_uint + +# Boolean PassManagerBuilder properties + +for _func in (ffi.lib.LLVMPY_PassManagerBuilderSetDisableUnrollLoops, + ffi.lib.LLVMPY_PassManagerBuilderSetLoopVectorize, + ffi.lib.LLVMPY_PassManagerBuilderSetSLPVectorize, + ): + _func.argtypes = [ffi.LLVMPassManagerBuilderRef, c_bool] + +for _func in (ffi.lib.LLVMPY_PassManagerBuilderGetDisableUnrollLoops, + ffi.lib.LLVMPY_PassManagerBuilderGetLoopVectorize, + ffi.lib.LLVMPY_PassManagerBuilderGetSLPVectorize, + ): + _func.argtypes = [ffi.LLVMPassManagerBuilderRef] + _func.restype = c_bool diff --git a/lib/python3.11/site-packages/llvmlite/binding/value.py b/lib/python3.11/site-packages/llvmlite/binding/value.py new file mode 100644 index 0000000000000000000000000000000000000000..9411c7b238e23fd7394f807e5915c5745a7e4c9a --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/binding/value.py @@ -0,0 +1,624 @@ +from ctypes import (POINTER, byref, cast, c_char_p, c_double, c_int, c_size_t, + c_uint, c_uint64, c_bool, c_void_p) +import enum + +from llvmlite.binding import ffi +from llvmlite.binding.common import _decode_string, _encode_string + + +class Linkage(enum.IntEnum): + # The LLVMLinkage enum from llvm-c/Core.h + + external = 0 + available_externally = 1 + linkonce_any = 2 + linkonce_odr = 3 + linkonce_odr_autohide = 4 + weak_any = 5 + weak_odr = 6 + appending = 7 + internal = 8 + private = 9 + dllimport = 10 + dllexport = 11 + external_weak = 12 + ghost = 13 + common = 14 + linker_private = 15 + linker_private_weak = 16 + + +class Visibility(enum.IntEnum): + # The LLVMVisibility enum from llvm-c/Core.h + + default = 0 + hidden = 1 + protected = 2 + + +class StorageClass(enum.IntEnum): + # The LLVMDLLStorageClass enum from llvm-c/Core.h + + default = 0 + dllimport = 1 + dllexport = 2 + + +class ValueKind(enum.IntEnum): + # The LLVMValueKind enum from llvm-c/Core.h + + argument = 0 + basic_block = 1 + memory_use = 2 + memory_def = 3 + memory_phi = 4 + + function = 5 + global_alias = 6 + global_ifunc = 7 + global_variable = 8 + block_address = 9 + constant_expr = 10 + constant_array = 11 + constant_struct = 12 + constant_vector = 13 + + undef_value = 14 + constant_aggregate_zero = 15 + constant_data_array = 16 + constant_data_vector = 17 + constant_int = 18 + constant_fp = 19 + constant_pointer_null = 20 + constant_token_none = 21 + + metadata_as_value = 22 + inline_asm = 23 + + instruction = 24 + poison_value = 25 + + +class TypeRef(ffi.ObjectRef): + """A weak reference to a LLVM type + """ + @property + def name(self): + """ + Get type name + """ + return ffi.ret_string(ffi.lib.LLVMPY_GetTypeName(self)) + + @property + def is_pointer(self): + """ + Returns true is the type is a pointer type. + """ + return ffi.lib.LLVMPY_TypeIsPointer(self) + + @property + def element_type(self): + """ + Returns the pointed-to type. When the type is not a pointer, + raises exception. + """ + if not self.is_pointer: + raise ValueError("Type {} is not a pointer".format(self)) + return TypeRef(ffi.lib.LLVMPY_GetElementType(self)) + + def __str__(self): + return ffi.ret_string(ffi.lib.LLVMPY_PrintType(self)) + + +class ValueRef(ffi.ObjectRef): + """A weak reference to a LLVM value. + """ + + def __init__(self, ptr, kind, parents): + self._kind = kind + self._parents = parents + ffi.ObjectRef.__init__(self, ptr) + + def __str__(self): + with ffi.OutputString() as outstr: + ffi.lib.LLVMPY_PrintValueToString(self, outstr) + return str(outstr) + + @property + def module(self): + """ + The module this function or global variable value was obtained from. + """ + return self._parents.get('module') + + @property + def function(self): + """ + The function this argument or basic block value was obtained from. + """ + return self._parents.get('function') + + @property + def block(self): + """ + The block this instruction value was obtained from. + """ + return self._parents.get('block') + + @property + def instruction(self): + """ + The instruction this operand value was obtained from. + """ + return self._parents.get('instruction') + + @property + def is_global(self): + return self._kind == 'global' + + @property + def is_function(self): + return self._kind == 'function' + + @property + def is_block(self): + return self._kind == 'block' + + @property + def is_argument(self): + return self._kind == 'argument' + + @property + def is_instruction(self): + return self._kind == 'instruction' + + @property + def is_operand(self): + return self._kind == 'operand' + + @property + def is_constant(self): + return bool(ffi.lib.LLVMPY_IsConstant(self)) + + @property + def value_kind(self): + return ValueKind(ffi.lib.LLVMPY_GetValueKind(self)) + + @property + def name(self): + return _decode_string(ffi.lib.LLVMPY_GetValueName(self)) + + @name.setter + def name(self, val): + ffi.lib.LLVMPY_SetValueName(self, _encode_string(val)) + + @property + def linkage(self): + return Linkage(ffi.lib.LLVMPY_GetLinkage(self)) + + @linkage.setter + def linkage(self, value): + if not isinstance(value, Linkage): + value = Linkage[value] + ffi.lib.LLVMPY_SetLinkage(self, value) + + @property + def visibility(self): + return Visibility(ffi.lib.LLVMPY_GetVisibility(self)) + + @visibility.setter + def visibility(self, value): + if not isinstance(value, Visibility): + value = Visibility[value] + ffi.lib.LLVMPY_SetVisibility(self, value) + + @property + def storage_class(self): + return StorageClass(ffi.lib.LLVMPY_GetDLLStorageClass(self)) + + @storage_class.setter + def storage_class(self, value): + if not isinstance(value, StorageClass): + value = StorageClass[value] + ffi.lib.LLVMPY_SetDLLStorageClass(self, value) + + def add_function_attribute(self, attr): + """Only works on function value + + Parameters + ----------- + attr : str + attribute name + """ + if not self.is_function: + raise ValueError('expected function value, got %s' % (self._kind,)) + attrname = str(attr) + attrval = ffi.lib.LLVMPY_GetEnumAttributeKindForName( + _encode_string(attrname), len(attrname)) + if attrval == 0: + raise ValueError('no such attribute {!r}'.format(attrname)) + ffi.lib.LLVMPY_AddFunctionAttr(self, attrval) + + @property + def type(self): + """ + This value's LLVM type. + """ + # XXX what does this return? + return TypeRef(ffi.lib.LLVMPY_TypeOf(self)) + + @property + def is_declaration(self): + """ + Whether this value (presumably global) is defined in the current + module. + """ + if not (self.is_global or self.is_function): + raise ValueError('expected global or function value, got %s' + % (self._kind,)) + return ffi.lib.LLVMPY_IsDeclaration(self) + + @property + def attributes(self): + """ + Return an iterator over this value's attributes. + The iterator will yield a string for each attribute. + """ + itr = iter(()) + if self.is_function: + it = ffi.lib.LLVMPY_FunctionAttributesIter(self) + itr = _AttributeListIterator(it) + elif self.is_instruction: + if self.opcode == 'call': + it = ffi.lib.LLVMPY_CallInstAttributesIter(self) + itr = _AttributeListIterator(it) + elif self.opcode == 'invoke': + it = ffi.lib.LLVMPY_InvokeInstAttributesIter(self) + itr = _AttributeListIterator(it) + elif self.is_global: + it = ffi.lib.LLVMPY_GlobalAttributesIter(self) + itr = _AttributeSetIterator(it) + elif self.is_argument: + it = ffi.lib.LLVMPY_ArgumentAttributesIter(self) + itr = _AttributeSetIterator(it) + return itr + + @property + def blocks(self): + """ + Return an iterator over this function's blocks. + The iterator will yield a ValueRef for each block. + """ + if not self.is_function: + raise ValueError('expected function value, got %s' % (self._kind,)) + it = ffi.lib.LLVMPY_FunctionBlocksIter(self) + parents = self._parents.copy() + parents.update(function=self) + return _BlocksIterator(it, parents) + + @property + def arguments(self): + """ + Return an iterator over this function's arguments. + The iterator will yield a ValueRef for each argument. + """ + if not self.is_function: + raise ValueError('expected function value, got %s' % (self._kind,)) + it = ffi.lib.LLVMPY_FunctionArgumentsIter(self) + parents = self._parents.copy() + parents.update(function=self) + return _ArgumentsIterator(it, parents) + + @property + def instructions(self): + """ + Return an iterator over this block's instructions. + The iterator will yield a ValueRef for each instruction. + """ + if not self.is_block: + raise ValueError('expected block value, got %s' % (self._kind,)) + it = ffi.lib.LLVMPY_BlockInstructionsIter(self) + parents = self._parents.copy() + parents.update(block=self) + return _InstructionsIterator(it, parents) + + @property + def operands(self): + """ + Return an iterator over this instruction's operands. + The iterator will yield a ValueRef for each operand. + """ + if not self.is_instruction: + raise ValueError('expected instruction value, got %s' + % (self._kind,)) + it = ffi.lib.LLVMPY_InstructionOperandsIter(self) + parents = self._parents.copy() + parents.update(instruction=self) + return _OperandsIterator(it, parents) + + @property + def opcode(self): + if not self.is_instruction: + raise ValueError('expected instruction value, got %s' + % (self._kind,)) + return ffi.ret_string(ffi.lib.LLVMPY_GetOpcodeName(self)) + + def get_constant_value(self, signed_int=False, round_fp=False): + """ + Return the constant value, either as a literal (when supported) + or as a string. + + Parameters + ----------- + signed_int : bool + if True and the constant is an integer, returns a signed version + round_fp : bool + if True and the constant is a floating point value, rounds the + result upon accuracy loss (e.g., when querying an fp128 value). + By default, raises an exception on accuracy loss + """ + if not self.is_constant: + raise ValueError('expected constant value, got %s' + % (self._kind,)) + + if self.value_kind == ValueKind.constant_int: + # Python integers are also arbitrary-precision + little_endian = c_bool(False) + words = ffi.lib.LLVMPY_GetConstantIntNumWords(self) + ptr = ffi.lib.LLVMPY_GetConstantIntRawValue( + self, byref(little_endian)) + asbytes = bytes(cast(ptr, POINTER(c_uint64 * words)).contents) + return int.from_bytes( + asbytes, + ('little' if little_endian.value else 'big'), + signed=signed_int, + ) + elif self.value_kind == ValueKind.constant_fp: + # Convert floating-point values to double-precision (Python float) + accuracy_loss = c_bool(False) + value = ffi.lib.LLVMPY_GetConstantFPValue(self, + byref(accuracy_loss)) + if accuracy_loss.value and not round_fp: + raise ValueError( + 'Accuracy loss encountered in conversion of constant ' + f'value {str(self)}') + + return value + + # Otherwise, return the IR string + return str(self) + + +class _ValueIterator(ffi.ObjectRef): + + kind = None # derived classes must specify the Value kind value + # as class attribute + + def __init__(self, ptr, parents): + ffi.ObjectRef.__init__(self, ptr) + # Keep parent objects (module, function, etc) alive + self._parents = parents + if self.kind is None: + raise NotImplementedError('%s must specify kind attribute' + % (type(self).__name__,)) + + def __next__(self): + vp = self._next() + if vp: + return ValueRef(vp, self.kind, self._parents) + else: + raise StopIteration + + next = __next__ + + def __iter__(self): + return self + + +class _AttributeIterator(ffi.ObjectRef): + + def __next__(self): + vp = self._next() + if vp: + return vp + else: + raise StopIteration + + next = __next__ + + def __iter__(self): + return self + + +class _AttributeListIterator(_AttributeIterator): + + def _dispose(self): + self._capi.LLVMPY_DisposeAttributeListIter(self) + + def _next(self): + return ffi.ret_bytes(ffi.lib.LLVMPY_AttributeListIterNext(self)) + + +class _AttributeSetIterator(_AttributeIterator): + + def _dispose(self): + self._capi.LLVMPY_DisposeAttributeSetIter(self) + + def _next(self): + return ffi.ret_bytes(ffi.lib.LLVMPY_AttributeSetIterNext(self)) + + +class _BlocksIterator(_ValueIterator): + + kind = 'block' + + def _dispose(self): + self._capi.LLVMPY_DisposeBlocksIter(self) + + def _next(self): + return ffi.lib.LLVMPY_BlocksIterNext(self) + + +class _ArgumentsIterator(_ValueIterator): + + kind = 'argument' + + def _dispose(self): + self._capi.LLVMPY_DisposeArgumentsIter(self) + + def _next(self): + return ffi.lib.LLVMPY_ArgumentsIterNext(self) + + +class _InstructionsIterator(_ValueIterator): + + kind = 'instruction' + + def _dispose(self): + self._capi.LLVMPY_DisposeInstructionsIter(self) + + def _next(self): + return ffi.lib.LLVMPY_InstructionsIterNext(self) + + +class _OperandsIterator(_ValueIterator): + + kind = 'operand' + + def _dispose(self): + self._capi.LLVMPY_DisposeOperandsIter(self) + + def _next(self): + return ffi.lib.LLVMPY_OperandsIterNext(self) + + +# FFI + +ffi.lib.LLVMPY_PrintValueToString.argtypes = [ + ffi.LLVMValueRef, + POINTER(c_char_p) +] + +ffi.lib.LLVMPY_GetGlobalParent.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GetGlobalParent.restype = ffi.LLVMModuleRef + +ffi.lib.LLVMPY_GetValueName.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GetValueName.restype = c_char_p + +ffi.lib.LLVMPY_SetValueName.argtypes = [ffi.LLVMValueRef, c_char_p] + +ffi.lib.LLVMPY_TypeOf.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_TypeOf.restype = ffi.LLVMTypeRef + + +ffi.lib.LLVMPY_PrintType.argtypes = [ffi.LLVMTypeRef] +ffi.lib.LLVMPY_PrintType.restype = c_void_p + +ffi.lib.LLVMPY_TypeIsPointer.argtypes = [ffi.LLVMTypeRef] +ffi.lib.LLVMPY_TypeIsPointer.restype = c_bool + +ffi.lib.LLVMPY_GetElementType.argtypes = [ffi.LLVMTypeRef] +ffi.lib.LLVMPY_GetElementType.restype = ffi.LLVMTypeRef + + +ffi.lib.LLVMPY_GetTypeName.argtypes = [ffi.LLVMTypeRef] +ffi.lib.LLVMPY_GetTypeName.restype = c_void_p + +ffi.lib.LLVMPY_GetLinkage.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GetLinkage.restype = c_int + +ffi.lib.LLVMPY_SetLinkage.argtypes = [ffi.LLVMValueRef, c_int] + +ffi.lib.LLVMPY_GetVisibility.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GetVisibility.restype = c_int + +ffi.lib.LLVMPY_SetVisibility.argtypes = [ffi.LLVMValueRef, c_int] + +ffi.lib.LLVMPY_GetDLLStorageClass.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GetDLLStorageClass.restype = c_int + +ffi.lib.LLVMPY_SetDLLStorageClass.argtypes = [ffi.LLVMValueRef, c_int] + +ffi.lib.LLVMPY_GetEnumAttributeKindForName.argtypes = [c_char_p, c_size_t] +ffi.lib.LLVMPY_GetEnumAttributeKindForName.restype = c_uint + +ffi.lib.LLVMPY_AddFunctionAttr.argtypes = [ffi.LLVMValueRef, c_uint] + +ffi.lib.LLVMPY_IsDeclaration.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_IsDeclaration.restype = c_int + +ffi.lib.LLVMPY_FunctionAttributesIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_FunctionAttributesIter.restype = ffi.LLVMAttributeListIterator + +ffi.lib.LLVMPY_CallInstAttributesIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_CallInstAttributesIter.restype = ffi.LLVMAttributeListIterator + +ffi.lib.LLVMPY_InvokeInstAttributesIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_InvokeInstAttributesIter.restype = ffi.LLVMAttributeListIterator + +ffi.lib.LLVMPY_GlobalAttributesIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GlobalAttributesIter.restype = ffi.LLVMAttributeSetIterator + +ffi.lib.LLVMPY_ArgumentAttributesIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_ArgumentAttributesIter.restype = ffi.LLVMAttributeSetIterator + +ffi.lib.LLVMPY_FunctionBlocksIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_FunctionBlocksIter.restype = ffi.LLVMBlocksIterator + +ffi.lib.LLVMPY_FunctionArgumentsIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_FunctionArgumentsIter.restype = ffi.LLVMArgumentsIterator + +ffi.lib.LLVMPY_BlockInstructionsIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_BlockInstructionsIter.restype = ffi.LLVMInstructionsIterator + +ffi.lib.LLVMPY_InstructionOperandsIter.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_InstructionOperandsIter.restype = ffi.LLVMOperandsIterator + +ffi.lib.LLVMPY_DisposeAttributeListIter.argtypes = [ + ffi.LLVMAttributeListIterator] + +ffi.lib.LLVMPY_DisposeAttributeSetIter.argtypes = [ffi.LLVMAttributeSetIterator] + +ffi.lib.LLVMPY_DisposeBlocksIter.argtypes = [ffi.LLVMBlocksIterator] + +ffi.lib.LLVMPY_DisposeInstructionsIter.argtypes = [ffi.LLVMInstructionsIterator] + +ffi.lib.LLVMPY_DisposeOperandsIter.argtypes = [ffi.LLVMOperandsIterator] + +ffi.lib.LLVMPY_AttributeListIterNext.argtypes = [ffi.LLVMAttributeListIterator] +ffi.lib.LLVMPY_AttributeListIterNext.restype = c_void_p + +ffi.lib.LLVMPY_AttributeSetIterNext.argtypes = [ffi.LLVMAttributeSetIterator] +ffi.lib.LLVMPY_AttributeSetIterNext.restype = c_void_p + +ffi.lib.LLVMPY_BlocksIterNext.argtypes = [ffi.LLVMBlocksIterator] +ffi.lib.LLVMPY_BlocksIterNext.restype = ffi.LLVMValueRef + +ffi.lib.LLVMPY_ArgumentsIterNext.argtypes = [ffi.LLVMArgumentsIterator] +ffi.lib.LLVMPY_ArgumentsIterNext.restype = ffi.LLVMValueRef + +ffi.lib.LLVMPY_InstructionsIterNext.argtypes = [ffi.LLVMInstructionsIterator] +ffi.lib.LLVMPY_InstructionsIterNext.restype = ffi.LLVMValueRef + +ffi.lib.LLVMPY_OperandsIterNext.argtypes = [ffi.LLVMOperandsIterator] +ffi.lib.LLVMPY_OperandsIterNext.restype = ffi.LLVMValueRef + +ffi.lib.LLVMPY_GetOpcodeName.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GetOpcodeName.restype = c_void_p + +ffi.lib.LLVMPY_IsConstant.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_IsConstant.restype = c_bool + +ffi.lib.LLVMPY_GetValueKind.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GetValueKind.restype = c_int + +ffi.lib.LLVMPY_GetConstantIntRawValue.argtypes = [ffi.LLVMValueRef, + POINTER(c_bool)] +ffi.lib.LLVMPY_GetConstantIntRawValue.restype = POINTER(c_uint64) + +ffi.lib.LLVMPY_GetConstantIntNumWords.argtypes = [ffi.LLVMValueRef] +ffi.lib.LLVMPY_GetConstantIntNumWords.restype = c_uint + +ffi.lib.LLVMPY_GetConstantFPValue.argtypes = [ffi.LLVMValueRef, + POINTER(c_bool)] +ffi.lib.LLVMPY_GetConstantFPValue.restype = c_double diff --git a/lib/python3.11/site-packages/llvmlite/ir/__init__.py b/lib/python3.11/site-packages/llvmlite/ir/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b7a0737b2d5325d5c40a8953520a260c013ed48f --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/__init__.py @@ -0,0 +1,11 @@ +""" +This subpackage implements the LLVM IR classes in pure python +""" + +from .types import * +from .values import * +from .module import * +from .builder import * +from .instructions import * +from .transforms import * +from .context import Context, global_context diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1b612ea043ab6c1baa10df1e43b0817f6e3951cc Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/__init__.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/_utils.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/_utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af602161849e5462d8abd33f289b0d38f7f3dee5 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/_utils.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/builder.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/builder.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6800014fe3cc534cac5ad6aa9fb53aeebdad5794 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/builder.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/context.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/context.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f790e4cb4edc3d3f27036ab4d5a81bd3e5aa34ba Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/context.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/instructions.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/instructions.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..896e6b564014605f80e7fc86918babbf0b48e55a Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/instructions.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/module.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/module.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..413094cd43efc429d4f08fd98664002f119074c1 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/module.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/transforms.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/transforms.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69bc9699d89db2f066029962b7c2e5e0fb68208e Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/transforms.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/types.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/types.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f014da152872d585a88868f2031f8845f99d60aa Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/types.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/__pycache__/values.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/values.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e606ed2fe893d907345ddedd511a7ec694bf314e Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/ir/__pycache__/values.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/ir/_utils.py b/lib/python3.11/site-packages/llvmlite/ir/_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..8287d77afb84f750be00ef0b001a175507c59da4 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/_utils.py @@ -0,0 +1,80 @@ +from collections import defaultdict + + +class DuplicatedNameError(NameError): + pass + + +class NameScope(object): + def __init__(self): + self._useset = set(['']) + self._basenamemap = defaultdict(int) + + def is_used(self, name): + return name in self._useset + + def register(self, name, deduplicate=False): + if deduplicate: + name = self.deduplicate(name) + elif self.is_used(name): + raise DuplicatedNameError(name) + self._useset.add(name) + return name + + def deduplicate(self, name): + basename = name + while self.is_used(name): + ident = self._basenamemap[basename] + 1 + self._basenamemap[basename] = ident + name = "{0}.{1}".format(basename, ident) + return name + + def get_child(self): + return type(self)(parent=self) + + +class _StrCaching(object): + + def _clear_string_cache(self): + try: + del self.__cached_str + except AttributeError: + pass + + def __str__(self): + try: + return self.__cached_str + except AttributeError: + s = self.__cached_str = self._to_string() + return s + + +class _StringReferenceCaching(object): + + def get_reference(self): + try: + return self.__cached_refstr + except AttributeError: + s = self.__cached_refstr = self._get_reference() + return s + + +class _HasMetadata(object): + + def set_metadata(self, name, node): + """ + Attach unnamed metadata *node* to the metadata slot *name* of this + value. + """ + self.metadata[name] = node + + def _stringify_metadata(self, leading_comma=False): + if self.metadata: + buf = [] + if leading_comma: + buf.append("") + buf += ["!{0} {1}".format(k, v.get_reference()) + for k, v in self.metadata.items()] + return ', '.join(buf) + else: + return '' diff --git a/lib/python3.11/site-packages/llvmlite/ir/builder.py b/lib/python3.11/site-packages/llvmlite/ir/builder.py new file mode 100644 index 0000000000000000000000000000000000000000..f62476ca8a4c470d7256bf9d20cf90b2bfe4682b --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/builder.py @@ -0,0 +1,1119 @@ +import contextlib +import functools + +from llvmlite.ir import instructions, types, values + +_CMP_MAP = { + '>': 'gt', + '<': 'lt', + '==': 'eq', + '!=': 'ne', + '>=': 'ge', + '<=': 'le', +} + + +def _unop(opname, cls=instructions.Instruction): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, arg, name='', flags=()): + instr = cls(self.block, arg.type, opname, [arg], name, flags) + self._insert(instr) + return instr + + return wrapped + + return wrap + + +def _binop(opname, cls=instructions.Instruction): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, lhs, rhs, name='', flags=()): + if lhs.type != rhs.type: + raise ValueError("Operands must be the same type, got (%s, %s)" + % (lhs.type, rhs.type)) + instr = cls(self.block, lhs.type, opname, (lhs, rhs), name, flags) + self._insert(instr) + return instr + + return wrapped + + return wrap + + +def _binop_with_overflow(opname, cls=instructions.Instruction): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, lhs, rhs, name=''): + if lhs.type != rhs.type: + raise ValueError("Operands must be the same type, got (%s, %s)" + % (lhs.type, rhs.type)) + ty = lhs.type + if not isinstance(ty, types.IntType): + raise TypeError("expected an integer type, got %s" % (ty,)) + bool_ty = types.IntType(1) + + mod = self.module + fnty = types.FunctionType(types.LiteralStructType([ty, bool_ty]), + [ty, ty]) + fn = mod.declare_intrinsic("llvm.%s.with.overflow" % (opname,), + [ty], fnty) + ret = self.call(fn, [lhs, rhs], name=name) + return ret + + return wrapped + + return wrap + + +def _uniop(opname, cls=instructions.Instruction): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, operand, name=''): + instr = cls(self.block, operand.type, opname, [operand], name) + self._insert(instr) + return instr + + return wrapped + + return wrap + + +def _uniop_intrinsic_int(opname): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, operand, name=''): + if not isinstance(operand.type, types.IntType): + raise TypeError( + "expected an integer type, got %s" % + operand.type) + fn = self.module.declare_intrinsic(opname, [operand.type]) + return self.call(fn, [operand], name) + + return wrapped + + return wrap + + +def _uniop_intrinsic_float(opname): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, operand, name=''): + if not isinstance( + operand.type, (types.FloatType, types.DoubleType)): + raise TypeError("expected a float type, got %s" % operand.type) + fn = self.module.declare_intrinsic(opname, [operand.type]) + return self.call(fn, [operand], name) + + return wrapped + + return wrap + + +def _uniop_intrinsic_with_flag(opname): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, operand, flag, name=''): + if not isinstance(operand.type, types.IntType): + raise TypeError( + "expected an integer type, got %s" % + operand.type) + if not (isinstance(flag.type, types.IntType) and + flag.type.width == 1): + raise TypeError("expected an i1 type, got %s" % flag.type) + fn = self.module.declare_intrinsic( + opname, [operand.type, flag.type]) + return self.call(fn, [operand, flag], name) + + return wrapped + + return wrap + + +def _triop_intrinsic(opname): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, a, b, c, name=''): + if a.type != b.type or b.type != c.type: + raise TypeError( + "expected types to be the same, got %s, %s, %s" % ( + a.type, + b.type, + c.type)) + elif not isinstance( + a.type, + (types.HalfType, types.FloatType, types.DoubleType)): + raise TypeError( + "expected an floating point type, got %s" % + a.type) + fn = self.module.declare_intrinsic(opname, [a.type, b.type, c.type]) + return self.call(fn, [a, b, c], name) + + return wrapped + + return wrap + + +def _castop(opname, cls=instructions.CastInstr): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, val, typ, name=''): + if val.type == typ: + return val + instr = cls(self.block, opname, val, typ, name) + self._insert(instr) + return instr + + return wrapped + + return wrap + + +def _label_suffix(label, suffix): + """Returns (label + suffix) or a truncated version if it's too long. + Parameters + ---------- + label : str + Label name + suffix : str + Label suffix + """ + if len(label) > 50: + nhead = 25 + return ''.join([label[:nhead], '..', suffix]) + else: + return label + suffix + + +class IRBuilder(object): + def __init__(self, block=None): + self._block = block + self._anchor = len(block.instructions) if block else 0 + self.debug_metadata = None + + @property + def block(self): + """ + The current basic block. + """ + return self._block + + basic_block = block + + @property + def function(self): + """ + The current function. + """ + return self.block.parent + + @property + def module(self): + """ + The current module. + """ + return self.block.parent.module + + def position_before(self, instr): + """ + Position immediately before the given instruction. The current block + is also changed to the instruction's basic block. + """ + self._block = instr.parent + self._anchor = self._block.instructions.index(instr) + + def position_after(self, instr): + """ + Position immediately after the given instruction. The current block + is also changed to the instruction's basic block. + """ + self._block = instr.parent + self._anchor = self._block.instructions.index(instr) + 1 + + def position_at_start(self, block): + """ + Position at the start of the basic *block*. + """ + self._block = block + self._anchor = 0 + + def position_at_end(self, block): + """ + Position at the end of the basic *block*. + """ + self._block = block + self._anchor = len(block.instructions) + + def append_basic_block(self, name=''): + """ + Append a basic block, with the given optional *name*, to the current + function. The current block is not changed. The new block is returned. + """ + return self.function.append_basic_block(name) + + def remove(self, instr): + """Remove the given instruction.""" + idx = self._block.instructions.index(instr) + del self._block.instructions[idx] + if self._block.terminator == instr: + self._block.terminator = None + if self._anchor > idx: + self._anchor -= 1 + + @contextlib.contextmanager + def goto_block(self, block): + """ + A context manager which temporarily positions the builder at the end + of basic block *bb* (but before any terminator). + """ + old_block = self.basic_block + term = block.terminator + if term is not None: + self.position_before(term) + else: + self.position_at_end(block) + try: + yield + finally: + self.position_at_end(old_block) + + @contextlib.contextmanager + def goto_entry_block(self): + """ + A context manager which temporarily positions the builder at the + end of the function's entry block. + """ + with self.goto_block(self.function.entry_basic_block): + yield + + @contextlib.contextmanager + def _branch_helper(self, bbenter, bbexit): + self.position_at_end(bbenter) + yield bbexit + if self.basic_block.terminator is None: + self.branch(bbexit) + + @contextlib.contextmanager + def if_then(self, pred, likely=None): + """ + A context manager which sets up a conditional basic block based + on the given predicate (a i1 value). If the conditional block + is not explicitly terminated, a branch will be added to the next + block. + If *likely* is given, its boolean value indicates whether the + predicate is likely to be true or not, and metadata is issued + for LLVM's optimizers to account for that. + """ + bb = self.basic_block + bbif = self.append_basic_block(name=_label_suffix(bb.name, '.if')) + bbend = self.append_basic_block(name=_label_suffix(bb.name, '.endif')) + br = self.cbranch(pred, bbif, bbend) + if likely is not None: + br.set_weights([99, 1] if likely else [1, 99]) + + with self._branch_helper(bbif, bbend): + yield bbend + + self.position_at_end(bbend) + + @contextlib.contextmanager + def if_else(self, pred, likely=None): + """ + A context manager which sets up two conditional basic blocks based + on the given predicate (a i1 value). + A tuple of context managers is yield'ed. Each context manager + acts as a if_then() block. + *likely* has the same meaning as in if_then(). + + Typical use:: + with builder.if_else(pred) as (then, otherwise): + with then: + # emit instructions for when the predicate is true + with otherwise: + # emit instructions for when the predicate is false + """ + bb = self.basic_block + bbif = self.append_basic_block(name=_label_suffix(bb.name, '.if')) + bbelse = self.append_basic_block(name=_label_suffix(bb.name, '.else')) + bbend = self.append_basic_block(name=_label_suffix(bb.name, '.endif')) + br = self.cbranch(pred, bbif, bbelse) + if likely is not None: + br.set_weights([99, 1] if likely else [1, 99]) + + then = self._branch_helper(bbif, bbend) + otherwise = self._branch_helper(bbelse, bbend) + + yield then, otherwise + + self.position_at_end(bbend) + + def _insert(self, instr): + if self.debug_metadata is not None and 'dbg' not in instr.metadata: + instr.metadata['dbg'] = self.debug_metadata + self._block.instructions.insert(self._anchor, instr) + self._anchor += 1 + + def _set_terminator(self, term): + assert not self.block.is_terminated + self._insert(term) + self.block.terminator = term + return term + + # + # Arithmetic APIs + # + + @_binop('shl') + def shl(self, lhs, rhs, name=''): + """ + Left integer shift: + name = lhs << rhs + """ + + @_binop('lshr') + def lshr(self, lhs, rhs, name=''): + """ + Logical (unsigned) right integer shift: + name = lhs >> rhs + """ + + @_binop('ashr') + def ashr(self, lhs, rhs, name=''): + """ + Arithmetic (signed) right integer shift: + name = lhs >> rhs + """ + + @_binop('add') + def add(self, lhs, rhs, name=''): + """ + Integer addition: + name = lhs + rhs + """ + + @_binop('fadd') + def fadd(self, lhs, rhs, name=''): + """ + Floating-point addition: + name = lhs + rhs + """ + + @_binop('sub') + def sub(self, lhs, rhs, name=''): + """ + Integer subtraction: + name = lhs - rhs + """ + + @_binop('fsub') + def fsub(self, lhs, rhs, name=''): + """ + Floating-point subtraction: + name = lhs - rhs + """ + + @_binop('mul') + def mul(self, lhs, rhs, name=''): + """ + Integer multiplication: + name = lhs * rhs + """ + + @_binop('fmul') + def fmul(self, lhs, rhs, name=''): + """ + Floating-point multiplication: + name = lhs * rhs + """ + + @_binop('udiv') + def udiv(self, lhs, rhs, name=''): + """ + Unsigned integer division: + name = lhs / rhs + """ + + @_binop('sdiv') + def sdiv(self, lhs, rhs, name=''): + """ + Signed integer division: + name = lhs / rhs + """ + + @_binop('fdiv') + def fdiv(self, lhs, rhs, name=''): + """ + Floating-point division: + name = lhs / rhs + """ + + @_binop('urem') + def urem(self, lhs, rhs, name=''): + """ + Unsigned integer remainder: + name = lhs % rhs + """ + + @_binop('srem') + def srem(self, lhs, rhs, name=''): + """ + Signed integer remainder: + name = lhs % rhs + """ + + @_binop('frem') + def frem(self, lhs, rhs, name=''): + """ + Floating-point remainder: + name = lhs % rhs + """ + + @_binop('or') + def or_(self, lhs, rhs, name=''): + """ + Bitwise integer OR: + name = lhs | rhs + """ + + @_binop('and') + def and_(self, lhs, rhs, name=''): + """ + Bitwise integer AND: + name = lhs & rhs + """ + + @_binop('xor') + def xor(self, lhs, rhs, name=''): + """ + Bitwise integer XOR: + name = lhs ^ rhs + """ + + @_binop_with_overflow('sadd') + def sadd_with_overflow(self, lhs, rhs, name=''): + """ + Signed integer addition with overflow: + name = {result, overflow bit} = lhs + rhs + """ + + @_binop_with_overflow('smul') + def smul_with_overflow(self, lhs, rhs, name=''): + """ + Signed integer multiplication with overflow: + name = {result, overflow bit} = lhs * rhs + """ + + @_binop_with_overflow('ssub') + def ssub_with_overflow(self, lhs, rhs, name=''): + """ + Signed integer subtraction with overflow: + name = {result, overflow bit} = lhs - rhs + """ + + @_binop_with_overflow('uadd') + def uadd_with_overflow(self, lhs, rhs, name=''): + """ + Unsigned integer addition with overflow: + name = {result, overflow bit} = lhs + rhs + """ + + @_binop_with_overflow('umul') + def umul_with_overflow(self, lhs, rhs, name=''): + """ + Unsigned integer multiplication with overflow: + name = {result, overflow bit} = lhs * rhs + """ + + @_binop_with_overflow('usub') + def usub_with_overflow(self, lhs, rhs, name=''): + """ + Unsigned integer subtraction with overflow: + name = {result, overflow bit} = lhs - rhs + """ + + # + # Unary APIs + # + + def not_(self, value, name=''): + """ + Bitwise integer complement: + name = ~value + """ + if isinstance(value.type, types.VectorType): + rhs = values.Constant(value.type, (-1,) * value.type.count) + else: + rhs = values.Constant(value.type, -1) + return self.xor(value, rhs, name=name) + + def neg(self, value, name=''): + """ + Integer negative: + name = -value + """ + return self.sub(values.Constant(value.type, 0), value, name=name) + + @_unop('fneg') + def fneg(self, arg, name='', flags=()): + """ + Floating-point negative: + name = -arg + """ + + # + # Comparison APIs + # + + def _icmp(self, prefix, cmpop, lhs, rhs, name): + try: + op = _CMP_MAP[cmpop] + except KeyError: + raise ValueError("invalid comparison %r for icmp" % (cmpop,)) + if cmpop not in ('==', '!='): + op = prefix + op + instr = instructions.ICMPInstr(self.block, op, lhs, rhs, name=name) + self._insert(instr) + return instr + + def icmp_signed(self, cmpop, lhs, rhs, name=''): + """ + Signed integer comparison: + name = lhs rhs + + where cmpop can be '==', '!=', '<', '<=', '>', '>=' + """ + return self._icmp('s', cmpop, lhs, rhs, name) + + def icmp_unsigned(self, cmpop, lhs, rhs, name=''): + """ + Unsigned integer (or pointer) comparison: + name = lhs rhs + + where cmpop can be '==', '!=', '<', '<=', '>', '>=' + """ + return self._icmp('u', cmpop, lhs, rhs, name) + + def fcmp_ordered(self, cmpop, lhs, rhs, name='', flags=()): + """ + Floating-point ordered comparison: + name = lhs rhs + + where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno' + """ + if cmpop in _CMP_MAP: + op = 'o' + _CMP_MAP[cmpop] + else: + op = cmpop + instr = instructions.FCMPInstr( + self.block, op, lhs, rhs, name=name, flags=flags) + self._insert(instr) + return instr + + def fcmp_unordered(self, cmpop, lhs, rhs, name='', flags=()): + """ + Floating-point unordered comparison: + name = lhs rhs + + where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno' + """ + if cmpop in _CMP_MAP: + op = 'u' + _CMP_MAP[cmpop] + else: + op = cmpop + instr = instructions.FCMPInstr( + self.block, op, lhs, rhs, name=name, flags=flags) + self._insert(instr) + return instr + + def select(self, cond, lhs, rhs, name='', flags=()): + """ + Ternary select operator: + name = cond ? lhs : rhs + """ + instr = instructions.SelectInstr(self.block, cond, lhs, rhs, name=name, + flags=flags) + self._insert(instr) + return instr + + # + # Cast APIs + # + + @_castop('trunc') + def trunc(self, value, typ, name=''): + """ + Truncating integer downcast to a smaller type: + name = (typ) value + """ + + @_castop('zext') + def zext(self, value, typ, name=''): + """ + Zero-extending integer upcast to a larger type: + name = (typ) value + """ + + @_castop('sext') + def sext(self, value, typ, name=''): + """ + Sign-extending integer upcast to a larger type: + name = (typ) value + """ + + @_castop('fptrunc') + def fptrunc(self, value, typ, name=''): + """ + Floating-point downcast to a less precise type: + name = (typ) value + """ + + @_castop('fpext') + def fpext(self, value, typ, name=''): + """ + Floating-point upcast to a more precise type: + name = (typ) value + """ + + @_castop('bitcast') + def bitcast(self, value, typ, name=''): + """ + Pointer cast to a different pointer type: + name = (typ) value + """ + + @_castop('addrspacecast') + def addrspacecast(self, value, typ, name=''): + """ + Pointer cast to a different address space: + name = (typ) value + """ + + @_castop('fptoui') + def fptoui(self, value, typ, name=''): + """ + Convert floating-point to unsigned integer: + name = (typ) value + """ + + @_castop('uitofp') + def uitofp(self, value, typ, name=''): + """ + Convert unsigned integer to floating-point: + name = (typ) value + """ + + @_castop('fptosi') + def fptosi(self, value, typ, name=''): + """ + Convert floating-point to signed integer: + name = (typ) value + """ + + @_castop('sitofp') + def sitofp(self, value, typ, name=''): + """ + Convert signed integer to floating-point: + name = (typ) value + """ + + @_castop('ptrtoint') + def ptrtoint(self, value, typ, name=''): + """ + Cast pointer to integer: + name = (typ) value + """ + + @_castop('inttoptr') + def inttoptr(self, value, typ, name=''): + """ + Cast integer to pointer: + name = (typ) value + """ + + # + # Memory APIs + # + + def alloca(self, typ, size=None, name=''): + """ + Stack-allocate a slot for *size* elements of the given type. + (default one element) + """ + if size is None: + pass + elif isinstance(size, (values.Value, values.Constant)): + assert isinstance(size.type, types.IntType) + else: + # If it is not a Value instance, + # assume to be a Python integer. + size = values.Constant(types.IntType(32), size) + + al = instructions.AllocaInstr(self.block, typ, size, name) + self._insert(al) + return al + + def load(self, ptr, name='', align=None): + """ + Load value from pointer, with optional guaranteed alignment: + name = *ptr + """ + if not isinstance(ptr.type, types.PointerType): + msg = "cannot load from value of type %s (%r): not a pointer" + raise TypeError(msg % (ptr.type, str(ptr))) + ld = instructions.LoadInstr(self.block, ptr, name) + ld.align = align + self._insert(ld) + return ld + + def store(self, value, ptr, align=None): + """ + Store value to pointer, with optional guaranteed alignment: + *ptr = name + """ + if not isinstance(ptr.type, types.PointerType): + msg = "cannot store to value of type %s (%r): not a pointer" + raise TypeError(msg % (ptr.type, str(ptr))) + if ptr.type.pointee != value.type: + raise TypeError("cannot store %s to %s: mismatching types" + % (value.type, ptr.type)) + st = instructions.StoreInstr(self.block, value, ptr) + st.align = align + self._insert(st) + return st + + def load_atomic(self, ptr, ordering, align, name=''): + """ + Load value from pointer, with optional guaranteed alignment: + name = *ptr + """ + if not isinstance(ptr.type, types.PointerType): + msg = "cannot load from value of type %s (%r): not a pointer" + raise TypeError(msg % (ptr.type, str(ptr))) + ld = instructions.LoadAtomicInstr( + self.block, ptr, ordering, align, name) + self._insert(ld) + return ld + + def store_atomic(self, value, ptr, ordering, align): + """ + Store value to pointer, with optional guaranteed alignment: + *ptr = name + """ + if not isinstance(ptr.type, types.PointerType): + msg = "cannot store to value of type %s (%r): not a pointer" + raise TypeError(msg % (ptr.type, str(ptr))) + if ptr.type.pointee != value.type: + raise TypeError("cannot store %s to %s: mismatching types" + % (value.type, ptr.type)) + st = instructions.StoreAtomicInstr( + self.block, value, ptr, ordering, align) + self._insert(st) + return st + + # + # Terminators APIs + # + + def switch(self, value, default): + """ + Create a switch-case with a single *default* target. + """ + swt = instructions.SwitchInstr(self.block, 'switch', value, default) + self._set_terminator(swt) + return swt + + def branch(self, target): + """ + Unconditional branch to *target*. + """ + br = instructions.Branch(self.block, "br", [target]) + self._set_terminator(br) + return br + + def cbranch(self, cond, truebr, falsebr): + """ + Conditional branch to *truebr* if *cond* is true, else to *falsebr*. + """ + br = instructions.ConditionalBranch(self.block, "br", + [cond, truebr, falsebr]) + self._set_terminator(br) + return br + + def branch_indirect(self, addr): + """ + Indirect branch to target *addr*. + """ + br = instructions.IndirectBranch(self.block, "indirectbr", addr) + self._set_terminator(br) + return br + + def ret_void(self): + """ + Return from function without a value. + """ + return self._set_terminator( + instructions.Ret(self.block, "ret void")) + + def ret(self, value): + """ + Return from function with the given *value*. + """ + return self._set_terminator( + instructions.Ret(self.block, "ret", value)) + + def resume(self, landingpad): + """ + Resume an in-flight exception. + """ + br = instructions.Branch(self.block, "resume", [landingpad]) + self._set_terminator(br) + return br + + # Call APIs + + def call(self, fn, args, name='', cconv=None, tail=False, fastmath=(), + attrs=(), arg_attrs=None): + """ + Call function *fn* with *args*: + name = fn(args...) + """ + inst = instructions.CallInstr(self.block, fn, args, name=name, + cconv=cconv, tail=tail, fastmath=fastmath, + attrs=attrs, arg_attrs=arg_attrs) + self._insert(inst) + return inst + + def asm(self, ftype, asm, constraint, args, side_effect, name=''): + """ + Inline assembler. + """ + asm = instructions.InlineAsm(ftype, asm, constraint, side_effect) + return self.call(asm, args, name) + + def load_reg(self, reg_type, reg_name, name=''): + """ + Load a register value into an LLVM value. + Example: v = load_reg(IntType(32), "eax") + """ + ftype = types.FunctionType(reg_type, []) + return self.asm(ftype, "", "={%s}" % reg_name, [], False, name) + + def store_reg(self, value, reg_type, reg_name, name=''): + """ + Store an LLVM value inside a register + Example: + store_reg(Constant(IntType(32), 0xAAAAAAAA), IntType(32), "eax") + """ + ftype = types.FunctionType(types.VoidType(), [reg_type]) + return self.asm(ftype, "", "{%s}" % reg_name, [value], True, name) + + def invoke(self, fn, args, normal_to, unwind_to, + name='', cconv=None, fastmath=(), attrs=(), arg_attrs=None): + inst = instructions.InvokeInstr(self.block, fn, args, normal_to, + unwind_to, name=name, cconv=cconv, + fastmath=fastmath, attrs=attrs, + arg_attrs=arg_attrs) + self._set_terminator(inst) + return inst + + # GEP APIs + + def gep(self, ptr, indices, inbounds=False, name=''): + """ + Compute effective address (getelementptr): + name = getelementptr ptr, + """ + instr = instructions.GEPInstr(self.block, ptr, indices, + inbounds=inbounds, name=name) + self._insert(instr) + return instr + + # Vector Operations APIs + + def extract_element(self, vector, idx, name=''): + """ + Returns the value at position idx. + """ + instr = instructions.ExtractElement(self.block, vector, idx, name=name) + self._insert(instr) + return instr + + def insert_element(self, vector, value, idx, name=''): + """ + Returns vector with vector[idx] replaced by value. + The result is undefined if the idx is larger or equal the vector length. + """ + instr = instructions.InsertElement(self.block, vector, value, idx, + name=name) + self._insert(instr) + return instr + + def shuffle_vector(self, vector1, vector2, mask, name=''): + """ + Constructs a permutation of elements from *vector1* and *vector2*. + Returns a new vector in the same length of *mask*. + + * *vector1* and *vector2* must have the same element type. + * *mask* must be a constant vector of integer types. + """ + instr = instructions.ShuffleVector(self.block, vector1, vector2, mask, + name=name) + self._insert(instr) + return instr + + # Aggregate APIs + + def extract_value(self, agg, idx, name=''): + """ + Extract member number *idx* from aggregate. + """ + if not isinstance(idx, (tuple, list)): + idx = [idx] + instr = instructions.ExtractValue(self.block, agg, idx, name=name) + self._insert(instr) + return instr + + def insert_value(self, agg, value, idx, name=''): + """ + Insert *value* into member number *idx* from aggregate. + """ + if not isinstance(idx, (tuple, list)): + idx = [idx] + instr = instructions.InsertValue(self.block, agg, value, idx, name=name) + self._insert(instr) + return instr + + # PHI APIs + + def phi(self, typ, name='', flags=()): + inst = instructions.PhiInstr(self.block, typ, name=name, flags=flags) + self._insert(inst) + return inst + + # Special API + + def unreachable(self): + inst = instructions.Unreachable(self.block) + self._set_terminator(inst) + return inst + + def atomic_rmw(self, op, ptr, val, ordering, name=''): + inst = instructions.AtomicRMW( + self.block, op, ptr, val, ordering, name=name) + self._insert(inst) + return inst + + def cmpxchg(self, ptr, cmp, val, ordering, failordering=None, name=''): + """ + Atomic compared-and-set: + atomic { + old = *ptr + success = (old == cmp) + if (success) + *ptr = val + } + name = { old, success } + + If failordering is `None`, the value of `ordering` is used. + """ + failordering = ordering if failordering is None else failordering + inst = instructions.CmpXchg(self.block, ptr, cmp, val, ordering, + failordering, name=name) + self._insert(inst) + return inst + + def landingpad(self, typ, name='', cleanup=False): + inst = instructions.LandingPadInstr(self.block, typ, name, cleanup) + self._insert(inst) + return inst + + def assume(self, cond): + """ + Optimizer hint: assume *cond* is always true. + """ + fn = self.module.declare_intrinsic("llvm.assume") + return self.call(fn, [cond]) + + def fence(self, ordering, targetscope=None, name=''): + """ + Add a memory barrier, preventing certain reorderings of load and/or + store accesses with + respect to other processors and devices. + """ + inst = instructions.Fence(self.block, ordering, targetscope, name=name) + self._insert(inst) + return inst + + def comment(self, text): + """ + Puts a single-line comment into the generated IR. This will be ignored + by LLVM, but can be useful for debugging the output of a compiler. Adds + a comment to the source file. + + * *text* is a string that does not contain new line characters. + """ + inst = instructions.Comment(self.block, text) + self._insert(inst) + return inst + + @_uniop_intrinsic_int("llvm.bswap") + def bswap(self, cond): + """ + Used to byte swap integer values with an even number of bytes (positive + multiple of 16 bits) + """ + + @_uniop_intrinsic_int("llvm.bitreverse") + def bitreverse(self, cond): + """ + Reverse the bitpattern of an integer value; for example 0b10110110 + becomes 0b01101101. + """ + + @_uniop_intrinsic_int("llvm.ctpop") + def ctpop(self, cond): + """ + Counts the number of bits set in a value. + """ + + @_uniop_intrinsic_with_flag("llvm.ctlz") + def ctlz(self, cond, flag): + """ + Counts leading zero bits in *value*. Boolean *flag* indicates whether + the result is defined for ``0``. + """ + + @_uniop_intrinsic_with_flag("llvm.cttz") + def cttz(self, cond, flag): + """ + Counts trailing zero bits in *value*. Boolean *flag* indicates whether + the result is defined for ``0``. + """ + + @_triop_intrinsic("llvm.fma") + def fma(self, a, b, c): + """ + Perform the fused multiply-add operation. + """ + + def convert_from_fp16(self, a, to=None, name=''): + """ + Convert from an i16 to the given FP type + """ + if not to: + raise TypeError("expected a float return type") + if not isinstance(to, (types.FloatType, types.DoubleType)): + raise TypeError("expected a float type, got %s" % to) + if not (isinstance(a.type, types.IntType) and a.type.width == 16): + raise TypeError("expected an i16 type, got %s" % a.type) + + opname = 'llvm.convert.from.fp16' + fn = self.module.declare_intrinsic(opname, [to]) + return self.call(fn, [a], name) + + @_uniop_intrinsic_float("llvm.convert.to.fp16") + def convert_to_fp16(self, a): + """ + Convert the given FP number to an i16 + """ diff --git a/lib/python3.11/site-packages/llvmlite/ir/context.py b/lib/python3.11/site-packages/llvmlite/ir/context.py new file mode 100644 index 0000000000000000000000000000000000000000..47d1ebbe2953d160f4dbb38b846b6d1d46582861 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/context.py @@ -0,0 +1,20 @@ +from llvmlite.ir import _utils +from llvmlite.ir import types + + +class Context(object): + def __init__(self): + self.scope = _utils.NameScope() + self.identified_types = {} + + def get_identified_type(self, name): + if name not in self.identified_types: + self.scope.register(name) + ty = types.IdentifiedStructType(self, name) + self.identified_types[name] = ty + else: + ty = self.identified_types[name] + return ty + + +global_context = Context() diff --git a/lib/python3.11/site-packages/llvmlite/ir/instructions.py b/lib/python3.11/site-packages/llvmlite/ir/instructions.py new file mode 100644 index 0000000000000000000000000000000000000000..044d434536f6e31f69673bbeca47bcb2f4f8b487 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/instructions.py @@ -0,0 +1,893 @@ +""" +Implementation of LLVM IR instructions. +""" + +from llvmlite.ir import types +from llvmlite.ir.values import (Block, Function, Value, NamedValue, Constant, + MetaDataArgument, MetaDataString, AttributeSet, + Undefined, ArgumentAttributes) +from llvmlite.ir._utils import _HasMetadata + + +class Instruction(NamedValue, _HasMetadata): + def __init__(self, parent, typ, opname, operands, name='', flags=()): + super(Instruction, self).__init__(parent, typ, name=name) + assert isinstance(parent, Block) + assert isinstance(flags, (tuple, list)) + self.opname = opname + self.operands = operands + self.flags = list(flags) + self.metadata = {} + + @property + def function(self): + return self.parent.function + + @property + def module(self): + return self.parent.function.module + + def descr(self, buf): + opname = self.opname + if self.flags: + opname = ' '.join([opname] + self.flags) + operands = ', '.join([op.get_reference() for op in self.operands]) + typ = self.type + metadata = self._stringify_metadata(leading_comma=True) + buf.append("{0} {1} {2}{3}\n" + .format(opname, typ, operands, metadata)) + + def replace_usage(self, old, new): + if old in self.operands: + ops = [] + for op in self.operands: + ops.append(new if op is old else op) + self.operands = tuple(ops) + self._clear_string_cache() + + def __repr__(self): + return "" % ( + self.__class__.__name__, self.name, self.type, + self.opname, self.operands) + + +class CallInstrAttributes(AttributeSet): + _known = frozenset(['noreturn', 'nounwind', 'readonly', 'readnone', + 'noinline', 'alwaysinline']) + + +TailMarkerOptions = frozenset(['tail', 'musttail', 'notail']) + + +class FastMathFlags(AttributeSet): + _known = frozenset(['fast', 'nnan', 'ninf', 'nsz', 'arcp', 'contract', + 'afn', 'reassoc']) + + +class CallInstr(Instruction): + def __init__(self, parent, func, args, name='', cconv=None, tail=None, + fastmath=(), attrs=(), arg_attrs=None): + self.cconv = (func.calling_convention + if cconv is None and isinstance(func, Function) + else cconv) + + # For backwards compatibility with previous API of accepting a "truthy" + # value for a hint to the optimizer to potentially tail optimize. + if isinstance(tail, str) and tail in TailMarkerOptions: + pass + elif tail: + tail = "tail" + else: + tail = "" + + self.tail = tail + self.fastmath = FastMathFlags(fastmath) + self.attributes = CallInstrAttributes(attrs) + self.arg_attributes = {} + if arg_attrs: + for idx, attrs in arg_attrs.items(): + if not (0 <= idx < len(args)): + raise ValueError("Invalid argument index {}" + .format(idx)) + self.arg_attributes[idx] = ArgumentAttributes(attrs) + + # Fix and validate arguments + args = list(args) + for i in range(len(func.function_type.args)): + arg = args[i] + expected_type = func.function_type.args[i] + if (isinstance(expected_type, types.MetaDataType) and + arg.type != expected_type): + arg = MetaDataArgument(arg) + if arg.type != expected_type: + msg = ("Type of #{0} arg mismatch: {1} != {2}" + .format(1 + i, expected_type, arg.type)) + raise TypeError(msg) + args[i] = arg + + super(CallInstr, self).__init__(parent, func.function_type.return_type, + "call", [func] + list(args), name=name) + + @property + def callee(self): + return self.operands[0] + + @callee.setter + def callee(self, newcallee): + self.operands[0] = newcallee + + @property + def args(self): + return self.operands[1:] + + def replace_callee(self, newfunc): + if newfunc.function_type != self.callee.function_type: + raise TypeError("New function has incompatible type") + self.callee = newfunc + + @property + def called_function(self): + """The callee function""" + return self.callee + + def _descr(self, buf, add_metadata): + def descr_arg(i, a): + if i in self.arg_attributes: + attrs = ' '.join(self.arg_attributes[i]._to_list(a.type)) + ' ' + else: + attrs = '' + return '{0} {1}{2}'.format(a.type, attrs, a.get_reference()) + args = ', '.join([descr_arg(i, a) for i, a in enumerate(self.args)]) + + fnty = self.callee.function_type + # Only print function type if variable-argument + if fnty.var_arg: + ty = fnty + # Otherwise, just print the return type. + else: + # Fastmath flag work only in this case + ty = fnty.return_type + callee_ref = "{0} {1}".format(ty, self.callee.get_reference()) + if self.cconv: + callee_ref = "{0} {1}".format(self.cconv, callee_ref) + + tail_marker = "" + if self.tail: + tail_marker = "{0} ".format(self.tail) + + fn_attrs = ' ' + ' '.join(self.attributes._to_list(fnty.return_type))\ + if self.attributes else '' + + fm_attrs = ' ' + ' '.join(self.fastmath._to_list(fnty.return_type))\ + if self.fastmath else '' + + buf.append("{tail}{op}{fastmath} {callee}({args}){attr}{meta}\n".format( + tail=tail_marker, + op=self.opname, + callee=callee_ref, + fastmath=fm_attrs, + args=args, + attr=fn_attrs, + meta=(self._stringify_metadata(leading_comma=True) + if add_metadata else ""), + )) + + def descr(self, buf): + self._descr(buf, add_metadata=True) + + +class InvokeInstr(CallInstr): + def __init__(self, parent, func, args, normal_to, unwind_to, name='', + cconv=None, fastmath=(), attrs=(), arg_attrs=None): + assert isinstance(normal_to, Block) + assert isinstance(unwind_to, Block) + super(InvokeInstr, self).__init__(parent, func, args, name, cconv, + tail=False, fastmath=fastmath, + attrs=attrs, arg_attrs=arg_attrs) + self.opname = "invoke" + self.normal_to = normal_to + self.unwind_to = unwind_to + + def descr(self, buf): + super(InvokeInstr, self)._descr(buf, add_metadata=False) + buf.append(" to label {0} unwind label {1}{metadata}\n".format( + self.normal_to.get_reference(), + self.unwind_to.get_reference(), + metadata=self._stringify_metadata(leading_comma=True), + )) + + +class Terminator(Instruction): + def __init__(self, parent, opname, operands): + super(Terminator, self).__init__(parent, types.VoidType(), opname, + operands) + + def descr(self, buf): + opname = self.opname + operands = ', '.join(["{0} {1}".format(op.type, op.get_reference()) + for op in self.operands]) + metadata = self._stringify_metadata(leading_comma=True) + buf.append("{0} {1}{2}".format(opname, operands, metadata)) + + +class PredictableInstr(Instruction): + + def set_weights(self, weights): + operands = [MetaDataString(self.module, "branch_weights")] + for w in weights: + if w < 0: + raise ValueError("branch weight must be a positive integer") + operands.append(Constant(types.IntType(32), w)) + md = self.module.add_metadata(operands) + self.set_metadata("prof", md) + + +class Ret(Terminator): + def __init__(self, parent, opname, return_value=None): + operands = [return_value] if return_value is not None else [] + super(Ret, self).__init__(parent, opname, operands) + + @property + def return_value(self): + if self.operands: + return self.operands[0] + else: + return None + + def descr(self, buf): + return_value = self.return_value + metadata = self._stringify_metadata(leading_comma=True) + if return_value is not None: + buf.append("{0} {1} {2}{3}\n" + .format(self.opname, return_value.type, + return_value.get_reference(), + metadata)) + else: + buf.append("{0}{1}\n".format(self.opname, metadata)) + + +class Branch(Terminator): + pass + + +class ConditionalBranch(PredictableInstr, Terminator): + pass + + +class IndirectBranch(PredictableInstr, Terminator): + def __init__(self, parent, opname, addr): + super(IndirectBranch, self).__init__(parent, opname, [addr]) + self.destinations = [] + + @property + def address(self): + return self.operands[0] + + def add_destination(self, block): + assert isinstance(block, Block) + self.destinations.append(block) + + def descr(self, buf): + destinations = ["label {0}".format(blk.get_reference()) + for blk in self.destinations] + buf.append("indirectbr {0} {1}, [{2}] {3}\n".format( + self.address.type, + self.address.get_reference(), + ', '.join(destinations), + self._stringify_metadata(leading_comma=True), + )) + + +class SwitchInstr(PredictableInstr, Terminator): + + def __init__(self, parent, opname, val, default): + super(SwitchInstr, self).__init__(parent, opname, [val]) + self.default = default + self.cases = [] + + @property + def value(self): + return self.operands[0] + + def add_case(self, val, block): + assert isinstance(block, Block) + if not isinstance(val, Value): + val = Constant(self.value.type, val) + self.cases.append((val, block)) + + def descr(self, buf): + cases = ["{0} {1}, label {2}".format(val.type, val.get_reference(), + blk.get_reference()) + for val, blk in self.cases] + buf.append("switch {0} {1}, label {2} [{3}] {4}\n".format( + self.value.type, + self.value.get_reference(), + self.default.get_reference(), + ' '.join(cases), + self._stringify_metadata(leading_comma=True), + )) + + +class Resume(Terminator): + pass + + +class SelectInstr(Instruction): + def __init__(self, parent, cond, lhs, rhs, name='', flags=()): + assert lhs.type == rhs.type + super(SelectInstr, self).__init__(parent, lhs.type, "select", + [cond, lhs, rhs], name=name, + flags=flags) + + @property + def cond(self): + return self.operands[0] + + @property + def lhs(self): + return self.operands[1] + + @property + def rhs(self): + return self.operands[2] + + def descr(self, buf): + buf.append("select {0} {1} {2}, {3} {4}, {5} {6} {7}\n".format( + ' '.join(self.flags), + self.cond.type, self.cond.get_reference(), + self.lhs.type, self.lhs.get_reference(), + self.rhs.type, self.rhs.get_reference(), + self._stringify_metadata(leading_comma=True), + )) + + +class CompareInstr(Instruction): + # Define the following in subclasses + OPNAME = 'invalid-compare' + VALID_OP = {} + + def __init__(self, parent, op, lhs, rhs, name='', flags=[]): + if op not in self.VALID_OP: + raise ValueError("invalid comparison %r for %s" % (op, self.OPNAME)) + for flag in flags: + if flag not in self.VALID_FLAG: + raise ValueError("invalid flag %r for %s" % (flag, self.OPNAME)) + opname = self.OPNAME + if isinstance(lhs.type, types.VectorType): + typ = types.VectorType(types.IntType(1), lhs.type.count) + else: + typ = types.IntType(1) + super(CompareInstr, self).__init__(parent, typ, + opname, [lhs, rhs], flags=flags, + name=name) + self.op = op + + def descr(self, buf): + buf.append("{opname}{flags} {op} {ty} {lhs}, {rhs} {meta}\n".format( + opname=self.opname, + flags=''.join(' ' + it for it in self.flags), + op=self.op, + ty=self.operands[0].type, + lhs=self.operands[0].get_reference(), + rhs=self.operands[1].get_reference(), + meta=self._stringify_metadata(leading_comma=True), + )) + + +class ICMPInstr(CompareInstr): + OPNAME = 'icmp' + VALID_OP = { + 'eq': 'equal', + 'ne': 'not equal', + 'ugt': 'unsigned greater than', + 'uge': 'unsigned greater or equal', + 'ult': 'unsigned less than', + 'ule': 'unsigned less or equal', + 'sgt': 'signed greater than', + 'sge': 'signed greater or equal', + 'slt': 'signed less than', + 'sle': 'signed less or equal', + } + VALID_FLAG = set() + + +class FCMPInstr(CompareInstr): + OPNAME = 'fcmp' + VALID_OP = { + 'false': 'no comparison, always returns false', + 'oeq': 'ordered and equal', + 'ogt': 'ordered and greater than', + 'oge': 'ordered and greater than or equal', + 'olt': 'ordered and less than', + 'ole': 'ordered and less than or equal', + 'one': 'ordered and not equal', + 'ord': 'ordered (no nans)', + 'ueq': 'unordered or equal', + 'ugt': 'unordered or greater than', + 'uge': 'unordered or greater than or equal', + 'ult': 'unordered or less than', + 'ule': 'unordered or less than or equal', + 'une': 'unordered or not equal', + 'uno': 'unordered (either nans)', + 'true': 'no comparison, always returns true', + } + VALID_FLAG = {'nnan', 'ninf', 'nsz', 'arcp', 'contract', 'afn', 'reassoc', + 'fast'} + + +class CastInstr(Instruction): + def __init__(self, parent, op, val, typ, name=''): + super(CastInstr, self).__init__(parent, typ, op, [val], name=name) + + def descr(self, buf): + buf.append("{0} {1} {2} to {3} {4}\n".format( + self.opname, + self.operands[0].type, + self.operands[0].get_reference(), + self.type, + self._stringify_metadata(leading_comma=True), + )) + + +class LoadInstr(Instruction): + + def __init__(self, parent, ptr, name=''): + super(LoadInstr, self).__init__(parent, ptr.type.pointee, "load", + [ptr], name=name) + self.align = None + + def descr(self, buf): + [val] = self.operands + if self.align is not None: + align = ', align %d' % (self.align) + else: + align = '' + buf.append("load {0}, {1} {2}{3}{4}\n".format( + val.type.pointee, + val.type, + val.get_reference(), + align, + self._stringify_metadata(leading_comma=True), + )) + + +class StoreInstr(Instruction): + def __init__(self, parent, val, ptr): + super(StoreInstr, self).__init__(parent, types.VoidType(), "store", + [val, ptr]) + + def descr(self, buf): + val, ptr = self.operands + if self.align is not None: + align = ', align %d' % (self.align) + else: + align = '' + buf.append("store {0} {1}, {2} {3}{4}{5}\n".format( + val.type, + val.get_reference(), + ptr.type, + ptr.get_reference(), + align, + self._stringify_metadata(leading_comma=True), + )) + + +class LoadAtomicInstr(Instruction): + def __init__(self, parent, ptr, ordering, align, name=''): + super(LoadAtomicInstr, self).__init__(parent, ptr.type.pointee, + "load atomic", [ptr], name=name) + self.ordering = ordering + self.align = align + + def descr(self, buf): + [val] = self.operands + buf.append("load atomic {0}, {1} {2} {3}, align {4}{5}\n".format( + val.type.pointee, + val.type, + val.get_reference(), + self.ordering, + self.align, + self._stringify_metadata(leading_comma=True), + )) + + +class StoreAtomicInstr(Instruction): + def __init__(self, parent, val, ptr, ordering, align): + super(StoreAtomicInstr, self).__init__(parent, types.VoidType(), + "store atomic", [val, ptr]) + self.ordering = ordering + self.align = align + + def descr(self, buf): + val, ptr = self.operands + buf.append("store atomic {0} {1}, {2} {3} {4}, align {5}{6}\n".format( + val.type, + val.get_reference(), + ptr.type, + ptr.get_reference(), + self.ordering, + self.align, + self._stringify_metadata(leading_comma=True), + )) + + +class AllocaInstr(Instruction): + def __init__(self, parent, typ, count, name): + operands = [count] if count else () + super(AllocaInstr, self).__init__(parent, typ.as_pointer(), "alloca", + operands, name) + self.align = None + + def descr(self, buf): + buf.append("{0} {1}".format(self.opname, self.type.pointee)) + if self.operands: + op, = self.operands + buf.append(", {0} {1}".format(op.type, op.get_reference())) + if self.align is not None: + buf.append(", align {0}".format(self.align)) + if self.metadata: + buf.append(self._stringify_metadata(leading_comma=True)) + + +class GEPInstr(Instruction): + def __init__(self, parent, ptr, indices, inbounds, name): + typ = ptr.type + lasttyp = None + lastaddrspace = 0 + for i in indices: + lasttyp, typ = typ, typ.gep(i) + # inherit the addrspace from the last seen pointer + if isinstance(lasttyp, types.PointerType): + lastaddrspace = lasttyp.addrspace + + if (not isinstance(typ, types.PointerType) and + isinstance(lasttyp, types.PointerType)): + typ = lasttyp + else: + typ = typ.as_pointer(lastaddrspace) + + super(GEPInstr, self).__init__(parent, typ, "getelementptr", + [ptr] + list(indices), name=name) + self.pointer = ptr + self.indices = indices + self.inbounds = inbounds + + def descr(self, buf): + indices = ['{0} {1}'.format(i.type, i.get_reference()) + for i in self.indices] + op = "getelementptr inbounds" if self.inbounds else "getelementptr" + buf.append("{0} {1}, {2} {3}, {4} {5}\n".format( + op, + self.pointer.type.pointee, + self.pointer.type, + self.pointer.get_reference(), + ', '.join(indices), + self._stringify_metadata(leading_comma=True), + )) + + +class PhiInstr(Instruction): + def __init__(self, parent, typ, name, flags=()): + super(PhiInstr, self).__init__(parent, typ, "phi", (), name=name, + flags=flags) + self.incomings = [] + + def descr(self, buf): + incs = ', '.join('[{0}, {1}]'.format(v.get_reference(), + b.get_reference()) + for v, b in self.incomings) + buf.append("phi {0} {1} {2} {3}\n".format( + ' '.join(self.flags), + self.type, + incs, + self._stringify_metadata(leading_comma=True), + )) + + def add_incoming(self, value, block): + assert isinstance(block, Block) + self.incomings.append((value, block)) + + def replace_usage(self, old, new): + self.incomings = [((new if val is old else val), blk) + for (val, blk) in self.incomings] + + +class ExtractElement(Instruction): + def __init__(self, parent, vector, index, name=''): + if not isinstance(vector.type, types.VectorType): + raise TypeError("vector needs to be of VectorType.") + if not isinstance(index.type, types.IntType): + raise TypeError("index needs to be of IntType.") + typ = vector.type.element + super(ExtractElement, self).__init__(parent, typ, "extractelement", + [vector, index], name=name) + + def descr(self, buf): + operands = ", ".join("{0} {1}".format( + op.type, op.get_reference()) for op in self.operands) + buf.append("{opname} {operands}\n".format( + opname=self.opname, operands=operands)) + + +class InsertElement(Instruction): + def __init__(self, parent, vector, value, index, name=''): + if not isinstance(vector.type, types.VectorType): + raise TypeError("vector needs to be of VectorType.") + if not value.type == vector.type.element: + raise TypeError( + "value needs to be of type {} not {}.".format( + vector.type.element, value.type)) + if not isinstance(index.type, types.IntType): + raise TypeError("index needs to be of IntType.") + typ = vector.type + super(InsertElement, self).__init__(parent, typ, "insertelement", + [vector, value, index], name=name) + + def descr(self, buf): + operands = ", ".join("{0} {1}".format( + op.type, op.get_reference()) for op in self.operands) + buf.append("{opname} {operands}\n".format( + opname=self.opname, operands=operands)) + + +class ShuffleVector(Instruction): + def __init__(self, parent, vector1, vector2, mask, name=''): + if not isinstance(vector1.type, types.VectorType): + raise TypeError("vector1 needs to be of VectorType.") + if vector2 != Undefined: + if vector2.type != vector1.type: + raise TypeError("vector2 needs to be " + + "Undefined or of the same type as vector1.") + if (not isinstance(mask, Constant) or + not isinstance(mask.type, types.VectorType) or + not (isinstance(mask.type.element, types.IntType) and + mask.type.element.width == 32)): + raise TypeError("mask needs to be a constant i32 vector.") + typ = types.VectorType(vector1.type.element, mask.type.count) + index_range = range(vector1.type.count + if vector2 == Undefined + else 2 * vector1.type.count) + if not all(ii.constant in index_range for ii in mask.constant): + raise IndexError( + "mask values need to be in {0}".format(index_range), + ) + super(ShuffleVector, self).__init__(parent, typ, "shufflevector", + [vector1, vector2, mask], name=name) + + def descr(self, buf): + buf.append("shufflevector {0} {1}\n".format( + ", ".join("{0} {1}".format(op.type, op.get_reference()) + for op in self.operands), + self._stringify_metadata(leading_comma=True), + )) + + +class ExtractValue(Instruction): + def __init__(self, parent, agg, indices, name=''): + typ = agg.type + try: + for i in indices: + typ = typ.elements[i] + except (AttributeError, IndexError): + raise TypeError("Can't index at %r in %s" + % (list(indices), agg.type)) + + super(ExtractValue, self).__init__(parent, typ, "extractvalue", + [agg], name=name) + + self.aggregate = agg + self.indices = indices + + def descr(self, buf): + indices = [str(i) for i in self.indices] + + buf.append("extractvalue {0} {1}, {2} {3}\n".format( + self.aggregate.type, + self.aggregate.get_reference(), + ', '.join(indices), + self._stringify_metadata(leading_comma=True), + )) + + +class InsertValue(Instruction): + def __init__(self, parent, agg, elem, indices, name=''): + typ = agg.type + try: + for i in indices: + typ = typ.elements[i] + except (AttributeError, IndexError): + raise TypeError("Can't index at %r in %s" + % (list(indices), agg.type)) + if elem.type != typ: + raise TypeError("Can only insert %s at %r in %s: got %s" + % (typ, list(indices), agg.type, elem.type)) + super(InsertValue, self).__init__(parent, agg.type, "insertvalue", + [agg, elem], name=name) + + self.aggregate = agg + self.value = elem + self.indices = indices + + def descr(self, buf): + indices = [str(i) for i in self.indices] + + buf.append("insertvalue {0} {1}, {2} {3}, {4} {5}\n".format( + self.aggregate.type, self.aggregate.get_reference(), + self.value.type, self.value.get_reference(), + ', '.join(indices), + self._stringify_metadata(leading_comma=True), + )) + + +class Unreachable(Instruction): + def __init__(self, parent): + super(Unreachable, self).__init__(parent, types.VoidType(), + "unreachable", (), name='') + + def descr(self, buf): + buf += (self.opname, "\n") + + +class InlineAsm(object): + def __init__(self, ftype, asm, constraint, side_effect=False): + self.type = ftype.return_type + self.function_type = ftype + self.asm = asm + self.constraint = constraint + self.side_effect = side_effect + + def descr(self, buf): + sideeffect = 'sideeffect' if self.side_effect else '' + fmt = 'asm {sideeffect} "{asm}", "{constraint}"\n' + buf.append(fmt.format(sideeffect=sideeffect, asm=self.asm, + constraint=self.constraint)) + + def get_reference(self): + buf = [] + self.descr(buf) + return "".join(buf) + + def __str__(self): + return "{0} {1}".format(self.type, self.get_reference()) + + +class AtomicRMW(Instruction): + def __init__(self, parent, op, ptr, val, ordering, name): + super(AtomicRMW, self).__init__(parent, val.type, "atomicrmw", + (ptr, val), name=name) + self.operation = op + self.ordering = ordering + + def descr(self, buf): + ptr, val = self.operands + fmt = ("atomicrmw {op} {ptrty} {ptr}, {valty} {val} {ordering} " + "{metadata}\n") + buf.append(fmt.format(op=self.operation, + ptrty=ptr.type, + ptr=ptr.get_reference(), + valty=val.type, + val=val.get_reference(), + ordering=self.ordering, + metadata=self._stringify_metadata( + leading_comma=True), + )) + + +class CmpXchg(Instruction): + """This instruction has changed since llvm3.5. It is not compatible with + older llvm versions. + """ + + def __init__(self, parent, ptr, cmp, val, ordering, failordering, name): + outtype = types.LiteralStructType([val.type, types.IntType(1)]) + super(CmpXchg, self).__init__(parent, outtype, "cmpxchg", + (ptr, cmp, val), name=name) + self.ordering = ordering + self.failordering = failordering + + def descr(self, buf): + ptr, cmpval, val = self.operands + fmt = "cmpxchg {ptrty} {ptr}, {ty} {cmp}, {ty} {val} {ordering} " \ + "{failordering} {metadata}\n" + buf.append(fmt.format(ptrty=ptr.type, + ptr=ptr.get_reference(), + ty=cmpval.type, + cmp=cmpval.get_reference(), + val=val.get_reference(), + ordering=self.ordering, + failordering=self.failordering, + metadata=self._stringify_metadata( + leading_comma=True), + )) + + +class _LandingPadClause(object): + def __init__(self, value): + self.value = value + + def __str__(self): + return "{kind} {type} {value}".format( + kind=self.kind, + type=self.value.type, + value=self.value.get_reference()) + + +class CatchClause(_LandingPadClause): + kind = 'catch' + + +class FilterClause(_LandingPadClause): + kind = 'filter' + + def __init__(self, value): + assert isinstance(value, Constant) + assert isinstance(value.type, types.ArrayType) + super(FilterClause, self).__init__(value) + + +class LandingPadInstr(Instruction): + def __init__(self, parent, typ, name='', cleanup=False): + super(LandingPadInstr, self).__init__(parent, typ, "landingpad", [], + name=name) + self.cleanup = cleanup + self.clauses = [] + + def add_clause(self, clause): + assert isinstance(clause, _LandingPadClause) + self.clauses.append(clause) + + def descr(self, buf): + fmt = "landingpad {type}{cleanup}{clauses}\n" + buf.append(fmt.format(type=self.type, + cleanup=' cleanup' if self.cleanup else '', + clauses=''.join(["\n {0}".format(clause) + for clause in self.clauses]), + )) + + +class Fence(Instruction): + """ + The `fence` instruction. + + As of LLVM 5.0.1: + + fence [syncscope("")] ; yields void + """ + + VALID_FENCE_ORDERINGS = {"acquire", "release", "acq_rel", "seq_cst"} + + def __init__(self, parent, ordering, targetscope=None, name=''): + super(Fence, self).__init__(parent, types.VoidType(), "fence", (), + name=name) + if ordering not in self.VALID_FENCE_ORDERINGS: + msg = "Invalid fence ordering \"{0}\"! Should be one of {1}." + raise ValueError(msg .format(ordering, + ", ".join(self.VALID_FENCE_ORDERINGS))) + self.ordering = ordering + self.targetscope = targetscope + + def descr(self, buf): + if self.targetscope is None: + syncscope = "" + else: + syncscope = 'syncscope("{0}") '.format(self.targetscope) + + fmt = "fence {syncscope}{ordering}\n" + buf.append(fmt.format(syncscope=syncscope, + ordering=self.ordering, + )) + + +class Comment(Instruction): + """ + A line comment. + """ + + def __init__(self, parent, text): + super(Comment, self).__init__(parent, types.VoidType(), ";", (), + name='') + assert "\n" not in text, "Comment cannot contain new line" + self.text = text + + def descr(self, buf): + buf.append(f"; {self.text}") diff --git a/lib/python3.11/site-packages/llvmlite/ir/module.py b/lib/python3.11/site-packages/llvmlite/ir/module.py new file mode 100644 index 0000000000000000000000000000000000000000..464f91ec34344e02bd9fb7e5f6dec46803407f00 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/module.py @@ -0,0 +1,246 @@ +import collections + +from llvmlite.ir import context, values, types, _utils + + +class Module(object): + def __init__(self, name='', context=context.global_context): + self.context = context + self.name = name # name is for debugging/informational + self.data_layout = "" + self.scope = _utils.NameScope() + self.triple = 'unknown-unknown-unknown' + self.globals = collections.OrderedDict() + # Innamed metadata nodes. + self.metadata = [] + # Named metadata nodes + self.namedmetadata = {} + # Cache for metadata node deduplication + self._metadatacache = {} + + def _fix_metadata_operands(self, operands): + fixed_ops = [] + for op in operands: + if op is None: + # A literal None creates a null metadata value + op = types.MetaDataType()(None) + elif isinstance(op, str): + # A literal string creates a metadata string value + op = values.MetaDataString(self, op) + elif isinstance(op, (list, tuple)): + # A sequence creates a metadata node reference + op = self.add_metadata(op) + fixed_ops.append(op) + return fixed_ops + + def _fix_di_operands(self, operands): + fixed_ops = [] + for name, op in operands: + if isinstance(op, (list, tuple)): + # A sequence creates a metadata node reference + op = self.add_metadata(op) + fixed_ops.append((name, op)) + return fixed_ops + + def add_metadata(self, operands): + """ + Add an unnamed metadata to the module with the given *operands* + (a sequence of values) or return a previous equivalent metadata. + A MDValue instance is returned, it can then be associated to + e.g. an instruction. + """ + if not isinstance(operands, (list, tuple)): + raise TypeError("expected a list or tuple of metadata values, " + "got %r" % (operands,)) + operands = self._fix_metadata_operands(operands) + key = tuple(operands) + if key not in self._metadatacache: + n = len(self.metadata) + md = values.MDValue(self, operands, name=str(n)) + self._metadatacache[key] = md + else: + md = self._metadatacache[key] + return md + + def add_debug_info(self, kind, operands, is_distinct=False): + """ + Add debug information metadata to the module with the given + *operands* (a dict of values with string keys) or return + a previous equivalent metadata. *kind* is a string of the + debug information kind (e.g. "DICompileUnit"). + + A DIValue instance is returned, it can then be associated to e.g. + an instruction. + """ + operands = tuple(sorted(self._fix_di_operands(operands.items()))) + key = (kind, operands, is_distinct) + if key not in self._metadatacache: + n = len(self.metadata) + di = values.DIValue(self, is_distinct, kind, operands, name=str(n)) + self._metadatacache[key] = di + else: + di = self._metadatacache[key] + return di + + def add_named_metadata(self, name, element=None): + """ + Add a named metadata node to the module, if it doesn't exist, + or return the existing node. + If *element* is given, it will append a new element to + the named metadata node. If *element* is a sequence of values + (rather than a metadata value), a new unnamed node will first be + created. + + Example:: + module.add_named_metadata("llvm.ident", ["llvmlite/1.0"]) + """ + if name in self.namedmetadata: + nmd = self.namedmetadata[name] + else: + nmd = self.namedmetadata[name] = values.NamedMetaData(self) + if element is not None: + if not isinstance(element, values.Value): + element = self.add_metadata(element) + if not isinstance(element.type, types.MetaDataType): + raise TypeError("wrong type for metadata element: got %r" + % (element,)) + nmd.add(element) + return nmd + + def get_named_metadata(self, name): + """ + Return the metadata node with the given *name*. KeyError is raised + if no such node exists (contrast with add_named_metadata()). + """ + return self.namedmetadata[name] + + @property + def functions(self): + """ + A list of functions declared or defined in this module. + """ + return [v for v in self.globals.values() + if isinstance(v, values.Function)] + + @property + def global_values(self): + """ + An iterable of global values in this module. + """ + return self.globals.values() + + def get_global(self, name): + """ + Get a global value by name. + """ + return self.globals[name] + + def add_global(self, globalvalue): + """ + Add a new global value. + """ + assert globalvalue.name not in self.globals + self.globals[globalvalue.name] = globalvalue + + def get_unique_name(self, name=''): + """ + Get a unique global name with the following *name* hint. + """ + return self.scope.deduplicate(name) + + def declare_intrinsic(self, intrinsic, tys=(), fnty=None): + def _error(): + raise NotImplementedError("unknown intrinsic %r with %d types" + % (intrinsic, len(tys))) + + if intrinsic in {'llvm.cttz', 'llvm.ctlz', 'llvm.fma'}: + suffixes = [tys[0].intrinsic_name] + else: + suffixes = [t.intrinsic_name for t in tys] + name = '.'.join([intrinsic] + suffixes) + if name in self.globals: + return self.globals[name] + + if fnty is not None: + # General case: function type is given + pass + # Compute function type if omitted for common cases + elif len(tys) == 0 and intrinsic == 'llvm.assume': + fnty = types.FunctionType(types.VoidType(), [types.IntType(1)]) + elif len(tys) == 1: + if intrinsic == 'llvm.powi': + fnty = types.FunctionType(tys[0], [tys[0], types.IntType(32)]) + elif intrinsic == 'llvm.pow': + fnty = types.FunctionType(tys[0], tys * 2) + elif intrinsic == 'llvm.convert.from.fp16': + fnty = types.FunctionType(tys[0], [types.IntType(16)]) + elif intrinsic == 'llvm.convert.to.fp16': + fnty = types.FunctionType(types.IntType(16), tys) + else: + fnty = types.FunctionType(tys[0], tys) + elif len(tys) == 2: + if intrinsic == 'llvm.memset': + tys = [tys[0], types.IntType(8), tys[1], + types.IntType(1)] + fnty = types.FunctionType(types.VoidType(), tys) + elif intrinsic in {'llvm.cttz', 'llvm.ctlz'}: + tys = [tys[0], types.IntType(1)] + fnty = types.FunctionType(tys[0], tys) + else: + _error() + elif len(tys) == 3: + if intrinsic in ('llvm.memcpy', 'llvm.memmove'): + tys = tys + [types.IntType(1)] + fnty = types.FunctionType(types.VoidType(), tys) + elif intrinsic == 'llvm.fma': + tys = [tys[0]] * 3 + fnty = types.FunctionType(tys[0], tys) + else: + _error() + else: + _error() + return values.Function(self, fnty, name=name) + + def get_identified_types(self): + return self.context.identified_types + + def _get_body_lines(self): + # Type declarations + lines = [it.get_declaration() + for it in self.get_identified_types().values()] + # Global values (including function definitions) + lines += [str(v) for v in self.globals.values()] + return lines + + def _get_metadata_lines(self): + mdbuf = [] + for k, v in self.namedmetadata.items(): + mdbuf.append("!{name} = !{{ {operands} }}".format( + name=k, operands=', '.join(i.get_reference() + for i in v.operands))) + for md in self.metadata: + mdbuf.append(str(md)) + return mdbuf + + def _stringify_body(self): + # For testing + return "\n".join(self._get_body_lines()) + + def _stringify_metadata(self): + # For testing + return "\n".join(self._get_metadata_lines()) + + def __repr__(self): + lines = [] + # Header + lines += [ + '; ModuleID = "%s"' % (self.name,), + 'target triple = "%s"' % (self.triple,), + 'target datalayout = "%s"' % (self.data_layout,), + ''] + # Body + lines += self._get_body_lines() + # Metadata + lines += self._get_metadata_lines() + + return "\n".join(lines) diff --git a/lib/python3.11/site-packages/llvmlite/ir/transforms.py b/lib/python3.11/site-packages/llvmlite/ir/transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..a69113d36e93b6b9e42a2a15119697375cff62e5 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/transforms.py @@ -0,0 +1,64 @@ +from llvmlite.ir import CallInstr + + +class Visitor(object): + def visit(self, module): + self._module = module + for func in module.functions: + self.visit_Function(func) + + def visit_Function(self, func): + self._function = func + for bb in func.blocks: + self.visit_BasicBlock(bb) + + def visit_BasicBlock(self, bb): + self._basic_block = bb + for instr in bb.instructions: + self.visit_Instruction(instr) + + def visit_Instruction(self, instr): + raise NotImplementedError + + @property + def module(self): + return self._module + + @property + def function(self): + return self._function + + @property + def basic_block(self): + return self._basic_block + + +class CallVisitor(Visitor): + def visit_Instruction(self, instr): + if isinstance(instr, CallInstr): + self.visit_Call(instr) + + def visit_Call(self, instr): + raise NotImplementedError + + +class ReplaceCalls(CallVisitor): + def __init__(self, orig, repl): + super(ReplaceCalls, self).__init__() + self.orig = orig + self.repl = repl + self.calls = [] + + def visit_Call(self, instr): + if instr.callee == self.orig: + instr.replace_callee(self.repl) + self.calls.append(instr) + + +def replace_all_calls(mod, orig, repl): + """Replace all calls to `orig` to `repl` in module `mod`. + Returns the references to the returned calls + """ + rc = ReplaceCalls(orig, repl) + rc.visit(mod) + return rc.calls diff --git a/lib/python3.11/site-packages/llvmlite/ir/types.py b/lib/python3.11/site-packages/llvmlite/ir/types.py new file mode 100644 index 0000000000000000000000000000000000000000..707246e617f04c2636b0098c6cb4b58f63873522 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/types.py @@ -0,0 +1,614 @@ +""" +Classes that are LLVM types +""" + +import struct + +from llvmlite.ir._utils import _StrCaching + + +def _wrapname(x): + return '"{0}"'.format(x.replace('\\', '\\5c').replace('"', '\\22')) + + +class Type(_StrCaching): + """ + The base class for all LLVM types. + """ + is_pointer = False + null = 'zeroinitializer' + + def __repr__(self): + return "<%s %s>" % (type(self), str(self)) + + def _to_string(self): + raise NotImplementedError + + def as_pointer(self, addrspace=0): + return PointerType(self, addrspace) + + def __ne__(self, other): + return not (self == other) + + def _get_ll_pointer_type(self, target_data, context=None): + """ + Convert this type object to an LLVM type. + """ + from llvmlite.ir import Module, GlobalVariable + from llvmlite.binding import parse_assembly + + if context is None: + m = Module() + else: + m = Module(context=context) + foo = GlobalVariable(m, self, name="foo") + with parse_assembly(str(m)) as llmod: + return llmod.get_global_variable(foo.name).type + + def get_abi_size(self, target_data, context=None): + """ + Get the ABI size of this type according to data layout *target_data*. + """ + llty = self._get_ll_pointer_type(target_data, context) + return target_data.get_pointee_abi_size(llty) + + def get_abi_alignment(self, target_data, context=None): + """ + Get the minimum ABI alignment of this type according to data layout + *target_data*. + """ + llty = self._get_ll_pointer_type(target_data, context) + return target_data.get_pointee_abi_alignment(llty) + + def format_constant(self, value): + """ + Format constant *value* of this type. This method may be overriden + by subclasses. + """ + return str(value) + + def wrap_constant_value(self, value): + """ + Wrap constant *value* if necessary. This method may be overriden + by subclasses (especially aggregate types). + """ + return value + + def __call__(self, value): + """ + Create a LLVM constant of this type with the given Python value. + """ + from llvmlite.ir import Constant + return Constant(self, value) + + +class MetaDataType(Type): + + def _to_string(self): + return "metadata" + + def as_pointer(self): + raise TypeError + + def __eq__(self, other): + return isinstance(other, MetaDataType) + + def __hash__(self): + return hash(MetaDataType) + + +class LabelType(Type): + """ + The label type is the type of e.g. basic blocks. + """ + + def _to_string(self): + return "label" + + +class PointerType(Type): + """ + The type of all pointer values. + """ + is_pointer = True + null = 'null' + + def __init__(self, pointee, addrspace=0): + assert not isinstance(pointee, VoidType) + self.pointee = pointee + self.addrspace = addrspace + + def _to_string(self): + if self.addrspace != 0: + return "{0} addrspace({1})*".format(self.pointee, self.addrspace) + else: + return "{0}*".format(self.pointee) + + def __eq__(self, other): + if isinstance(other, PointerType): + return (self.pointee, self.addrspace) == (other.pointee, + other.addrspace) + else: + return False + + def __hash__(self): + return hash(PointerType) + + def gep(self, i): + """ + Resolve the type of the i-th element (for getelementptr lookups). + """ + if not isinstance(i.type, IntType): + raise TypeError(i.type) + return self.pointee + + @property + def intrinsic_name(self): + return 'p%d%s' % (self.addrspace, self.pointee.intrinsic_name) + + +class VoidType(Type): + """ + The type for empty values (e.g. a function returning no value). + """ + + def _to_string(self): + return 'void' + + def __eq__(self, other): + return isinstance(other, VoidType) + + def __hash__(self): + return hash(VoidType) + + +class FunctionType(Type): + """ + The type for functions. + """ + + def __init__(self, return_type, args, var_arg=False): + self.return_type = return_type + self.args = tuple(args) + self.var_arg = var_arg + + def _to_string(self): + if self.args: + strargs = ', '.join([str(a) for a in self.args]) + if self.var_arg: + return '{0} ({1}, ...)'.format(self.return_type, strargs) + else: + return '{0} ({1})'.format(self.return_type, strargs) + elif self.var_arg: + return '{0} (...)'.format(self.return_type) + else: + return '{0} ()'.format(self.return_type) + + def __eq__(self, other): + if isinstance(other, FunctionType): + return (self.return_type == other.return_type and + self.args == other.args and self.var_arg == other.var_arg) + else: + return False + + def __hash__(self): + return hash(FunctionType) + + +class IntType(Type): + """ + The type for integers. + """ + null = '0' + _instance_cache = {} + width: int + + def __new__(cls, bits): + # Cache all common integer types + if 0 <= bits <= 128: + try: + return cls._instance_cache[bits] + except KeyError: + inst = cls._instance_cache[bits] = cls.__new(bits) + return inst + return cls.__new(bits) + + @classmethod + def __new(cls, bits): + assert isinstance(bits, int) and bits >= 0 + self = super(IntType, cls).__new__(cls) + self.width = bits + return self + + def __getnewargs__(self): + return self.width, + + def __copy__(self): + return self + + def _to_string(self): + return 'i%u' % (self.width,) + + def __eq__(self, other): + if isinstance(other, IntType): + return self.width == other.width + else: + return False + + def __hash__(self): + return hash(IntType) + + def format_constant(self, val): + if isinstance(val, bool): + return str(val).lower() + else: + return str(val) + + def wrap_constant_value(self, val): + if val is None: + return 0 + return val + + @property + def intrinsic_name(self): + return str(self) + + +def _as_float(value): + """ + Truncate to single-precision float. + """ + return struct.unpack('f', struct.pack('f', value))[0] + + +def _as_half(value): + """ + Truncate to half-precision float. + """ + try: + return struct.unpack('e', struct.pack('e', value))[0] + except struct.error: + # 'e' only added in Python 3.6+ + return _as_float(value) + + +def _format_float_as_hex(value, packfmt, unpackfmt, numdigits): + raw = struct.pack(packfmt, float(value)) + intrep = struct.unpack(unpackfmt, raw)[0] + out = '{{0:#{0}x}}'.format(numdigits).format(intrep) + return out + + +def _format_double(value): + """ + Format *value* as a hexadecimal string of its IEEE double precision + representation. + """ + return _format_float_as_hex(value, 'd', 'Q', 16) + + +class _BaseFloatType(Type): + + def __new__(cls): + return cls._instance_cache + + def __eq__(self, other): + return isinstance(other, type(self)) + + def __hash__(self): + return hash(type(self)) + + @classmethod + def _create_instance(cls): + cls._instance_cache = super(_BaseFloatType, cls).__new__(cls) + + +class HalfType(_BaseFloatType): + """ + The type for single-precision floats. + """ + null = '0.0' + intrinsic_name = 'f16' + + def __str__(self): + return 'half' + + def format_constant(self, value): + return _format_double(_as_half(value)) + + +class FloatType(_BaseFloatType): + """ + The type for single-precision floats. + """ + null = '0.0' + intrinsic_name = 'f32' + + def __str__(self): + return 'float' + + def format_constant(self, value): + return _format_double(_as_float(value)) + + +class DoubleType(_BaseFloatType): + """ + The type for double-precision floats. + """ + null = '0.0' + intrinsic_name = 'f64' + + def __str__(self): + return 'double' + + def format_constant(self, value): + return _format_double(value) + + +for _cls in (HalfType, FloatType, DoubleType): + _cls._create_instance() + + +class _Repeat(object): + def __init__(self, value, size): + self.value = value + self.size = size + + def __len__(self): + return self.size + + def __getitem__(self, item): + if 0 <= item < self.size: + return self.value + else: + raise IndexError(item) + + +class VectorType(Type): + """ + The type for vectors of primitive data items (e.g. ""). + """ + + def __init__(self, element, count): + self.element = element + self.count = count + + @property + def elements(self): + return _Repeat(self.element, self.count) + + def __len__(self): + return self.count + + def _to_string(self): + return "<%d x %s>" % (self.count, self.element) + + def __eq__(self, other): + if isinstance(other, VectorType): + return self.element == other.element and self.count == other.count + + def __hash__(self): + # TODO: why does this not take self.element/self.count into account? + return hash(VectorType) + + def __copy__(self): + return self + + def format_constant(self, value): + itemstring = ", " .join(["{0} {1}".format(x.type, x.get_reference()) + for x in value]) + return "<{0}>".format(itemstring) + + def wrap_constant_value(self, values): + from . import Value, Constant + if not isinstance(values, (list, tuple)): + if isinstance(values, Constant): + if values.type != self.element: + raise TypeError("expected {} for {}".format( + self.element, values.type)) + return (values, ) * self.count + return (Constant(self.element, values), ) * self.count + if len(values) != len(self): + raise ValueError("wrong constant size for %s: got %d elements" + % (self, len(values))) + return [Constant(ty, val) if not isinstance(val, Value) else val + for ty, val in zip(self.elements, values)] + + +class Aggregate(Type): + """ + Base class for aggregate types. + See http://llvm.org/docs/LangRef.html#t-aggregate + """ + + def wrap_constant_value(self, values): + from . import Value, Constant + + if not isinstance(values, (list, tuple)): + return values + if len(values) != len(self): + raise ValueError("wrong constant size for %s: got %d elements" + % (self, len(values))) + return [Constant(ty, val) if not isinstance(val, Value) else val + for ty, val in zip(self.elements, values)] + + +class ArrayType(Aggregate): + """ + The type for fixed-size homogenous arrays (e.g. "[f32 x 3]"). + """ + + def __init__(self, element, count): + self.element = element + self.count = count + + @property + def elements(self): + return _Repeat(self.element, self.count) + + def __len__(self): + return self.count + + def _to_string(self): + return "[%d x %s]" % (self.count, self.element) + + def __eq__(self, other): + if isinstance(other, ArrayType): + return self.element == other.element and self.count == other.count + + def __hash__(self): + return hash(ArrayType) + + def gep(self, i): + """ + Resolve the type of the i-th element (for getelementptr lookups). + """ + if not isinstance(i.type, IntType): + raise TypeError(i.type) + return self.element + + def format_constant(self, value): + itemstring = ", " .join(["{0} {1}".format(x.type, x.get_reference()) + for x in value]) + return "[{0}]".format(itemstring) + + +class BaseStructType(Aggregate): + """ + The base type for heterogenous struct types. + """ + _packed = False + + @property + def packed(self): + """ + A boolean attribute that indicates whether the structure uses + packed layout. + """ + return self._packed + + @packed.setter + def packed(self, val): + self._packed = bool(val) + + def __len__(self): + assert self.elements is not None + return len(self.elements) + + def __iter__(self): + assert self.elements is not None + return iter(self.elements) + + @property + def is_opaque(self): + return self.elements is None + + def structure_repr(self): + """ + Return the LLVM IR for the structure representation + """ + ret = '{%s}' % ', '.join([str(x) for x in self.elements]) + return self._wrap_packed(ret) + + def format_constant(self, value): + itemstring = ", " .join(["{0} {1}".format(x.type, x.get_reference()) + for x in value]) + ret = "{{{0}}}".format(itemstring) + return self._wrap_packed(ret) + + def gep(self, i): + """ + Resolve the type of the i-th element (for getelementptr lookups). + + *i* needs to be a LLVM constant, so that the type can be determined + at compile-time. + """ + if not isinstance(i.type, IntType): + raise TypeError(i.type) + return self.elements[i.constant] + + def _wrap_packed(self, textrepr): + """ + Internal helper to wrap textual repr of struct type into packed struct + """ + if self.packed: + return '<{}>'.format(textrepr) + else: + return textrepr + + +class LiteralStructType(BaseStructType): + """ + The type of "literal" structs, i.e. structs with a literally-defined + type (by contrast with IdentifiedStructType). + """ + + null = 'zeroinitializer' + + def __init__(self, elems, packed=False): + """ + *elems* is a sequence of types to be used as members. + *packed* controls the use of packed layout. + """ + self.elements = tuple(elems) + self.packed = packed + + def _to_string(self): + return self.structure_repr() + + def __eq__(self, other): + if isinstance(other, LiteralStructType): + return self.elements == other.elements + + def __hash__(self): + return hash(LiteralStructType) + + +class IdentifiedStructType(BaseStructType): + """ + A type which is a named alias for another struct type, akin to a typedef. + While literal struct types can be structurally equal (see + LiteralStructType), identified struct types are compared by name. + + Do not use this directly. + """ + null = 'zeroinitializer' + + def __init__(self, context, name, packed=False): + """ + *context* is a llvmlite.ir.Context. + *name* is the identifier for the new struct type. + *packed* controls the use of packed layout. + """ + assert name + self.context = context + self.name = name + self.elements = None + self.packed = packed + + def _to_string(self): + return "%{name}".format(name=_wrapname(self.name)) + + def get_declaration(self): + """ + Returns the string for the declaration of the type + """ + if self.is_opaque: + out = "{strrep} = type opaque".format(strrep=str(self)) + else: + out = "{strrep} = type {struct}".format( + strrep=str(self), struct=self.structure_repr()) + return out + + def __eq__(self, other): + if isinstance(other, IdentifiedStructType): + return self.name == other.name + + def __hash__(self): + return hash(IdentifiedStructType) + + def set_body(self, *elems): + if not self.is_opaque: + raise RuntimeError("{name} is already defined".format( + name=self.name)) + self.elements = tuple(elems) diff --git a/lib/python3.11/site-packages/llvmlite/ir/values.py b/lib/python3.11/site-packages/llvmlite/ir/values.py new file mode 100644 index 0000000000000000000000000000000000000000..93431210da4a81346deedd01ce4dbefc969898e0 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/ir/values.py @@ -0,0 +1,1217 @@ +""" +Classes that are LLVM values: Value, Constant... +Instructions are in the instructions module. +""" + +import functools +import string +import re +from types import MappingProxyType + +from llvmlite.ir import values, types, _utils +from llvmlite.ir._utils import (_StrCaching, _StringReferenceCaching, + _HasMetadata) + +_VALID_CHARS = (frozenset(map(ord, string.ascii_letters)) | + frozenset(map(ord, string.digits)) | + frozenset(map(ord, ' !#$%&\'()*+,-./:;<=>?@[]^_`{|}~'))) + +_SIMPLE_IDENTIFIER_RE = re.compile(r"[-a-zA-Z$._][-a-zA-Z$._0-9]*$") + +_CMP_MAP = { + '>': 'gt', + '<': 'lt', + '==': 'eq', + '!=': 'ne', + '>=': 'ge', + '<=': 'le', +} + + +def _escape_string(text, _map={}): + """ + Escape the given bytestring for safe use as a LLVM array constant. + Any unicode string input is first encoded with utf8 into bytes. + """ + if isinstance(text, str): + text = text.encode() + assert isinstance(text, (bytes, bytearray)) + + if not _map: + for ch in range(256): + if ch in _VALID_CHARS: + _map[ch] = chr(ch) + else: + _map[ch] = '\\%02x' % ch + + buf = [_map[ch] for ch in text] + return ''.join(buf) + + +def _binop(opname): + def wrap(fn): + @functools.wraps(fn) + def wrapped(lhs, rhs): + if lhs.type != rhs.type: + raise ValueError("Operands must be the same type, got (%s, %s)" + % (lhs.type, rhs.type)) + + fmt = "{0} ({1} {2}, {3} {4})".format(opname, + lhs.type, lhs.get_reference(), + rhs.type, rhs.get_reference()) + return FormattedConstant(lhs.type, fmt) + + return wrapped + return wrap + + +def _castop(opname): + def wrap(fn): + @functools.wraps(fn) + def wrapped(self, typ): + fn(self, typ) + if typ == self.type: + return self + + op = "{0} ({1} {2} to {3})".format(opname, self.type, + self.get_reference(), typ) + return FormattedConstant(typ, op) + + return wrapped + return wrap + + +class _ConstOpMixin(object): + """ + A mixin defining constant operations, for use in constant-like classes. + """ + + # + # Arithmetic APIs + # + + @_binop('shl') + def shl(self, other): + """ + Left integer shift: + lhs << rhs + """ + + @_binop('lshr') + def lshr(self, other): + """ + Logical (unsigned) right integer shift: + lhs >> rhs + """ + + @_binop('ashr') + def ashr(self, other): + """ + Arithmetic (signed) right integer shift: + lhs >> rhs + """ + + @_binop('add') + def add(self, other): + """ + Integer addition: + lhs + rhs + """ + + @_binop('fadd') + def fadd(self, other): + """ + Floating-point addition: + lhs + rhs + """ + + @_binop('sub') + def sub(self, other): + """ + Integer subtraction: + lhs - rhs + """ + + @_binop('fsub') + def fsub(self, other): + """ + Floating-point subtraction: + lhs - rhs + """ + + @_binop('mul') + def mul(self, other): + """ + Integer multiplication: + lhs * rhs + """ + + @_binop('fmul') + def fmul(self, other): + """ + Floating-point multiplication: + lhs * rhs + """ + + @_binop('udiv') + def udiv(self, other): + """ + Unsigned integer division: + lhs / rhs + """ + + @_binop('sdiv') + def sdiv(self, other): + """ + Signed integer division: + lhs / rhs + """ + + @_binop('fdiv') + def fdiv(self, other): + """ + Floating-point division: + lhs / rhs + """ + + @_binop('urem') + def urem(self, other): + """ + Unsigned integer remainder: + lhs % rhs + """ + + @_binop('srem') + def srem(self, other): + """ + Signed integer remainder: + lhs % rhs + """ + + @_binop('frem') + def frem(self, other): + """ + Floating-point remainder: + lhs % rhs + """ + + @_binop('or') + def or_(self, other): + """ + Bitwise integer OR: + lhs | rhs + """ + + @_binop('and') + def and_(self, other): + """ + Bitwise integer AND: + lhs & rhs + """ + + @_binop('xor') + def xor(self, other): + """ + Bitwise integer XOR: + lhs ^ rhs + """ + + def _cmp(self, prefix, sign, cmpop, other): + ins = prefix + 'cmp' + try: + op = _CMP_MAP[cmpop] + except KeyError: + raise ValueError("invalid comparison %r for %s" % (cmpop, ins)) + + if not (prefix == 'i' and cmpop in ('==', '!=')): + op = sign + op + + if self.type != other.type: + raise ValueError("Operands must be the same type, got (%s, %s)" + % (self.type, other.type)) + + fmt = "{0} {1} ({2} {3}, {4} {5})".format( + ins, op, + self.type, self.get_reference(), + other.type, other.get_reference()) + + return FormattedConstant(types.IntType(1), fmt) + + def icmp_signed(self, cmpop, other): + """ + Signed integer comparison: + lhs rhs + + where cmpop can be '==', '!=', '<', '<=', '>', '>=' + """ + return self._cmp('i', 's', cmpop, other) + + def icmp_unsigned(self, cmpop, other): + """ + Unsigned integer (or pointer) comparison: + lhs rhs + + where cmpop can be '==', '!=', '<', '<=', '>', '>=' + """ + return self._cmp('i', 'u', cmpop, other) + + def fcmp_ordered(self, cmpop, other): + """ + Floating-point ordered comparison: + lhs rhs + + where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno' + """ + return self._cmp('f', 'o', cmpop, other) + + def fcmp_unordered(self, cmpop, other): + """ + Floating-point unordered comparison: + lhs rhs + + where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno' + """ + return self._cmp('f', 'u', cmpop, other) + + # + # Unary APIs + # + + def not_(self): + """ + Bitwise integer complement: + ~value + """ + if isinstance(self.type, types.VectorType): + rhs = values.Constant(self.type, (-1,) * self.type.count) + else: + rhs = values.Constant(self.type, -1) + + return self.xor(rhs) + + def neg(self): + """ + Integer negative: + -value + """ + zero = values.Constant(self.type, 0) + return zero.sub(self) + + def fneg(self): + """ + Floating-point negative: + -value + """ + fmt = "fneg ({0} {1})".format(self.type, self.get_reference()) + return FormattedConstant(self.type, fmt) + + # + # Cast APIs + # + + @_castop('trunc') + def trunc(self, typ): + """ + Truncating integer downcast to a smaller type. + """ + + @_castop('zext') + def zext(self, typ): + """ + Zero-extending integer upcast to a larger type + """ + + @_castop('sext') + def sext(self, typ): + """ + Sign-extending integer upcast to a larger type. + """ + + @_castop('fptrunc') + def fptrunc(self, typ): + """ + Floating-point downcast to a less precise type. + """ + + @_castop('fpext') + def fpext(self, typ): + """ + Floating-point upcast to a more precise type. + """ + + @_castop('bitcast') + def bitcast(self, typ): + """ + Pointer cast to a different pointer type. + """ + + @_castop('fptoui') + def fptoui(self, typ): + """ + Convert floating-point to unsigned integer. + """ + + @_castop('uitofp') + def uitofp(self, typ): + """ + Convert unsigned integer to floating-point. + """ + + @_castop('fptosi') + def fptosi(self, typ): + """ + Convert floating-point to signed integer. + """ + + @_castop('sitofp') + def sitofp(self, typ): + """ + Convert signed integer to floating-point. + """ + + @_castop('ptrtoint') + def ptrtoint(self, typ): + """ + Cast pointer to integer. + """ + if not isinstance(self.type, types.PointerType): + msg = "can only call ptrtoint() on pointer type, not '%s'" + raise TypeError(msg % (self.type,)) + if not isinstance(typ, types.IntType): + raise TypeError("can only ptrtoint() to integer type, not '%s'" + % (typ,)) + + @_castop('inttoptr') + def inttoptr(self, typ): + """ + Cast integer to pointer. + """ + if not isinstance(self.type, types.IntType): + msg = "can only call inttoptr() on integer constants, not '%s'" + raise TypeError(msg % (self.type,)) + if not isinstance(typ, types.PointerType): + raise TypeError("can only inttoptr() to pointer type, not '%s'" + % (typ,)) + + def gep(self, indices): + """ + Call getelementptr on this pointer constant. + """ + if not isinstance(self.type, types.PointerType): + raise TypeError("can only call gep() on pointer constants, not '%s'" + % (self.type,)) + + outtype = self.type + for i in indices: + outtype = outtype.gep(i) + + strindices = ["{0} {1}".format(idx.type, idx.get_reference()) + for idx in indices] + + op = "getelementptr ({0}, {1} {2}, {3})".format( + self.type.pointee, self.type, + self.get_reference(), ', '.join(strindices)) + return FormattedConstant(outtype.as_pointer(self.addrspace), op) + + +class Value(object): + """ + The base class for all values. + """ + + def __repr__(self): + return "" % (self.__class__.__name__, self.type,) + + +class _Undefined(object): + """ + 'undef': a value for undefined values. + """ + def __new__(cls): + try: + return Undefined + except NameError: + return object.__new__(_Undefined) + + +Undefined = _Undefined() + + +class Constant(_StrCaching, _StringReferenceCaching, _ConstOpMixin, Value): + """ + A constant LLVM value. + """ + + def __init__(self, typ, constant): + assert isinstance(typ, types.Type) + assert not isinstance(typ, types.VoidType) + self.type = typ + constant = typ.wrap_constant_value(constant) + self.constant = constant + + def _to_string(self): + return '{0} {1}'.format(self.type, self.get_reference()) + + def _get_reference(self): + if self.constant is None: + val = self.type.null + + elif self.constant is Undefined: + val = "undef" + + elif isinstance(self.constant, bytearray): + val = 'c"{0}"'.format(_escape_string(self.constant)) + + else: + val = self.type.format_constant(self.constant) + + return val + + @classmethod + def literal_array(cls, elems): + """ + Construct a literal array constant made of the given members. + """ + tys = [el.type for el in elems] + if len(tys) == 0: + raise ValueError("need at least one element") + ty = tys[0] + for other in tys: + if ty != other: + raise TypeError("all elements must have the same type") + return cls(types.ArrayType(ty, len(elems)), elems) + + @classmethod + def literal_struct(cls, elems): + """ + Construct a literal structure constant made of the given members. + """ + tys = [el.type for el in elems] + return cls(types.LiteralStructType(tys), elems) + + @property + def addrspace(self): + if not isinstance(self.type, types.PointerType): + raise TypeError("Only pointer constant have address spaces") + return self.type.addrspace + + def __eq__(self, other): + if isinstance(other, Constant): + return str(self) == str(other) + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(str(self)) + + def __repr__(self): + return "" % (self.type, self.constant) + + +class FormattedConstant(Constant): + """ + A constant with an already formatted IR representation. + """ + + def __init__(self, typ, constant): + assert isinstance(constant, str) + Constant.__init__(self, typ, constant) + + def _to_string(self): + return self.constant + + def _get_reference(self): + return self.constant + + +class NamedValue(_StrCaching, _StringReferenceCaching, Value): + """ + The base class for named values. + """ + name_prefix = '%' + deduplicate_name = True + + def __init__(self, parent, type, name): + assert parent is not None + assert isinstance(type, types.Type) + self.parent = parent + self.type = type + self._set_name(name) + + def _to_string(self): + buf = [] + if not isinstance(self.type, types.VoidType): + buf.append("{0} = ".format(self.get_reference())) + self.descr(buf) + return "".join(buf).rstrip() + + def descr(self, buf): + raise NotImplementedError + + def _get_name(self): + return self._name + + def _set_name(self, name): + name = self.parent.scope.register(name, + deduplicate=self.deduplicate_name) + self._name = name + + name = property(_get_name, _set_name) + + def _get_reference(self): + name = self.name + # Quote and escape value name + if '\\' in name or '"' in name: + name = name.replace('\\', '\\5c').replace('"', '\\22') + return '{0}"{1}"'.format(self.name_prefix, name) + + def __repr__(self): + return "" % ( + self.__class__.__name__, self.name, self.type) + + @property + def function_type(self): + ty = self.type + if isinstance(ty, types.PointerType): + ty = self.type.pointee + if isinstance(ty, types.FunctionType): + return ty + else: + raise TypeError("Not a function: {0}".format(self.type)) + + +class MetaDataString(NamedValue): + """ + A metadata string, i.e. a constant string used as a value in a metadata + node. + """ + + def __init__(self, parent, string): + super(MetaDataString, self).__init__(parent, + types.MetaDataType(), + name="") + self.string = string + + def descr(self, buf): + buf += (self.get_reference(), "\n") + + def _get_reference(self): + return '!"{0}"'.format(_escape_string(self.string)) + + _to_string = _get_reference + + def __eq__(self, other): + if isinstance(other, MetaDataString): + return self.string == other.string + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.string) + + +class MetaDataArgument(_StrCaching, _StringReferenceCaching, Value): + """ + An argument value to a function taking metadata arguments. + This can wrap any other kind of LLVM value. + + Do not instantiate directly, Builder.call() will create these + automatically. + """ + + def __init__(self, value): + assert isinstance(value, Value) + assert not isinstance(value.type, types.MetaDataType) + self.type = types.MetaDataType() + self.wrapped_value = value + + def _get_reference(self): + # e.g. "i32* %2" + return "{0} {1}".format(self.wrapped_value.type, + self.wrapped_value.get_reference()) + + _to_string = _get_reference + + +class NamedMetaData(object): + """ + A named metadata node. + + Do not instantiate directly, use Module.add_named_metadata() instead. + """ + + def __init__(self, parent): + self.parent = parent + self.operands = [] + + def add(self, md): + self.operands.append(md) + + +class MDValue(NamedValue): + """ + A metadata node's value, consisting of a sequence of elements ("operands"). + + Do not instantiate directly, use Module.add_metadata() instead. + """ + name_prefix = '!' + + def __init__(self, parent, values, name): + super(MDValue, self).__init__(parent, + types.MetaDataType(), + name=name) + self.operands = tuple(values) + parent.metadata.append(self) + + def descr(self, buf): + operands = [] + for op in self.operands: + if isinstance(op.type, types.MetaDataType): + if isinstance(op, Constant) and op.constant is None: + operands.append("null") + else: + operands.append(op.get_reference()) + else: + operands.append("{0} {1}".format(op.type, op.get_reference())) + operands = ', '.join(operands) + buf += ("!{{ {0} }}".format(operands), "\n") + + def _get_reference(self): + return self.name_prefix + str(self.name) + + def __eq__(self, other): + if isinstance(other, MDValue): + return self.operands == other.operands + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.operands) + + +class DIToken: + """ + A debug information enumeration value that should appear bare in + the emitted metadata. + + Use this to wrap known constants, e.g. the DW_* enumerations. + """ + + def __init__(self, value): + self.value = value + + +class DIValue(NamedValue): + """ + A debug information descriptor, containing key-value pairs. + + Do not instantiate directly, use Module.add_debug_info() instead. + """ + name_prefix = '!' + + def __init__(self, parent, is_distinct, kind, operands, name): + super(DIValue, self).__init__(parent, + types.MetaDataType(), + name=name) + self.is_distinct = is_distinct + self.kind = kind + self.operands = tuple(operands) + parent.metadata.append(self) + + def descr(self, buf): + if self.is_distinct: + buf += ("distinct ",) + operands = [] + for key, value in self.operands: + if value is None: + strvalue = "null" + elif value is True: + strvalue = "true" + elif value is False: + strvalue = "false" + elif isinstance(value, DIToken): + strvalue = value.value + elif isinstance(value, str): + strvalue = '"{}"'.format(_escape_string(value)) + elif isinstance(value, int): + strvalue = str(value) + elif isinstance(value, NamedValue): + strvalue = value.get_reference() + else: + raise TypeError("invalid operand type for debug info: %r" + % (value,)) + operands.append("{0}: {1}".format(key, strvalue)) + operands = ', '.join(operands) + buf += ("!", self.kind, "(", operands, ")\n") + + def _get_reference(self): + return self.name_prefix + str(self.name) + + def __eq__(self, other): + if isinstance(other, DIValue): + return self.is_distinct == other.is_distinct and \ + self.kind == other.kind and \ + self.operands == other.operands + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash((self.is_distinct, self.kind, self.operands)) + + +class GlobalValue(NamedValue, _ConstOpMixin, _HasMetadata): + """ + A global value. + """ + name_prefix = '@' + deduplicate_name = False + + def __init__(self, *args, **kwargs): + super(GlobalValue, self).__init__(*args, **kwargs) + self.linkage = '' + self.storage_class = '' + self.section = '' + self.metadata = {} + + +class GlobalVariable(GlobalValue): + """ + A global variable. + """ + + def __init__(self, module, typ, name, addrspace=0): + assert isinstance(typ, types.Type) + super(GlobalVariable, self).__init__(module, typ.as_pointer(addrspace), + name=name) + self.value_type = typ + self.initializer = None + self.unnamed_addr = False + self.global_constant = False + self.addrspace = addrspace + self.align = None + self.parent.add_global(self) + + def descr(self, buf): + if self.global_constant: + kind = 'constant' + else: + kind = 'global' + + if not self.linkage: + # Default to external linkage + linkage = 'external' if self.initializer is None else '' + else: + linkage = self.linkage + + if linkage: + buf.append(linkage + " ") + if self.storage_class: + buf.append(self.storage_class + " ") + if self.unnamed_addr: + buf.append("unnamed_addr ") + if self.addrspace != 0: + buf.append('addrspace({0:d}) '.format(self.addrspace)) + + buf.append("{kind} {type}" .format(kind=kind, type=self.value_type)) + + if self.initializer is not None: + if self.initializer.type != self.value_type: + raise TypeError("got initializer of type %s " + "for global value type %s" + % (self.initializer.type, self.value_type)) + buf.append(" " + self.initializer.get_reference()) + elif linkage not in ('external', 'extern_weak'): + # emit 'undef' for non-external linkage GV + buf.append(" " + self.value_type(Undefined).get_reference()) + + if self.section: + buf.append(", section \"%s\"" % (self.section,)) + + if self.align is not None: + buf.append(", align %d" % (self.align,)) + + if self.metadata: + buf.append(self._stringify_metadata(leading_comma=True)) + + buf.append("\n") + + +class AttributeSet(set): + """A set of string attribute. + Only accept items listed in *_known*. + + Properties: + * Iterate in sorted order + """ + _known = () + + def __init__(self, args=()): + super().__init__() + if isinstance(args, str): + args = [args] + for name in args: + self.add(name) + + def _expand(self, name, typ): + return name + + def add(self, name): + if name not in self._known: + raise ValueError('unknown attr {!r} for {}'.format(name, self)) + return super(AttributeSet, self).add(name) + + def _to_list(self, typ): + return [self._expand(i, typ) for i in sorted(self)] + + +class FunctionAttributes(AttributeSet): + _known = frozenset([ + 'argmemonly', 'alwaysinline', 'builtin', 'cold', + 'inaccessiblememonly', 'inaccessiblemem_or_argmemonly', 'inlinehint', + 'jumptable', 'minsize', 'naked', 'nobuiltin', 'noduplicate', + 'noimplicitfloat', 'noinline', 'nonlazybind', 'norecurse', + 'noredzone', 'noreturn', 'nounwind', 'optnone', 'optsize', + 'readnone', 'readonly', 'returns_twice', 'sanitize_address', + 'sanitize_memory', 'sanitize_thread', 'ssp', + 'sspreg', 'sspstrong', 'uwtable']) + + def __init__(self, args=()): + self._alignstack = 0 + self._personality = None + super(FunctionAttributes, self).__init__(args) + + def add(self, name): + if ((name == 'alwaysinline' and 'noinline' in self) or + (name == 'noinline' and 'alwaysinline' in self)): + raise ValueError("Can't have alwaysinline and noinline") + + super().add(name) + + @property + def alignstack(self): + return self._alignstack + + @alignstack.setter + def alignstack(self, val): + assert val >= 0 + self._alignstack = val + + @property + def personality(self): + return self._personality + + @personality.setter + def personality(self, val): + assert val is None or isinstance(val, GlobalValue) + self._personality = val + + def _to_list(self, ret_type): + attrs = super()._to_list(ret_type) + if self.alignstack: + attrs.append('alignstack({0:d})'.format(self.alignstack)) + if self.personality: + attrs.append('personality {persty} {persfn}'.format( + persty=self.personality.type, + persfn=self.personality.get_reference())) + return attrs + + +class Function(GlobalValue): + """Represent a LLVM Function but does uses a Module as parent. + Global Values are stored as a set of dependencies (attribute `depends`). + """ + + def __init__(self, module, ftype, name): + assert isinstance(ftype, types.Type) + super(Function, self).__init__(module, ftype.as_pointer(), name=name) + self.ftype = ftype + self.scope = _utils.NameScope() + self.blocks = [] + self.attributes = FunctionAttributes() + self.args = tuple([Argument(self, t) + for t in ftype.args]) + self.return_value = ReturnValue(self, ftype.return_type) + self.parent.add_global(self) + self.calling_convention = '' + + @property + def module(self): + return self.parent + + @property + def entry_basic_block(self): + return self.blocks[0] + + @property + def basic_blocks(self): + return self.blocks + + def append_basic_block(self, name=''): + blk = Block(parent=self, name=name) + self.blocks.append(blk) + return blk + + def insert_basic_block(self, before, name=''): + """Insert block before + """ + blk = Block(parent=self, name=name) + self.blocks.insert(before, blk) + return blk + + def descr_prototype(self, buf): + """ + Describe the prototype ("head") of the function. + """ + state = "define" if self.blocks else "declare" + ret = self.return_value + args = ", ".join(str(a) for a in self.args) + name = self.get_reference() + attrs = ' ' + ' '.join(self.attributes._to_list( + self.ftype.return_type)) if self.attributes else '' + if any(self.args): + vararg = ', ...' if self.ftype.var_arg else '' + else: + vararg = '...' if self.ftype.var_arg else '' + linkage = self.linkage + cconv = self.calling_convention + prefix = " ".join(str(x) for x in [state, linkage, cconv, ret] if x) + metadata = self._stringify_metadata() + metadata = ' {}'.format(metadata) if metadata else '' + section = ' section "{}"'.format(self.section) if self.section else '' + pt_str = "{prefix} {name}({args}{vararg}){attrs}{section}{metadata}\n" + prototype = pt_str.format(prefix=prefix, name=name, args=args, + vararg=vararg, attrs=attrs, section=section, + metadata=metadata) + buf.append(prototype) + + def descr_body(self, buf): + """ + Describe of the body of the function. + """ + for blk in self.blocks: + blk.descr(buf) + + def descr(self, buf): + self.descr_prototype(buf) + if self.blocks: + buf.append("{\n") + self.descr_body(buf) + buf.append("}\n") + + def __str__(self): + buf = [] + self.descr(buf) + return "".join(buf) + + @property + def is_declaration(self): + return len(self.blocks) == 0 + + +class ArgumentAttributes(AttributeSet): + # List from + # https://releases.llvm.org/14.0.0/docs/LangRef.html#parameter-attributes + _known = MappingProxyType({ + # True (emit type), + # False (emit name only) + 'byref': True, + 'byval': True, + 'elementtype': True, + 'immarg': False, + 'inalloca': True, + 'inreg': False, + 'nest': False, + 'noalias': False, + 'nocapture': False, + 'nofree': False, + 'nonnull': False, + 'noundef': False, + 'preallocated': True, + 'returned': False, + 'signext': False, + 'sret': True, + 'swiftasync': False, + 'swifterror': False, + 'swiftself': False, + 'zeroext': False, + }) + + def __init__(self, args=()): + self._align = 0 + self._dereferenceable = 0 + self._dereferenceable_or_null = 0 + super(ArgumentAttributes, self).__init__(args) + + def _expand(self, name, typ): + requires_type = self._known.get(name) + if requires_type: + return f"{name}({typ.pointee})" + else: + return name + + @property + def align(self): + return self._align + + @align.setter + def align(self, val): + assert isinstance(val, int) and val >= 0 + self._align = val + + @property + def dereferenceable(self): + return self._dereferenceable + + @dereferenceable.setter + def dereferenceable(self, val): + assert isinstance(val, int) and val >= 0 + self._dereferenceable = val + + @property + def dereferenceable_or_null(self): + return self._dereferenceable_or_null + + @dereferenceable_or_null.setter + def dereferenceable_or_null(self, val): + assert isinstance(val, int) and val >= 0 + self._dereferenceable_or_null = val + + def _to_list(self, typ): + attrs = super()._to_list(typ) + if self.align: + attrs.append('align {0:d}'.format(self.align)) + if self.dereferenceable: + attrs.append('dereferenceable({0:d})'.format(self.dereferenceable)) + if self.dereferenceable_or_null: + dref = 'dereferenceable_or_null({0:d})' + attrs.append(dref.format(self.dereferenceable_or_null)) + return attrs + + +class _BaseArgument(NamedValue): + def __init__(self, parent, typ, name=''): + assert isinstance(typ, types.Type) + super(_BaseArgument, self).__init__(parent, typ, name=name) + self.parent = parent + self.attributes = ArgumentAttributes() + + def __repr__(self): + return "" % (self.__class__.__name__, self.name, + self.type) + + def add_attribute(self, attr): + self.attributes.add(attr) + + +class Argument(_BaseArgument): + """ + The specification of a function argument. + """ + + def __str__(self): + attrs = self.attributes._to_list(self.type) + if attrs: + return "{0} {1} {2}".format(self.type, ' '.join(attrs), + self.get_reference()) + else: + return "{0} {1}".format(self.type, self.get_reference()) + + +class ReturnValue(_BaseArgument): + """ + The specification of a function's return value. + """ + + def __str__(self): + attrs = self.attributes._to_list(self.type) + if attrs: + return "{0} {1}".format(' '.join(attrs), self.type) + else: + return str(self.type) + + +class Block(NamedValue): + """ + A LLVM IR basic block. A basic block is a sequence of + instructions whose execution always goes from start to end. That + is, a control flow instruction (branch) can only appear as the + last instruction, and incoming branches can only jump to the first + instruction. + """ + + def __init__(self, parent, name=''): + super(Block, self).__init__(parent, types.LabelType(), name=name) + self.scope = parent.scope + self.instructions = [] + self.terminator = None + + @property + def is_terminated(self): + return self.terminator is not None + + @property + def function(self): + return self.parent + + @property + def module(self): + return self.parent.module + + def descr(self, buf): + buf.append("{0}:\n".format(self._format_name())) + buf += [" {0}\n".format(instr) for instr in self.instructions] + + def replace(self, old, new): + """Replace an instruction""" + if old.type != new.type: + raise TypeError("new instruction has a different type") + pos = self.instructions.index(old) + self.instructions.remove(old) + self.instructions.insert(pos, new) + + for bb in self.parent.basic_blocks: + for instr in bb.instructions: + instr.replace_usage(old, new) + + def _format_name(self): + # Per the LLVM Language Ref on identifiers, names matching the following + # regex do not need to be quoted: [%@][-a-zA-Z$._][-a-zA-Z$._0-9]* + # Otherwise, the identifier must be quoted and escaped. + name = self.name + if not _SIMPLE_IDENTIFIER_RE.match(name): + name = name.replace('\\', '\\5c').replace('"', '\\22') + name = '"{0}"'.format(name) + return name + + +class BlockAddress(Value): + """ + The address of a basic block. + """ + + def __init__(self, function, basic_block): + assert isinstance(function, Function) + assert isinstance(basic_block, Block) + self.type = types.IntType(8).as_pointer() + self.function = function + self.basic_block = basic_block + + def __str__(self): + return '{0} {1}'.format(self.type, self.get_reference()) + + def get_reference(self): + return "blockaddress({0}, {1})".format( + self.function.get_reference(), + self.basic_block.get_reference()) diff --git a/lib/python3.11/site-packages/llvmlite/tests/__init__.py b/lib/python3.11/site-packages/llvmlite/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7f2b3b082d2722e587263fb4ce5307287715a1d5 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/tests/__init__.py @@ -0,0 +1,57 @@ +import sys + +import unittest +from unittest import TestCase + +import faulthandler + + +try: + # May fail in IPython Notebook with UnsupportedOperation + faulthandler.enable() +except BaseException as e: + msg = "Failed to enable faulthandler due to:\n{err}" + warnings.warn(msg.format(err=e)) + + +# Try to inject Numba's unittest customizations. +from llvmlite.tests import customize + + +def discover_tests(startdir): + """Discover test under a directory + """ + # Avoid importing unittest + loader = unittest.TestLoader() + suite = loader.discover(startdir) + return suite + + +def run_tests(suite=None, xmloutput=None, verbosity=1): + """ + args + ---- + - suite [TestSuite] + A suite of all tests to run + - xmloutput [str or None] + Path of XML output directory (optional) + - verbosity [int] + Verbosity level of tests output + + Returns the TestResult object after running the test *suite*. + """ + if suite is None: + suite = discover_tests("llvmlite.tests") + if xmloutput is not None: + import xmlrunner + runner = xmlrunner.XMLTestRunner(output=xmloutput) + else: + runner = None + prog = unittest.main(suite=suite, testRunner=runner, exit=False, + verbosity=verbosity) + return prog.result + + +def main(): + res = run_tests() + sys.exit(0 if res.wasSuccessful() else 1) diff --git a/lib/python3.11/site-packages/llvmlite/tests/__main__.py b/lib/python3.11/site-packages/llvmlite/tests/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..97563d18687da90316eef738c8aa3ffbacec4007 --- /dev/null +++ b/lib/python3.11/site-packages/llvmlite/tests/__main__.py @@ -0,0 +1,3 @@ +from llvmlite.tests import main + +main() diff --git a/lib/python3.11/site-packages/llvmlite/tests/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/tests/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8179f1b85483a6f6131c700f52cdf9dc7b402f2a Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/tests/__pycache__/__init__.cpython-311.pyc differ diff --git a/lib/python3.11/site-packages/llvmlite/tests/__pycache__/__main__.cpython-311.pyc b/lib/python3.11/site-packages/llvmlite/tests/__pycache__/__main__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fdf251183ad135ab1ca9d25ad3c5263fb88c87c8 Binary files /dev/null and b/lib/python3.11/site-packages/llvmlite/tests/__pycache__/__main__.cpython-311.pyc differ