662f462e0f601fcce9aec0bf0aceeab3e0c0e219783432fa02431d37567ec282
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/ffi.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/initfini.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/linker.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/module.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/object_file.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/options.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/orcjit.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/passmanagers.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/targets.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/transforms.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/__pycache__/value.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/binding/analysis.py +69 -0
- lib/python3.11/site-packages/llvmlite/binding/common.py +34 -0
- lib/python3.11/site-packages/llvmlite/binding/context.py +29 -0
- lib/python3.11/site-packages/llvmlite/binding/dylib.py +45 -0
- lib/python3.11/site-packages/llvmlite/binding/executionengine.py +322 -0
- lib/python3.11/site-packages/llvmlite/binding/ffi.py +388 -0
- lib/python3.11/site-packages/llvmlite/binding/initfini.py +73 -0
- lib/python3.11/site-packages/llvmlite/binding/libllvmlite.dylib +3 -0
- lib/python3.11/site-packages/llvmlite/binding/linker.py +20 -0
- lib/python3.11/site-packages/llvmlite/binding/module.py +349 -0
- lib/python3.11/site-packages/llvmlite/binding/object_file.py +82 -0
- lib/python3.11/site-packages/llvmlite/binding/options.py +17 -0
- lib/python3.11/site-packages/llvmlite/binding/orcjit.py +342 -0
- lib/python3.11/site-packages/llvmlite/binding/passmanagers.py +923 -0
- lib/python3.11/site-packages/llvmlite/binding/targets.py +450 -0
- lib/python3.11/site-packages/llvmlite/binding/transforms.py +151 -0
- lib/python3.11/site-packages/llvmlite/binding/value.py +624 -0
- lib/python3.11/site-packages/llvmlite/ir/__init__.py +11 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/__init__.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/_utils.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/builder.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/context.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/instructions.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/module.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/transforms.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/types.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/__pycache__/values.cpython-311.pyc +0 -0
- lib/python3.11/site-packages/llvmlite/ir/_utils.py +80 -0
- lib/python3.11/site-packages/llvmlite/ir/builder.py +1119 -0
- lib/python3.11/site-packages/llvmlite/ir/context.py +20 -0
- lib/python3.11/site-packages/llvmlite/ir/instructions.py +893 -0
- lib/python3.11/site-packages/llvmlite/ir/module.py +246 -0
- lib/python3.11/site-packages/llvmlite/ir/transforms.py +64 -0
- lib/python3.11/site-packages/llvmlite/ir/types.py +614 -0
- lib/python3.11/site-packages/llvmlite/ir/values.py +1217 -0
- lib/python3.11/site-packages/llvmlite/tests/__init__.py +57 -0
- lib/python3.11/site-packages/llvmlite/tests/__main__.py +3 -0
- lib/python3.11/site-packages/llvmlite/tests/__pycache__/__init__.cpython-311.pyc +0 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
lib/python3.11/site-packages/llvmlite/binding/libllvmlite.dylib filter=lfs diff=lfs merge=lfs -text
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/ffi.cpython-311.pyc
ADDED
Binary file (20.4 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/initfini.cpython-311.pyc
ADDED
Binary file (3.43 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/linker.cpython-311.pyc
ADDED
Binary file (1.27 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/module.cpython-311.pyc
ADDED
Binary file (19.9 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/object_file.cpython-311.pyc
ADDED
Binary file (6.11 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/options.cpython-311.pyc
ADDED
Binary file (1.01 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/orcjit.cpython-311.pyc
ADDED
Binary file (18.3 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/passmanagers.cpython-311.pyc
ADDED
Binary file (49.6 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/targets.cpython-311.pyc
ADDED
Binary file (22.3 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/transforms.cpython-311.pyc
ADDED
Binary file (8.33 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/__pycache__/value.cpython-311.pyc
ADDED
Binary file (32.1 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/binding/analysis.py
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
A collection of analysis utilities
|
3 |
+
"""
|
4 |
+
|
5 |
+
from ctypes import POINTER, c_char_p, c_int
|
6 |
+
|
7 |
+
from llvmlite.binding import ffi
|
8 |
+
from llvmlite.binding.module import parse_assembly
|
9 |
+
|
10 |
+
|
11 |
+
def get_function_cfg(func, show_inst=True):
|
12 |
+
"""Return a string of the control-flow graph of the function in DOT
|
13 |
+
format. If the input `func` is not a materialized function, the module
|
14 |
+
containing the function is parsed to create an actual LLVM module.
|
15 |
+
The `show_inst` flag controls whether the instructions of each block
|
16 |
+
are printed.
|
17 |
+
"""
|
18 |
+
assert func is not None
|
19 |
+
from llvmlite import ir
|
20 |
+
if isinstance(func, ir.Function):
|
21 |
+
mod = parse_assembly(str(func.module))
|
22 |
+
func = mod.get_function(func.name)
|
23 |
+
|
24 |
+
# Assume func is a materialized function
|
25 |
+
with ffi.OutputString() as dotstr:
|
26 |
+
ffi.lib.LLVMPY_WriteCFG(func, dotstr, show_inst)
|
27 |
+
return str(dotstr)
|
28 |
+
|
29 |
+
|
30 |
+
def view_dot_graph(graph, filename=None, view=False):
|
31 |
+
"""
|
32 |
+
View the given DOT source. If view is True, the image is rendered
|
33 |
+
and viewed by the default application in the system. The file path of
|
34 |
+
the output is returned. If view is False, a graphviz.Source object is
|
35 |
+
returned. If view is False and the environment is in a IPython session,
|
36 |
+
an IPython image object is returned and can be displayed inline in the
|
37 |
+
notebook.
|
38 |
+
|
39 |
+
This function requires the graphviz package.
|
40 |
+
|
41 |
+
Args
|
42 |
+
----
|
43 |
+
- graph [str]: a DOT source code
|
44 |
+
- filename [str]: optional. if given and view is True, this specifies
|
45 |
+
the file path for the rendered output to write to.
|
46 |
+
- view [bool]: if True, opens the rendered output file.
|
47 |
+
|
48 |
+
"""
|
49 |
+
# Optionally depends on graphviz package
|
50 |
+
import graphviz as gv
|
51 |
+
|
52 |
+
src = gv.Source(graph)
|
53 |
+
if view:
|
54 |
+
# Returns the output file path
|
55 |
+
return src.render(filename, view=view)
|
56 |
+
else:
|
57 |
+
# Attempts to show the graph in IPython notebook
|
58 |
+
try:
|
59 |
+
__IPYTHON__
|
60 |
+
except NameError:
|
61 |
+
return src
|
62 |
+
else:
|
63 |
+
import IPython.display as display
|
64 |
+
format = 'svg'
|
65 |
+
return display.SVG(data=src.pipe(format))
|
66 |
+
|
67 |
+
|
68 |
+
# Ctypes binding
|
69 |
+
ffi.lib.LLVMPY_WriteCFG.argtypes = [ffi.LLVMValueRef, POINTER(c_char_p), c_int]
|
lib/python3.11/site-packages/llvmlite/binding/common.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import atexit
|
2 |
+
|
3 |
+
|
4 |
+
def _encode_string(s):
|
5 |
+
encoded = s.encode('utf-8')
|
6 |
+
return encoded
|
7 |
+
|
8 |
+
|
9 |
+
def _decode_string(b):
|
10 |
+
return b.decode('utf-8')
|
11 |
+
|
12 |
+
|
13 |
+
_encode_string.__doc__ = """Encode a string for use by LLVM."""
|
14 |
+
_decode_string.__doc__ = """Decode a LLVM character (byte)string."""
|
15 |
+
|
16 |
+
|
17 |
+
_shutting_down = [False]
|
18 |
+
|
19 |
+
|
20 |
+
def _at_shutdown():
|
21 |
+
_shutting_down[0] = True
|
22 |
+
|
23 |
+
|
24 |
+
atexit.register(_at_shutdown)
|
25 |
+
|
26 |
+
|
27 |
+
def _is_shutting_down(_shutting_down=_shutting_down):
|
28 |
+
"""
|
29 |
+
Whether the interpreter is currently shutting down.
|
30 |
+
For use in finalizers, __del__ methods, and similar; it is advised
|
31 |
+
to early bind this function rather than look it up when calling it,
|
32 |
+
since at shutdown module globals may be cleared.
|
33 |
+
"""
|
34 |
+
return _shutting_down[0]
|
lib/python3.11/site-packages/llvmlite/binding/context.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llvmlite.binding import ffi
|
2 |
+
|
3 |
+
|
4 |
+
def create_context():
|
5 |
+
return ContextRef(ffi.lib.LLVMPY_ContextCreate())
|
6 |
+
|
7 |
+
|
8 |
+
def get_global_context():
|
9 |
+
return GlobalContextRef(ffi.lib.LLVMPY_GetGlobalContext())
|
10 |
+
|
11 |
+
|
12 |
+
class ContextRef(ffi.ObjectRef):
|
13 |
+
def __init__(self, context_ptr):
|
14 |
+
super(ContextRef, self).__init__(context_ptr)
|
15 |
+
|
16 |
+
def _dispose(self):
|
17 |
+
ffi.lib.LLVMPY_ContextDispose(self)
|
18 |
+
|
19 |
+
|
20 |
+
class GlobalContextRef(ContextRef):
|
21 |
+
def _dispose(self):
|
22 |
+
pass
|
23 |
+
|
24 |
+
|
25 |
+
ffi.lib.LLVMPY_GetGlobalContext.restype = ffi.LLVMContextRef
|
26 |
+
|
27 |
+
ffi.lib.LLVMPY_ContextCreate.restype = ffi.LLVMContextRef
|
28 |
+
|
29 |
+
ffi.lib.LLVMPY_ContextDispose.argtypes = [ffi.LLVMContextRef]
|
lib/python3.11/site-packages/llvmlite/binding/dylib.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ctypes import c_void_p, c_char_p, c_bool, POINTER
|
2 |
+
|
3 |
+
from llvmlite.binding import ffi
|
4 |
+
from llvmlite.binding.common import _encode_string
|
5 |
+
|
6 |
+
|
7 |
+
def address_of_symbol(name):
|
8 |
+
"""
|
9 |
+
Get the in-process address of symbol named *name*.
|
10 |
+
An integer is returned, or None if the symbol isn't found.
|
11 |
+
"""
|
12 |
+
return ffi.lib.LLVMPY_SearchAddressOfSymbol(_encode_string(name))
|
13 |
+
|
14 |
+
|
15 |
+
def add_symbol(name, address):
|
16 |
+
"""
|
17 |
+
Register the *address* of global symbol *name*. This will make
|
18 |
+
it usable (e.g. callable) from LLVM-compiled functions.
|
19 |
+
"""
|
20 |
+
ffi.lib.LLVMPY_AddSymbol(_encode_string(name), c_void_p(address))
|
21 |
+
|
22 |
+
|
23 |
+
def load_library_permanently(filename):
|
24 |
+
"""
|
25 |
+
Load an external library
|
26 |
+
"""
|
27 |
+
with ffi.OutputString() as outerr:
|
28 |
+
if ffi.lib.LLVMPY_LoadLibraryPermanently(
|
29 |
+
_encode_string(filename), outerr):
|
30 |
+
raise RuntimeError(str(outerr))
|
31 |
+
|
32 |
+
# ============================================================================
|
33 |
+
# FFI
|
34 |
+
|
35 |
+
|
36 |
+
ffi.lib.LLVMPY_AddSymbol.argtypes = [
|
37 |
+
c_char_p,
|
38 |
+
c_void_p,
|
39 |
+
]
|
40 |
+
|
41 |
+
ffi.lib.LLVMPY_SearchAddressOfSymbol.argtypes = [c_char_p]
|
42 |
+
ffi.lib.LLVMPY_SearchAddressOfSymbol.restype = c_void_p
|
43 |
+
|
44 |
+
ffi.lib.LLVMPY_LoadLibraryPermanently.argtypes = [c_char_p, POINTER(c_char_p)]
|
45 |
+
ffi.lib.LLVMPY_LoadLibraryPermanently.restype = c_bool
|
lib/python3.11/site-packages/llvmlite/binding/executionengine.py
ADDED
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ctypes import (POINTER, c_char_p, c_bool, c_void_p,
|
2 |
+
c_int, c_uint64, c_size_t, CFUNCTYPE, string_at, cast,
|
3 |
+
py_object, Structure)
|
4 |
+
|
5 |
+
from llvmlite.binding import ffi, targets, object_file
|
6 |
+
|
7 |
+
|
8 |
+
# Just check these weren't optimized out of the DLL.
|
9 |
+
ffi.lib.LLVMPY_LinkInMCJIT
|
10 |
+
|
11 |
+
|
12 |
+
def create_mcjit_compiler(module, target_machine):
|
13 |
+
"""
|
14 |
+
Create a MCJIT ExecutionEngine from the given *module* and
|
15 |
+
*target_machine*.
|
16 |
+
"""
|
17 |
+
with ffi.OutputString() as outerr:
|
18 |
+
engine = ffi.lib.LLVMPY_CreateMCJITCompiler(
|
19 |
+
module, target_machine, outerr)
|
20 |
+
if not engine:
|
21 |
+
raise RuntimeError(str(outerr))
|
22 |
+
|
23 |
+
target_machine._owned = True
|
24 |
+
return ExecutionEngine(engine, module=module)
|
25 |
+
|
26 |
+
|
27 |
+
def check_jit_execution():
|
28 |
+
"""
|
29 |
+
Check the system allows execution of in-memory JITted functions.
|
30 |
+
An exception is raised otherwise.
|
31 |
+
"""
|
32 |
+
errno = ffi.lib.LLVMPY_TryAllocateExecutableMemory()
|
33 |
+
if errno != 0:
|
34 |
+
raise OSError(errno,
|
35 |
+
"cannot allocate executable memory. "
|
36 |
+
"This may be due to security restrictions on your "
|
37 |
+
"system, such as SELinux or similar mechanisms."
|
38 |
+
)
|
39 |
+
|
40 |
+
|
41 |
+
class ExecutionEngine(ffi.ObjectRef):
|
42 |
+
"""An ExecutionEngine owns all Modules associated with it.
|
43 |
+
Deleting the engine will remove all associated modules.
|
44 |
+
It is an error to delete the associated modules.
|
45 |
+
"""
|
46 |
+
_object_cache = None
|
47 |
+
|
48 |
+
def __init__(self, ptr, module):
|
49 |
+
"""
|
50 |
+
Module ownership is transferred to the EE
|
51 |
+
"""
|
52 |
+
self._modules = set([module])
|
53 |
+
self._td = None
|
54 |
+
module._owned = True
|
55 |
+
ffi.ObjectRef.__init__(self, ptr)
|
56 |
+
|
57 |
+
def get_function_address(self, name):
|
58 |
+
"""
|
59 |
+
Return the address of the function named *name* as an integer.
|
60 |
+
|
61 |
+
It's a fatal error in LLVM if the symbol of *name* doesn't exist.
|
62 |
+
"""
|
63 |
+
return ffi.lib.LLVMPY_GetFunctionAddress(self, name.encode("ascii"))
|
64 |
+
|
65 |
+
def get_global_value_address(self, name):
|
66 |
+
"""
|
67 |
+
Return the address of the global value named *name* as an integer.
|
68 |
+
|
69 |
+
It's a fatal error in LLVM if the symbol of *name* doesn't exist.
|
70 |
+
"""
|
71 |
+
return ffi.lib.LLVMPY_GetGlobalValueAddress(self, name.encode("ascii"))
|
72 |
+
|
73 |
+
def add_global_mapping(self, gv, addr):
|
74 |
+
# XXX unused?
|
75 |
+
ffi.lib.LLVMPY_AddGlobalMapping(self, gv, addr)
|
76 |
+
|
77 |
+
def add_module(self, module):
|
78 |
+
"""
|
79 |
+
Ownership of module is transferred to the execution engine
|
80 |
+
"""
|
81 |
+
if module in self._modules:
|
82 |
+
raise KeyError("module already added to this engine")
|
83 |
+
ffi.lib.LLVMPY_AddModule(self, module)
|
84 |
+
module._owned = True
|
85 |
+
self._modules.add(module)
|
86 |
+
|
87 |
+
def finalize_object(self):
|
88 |
+
"""
|
89 |
+
Make sure all modules owned by the execution engine are fully processed
|
90 |
+
and "usable" for execution.
|
91 |
+
"""
|
92 |
+
ffi.lib.LLVMPY_FinalizeObject(self)
|
93 |
+
|
94 |
+
def run_static_constructors(self):
|
95 |
+
"""
|
96 |
+
Run static constructors which initialize module-level static objects.
|
97 |
+
"""
|
98 |
+
ffi.lib.LLVMPY_RunStaticConstructors(self)
|
99 |
+
|
100 |
+
def run_static_destructors(self):
|
101 |
+
"""
|
102 |
+
Run static destructors which perform module-level cleanup of static
|
103 |
+
resources.
|
104 |
+
"""
|
105 |
+
ffi.lib.LLVMPY_RunStaticDestructors(self)
|
106 |
+
|
107 |
+
def remove_module(self, module):
|
108 |
+
"""
|
109 |
+
Ownership of module is returned
|
110 |
+
"""
|
111 |
+
with ffi.OutputString() as outerr:
|
112 |
+
if ffi.lib.LLVMPY_RemoveModule(self, module, outerr):
|
113 |
+
raise RuntimeError(str(outerr))
|
114 |
+
self._modules.remove(module)
|
115 |
+
module._owned = False
|
116 |
+
|
117 |
+
@property
|
118 |
+
def target_data(self):
|
119 |
+
"""
|
120 |
+
The TargetData for this execution engine.
|
121 |
+
"""
|
122 |
+
if self._td is not None:
|
123 |
+
return self._td
|
124 |
+
ptr = ffi.lib.LLVMPY_GetExecutionEngineTargetData(self)
|
125 |
+
self._td = targets.TargetData(ptr)
|
126 |
+
self._td._owned = True
|
127 |
+
return self._td
|
128 |
+
|
129 |
+
def enable_jit_events(self):
|
130 |
+
"""
|
131 |
+
Enable JIT events for profiling of generated code.
|
132 |
+
Return value indicates whether connection to profiling tool
|
133 |
+
was successful.
|
134 |
+
"""
|
135 |
+
ret = ffi.lib.LLVMPY_EnableJITEvents(self)
|
136 |
+
return ret
|
137 |
+
|
138 |
+
def _find_module_ptr(self, module_ptr):
|
139 |
+
"""
|
140 |
+
Find the ModuleRef corresponding to the given pointer.
|
141 |
+
"""
|
142 |
+
ptr = cast(module_ptr, c_void_p).value
|
143 |
+
for module in self._modules:
|
144 |
+
if cast(module._ptr, c_void_p).value == ptr:
|
145 |
+
return module
|
146 |
+
return None
|
147 |
+
|
148 |
+
def add_object_file(self, obj_file):
|
149 |
+
"""
|
150 |
+
Add object file to the jit. object_file can be instance of
|
151 |
+
:class:ObjectFile or a string representing file system path
|
152 |
+
"""
|
153 |
+
if isinstance(obj_file, str):
|
154 |
+
obj_file = object_file.ObjectFileRef.from_path(obj_file)
|
155 |
+
|
156 |
+
ffi.lib.LLVMPY_MCJITAddObjectFile(self, obj_file)
|
157 |
+
|
158 |
+
def set_object_cache(self, notify_func=None, getbuffer_func=None):
|
159 |
+
"""
|
160 |
+
Set the object cache "notifyObjectCompiled" and "getBuffer"
|
161 |
+
callbacks to the given Python functions.
|
162 |
+
"""
|
163 |
+
self._object_cache_notify = notify_func
|
164 |
+
self._object_cache_getbuffer = getbuffer_func
|
165 |
+
# Lifetime of the object cache is managed by us.
|
166 |
+
self._object_cache = _ObjectCacheRef(self)
|
167 |
+
# Note this doesn't keep a reference to self, to avoid reference
|
168 |
+
# cycles.
|
169 |
+
ffi.lib.LLVMPY_SetObjectCache(self, self._object_cache)
|
170 |
+
|
171 |
+
def _raw_object_cache_notify(self, data):
|
172 |
+
"""
|
173 |
+
Low-level notify hook.
|
174 |
+
"""
|
175 |
+
if self._object_cache_notify is None:
|
176 |
+
return
|
177 |
+
module_ptr = data.contents.module_ptr
|
178 |
+
buf_ptr = data.contents.buf_ptr
|
179 |
+
buf_len = data.contents.buf_len
|
180 |
+
buf = string_at(buf_ptr, buf_len)
|
181 |
+
module = self._find_module_ptr(module_ptr)
|
182 |
+
if module is None:
|
183 |
+
# The LLVM EE should only give notifications for modules
|
184 |
+
# known by us.
|
185 |
+
raise RuntimeError("object compilation notification "
|
186 |
+
"for unknown module %s" % (module_ptr,))
|
187 |
+
self._object_cache_notify(module, buf)
|
188 |
+
|
189 |
+
def _raw_object_cache_getbuffer(self, data):
|
190 |
+
"""
|
191 |
+
Low-level getbuffer hook.
|
192 |
+
"""
|
193 |
+
if self._object_cache_getbuffer is None:
|
194 |
+
return
|
195 |
+
module_ptr = data.contents.module_ptr
|
196 |
+
module = self._find_module_ptr(module_ptr)
|
197 |
+
if module is None:
|
198 |
+
# The LLVM EE should only give notifications for modules
|
199 |
+
# known by us.
|
200 |
+
raise RuntimeError("object compilation notification "
|
201 |
+
"for unknown module %s" % (module_ptr,))
|
202 |
+
|
203 |
+
buf = self._object_cache_getbuffer(module)
|
204 |
+
if buf is not None:
|
205 |
+
# Create a copy, which will be freed by the caller
|
206 |
+
data[0].buf_ptr = ffi.lib.LLVMPY_CreateByteString(buf, len(buf))
|
207 |
+
data[0].buf_len = len(buf)
|
208 |
+
|
209 |
+
def _dispose(self):
|
210 |
+
# The modules will be cleaned up by the EE
|
211 |
+
for mod in self._modules:
|
212 |
+
mod.detach()
|
213 |
+
if self._td is not None:
|
214 |
+
self._td.detach()
|
215 |
+
self._modules.clear()
|
216 |
+
self._object_cache = None
|
217 |
+
self._capi.LLVMPY_DisposeExecutionEngine(self)
|
218 |
+
|
219 |
+
|
220 |
+
class _ObjectCacheRef(ffi.ObjectRef):
|
221 |
+
"""
|
222 |
+
Internal: an ObjectCache instance for use within an ExecutionEngine.
|
223 |
+
"""
|
224 |
+
|
225 |
+
def __init__(self, obj):
|
226 |
+
ptr = ffi.lib.LLVMPY_CreateObjectCache(_notify_c_hook,
|
227 |
+
_getbuffer_c_hook,
|
228 |
+
obj)
|
229 |
+
ffi.ObjectRef.__init__(self, ptr)
|
230 |
+
|
231 |
+
def _dispose(self):
|
232 |
+
self._capi.LLVMPY_DisposeObjectCache(self)
|
233 |
+
|
234 |
+
|
235 |
+
# ============================================================================
|
236 |
+
# FFI
|
237 |
+
|
238 |
+
|
239 |
+
ffi.lib.LLVMPY_CreateMCJITCompiler.argtypes = [
|
240 |
+
ffi.LLVMModuleRef,
|
241 |
+
ffi.LLVMTargetMachineRef,
|
242 |
+
POINTER(c_char_p),
|
243 |
+
]
|
244 |
+
ffi.lib.LLVMPY_CreateMCJITCompiler.restype = ffi.LLVMExecutionEngineRef
|
245 |
+
|
246 |
+
ffi.lib.LLVMPY_RemoveModule.argtypes = [
|
247 |
+
ffi.LLVMExecutionEngineRef,
|
248 |
+
ffi.LLVMModuleRef,
|
249 |
+
POINTER(c_char_p),
|
250 |
+
]
|
251 |
+
ffi.lib.LLVMPY_RemoveModule.restype = c_bool
|
252 |
+
|
253 |
+
ffi.lib.LLVMPY_AddModule.argtypes = [
|
254 |
+
ffi.LLVMExecutionEngineRef,
|
255 |
+
ffi.LLVMModuleRef
|
256 |
+
]
|
257 |
+
|
258 |
+
ffi.lib.LLVMPY_AddGlobalMapping.argtypes = [ffi.LLVMExecutionEngineRef,
|
259 |
+
ffi.LLVMValueRef,
|
260 |
+
c_void_p]
|
261 |
+
|
262 |
+
ffi.lib.LLVMPY_FinalizeObject.argtypes = [ffi.LLVMExecutionEngineRef]
|
263 |
+
|
264 |
+
ffi.lib.LLVMPY_GetExecutionEngineTargetData.argtypes = [
|
265 |
+
ffi.LLVMExecutionEngineRef
|
266 |
+
]
|
267 |
+
ffi.lib.LLVMPY_GetExecutionEngineTargetData.restype = ffi.LLVMTargetDataRef
|
268 |
+
|
269 |
+
ffi.lib.LLVMPY_TryAllocateExecutableMemory.argtypes = []
|
270 |
+
ffi.lib.LLVMPY_TryAllocateExecutableMemory.restype = c_int
|
271 |
+
|
272 |
+
ffi.lib.LLVMPY_GetFunctionAddress.argtypes = [
|
273 |
+
ffi.LLVMExecutionEngineRef,
|
274 |
+
c_char_p
|
275 |
+
]
|
276 |
+
ffi.lib.LLVMPY_GetFunctionAddress.restype = c_uint64
|
277 |
+
|
278 |
+
ffi.lib.LLVMPY_GetGlobalValueAddress.argtypes = [
|
279 |
+
ffi.LLVMExecutionEngineRef,
|
280 |
+
c_char_p
|
281 |
+
]
|
282 |
+
ffi.lib.LLVMPY_GetGlobalValueAddress.restype = c_uint64
|
283 |
+
|
284 |
+
ffi.lib.LLVMPY_MCJITAddObjectFile.argtypes = [
|
285 |
+
ffi.LLVMExecutionEngineRef,
|
286 |
+
ffi.LLVMObjectFileRef
|
287 |
+
]
|
288 |
+
|
289 |
+
|
290 |
+
class _ObjectCacheData(Structure):
|
291 |
+
_fields_ = [
|
292 |
+
('module_ptr', ffi.LLVMModuleRef),
|
293 |
+
('buf_ptr', c_void_p),
|
294 |
+
('buf_len', c_size_t),
|
295 |
+
]
|
296 |
+
|
297 |
+
|
298 |
+
_ObjectCacheNotifyFunc = CFUNCTYPE(None, py_object,
|
299 |
+
POINTER(_ObjectCacheData))
|
300 |
+
_ObjectCacheGetBufferFunc = CFUNCTYPE(None, py_object,
|
301 |
+
POINTER(_ObjectCacheData))
|
302 |
+
|
303 |
+
# XXX The ctypes function wrappers are created at the top-level, otherwise
|
304 |
+
# there are issues when creating CFUNCTYPEs in child processes on CentOS 5
|
305 |
+
# 32 bits.
|
306 |
+
_notify_c_hook = _ObjectCacheNotifyFunc(
|
307 |
+
ExecutionEngine._raw_object_cache_notify)
|
308 |
+
_getbuffer_c_hook = _ObjectCacheGetBufferFunc(
|
309 |
+
ExecutionEngine._raw_object_cache_getbuffer)
|
310 |
+
|
311 |
+
ffi.lib.LLVMPY_CreateObjectCache.argtypes = [_ObjectCacheNotifyFunc,
|
312 |
+
_ObjectCacheGetBufferFunc,
|
313 |
+
py_object]
|
314 |
+
ffi.lib.LLVMPY_CreateObjectCache.restype = ffi.LLVMObjectCacheRef
|
315 |
+
|
316 |
+
ffi.lib.LLVMPY_DisposeObjectCache.argtypes = [ffi.LLVMObjectCacheRef]
|
317 |
+
|
318 |
+
ffi.lib.LLVMPY_SetObjectCache.argtypes = [ffi.LLVMExecutionEngineRef,
|
319 |
+
ffi.LLVMObjectCacheRef]
|
320 |
+
|
321 |
+
ffi.lib.LLVMPY_CreateByteString.restype = c_void_p
|
322 |
+
ffi.lib.LLVMPY_CreateByteString.argtypes = [c_void_p, c_size_t]
|
lib/python3.11/site-packages/llvmlite/binding/ffi.py
ADDED
@@ -0,0 +1,388 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
import ctypes
|
3 |
+
import threading
|
4 |
+
import importlib.resources as _impres
|
5 |
+
|
6 |
+
from llvmlite.binding.common import _decode_string, _is_shutting_down
|
7 |
+
from llvmlite.utils import get_library_name
|
8 |
+
|
9 |
+
|
10 |
+
def _make_opaque_ref(name):
|
11 |
+
newcls = type(name, (ctypes.Structure,), {})
|
12 |
+
return ctypes.POINTER(newcls)
|
13 |
+
|
14 |
+
|
15 |
+
LLVMContextRef = _make_opaque_ref("LLVMContext")
|
16 |
+
LLVMModuleRef = _make_opaque_ref("LLVMModule")
|
17 |
+
LLVMValueRef = _make_opaque_ref("LLVMValue")
|
18 |
+
LLVMTypeRef = _make_opaque_ref("LLVMType")
|
19 |
+
LLVMExecutionEngineRef = _make_opaque_ref("LLVMExecutionEngine")
|
20 |
+
LLVMPassManagerBuilderRef = _make_opaque_ref("LLVMPassManagerBuilder")
|
21 |
+
LLVMPassManagerRef = _make_opaque_ref("LLVMPassManager")
|
22 |
+
LLVMTargetDataRef = _make_opaque_ref("LLVMTargetData")
|
23 |
+
LLVMTargetLibraryInfoRef = _make_opaque_ref("LLVMTargetLibraryInfo")
|
24 |
+
LLVMTargetRef = _make_opaque_ref("LLVMTarget")
|
25 |
+
LLVMTargetMachineRef = _make_opaque_ref("LLVMTargetMachine")
|
26 |
+
LLVMMemoryBufferRef = _make_opaque_ref("LLVMMemoryBuffer")
|
27 |
+
LLVMAttributeListIterator = _make_opaque_ref("LLVMAttributeListIterator")
|
28 |
+
LLVMAttributeSetIterator = _make_opaque_ref("LLVMAttributeSetIterator")
|
29 |
+
LLVMGlobalsIterator = _make_opaque_ref("LLVMGlobalsIterator")
|
30 |
+
LLVMFunctionsIterator = _make_opaque_ref("LLVMFunctionsIterator")
|
31 |
+
LLVMBlocksIterator = _make_opaque_ref("LLVMBlocksIterator")
|
32 |
+
LLVMArgumentsIterator = _make_opaque_ref("LLVMArgumentsIterator")
|
33 |
+
LLVMInstructionsIterator = _make_opaque_ref("LLVMInstructionsIterator")
|
34 |
+
LLVMOperandsIterator = _make_opaque_ref("LLVMOperandsIterator")
|
35 |
+
LLVMTypesIterator = _make_opaque_ref("LLVMTypesIterator")
|
36 |
+
LLVMObjectCacheRef = _make_opaque_ref("LLVMObjectCache")
|
37 |
+
LLVMObjectFileRef = _make_opaque_ref("LLVMObjectFile")
|
38 |
+
LLVMSectionIteratorRef = _make_opaque_ref("LLVMSectionIterator")
|
39 |
+
LLVMOrcLLJITRef = _make_opaque_ref("LLVMOrcLLJITRef")
|
40 |
+
LLVMOrcDylibTrackerRef = _make_opaque_ref("LLVMOrcDylibTrackerRef")
|
41 |
+
|
42 |
+
|
43 |
+
class _LLVMLock:
|
44 |
+
"""A Lock to guarantee thread-safety for the LLVM C-API.
|
45 |
+
|
46 |
+
This class implements __enter__ and __exit__ for acquiring and releasing
|
47 |
+
the lock as a context manager.
|
48 |
+
|
49 |
+
Also, callbacks can be attached so that every time the lock is acquired
|
50 |
+
and released the corresponding callbacks will be invoked.
|
51 |
+
"""
|
52 |
+
def __init__(self):
|
53 |
+
# The reentrant lock is needed for callbacks that re-enter
|
54 |
+
# the Python interpreter.
|
55 |
+
self._lock = threading.RLock()
|
56 |
+
self._cblist = []
|
57 |
+
|
58 |
+
def register(self, acq_fn, rel_fn):
|
59 |
+
"""Register callbacks that are invoked immediately after the lock is
|
60 |
+
acquired (``acq_fn()``) and immediately before the lock is released
|
61 |
+
(``rel_fn()``).
|
62 |
+
"""
|
63 |
+
self._cblist.append((acq_fn, rel_fn))
|
64 |
+
|
65 |
+
def unregister(self, acq_fn, rel_fn):
|
66 |
+
"""Remove the registered callbacks.
|
67 |
+
"""
|
68 |
+
self._cblist.remove((acq_fn, rel_fn))
|
69 |
+
|
70 |
+
def __enter__(self):
|
71 |
+
self._lock.acquire()
|
72 |
+
# Invoke all callbacks
|
73 |
+
for acq_fn, rel_fn in self._cblist:
|
74 |
+
acq_fn()
|
75 |
+
|
76 |
+
def __exit__(self, *exc_details):
|
77 |
+
# Invoke all callbacks
|
78 |
+
for acq_fn, rel_fn in self._cblist:
|
79 |
+
rel_fn()
|
80 |
+
self._lock.release()
|
81 |
+
|
82 |
+
|
83 |
+
class _suppress_cleanup_errors:
|
84 |
+
def __init__(self, context):
|
85 |
+
self._context = context
|
86 |
+
|
87 |
+
def __enter__(self):
|
88 |
+
return self._context.__enter__()
|
89 |
+
|
90 |
+
def __exit__(self, exc_type, exc_value, traceback):
|
91 |
+
try:
|
92 |
+
return self._context.__exit__(exc_type, exc_value, traceback)
|
93 |
+
except PermissionError:
|
94 |
+
pass # Resource dylibs can't be deleted on Windows.
|
95 |
+
|
96 |
+
|
97 |
+
class _lib_wrapper(object):
|
98 |
+
"""Wrap libllvmlite with a lock such that only one thread may access it at
|
99 |
+
a time.
|
100 |
+
|
101 |
+
This class duck-types a CDLL.
|
102 |
+
"""
|
103 |
+
__slots__ = ['_lib_handle', '_fntab', '_lock']
|
104 |
+
|
105 |
+
def __init__(self):
|
106 |
+
self._lib_handle = None
|
107 |
+
self._fntab = {}
|
108 |
+
self._lock = _LLVMLock()
|
109 |
+
|
110 |
+
def _load_lib(self):
|
111 |
+
try:
|
112 |
+
with _suppress_cleanup_errors(_importlib_resources_path(
|
113 |
+
__name__.rpartition(".")[0],
|
114 |
+
get_library_name())) as lib_path:
|
115 |
+
self._lib_handle = ctypes.CDLL(str(lib_path))
|
116 |
+
# Check that we can look up expected symbols.
|
117 |
+
_ = self._lib_handle.LLVMPY_GetVersionInfo()
|
118 |
+
except (OSError, AttributeError) as e:
|
119 |
+
# OSError may be raised if the file cannot be opened, or is not
|
120 |
+
# a shared library.
|
121 |
+
# AttributeError is raised if LLVMPY_GetVersionInfo does not
|
122 |
+
# exist.
|
123 |
+
raise OSError("Could not find/load shared object file") from e
|
124 |
+
|
125 |
+
@property
|
126 |
+
def _lib(self):
|
127 |
+
# Not threadsafe.
|
128 |
+
if not self._lib_handle:
|
129 |
+
self._load_lib()
|
130 |
+
return self._lib_handle
|
131 |
+
|
132 |
+
def __getattr__(self, name):
|
133 |
+
try:
|
134 |
+
return self._fntab[name]
|
135 |
+
except KeyError:
|
136 |
+
# Lazily wraps new functions as they are requested
|
137 |
+
cfn = getattr(self._lib, name)
|
138 |
+
wrapped = _lib_fn_wrapper(self._lock, cfn)
|
139 |
+
self._fntab[name] = wrapped
|
140 |
+
return wrapped
|
141 |
+
|
142 |
+
@property
|
143 |
+
def _name(self):
|
144 |
+
"""The name of the library passed in the CDLL constructor.
|
145 |
+
|
146 |
+
For duck-typing a ctypes.CDLL
|
147 |
+
"""
|
148 |
+
return self._lib._name
|
149 |
+
|
150 |
+
@property
|
151 |
+
def _handle(self):
|
152 |
+
"""The system handle used to access the library.
|
153 |
+
|
154 |
+
For duck-typing a ctypes.CDLL
|
155 |
+
"""
|
156 |
+
return self._lib._handle
|
157 |
+
|
158 |
+
|
159 |
+
class _lib_fn_wrapper(object):
|
160 |
+
"""Wraps and duck-types a ctypes.CFUNCTYPE to provide
|
161 |
+
automatic locking when the wrapped function is called.
|
162 |
+
|
163 |
+
TODO: we can add methods to mark the function as threadsafe
|
164 |
+
and remove the locking-step on call when marked.
|
165 |
+
"""
|
166 |
+
__slots__ = ['_lock', '_cfn']
|
167 |
+
|
168 |
+
def __init__(self, lock, cfn):
|
169 |
+
self._lock = lock
|
170 |
+
self._cfn = cfn
|
171 |
+
|
172 |
+
@property
|
173 |
+
def argtypes(self):
|
174 |
+
return self._cfn.argtypes
|
175 |
+
|
176 |
+
@argtypes.setter
|
177 |
+
def argtypes(self, argtypes):
|
178 |
+
self._cfn.argtypes = argtypes
|
179 |
+
|
180 |
+
@property
|
181 |
+
def restype(self):
|
182 |
+
return self._cfn.restype
|
183 |
+
|
184 |
+
@restype.setter
|
185 |
+
def restype(self, restype):
|
186 |
+
self._cfn.restype = restype
|
187 |
+
|
188 |
+
def __call__(self, *args, **kwargs):
|
189 |
+
with self._lock:
|
190 |
+
return self._cfn(*args, **kwargs)
|
191 |
+
|
192 |
+
|
193 |
+
def _importlib_resources_path_repl(package, resource):
|
194 |
+
"""Replacement implementation of `import.resources.path` to avoid
|
195 |
+
deprecation warning following code at importlib_resources/_legacy.py
|
196 |
+
as suggested by https://importlib-resources.readthedocs.io/en/latest/using.html#migrating-from-legacy
|
197 |
+
|
198 |
+
Notes on differences from importlib.resources implementation:
|
199 |
+
|
200 |
+
The `_common.normalize_path(resource)` call is skipped because it is an
|
201 |
+
internal API and it is unnecessary for the use here. What it does is
|
202 |
+
ensuring `resource` is a str and that it does not contain path separators.
|
203 |
+
""" # noqa E501
|
204 |
+
return _impres.as_file(_impres.files(package) / resource)
|
205 |
+
|
206 |
+
|
207 |
+
_importlib_resources_path = (_importlib_resources_path_repl
|
208 |
+
if sys.version_info[:2] >= (3, 9)
|
209 |
+
else _impres.path)
|
210 |
+
|
211 |
+
|
212 |
+
lib = _lib_wrapper()
|
213 |
+
|
214 |
+
|
215 |
+
def register_lock_callback(acq_fn, rel_fn):
|
216 |
+
"""Register callback functions for lock acquire and release.
|
217 |
+
*acq_fn* and *rel_fn* are callables that take no arguments.
|
218 |
+
"""
|
219 |
+
lib._lock.register(acq_fn, rel_fn)
|
220 |
+
|
221 |
+
|
222 |
+
def unregister_lock_callback(acq_fn, rel_fn):
|
223 |
+
"""Remove the registered callback functions for lock acquire and release.
|
224 |
+
The arguments are the same as used in `register_lock_callback()`.
|
225 |
+
"""
|
226 |
+
lib._lock.unregister(acq_fn, rel_fn)
|
227 |
+
|
228 |
+
|
229 |
+
class _DeadPointer(object):
|
230 |
+
"""
|
231 |
+
Dummy class to make error messages more helpful.
|
232 |
+
"""
|
233 |
+
|
234 |
+
|
235 |
+
class OutputString(object):
|
236 |
+
"""
|
237 |
+
Object for managing the char* output of LLVM APIs.
|
238 |
+
"""
|
239 |
+
_as_parameter_ = _DeadPointer()
|
240 |
+
|
241 |
+
@classmethod
|
242 |
+
def from_return(cls, ptr):
|
243 |
+
"""Constructing from a pointer returned from the C-API.
|
244 |
+
The pointer must be allocated with LLVMPY_CreateString.
|
245 |
+
|
246 |
+
Note
|
247 |
+
----
|
248 |
+
Because ctypes auto-converts *restype* of *c_char_p* into a python
|
249 |
+
string, we must use *c_void_p* to obtain the raw pointer.
|
250 |
+
"""
|
251 |
+
return cls(init=ctypes.cast(ptr, ctypes.c_char_p))
|
252 |
+
|
253 |
+
def __init__(self, owned=True, init=None):
|
254 |
+
self._ptr = init if init is not None else ctypes.c_char_p(None)
|
255 |
+
self._as_parameter_ = ctypes.byref(self._ptr)
|
256 |
+
self._owned = owned
|
257 |
+
|
258 |
+
def close(self):
|
259 |
+
if self._ptr is not None:
|
260 |
+
if self._owned:
|
261 |
+
lib.LLVMPY_DisposeString(self._ptr)
|
262 |
+
self._ptr = None
|
263 |
+
del self._as_parameter_
|
264 |
+
|
265 |
+
def __enter__(self):
|
266 |
+
return self
|
267 |
+
|
268 |
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
269 |
+
self.close()
|
270 |
+
|
271 |
+
def __del__(self, _is_shutting_down=_is_shutting_down):
|
272 |
+
# Avoid errors trying to rely on globals and modules at interpreter
|
273 |
+
# shutdown.
|
274 |
+
if not _is_shutting_down():
|
275 |
+
if self.close is not None:
|
276 |
+
self.close()
|
277 |
+
|
278 |
+
def __str__(self):
|
279 |
+
if self._ptr is None:
|
280 |
+
return "<dead OutputString>"
|
281 |
+
s = self._ptr.value
|
282 |
+
assert s is not None
|
283 |
+
return _decode_string(s)
|
284 |
+
|
285 |
+
def __bool__(self):
|
286 |
+
return bool(self._ptr)
|
287 |
+
|
288 |
+
__nonzero__ = __bool__
|
289 |
+
|
290 |
+
@property
|
291 |
+
def bytes(self):
|
292 |
+
"""Get the raw bytes of content of the char pointer.
|
293 |
+
"""
|
294 |
+
return self._ptr.value
|
295 |
+
|
296 |
+
|
297 |
+
def ret_string(ptr):
|
298 |
+
"""To wrap string return-value from C-API.
|
299 |
+
"""
|
300 |
+
if ptr is not None:
|
301 |
+
return str(OutputString.from_return(ptr))
|
302 |
+
|
303 |
+
|
304 |
+
def ret_bytes(ptr):
|
305 |
+
"""To wrap bytes return-value from C-API.
|
306 |
+
"""
|
307 |
+
if ptr is not None:
|
308 |
+
return OutputString.from_return(ptr).bytes
|
309 |
+
|
310 |
+
|
311 |
+
class ObjectRef(object):
|
312 |
+
"""
|
313 |
+
A wrapper around a ctypes pointer to a LLVM object ("resource").
|
314 |
+
"""
|
315 |
+
_closed = False
|
316 |
+
_as_parameter_ = _DeadPointer()
|
317 |
+
# Whether this object pointer is owned by another one.
|
318 |
+
_owned = False
|
319 |
+
|
320 |
+
def __init__(self, ptr):
|
321 |
+
if ptr is None:
|
322 |
+
raise ValueError("NULL pointer")
|
323 |
+
self._ptr = ptr
|
324 |
+
self._as_parameter_ = ptr
|
325 |
+
self._capi = lib
|
326 |
+
|
327 |
+
def close(self):
|
328 |
+
"""
|
329 |
+
Close this object and do any required clean-up actions.
|
330 |
+
"""
|
331 |
+
try:
|
332 |
+
if not self._closed and not self._owned:
|
333 |
+
self._dispose()
|
334 |
+
finally:
|
335 |
+
self.detach()
|
336 |
+
|
337 |
+
def detach(self):
|
338 |
+
"""
|
339 |
+
Detach the underlying LLVM resource without disposing of it.
|
340 |
+
"""
|
341 |
+
if not self._closed:
|
342 |
+
del self._as_parameter_
|
343 |
+
self._closed = True
|
344 |
+
self._ptr = None
|
345 |
+
|
346 |
+
def _dispose(self):
|
347 |
+
"""
|
348 |
+
Dispose of the underlying LLVM resource. Should be overriden
|
349 |
+
by subclasses. Automatically called by close(), __del__() and
|
350 |
+
__exit__() (unless the resource has been detached).
|
351 |
+
"""
|
352 |
+
|
353 |
+
@property
|
354 |
+
def closed(self):
|
355 |
+
"""
|
356 |
+
Whether this object has been closed. A closed object can't
|
357 |
+
be used anymore.
|
358 |
+
"""
|
359 |
+
return self._closed
|
360 |
+
|
361 |
+
def __enter__(self):
|
362 |
+
assert hasattr(self, "close")
|
363 |
+
if self._closed:
|
364 |
+
raise RuntimeError("%s instance already closed" % (self.__class__,))
|
365 |
+
return self
|
366 |
+
|
367 |
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
368 |
+
self.close()
|
369 |
+
|
370 |
+
def __del__(self, _is_shutting_down=_is_shutting_down):
|
371 |
+
if not _is_shutting_down():
|
372 |
+
if self.close is not None:
|
373 |
+
self.close()
|
374 |
+
|
375 |
+
def __bool__(self):
|
376 |
+
return bool(self._ptr)
|
377 |
+
|
378 |
+
def __eq__(self, other):
|
379 |
+
if not hasattr(other, "_ptr"):
|
380 |
+
return False
|
381 |
+
return ctypes.addressof(self._ptr[0]) == \
|
382 |
+
ctypes.addressof(other._ptr[0])
|
383 |
+
|
384 |
+
__nonzero__ = __bool__
|
385 |
+
|
386 |
+
# XXX useful?
|
387 |
+
def __hash__(self):
|
388 |
+
return hash(ctypes.cast(self._ptr, ctypes.c_void_p).value)
|
lib/python3.11/site-packages/llvmlite/binding/initfini.py
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ctypes import c_uint
|
2 |
+
|
3 |
+
from llvmlite.binding import ffi
|
4 |
+
|
5 |
+
|
6 |
+
def initialize():
|
7 |
+
"""
|
8 |
+
Initialize the LLVM core.
|
9 |
+
"""
|
10 |
+
ffi.lib.LLVMPY_InitializeCore()
|
11 |
+
|
12 |
+
|
13 |
+
def initialize_all_targets():
|
14 |
+
"""
|
15 |
+
Initialize all targets. Necessary before targets can be looked up
|
16 |
+
via the :class:`Target` class.
|
17 |
+
"""
|
18 |
+
ffi.lib.LLVMPY_InitializeAllTargetInfos()
|
19 |
+
ffi.lib.LLVMPY_InitializeAllTargets()
|
20 |
+
ffi.lib.LLVMPY_InitializeAllTargetMCs()
|
21 |
+
|
22 |
+
|
23 |
+
def initialize_all_asmprinters():
|
24 |
+
"""
|
25 |
+
Initialize all code generators. Necessary before generating
|
26 |
+
any assembly or machine code via the :meth:`TargetMachine.emit_object`
|
27 |
+
and :meth:`TargetMachine.emit_assembly` methods.
|
28 |
+
"""
|
29 |
+
ffi.lib.LLVMPY_InitializeAllAsmPrinters()
|
30 |
+
|
31 |
+
|
32 |
+
def initialize_native_target():
|
33 |
+
"""
|
34 |
+
Initialize the native (host) target. Necessary before doing any
|
35 |
+
code generation.
|
36 |
+
"""
|
37 |
+
ffi.lib.LLVMPY_InitializeNativeTarget()
|
38 |
+
|
39 |
+
|
40 |
+
def initialize_native_asmprinter():
|
41 |
+
"""
|
42 |
+
Initialize the native ASM printer.
|
43 |
+
"""
|
44 |
+
ffi.lib.LLVMPY_InitializeNativeAsmPrinter()
|
45 |
+
|
46 |
+
|
47 |
+
def initialize_native_asmparser():
|
48 |
+
"""
|
49 |
+
Initialize the native ASM parser.
|
50 |
+
"""
|
51 |
+
ffi.lib.LLVMPY_InitializeNativeAsmParser()
|
52 |
+
|
53 |
+
|
54 |
+
def shutdown():
|
55 |
+
ffi.lib.LLVMPY_Shutdown()
|
56 |
+
|
57 |
+
|
58 |
+
# =============================================================================
|
59 |
+
# Set function FFI
|
60 |
+
|
61 |
+
ffi.lib.LLVMPY_GetVersionInfo.restype = c_uint
|
62 |
+
|
63 |
+
|
64 |
+
def _version_info():
|
65 |
+
v = []
|
66 |
+
x = ffi.lib.LLVMPY_GetVersionInfo()
|
67 |
+
while x:
|
68 |
+
v.append(x & 0xff)
|
69 |
+
x >>= 8
|
70 |
+
return tuple(reversed(v))
|
71 |
+
|
72 |
+
|
73 |
+
llvm_version_info = _version_info()
|
lib/python3.11/site-packages/llvmlite/binding/libllvmlite.dylib
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3357cc66e6582cf25850ce9b1f710cbe4160f871a90c8bbe96cfd87fe857ea30
|
3 |
+
size 91363294
|
lib/python3.11/site-packages/llvmlite/binding/linker.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ctypes import c_int, c_char_p, POINTER
|
2 |
+
from llvmlite.binding import ffi
|
3 |
+
|
4 |
+
|
5 |
+
def link_modules(dst, src):
|
6 |
+
with ffi.OutputString() as outerr:
|
7 |
+
err = ffi.lib.LLVMPY_LinkModules(dst, src, outerr)
|
8 |
+
# The underlying module was destroyed
|
9 |
+
src.detach()
|
10 |
+
if err:
|
11 |
+
raise RuntimeError(str(outerr))
|
12 |
+
|
13 |
+
|
14 |
+
ffi.lib.LLVMPY_LinkModules.argtypes = [
|
15 |
+
ffi.LLVMModuleRef,
|
16 |
+
ffi.LLVMModuleRef,
|
17 |
+
POINTER(c_char_p),
|
18 |
+
]
|
19 |
+
|
20 |
+
ffi.lib.LLVMPY_LinkModules.restype = c_int
|
lib/python3.11/site-packages/llvmlite/binding/module.py
ADDED
@@ -0,0 +1,349 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ctypes import (c_char_p, byref, POINTER, c_bool, create_string_buffer,
|
2 |
+
c_size_t, string_at)
|
3 |
+
|
4 |
+
from llvmlite.binding import ffi
|
5 |
+
from llvmlite.binding.linker import link_modules
|
6 |
+
from llvmlite.binding.common import _decode_string, _encode_string
|
7 |
+
from llvmlite.binding.value import ValueRef, TypeRef
|
8 |
+
from llvmlite.binding.context import get_global_context
|
9 |
+
|
10 |
+
|
11 |
+
def parse_assembly(llvmir, context=None):
|
12 |
+
"""
|
13 |
+
Create Module from a LLVM IR string
|
14 |
+
"""
|
15 |
+
if context is None:
|
16 |
+
context = get_global_context()
|
17 |
+
llvmir = _encode_string(llvmir)
|
18 |
+
strbuf = c_char_p(llvmir)
|
19 |
+
with ffi.OutputString() as errmsg:
|
20 |
+
mod = ModuleRef(
|
21 |
+
ffi.lib.LLVMPY_ParseAssembly(context, strbuf, errmsg),
|
22 |
+
context)
|
23 |
+
if errmsg:
|
24 |
+
mod.close()
|
25 |
+
raise RuntimeError("LLVM IR parsing error\n{0}".format(errmsg))
|
26 |
+
return mod
|
27 |
+
|
28 |
+
|
29 |
+
def parse_bitcode(bitcode, context=None):
|
30 |
+
"""
|
31 |
+
Create Module from a LLVM *bitcode* (a bytes object).
|
32 |
+
"""
|
33 |
+
if context is None:
|
34 |
+
context = get_global_context()
|
35 |
+
buf = c_char_p(bitcode)
|
36 |
+
bufsize = len(bitcode)
|
37 |
+
with ffi.OutputString() as errmsg:
|
38 |
+
mod = ModuleRef(ffi.lib.LLVMPY_ParseBitcode(
|
39 |
+
context, buf, bufsize, errmsg), context)
|
40 |
+
if errmsg:
|
41 |
+
mod.close()
|
42 |
+
raise RuntimeError(
|
43 |
+
"LLVM bitcode parsing error\n{0}".format(errmsg))
|
44 |
+
return mod
|
45 |
+
|
46 |
+
|
47 |
+
class ModuleRef(ffi.ObjectRef):
|
48 |
+
"""
|
49 |
+
A reference to a LLVM module.
|
50 |
+
"""
|
51 |
+
|
52 |
+
def __init__(self, module_ptr, context):
|
53 |
+
super(ModuleRef, self).__init__(module_ptr)
|
54 |
+
self._context = context
|
55 |
+
|
56 |
+
def __str__(self):
|
57 |
+
with ffi.OutputString() as outstr:
|
58 |
+
ffi.lib.LLVMPY_PrintModuleToString(self, outstr)
|
59 |
+
return str(outstr)
|
60 |
+
|
61 |
+
def as_bitcode(self):
|
62 |
+
"""
|
63 |
+
Return the module's LLVM bitcode, as a bytes object.
|
64 |
+
"""
|
65 |
+
ptr = c_char_p(None)
|
66 |
+
size = c_size_t(-1)
|
67 |
+
ffi.lib.LLVMPY_WriteBitcodeToString(self, byref(ptr), byref(size))
|
68 |
+
if not ptr:
|
69 |
+
raise MemoryError
|
70 |
+
try:
|
71 |
+
assert size.value >= 0
|
72 |
+
return string_at(ptr, size.value)
|
73 |
+
finally:
|
74 |
+
ffi.lib.LLVMPY_DisposeString(ptr)
|
75 |
+
|
76 |
+
def _dispose(self):
|
77 |
+
self._capi.LLVMPY_DisposeModule(self)
|
78 |
+
|
79 |
+
def get_function(self, name):
|
80 |
+
"""
|
81 |
+
Get a ValueRef pointing to the function named *name*.
|
82 |
+
NameError is raised if the symbol isn't found.
|
83 |
+
"""
|
84 |
+
p = ffi.lib.LLVMPY_GetNamedFunction(self, _encode_string(name))
|
85 |
+
if not p:
|
86 |
+
raise NameError(name)
|
87 |
+
return ValueRef(p, 'function', dict(module=self))
|
88 |
+
|
89 |
+
def get_global_variable(self, name):
|
90 |
+
"""
|
91 |
+
Get a ValueRef pointing to the global variable named *name*.
|
92 |
+
NameError is raised if the symbol isn't found.
|
93 |
+
"""
|
94 |
+
p = ffi.lib.LLVMPY_GetNamedGlobalVariable(self, _encode_string(name))
|
95 |
+
if not p:
|
96 |
+
raise NameError(name)
|
97 |
+
return ValueRef(p, 'global', dict(module=self))
|
98 |
+
|
99 |
+
def get_struct_type(self, name):
|
100 |
+
"""
|
101 |
+
Get a TypeRef pointing to a structure type named *name*.
|
102 |
+
NameError is raised if the struct type isn't found.
|
103 |
+
"""
|
104 |
+
p = ffi.lib.LLVMPY_GetNamedStructType(self, _encode_string(name))
|
105 |
+
if not p:
|
106 |
+
raise NameError(name)
|
107 |
+
return TypeRef(p)
|
108 |
+
|
109 |
+
def verify(self):
|
110 |
+
"""
|
111 |
+
Verify the module IR's correctness. RuntimeError is raised on error.
|
112 |
+
"""
|
113 |
+
with ffi.OutputString() as outmsg:
|
114 |
+
if ffi.lib.LLVMPY_VerifyModule(self, outmsg):
|
115 |
+
raise RuntimeError(str(outmsg))
|
116 |
+
|
117 |
+
@property
|
118 |
+
def name(self):
|
119 |
+
"""
|
120 |
+
The module's identifier.
|
121 |
+
"""
|
122 |
+
return _decode_string(ffi.lib.LLVMPY_GetModuleName(self))
|
123 |
+
|
124 |
+
@name.setter
|
125 |
+
def name(self, value):
|
126 |
+
ffi.lib.LLVMPY_SetModuleName(self, _encode_string(value))
|
127 |
+
|
128 |
+
@property
|
129 |
+
def source_file(self):
|
130 |
+
"""
|
131 |
+
The module's original source file name
|
132 |
+
"""
|
133 |
+
return _decode_string(ffi.lib.LLVMPY_GetModuleSourceFileName(self))
|
134 |
+
|
135 |
+
@property
|
136 |
+
def data_layout(self):
|
137 |
+
"""
|
138 |
+
This module's data layout specification, as a string.
|
139 |
+
"""
|
140 |
+
# LLVMGetDataLayout() points inside a std::string managed by LLVM.
|
141 |
+
with ffi.OutputString(owned=False) as outmsg:
|
142 |
+
ffi.lib.LLVMPY_GetDataLayout(self, outmsg)
|
143 |
+
return str(outmsg)
|
144 |
+
|
145 |
+
@data_layout.setter
|
146 |
+
def data_layout(self, strrep):
|
147 |
+
ffi.lib.LLVMPY_SetDataLayout(self,
|
148 |
+
create_string_buffer(
|
149 |
+
strrep.encode('utf8')))
|
150 |
+
|
151 |
+
@property
|
152 |
+
def triple(self):
|
153 |
+
"""
|
154 |
+
This module's target "triple" specification, as a string.
|
155 |
+
"""
|
156 |
+
# LLVMGetTarget() points inside a std::string managed by LLVM.
|
157 |
+
with ffi.OutputString(owned=False) as outmsg:
|
158 |
+
ffi.lib.LLVMPY_GetTarget(self, outmsg)
|
159 |
+
return str(outmsg)
|
160 |
+
|
161 |
+
@triple.setter
|
162 |
+
def triple(self, strrep):
|
163 |
+
ffi.lib.LLVMPY_SetTarget(self,
|
164 |
+
create_string_buffer(
|
165 |
+
strrep.encode('utf8')))
|
166 |
+
|
167 |
+
def link_in(self, other, preserve=False):
|
168 |
+
"""
|
169 |
+
Link the *other* module into this one. The *other* module will
|
170 |
+
be destroyed unless *preserve* is true.
|
171 |
+
"""
|
172 |
+
if preserve:
|
173 |
+
other = other.clone()
|
174 |
+
link_modules(self, other)
|
175 |
+
|
176 |
+
@property
|
177 |
+
def global_variables(self):
|
178 |
+
"""
|
179 |
+
Return an iterator over this module's global variables.
|
180 |
+
The iterator will yield a ValueRef for each global variable.
|
181 |
+
|
182 |
+
Note that global variables don't include functions
|
183 |
+
(a function is a "global value" but not a "global variable" in
|
184 |
+
LLVM parlance)
|
185 |
+
"""
|
186 |
+
it = ffi.lib.LLVMPY_ModuleGlobalsIter(self)
|
187 |
+
return _GlobalsIterator(it, dict(module=self))
|
188 |
+
|
189 |
+
@property
|
190 |
+
def functions(self):
|
191 |
+
"""
|
192 |
+
Return an iterator over this module's functions.
|
193 |
+
The iterator will yield a ValueRef for each function.
|
194 |
+
"""
|
195 |
+
it = ffi.lib.LLVMPY_ModuleFunctionsIter(self)
|
196 |
+
return _FunctionsIterator(it, dict(module=self))
|
197 |
+
|
198 |
+
@property
|
199 |
+
def struct_types(self):
|
200 |
+
"""
|
201 |
+
Return an iterator over the struct types defined in
|
202 |
+
the module. The iterator will yield a TypeRef.
|
203 |
+
"""
|
204 |
+
it = ffi.lib.LLVMPY_ModuleTypesIter(self)
|
205 |
+
return _TypesIterator(it, dict(module=self))
|
206 |
+
|
207 |
+
def clone(self):
|
208 |
+
return ModuleRef(ffi.lib.LLVMPY_CloneModule(self), self._context)
|
209 |
+
|
210 |
+
|
211 |
+
class _Iterator(ffi.ObjectRef):
|
212 |
+
|
213 |
+
kind = None
|
214 |
+
|
215 |
+
def __init__(self, ptr, parents):
|
216 |
+
ffi.ObjectRef.__init__(self, ptr)
|
217 |
+
self._parents = parents
|
218 |
+
assert self.kind is not None
|
219 |
+
|
220 |
+
def __next__(self):
|
221 |
+
vp = self._next()
|
222 |
+
if vp:
|
223 |
+
return ValueRef(vp, self.kind, self._parents)
|
224 |
+
else:
|
225 |
+
raise StopIteration
|
226 |
+
|
227 |
+
next = __next__
|
228 |
+
|
229 |
+
def __iter__(self):
|
230 |
+
return self
|
231 |
+
|
232 |
+
|
233 |
+
class _GlobalsIterator(_Iterator):
|
234 |
+
|
235 |
+
kind = 'global'
|
236 |
+
|
237 |
+
def _dispose(self):
|
238 |
+
self._capi.LLVMPY_DisposeGlobalsIter(self)
|
239 |
+
|
240 |
+
def _next(self):
|
241 |
+
return ffi.lib.LLVMPY_GlobalsIterNext(self)
|
242 |
+
|
243 |
+
|
244 |
+
class _FunctionsIterator(_Iterator):
|
245 |
+
|
246 |
+
kind = 'function'
|
247 |
+
|
248 |
+
def _dispose(self):
|
249 |
+
self._capi.LLVMPY_DisposeFunctionsIter(self)
|
250 |
+
|
251 |
+
def _next(self):
|
252 |
+
return ffi.lib.LLVMPY_FunctionsIterNext(self)
|
253 |
+
|
254 |
+
|
255 |
+
class _TypesIterator(_Iterator):
|
256 |
+
|
257 |
+
kind = 'type'
|
258 |
+
|
259 |
+
def _dispose(self):
|
260 |
+
self._capi.LLVMPY_DisposeTypesIter(self)
|
261 |
+
|
262 |
+
def __next__(self):
|
263 |
+
vp = self._next()
|
264 |
+
if vp:
|
265 |
+
return TypeRef(vp)
|
266 |
+
else:
|
267 |
+
raise StopIteration
|
268 |
+
|
269 |
+
def _next(self):
|
270 |
+
return ffi.lib.LLVMPY_TypesIterNext(self)
|
271 |
+
|
272 |
+
next = __next__
|
273 |
+
|
274 |
+
|
275 |
+
# =============================================================================
|
276 |
+
# Set function FFI
|
277 |
+
|
278 |
+
ffi.lib.LLVMPY_ParseAssembly.argtypes = [ffi.LLVMContextRef,
|
279 |
+
c_char_p,
|
280 |
+
POINTER(c_char_p)]
|
281 |
+
ffi.lib.LLVMPY_ParseAssembly.restype = ffi.LLVMModuleRef
|
282 |
+
|
283 |
+
ffi.lib.LLVMPY_ParseBitcode.argtypes = [ffi.LLVMContextRef,
|
284 |
+
c_char_p, c_size_t,
|
285 |
+
POINTER(c_char_p)]
|
286 |
+
ffi.lib.LLVMPY_ParseBitcode.restype = ffi.LLVMModuleRef
|
287 |
+
|
288 |
+
ffi.lib.LLVMPY_DisposeModule.argtypes = [ffi.LLVMModuleRef]
|
289 |
+
|
290 |
+
ffi.lib.LLVMPY_PrintModuleToString.argtypes = [ffi.LLVMModuleRef,
|
291 |
+
POINTER(c_char_p)]
|
292 |
+
ffi.lib.LLVMPY_WriteBitcodeToString.argtypes = [ffi.LLVMModuleRef,
|
293 |
+
POINTER(c_char_p),
|
294 |
+
POINTER(c_size_t)]
|
295 |
+
|
296 |
+
ffi.lib.LLVMPY_GetNamedFunction.argtypes = [ffi.LLVMModuleRef,
|
297 |
+
c_char_p]
|
298 |
+
ffi.lib.LLVMPY_GetNamedFunction.restype = ffi.LLVMValueRef
|
299 |
+
|
300 |
+
ffi.lib.LLVMPY_VerifyModule.argtypes = [ffi.LLVMModuleRef,
|
301 |
+
POINTER(c_char_p)]
|
302 |
+
ffi.lib.LLVMPY_VerifyModule.restype = c_bool
|
303 |
+
|
304 |
+
ffi.lib.LLVMPY_GetDataLayout.argtypes = [ffi.LLVMModuleRef, POINTER(c_char_p)]
|
305 |
+
ffi.lib.LLVMPY_SetDataLayout.argtypes = [ffi.LLVMModuleRef, c_char_p]
|
306 |
+
|
307 |
+
ffi.lib.LLVMPY_GetTarget.argtypes = [ffi.LLVMModuleRef, POINTER(c_char_p)]
|
308 |
+
ffi.lib.LLVMPY_SetTarget.argtypes = [ffi.LLVMModuleRef, c_char_p]
|
309 |
+
|
310 |
+
ffi.lib.LLVMPY_GetNamedGlobalVariable.argtypes = [ffi.LLVMModuleRef, c_char_p]
|
311 |
+
ffi.lib.LLVMPY_GetNamedGlobalVariable.restype = ffi.LLVMValueRef
|
312 |
+
|
313 |
+
ffi.lib.LLVMPY_GetNamedStructType.argtypes = [ffi.LLVMModuleRef, c_char_p]
|
314 |
+
ffi.lib.LLVMPY_GetNamedStructType.restype = ffi.LLVMTypeRef
|
315 |
+
|
316 |
+
ffi.lib.LLVMPY_ModuleGlobalsIter.argtypes = [ffi.LLVMModuleRef]
|
317 |
+
ffi.lib.LLVMPY_ModuleGlobalsIter.restype = ffi.LLVMGlobalsIterator
|
318 |
+
|
319 |
+
ffi.lib.LLVMPY_DisposeGlobalsIter.argtypes = [ffi.LLVMGlobalsIterator]
|
320 |
+
|
321 |
+
ffi.lib.LLVMPY_GlobalsIterNext.argtypes = [ffi.LLVMGlobalsIterator]
|
322 |
+
ffi.lib.LLVMPY_GlobalsIterNext.restype = ffi.LLVMValueRef
|
323 |
+
|
324 |
+
ffi.lib.LLVMPY_ModuleFunctionsIter.argtypes = [ffi.LLVMModuleRef]
|
325 |
+
ffi.lib.LLVMPY_ModuleFunctionsIter.restype = ffi.LLVMFunctionsIterator
|
326 |
+
|
327 |
+
ffi.lib.LLVMPY_ModuleTypesIter.argtypes = [ffi.LLVMModuleRef]
|
328 |
+
ffi.lib.LLVMPY_ModuleTypesIter.restype = ffi.LLVMTypesIterator
|
329 |
+
|
330 |
+
ffi.lib.LLVMPY_DisposeFunctionsIter.argtypes = [ffi.LLVMFunctionsIterator]
|
331 |
+
|
332 |
+
ffi.lib.LLVMPY_DisposeTypesIter.argtypes = [ffi.LLVMTypesIterator]
|
333 |
+
|
334 |
+
ffi.lib.LLVMPY_FunctionsIterNext.argtypes = [ffi.LLVMFunctionsIterator]
|
335 |
+
ffi.lib.LLVMPY_FunctionsIterNext.restype = ffi.LLVMValueRef
|
336 |
+
|
337 |
+
ffi.lib.LLVMPY_TypesIterNext.argtypes = [ffi.LLVMTypesIterator]
|
338 |
+
ffi.lib.LLVMPY_TypesIterNext.restype = ffi.LLVMTypeRef
|
339 |
+
|
340 |
+
ffi.lib.LLVMPY_CloneModule.argtypes = [ffi.LLVMModuleRef]
|
341 |
+
ffi.lib.LLVMPY_CloneModule.restype = ffi.LLVMModuleRef
|
342 |
+
|
343 |
+
ffi.lib.LLVMPY_GetModuleName.argtypes = [ffi.LLVMModuleRef]
|
344 |
+
ffi.lib.LLVMPY_GetModuleName.restype = c_char_p
|
345 |
+
|
346 |
+
ffi.lib.LLVMPY_SetModuleName.argtypes = [ffi.LLVMModuleRef, c_char_p]
|
347 |
+
|
348 |
+
ffi.lib.LLVMPY_GetModuleSourceFileName.argtypes = [ffi.LLVMModuleRef]
|
349 |
+
ffi.lib.LLVMPY_GetModuleSourceFileName.restype = c_char_p
|
lib/python3.11/site-packages/llvmlite/binding/object_file.py
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llvmlite.binding import ffi
|
2 |
+
from ctypes import (c_bool, c_char_p, c_char, c_size_t, string_at, c_uint64,
|
3 |
+
POINTER)
|
4 |
+
|
5 |
+
|
6 |
+
class SectionIteratorRef(ffi.ObjectRef):
|
7 |
+
def name(self):
|
8 |
+
return ffi.lib.LLVMPY_GetSectionName(self)
|
9 |
+
|
10 |
+
def is_text(self):
|
11 |
+
return ffi.lib.LLVMPY_IsSectionText(self)
|
12 |
+
|
13 |
+
def size(self):
|
14 |
+
return ffi.lib.LLVMPY_GetSectionSize(self)
|
15 |
+
|
16 |
+
def address(self):
|
17 |
+
return ffi.lib.LLVMPY_GetSectionAddress(self)
|
18 |
+
|
19 |
+
def data(self):
|
20 |
+
return string_at(ffi.lib.LLVMPY_GetSectionContents(self), self.size())
|
21 |
+
|
22 |
+
def is_end(self, object_file):
|
23 |
+
return ffi.lib.LLVMPY_IsSectionIteratorAtEnd(object_file, self)
|
24 |
+
|
25 |
+
def next(self):
|
26 |
+
ffi.lib.LLVMPY_MoveToNextSection(self)
|
27 |
+
|
28 |
+
def _dispose(self):
|
29 |
+
ffi.lib.LLVMPY_DisposeSectionIterator(self)
|
30 |
+
|
31 |
+
|
32 |
+
class ObjectFileRef(ffi.ObjectRef):
|
33 |
+
@classmethod
|
34 |
+
def from_data(cls, data):
|
35 |
+
return cls(ffi.lib.LLVMPY_CreateObjectFile(data, len(data)))
|
36 |
+
|
37 |
+
@classmethod
|
38 |
+
def from_path(cls, path):
|
39 |
+
with open(path, 'rb') as f:
|
40 |
+
data = f.read()
|
41 |
+
return cls(ffi.lib.LLVMPY_CreateObjectFile(data, len(data)))
|
42 |
+
|
43 |
+
def sections(self):
|
44 |
+
it = SectionIteratorRef(ffi.lib.LLVMPY_GetSections(self))
|
45 |
+
while not it.is_end(self):
|
46 |
+
yield it
|
47 |
+
it.next()
|
48 |
+
|
49 |
+
def _dispose(self):
|
50 |
+
ffi.lib.LLVMPY_DisposeObjectFile(self)
|
51 |
+
|
52 |
+
|
53 |
+
ffi.lib.LLVMPY_CreateObjectFile.argtypes = [c_char_p, c_size_t]
|
54 |
+
ffi.lib.LLVMPY_CreateObjectFile.restype = ffi.LLVMObjectFileRef
|
55 |
+
|
56 |
+
ffi.lib.LLVMPY_DisposeObjectFile.argtypes = [ffi.LLVMObjectFileRef]
|
57 |
+
|
58 |
+
ffi.lib.LLVMPY_GetSections.argtypes = [ffi.LLVMObjectFileRef]
|
59 |
+
ffi.lib.LLVMPY_GetSections.restype = ffi.LLVMSectionIteratorRef
|
60 |
+
|
61 |
+
ffi.lib.LLVMPY_DisposeSectionIterator.argtypes = [ffi.LLVMSectionIteratorRef]
|
62 |
+
|
63 |
+
ffi.lib.LLVMPY_MoveToNextSection.argtypes = [ffi.LLVMSectionIteratorRef]
|
64 |
+
|
65 |
+
ffi.lib.LLVMPY_IsSectionIteratorAtEnd.argtypes = [
|
66 |
+
ffi.LLVMObjectFileRef, ffi.LLVMSectionIteratorRef]
|
67 |
+
ffi.lib.LLVMPY_IsSectionIteratorAtEnd.restype = c_bool
|
68 |
+
|
69 |
+
ffi.lib.LLVMPY_GetSectionName.argtypes = [ffi.LLVMSectionIteratorRef]
|
70 |
+
ffi.lib.LLVMPY_GetSectionName.restype = c_char_p
|
71 |
+
|
72 |
+
ffi.lib.LLVMPY_GetSectionSize.argtypes = [ffi.LLVMSectionIteratorRef]
|
73 |
+
ffi.lib.LLVMPY_GetSectionSize.restype = c_uint64
|
74 |
+
|
75 |
+
ffi.lib.LLVMPY_GetSectionAddress.argtypes = [ffi.LLVMSectionIteratorRef]
|
76 |
+
ffi.lib.LLVMPY_GetSectionAddress.restype = c_uint64
|
77 |
+
|
78 |
+
ffi.lib.LLVMPY_GetSectionContents.argtypes = [ffi.LLVMSectionIteratorRef]
|
79 |
+
ffi.lib.LLVMPY_GetSectionContents.restype = POINTER(c_char)
|
80 |
+
|
81 |
+
ffi.lib.LLVMPY_IsSectionText.argtypes = [ffi.LLVMSectionIteratorRef]
|
82 |
+
ffi.lib.LLVMPY_IsSectionText.restype = c_bool
|
lib/python3.11/site-packages/llvmlite/binding/options.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llvmlite.binding import ffi
|
2 |
+
from llvmlite.binding.common import _encode_string
|
3 |
+
from ctypes import c_char_p
|
4 |
+
|
5 |
+
|
6 |
+
def set_option(name, option):
|
7 |
+
"""
|
8 |
+
Set the given LLVM "command-line" option.
|
9 |
+
|
10 |
+
For example set_option("test", "-debug-pass=Structure") would display
|
11 |
+
all optimization passes when generating code.
|
12 |
+
"""
|
13 |
+
ffi.lib.LLVMPY_SetCommandLine(_encode_string(name),
|
14 |
+
_encode_string(option))
|
15 |
+
|
16 |
+
|
17 |
+
ffi.lib.LLVMPY_SetCommandLine.argtypes = [c_char_p, c_char_p]
|
lib/python3.11/site-packages/llvmlite/binding/orcjit.py
ADDED
@@ -0,0 +1,342 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import ctypes
|
2 |
+
from ctypes import POINTER, c_bool, c_char_p, c_uint8, c_uint64, c_size_t
|
3 |
+
|
4 |
+
from llvmlite.binding import ffi, targets
|
5 |
+
|
6 |
+
|
7 |
+
class _LinkElement(ctypes.Structure):
|
8 |
+
_fields_ = [("element_kind", c_uint8),
|
9 |
+
("value", c_char_p),
|
10 |
+
("value_len", c_size_t)]
|
11 |
+
|
12 |
+
|
13 |
+
class _SymbolAddress(ctypes.Structure):
|
14 |
+
_fields_ = [("name", c_char_p), ("address", c_uint64)]
|
15 |
+
|
16 |
+
|
17 |
+
class JITLibraryBuilder:
|
18 |
+
"""
|
19 |
+
Create a library for linking by OrcJIT
|
20 |
+
|
21 |
+
OrcJIT operates like a linker: a number of compilation units and
|
22 |
+
dependencies are collected together and linked into a single dynamic library
|
23 |
+
that can export functions to other libraries or to be consumed directly as
|
24 |
+
entry points into JITted code. The native OrcJIT has a lot of memory
|
25 |
+
management complications so this API is designed to work well with Python's
|
26 |
+
garbage collection.
|
27 |
+
|
28 |
+
The creation of a new library is a bit like a linker command line where
|
29 |
+
compilation units, mostly as LLVM IR, and previously constructed libraries
|
30 |
+
are linked together, then loaded into memory, and the addresses of exported
|
31 |
+
symbols are extracted. Any static initializers are run and the exported
|
32 |
+
addresses and a resource tracker is produced. As long as the resource
|
33 |
+
tracker is referenced somewhere in Python, the exported addresses will be
|
34 |
+
valid. Once the resource tracker is garbage collected, the static
|
35 |
+
destructors will run and library will be unloaded from memory.
|
36 |
+
"""
|
37 |
+
def __init__(self):
|
38 |
+
self.__entries = []
|
39 |
+
self.__exports = set()
|
40 |
+
self.__imports = {}
|
41 |
+
|
42 |
+
def add_ir(self, llvmir):
|
43 |
+
"""
|
44 |
+
Adds a compilation unit to the library using LLVM IR as the input
|
45 |
+
format.
|
46 |
+
|
47 |
+
This takes a string or an object that can be converted to a string,
|
48 |
+
including IRBuilder, that contains LLVM IR.
|
49 |
+
"""
|
50 |
+
self.__entries.append((0, str(llvmir).encode('utf-8')))
|
51 |
+
return self
|
52 |
+
|
53 |
+
def add_native_assembly(self, asm):
|
54 |
+
"""
|
55 |
+
Adds a compilation unit to the library using native assembly as the
|
56 |
+
input format.
|
57 |
+
|
58 |
+
This takes a string or an object that can be converted to a string that
|
59 |
+
contains native assembly, which will be
|
60 |
+
parsed by LLVM.
|
61 |
+
"""
|
62 |
+
self.__entries.append((1, str(asm).encode('utf-8')))
|
63 |
+
return self
|
64 |
+
|
65 |
+
def add_object_img(self, data):
|
66 |
+
"""
|
67 |
+
Adds a compilation unit to the library using pre-compiled object code.
|
68 |
+
|
69 |
+
This takes the bytes of the contents of an object artifact which will be
|
70 |
+
loaded by LLVM.
|
71 |
+
"""
|
72 |
+
self.__entries.append((2, bytes(data)))
|
73 |
+
return self
|
74 |
+
|
75 |
+
def add_object_file(self, file_path):
|
76 |
+
"""
|
77 |
+
Adds a compilation unit to the library using pre-compiled object file.
|
78 |
+
|
79 |
+
This takes a string or path-like object that references an object file
|
80 |
+
which will be loaded by LLVM.
|
81 |
+
"""
|
82 |
+
with open(file_path, "rb") as f:
|
83 |
+
self.__entries.append((2, f.read()))
|
84 |
+
return self
|
85 |
+
|
86 |
+
def add_jit_library(self, name):
|
87 |
+
"""
|
88 |
+
Adds an existing JIT library as prerequisite.
|
89 |
+
|
90 |
+
The name of the library must match the one provided in a previous link
|
91 |
+
command.
|
92 |
+
"""
|
93 |
+
self.__entries.append((3, str(name).encode('utf-8')))
|
94 |
+
return self
|
95 |
+
|
96 |
+
def add_current_process(self):
|
97 |
+
"""
|
98 |
+
Allows the JITted library to access symbols in the current binary.
|
99 |
+
|
100 |
+
That is, it allows exporting the current binary's symbols, including
|
101 |
+
loaded libraries, as imports to the JITted
|
102 |
+
library.
|
103 |
+
"""
|
104 |
+
self.__entries.append((3, b''))
|
105 |
+
return self
|
106 |
+
|
107 |
+
def import_symbol(self, name, address):
|
108 |
+
"""
|
109 |
+
Register the *address* of global symbol *name*. This will make
|
110 |
+
it usable (e.g. callable) from LLVM-compiled functions.
|
111 |
+
"""
|
112 |
+
self.__imports[str(name)] = c_uint64(address)
|
113 |
+
return self
|
114 |
+
|
115 |
+
def export_symbol(self, name):
|
116 |
+
"""
|
117 |
+
During linking, extract the address of a symbol that was defined in one
|
118 |
+
of the compilation units.
|
119 |
+
|
120 |
+
This allows getting symbols, functions or global variables, out of the
|
121 |
+
JIT linked library. The addresses will be
|
122 |
+
available when the link method is called.
|
123 |
+
"""
|
124 |
+
self.__exports.add(str(name))
|
125 |
+
return self
|
126 |
+
|
127 |
+
def link(self, lljit, library_name):
|
128 |
+
"""
|
129 |
+
Link all the current compilation units into a JITted library and extract
|
130 |
+
the address of exported symbols.
|
131 |
+
|
132 |
+
An instance of the OrcJIT instance must be provided and this will be the
|
133 |
+
scope that is used to find other JITted libraries that are dependencies
|
134 |
+
and also be the place where this library will be defined.
|
135 |
+
|
136 |
+
After linking, the method will return a resource tracker that keeps the
|
137 |
+
library alive. This tracker also knows the addresses of any exported
|
138 |
+
symbols that were requested.
|
139 |
+
|
140 |
+
The addresses will be valid as long as the resource tracker is
|
141 |
+
referenced.
|
142 |
+
|
143 |
+
When the resource tracker is destroyed, the library will be cleaned up,
|
144 |
+
however, the name of the library cannot be reused.
|
145 |
+
"""
|
146 |
+
assert not lljit.closed, "Cannot add to closed JIT"
|
147 |
+
encoded_library_name = str(library_name).encode('utf-8')
|
148 |
+
assert len(encoded_library_name) > 0, "Library cannot be empty"
|
149 |
+
elements = (_LinkElement * len(self.__entries))()
|
150 |
+
for idx, (kind, value) in enumerate(self.__entries):
|
151 |
+
elements[idx].element_kind = c_uint8(kind)
|
152 |
+
elements[idx].value = c_char_p(value)
|
153 |
+
elements[idx].value_len = c_size_t(len(value))
|
154 |
+
exports = (_SymbolAddress * len(self.__exports))()
|
155 |
+
for idx, name in enumerate(self.__exports):
|
156 |
+
exports[idx].name = name.encode('utf-8')
|
157 |
+
|
158 |
+
imports = (_SymbolAddress * len(self.__imports))()
|
159 |
+
for idx, (name, addr) in enumerate(self.__imports.items()):
|
160 |
+
imports[idx].name = name.encode('utf-8')
|
161 |
+
imports[idx].address = addr
|
162 |
+
|
163 |
+
with ffi.OutputString() as outerr:
|
164 |
+
tracker = lljit._capi.LLVMPY_LLJIT_Link(
|
165 |
+
lljit._ptr,
|
166 |
+
encoded_library_name,
|
167 |
+
elements,
|
168 |
+
len(self.__entries),
|
169 |
+
imports,
|
170 |
+
len(self.__imports),
|
171 |
+
exports,
|
172 |
+
len(self.__exports),
|
173 |
+
outerr)
|
174 |
+
if not tracker:
|
175 |
+
raise RuntimeError(str(outerr))
|
176 |
+
return ResourceTracker(tracker,
|
177 |
+
library_name,
|
178 |
+
{name: exports[idx].address
|
179 |
+
for idx, name in enumerate(self.__exports)})
|
180 |
+
|
181 |
+
|
182 |
+
class ResourceTracker(ffi.ObjectRef):
|
183 |
+
"""
|
184 |
+
A resource tracker is created for each loaded JIT library and keeps the
|
185 |
+
module alive.
|
186 |
+
|
187 |
+
OrcJIT supports unloading libraries that are no longer used. This resource
|
188 |
+
tracker should be stored in any object that reference functions or constants
|
189 |
+
for a JITted library. When all references to the resource tracker are
|
190 |
+
dropped, this will trigger LLVM to unload the library and destroy any
|
191 |
+
functions.
|
192 |
+
|
193 |
+
Failure to keep resource trackers while calling a function or accessing a
|
194 |
+
symbol can result in crashes or memory corruption.
|
195 |
+
|
196 |
+
LLVM internally tracks references between different libraries, so only
|
197 |
+
"leaf" libraries need to be tracked.
|
198 |
+
"""
|
199 |
+
def __init__(self, ptr, name, addresses):
|
200 |
+
self.__addresses = addresses
|
201 |
+
self.__name = name
|
202 |
+
ffi.ObjectRef.__init__(self, ptr)
|
203 |
+
|
204 |
+
def __getitem__(self, item):
|
205 |
+
"""
|
206 |
+
Get the address of an exported symbol as an integer
|
207 |
+
"""
|
208 |
+
return self.__addresses[item]
|
209 |
+
|
210 |
+
@property
|
211 |
+
def name(self):
|
212 |
+
return self.__name
|
213 |
+
|
214 |
+
def _dispose(self):
|
215 |
+
with ffi.OutputString() as outerr:
|
216 |
+
if self._capi.LLVMPY_LLJIT_Dylib_Tracker_Dispose(self, outerr):
|
217 |
+
raise RuntimeError(str(outerr))
|
218 |
+
|
219 |
+
|
220 |
+
class LLJIT(ffi.ObjectRef):
|
221 |
+
"""
|
222 |
+
A OrcJIT-based LLVM JIT engine that can compile and run LLVM IR as a
|
223 |
+
collection of JITted dynamic libraries
|
224 |
+
|
225 |
+
The C++ OrcJIT API has a lot of memory ownership patterns that do not work
|
226 |
+
with Python. This API attempts to provide ones that are safe at the expense
|
227 |
+
of some features. Each LLJIT instance is a collection of JIT-compiled
|
228 |
+
libraries. In the C++ API, there is a "main" library; this API does not
|
229 |
+
provide access to the main library. Use the JITLibraryBuilder to create a
|
230 |
+
new named library instead.
|
231 |
+
"""
|
232 |
+
def __init__(self, ptr):
|
233 |
+
self._td = None
|
234 |
+
ffi.ObjectRef.__init__(self, ptr)
|
235 |
+
|
236 |
+
def lookup(self, dylib, fn):
|
237 |
+
"""
|
238 |
+
Find a function in this dynamic library and construct a new tracking
|
239 |
+
object for it
|
240 |
+
|
241 |
+
If the library or function do not exist, an exception will occur.
|
242 |
+
|
243 |
+
Parameters
|
244 |
+
----------
|
245 |
+
dylib : str or None
|
246 |
+
the name of the library containing the symbol
|
247 |
+
fn : str
|
248 |
+
the name of the function to get
|
249 |
+
"""
|
250 |
+
assert not self.closed, "Cannot lookup in closed JIT"
|
251 |
+
address = ctypes.c_uint64()
|
252 |
+
with ffi.OutputString() as outerr:
|
253 |
+
tracker = ffi.lib.LLVMPY_LLJITLookup(self,
|
254 |
+
dylib.encode("utf-8"),
|
255 |
+
fn.encode("utf-8"),
|
256 |
+
ctypes.byref(address),
|
257 |
+
outerr)
|
258 |
+
if not tracker:
|
259 |
+
raise RuntimeError(str(outerr))
|
260 |
+
|
261 |
+
return ResourceTracker(tracker, dylib, {fn: address.value})
|
262 |
+
|
263 |
+
@property
|
264 |
+
def target_data(self):
|
265 |
+
"""
|
266 |
+
The TargetData for this LLJIT instance.
|
267 |
+
"""
|
268 |
+
if self._td is not None:
|
269 |
+
return self._td
|
270 |
+
ptr = ffi.lib.LLVMPY_LLJITGetDataLayout(self)
|
271 |
+
self._td = targets.TargetData(ptr)
|
272 |
+
self._td._owned = True
|
273 |
+
return self._td
|
274 |
+
|
275 |
+
def _dispose(self):
|
276 |
+
if self._td is not None:
|
277 |
+
self._td.detach()
|
278 |
+
self._capi.LLVMPY_LLJITDispose(self)
|
279 |
+
|
280 |
+
|
281 |
+
def create_lljit_compiler(target_machine=None, *,
|
282 |
+
use_jit_link=False,
|
283 |
+
suppress_errors=False):
|
284 |
+
"""
|
285 |
+
Create an LLJIT instance
|
286 |
+
"""
|
287 |
+
with ffi.OutputString() as outerr:
|
288 |
+
lljit = ffi.lib.LLVMPY_CreateLLJITCompiler(target_machine,
|
289 |
+
suppress_errors,
|
290 |
+
use_jit_link,
|
291 |
+
outerr)
|
292 |
+
if not lljit:
|
293 |
+
raise RuntimeError(str(outerr))
|
294 |
+
|
295 |
+
return LLJIT(lljit)
|
296 |
+
|
297 |
+
|
298 |
+
ffi.lib.LLVMPY_LLJITLookup.argtypes = [
|
299 |
+
ffi.LLVMOrcLLJITRef,
|
300 |
+
c_char_p,
|
301 |
+
c_char_p,
|
302 |
+
POINTER(c_uint64),
|
303 |
+
POINTER(c_char_p),
|
304 |
+
]
|
305 |
+
ffi.lib.LLVMPY_LLJITLookup.restype = ffi.LLVMOrcDylibTrackerRef
|
306 |
+
|
307 |
+
ffi.lib.LLVMPY_LLJITGetDataLayout.argtypes = [
|
308 |
+
ffi.LLVMOrcLLJITRef,
|
309 |
+
]
|
310 |
+
ffi.lib.LLVMPY_LLJITGetDataLayout.restype = ffi.LLVMTargetDataRef
|
311 |
+
|
312 |
+
ffi.lib.LLVMPY_CreateLLJITCompiler.argtypes = [
|
313 |
+
ffi.LLVMTargetMachineRef,
|
314 |
+
c_bool,
|
315 |
+
c_bool,
|
316 |
+
POINTER(c_char_p),
|
317 |
+
]
|
318 |
+
ffi.lib.LLVMPY_CreateLLJITCompiler.restype = ffi.LLVMOrcLLJITRef
|
319 |
+
|
320 |
+
ffi.lib.LLVMPY_LLJITDispose.argtypes = [
|
321 |
+
ffi.LLVMOrcLLJITRef,
|
322 |
+
]
|
323 |
+
|
324 |
+
|
325 |
+
ffi.lib.LLVMPY_LLJIT_Link.argtypes = [
|
326 |
+
ffi.LLVMOrcLLJITRef,
|
327 |
+
c_char_p,
|
328 |
+
POINTER(_LinkElement),
|
329 |
+
c_size_t,
|
330 |
+
POINTER(_SymbolAddress),
|
331 |
+
c_size_t,
|
332 |
+
POINTER(_SymbolAddress),
|
333 |
+
c_size_t,
|
334 |
+
POINTER(c_char_p)
|
335 |
+
]
|
336 |
+
ffi.lib.LLVMPY_LLJIT_Link.restype = ffi.LLVMOrcDylibTrackerRef
|
337 |
+
|
338 |
+
ffi.lib.LLVMPY_LLJIT_Dylib_Tracker_Dispose.argtypes = [
|
339 |
+
ffi.LLVMOrcDylibTrackerRef,
|
340 |
+
POINTER(c_char_p)
|
341 |
+
]
|
342 |
+
ffi.lib.LLVMPY_LLJIT_Dylib_Tracker_Dispose.restype = c_bool
|
lib/python3.11/site-packages/llvmlite/binding/passmanagers.py
ADDED
@@ -0,0 +1,923 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ctypes import (c_bool, c_char_p, c_int, c_size_t, c_uint, Structure, byref,
|
2 |
+
POINTER)
|
3 |
+
from collections import namedtuple
|
4 |
+
from enum import IntFlag
|
5 |
+
from llvmlite.binding import ffi
|
6 |
+
import os
|
7 |
+
from tempfile import mkstemp
|
8 |
+
from llvmlite.binding.common import _encode_string
|
9 |
+
|
10 |
+
_prunestats = namedtuple('PruneStats',
|
11 |
+
('basicblock diamond fanout fanout_raise'))
|
12 |
+
|
13 |
+
|
14 |
+
class PruneStats(_prunestats):
|
15 |
+
""" Holds statistics from reference count pruning.
|
16 |
+
"""
|
17 |
+
|
18 |
+
def __add__(self, other):
|
19 |
+
if not isinstance(other, PruneStats):
|
20 |
+
msg = 'PruneStats can only be added to another PruneStats, got {}.'
|
21 |
+
raise TypeError(msg.format(type(other)))
|
22 |
+
return PruneStats(self.basicblock + other.basicblock,
|
23 |
+
self.diamond + other.diamond,
|
24 |
+
self.fanout + other.fanout,
|
25 |
+
self.fanout_raise + other.fanout_raise)
|
26 |
+
|
27 |
+
def __sub__(self, other):
|
28 |
+
if not isinstance(other, PruneStats):
|
29 |
+
msg = ('PruneStats can only be subtracted from another PruneStats, '
|
30 |
+
'got {}.')
|
31 |
+
raise TypeError(msg.format(type(other)))
|
32 |
+
return PruneStats(self.basicblock - other.basicblock,
|
33 |
+
self.diamond - other.diamond,
|
34 |
+
self.fanout - other.fanout,
|
35 |
+
self.fanout_raise - other.fanout_raise)
|
36 |
+
|
37 |
+
|
38 |
+
class _c_PruneStats(Structure):
|
39 |
+
_fields_ = [
|
40 |
+
('basicblock', c_size_t),
|
41 |
+
('diamond', c_size_t),
|
42 |
+
('fanout', c_size_t),
|
43 |
+
('fanout_raise', c_size_t)]
|
44 |
+
|
45 |
+
|
46 |
+
def dump_refprune_stats(printout=False):
|
47 |
+
""" Returns a namedtuple containing the current values for the refop pruning
|
48 |
+
statistics. If kwarg `printout` is True the stats are printed to stderr,
|
49 |
+
default is False.
|
50 |
+
"""
|
51 |
+
|
52 |
+
stats = _c_PruneStats(0, 0, 0, 0)
|
53 |
+
do_print = c_bool(printout)
|
54 |
+
|
55 |
+
ffi.lib.LLVMPY_DumpRefPruneStats(byref(stats), do_print)
|
56 |
+
return PruneStats(stats.basicblock, stats.diamond, stats.fanout,
|
57 |
+
stats.fanout_raise)
|
58 |
+
|
59 |
+
|
60 |
+
def set_time_passes(enable):
|
61 |
+
"""Enable or disable the pass timers.
|
62 |
+
|
63 |
+
Parameters
|
64 |
+
----------
|
65 |
+
enable : bool
|
66 |
+
Set to True to enable the pass timers.
|
67 |
+
Set to False to disable the pass timers.
|
68 |
+
"""
|
69 |
+
ffi.lib.LLVMPY_SetTimePasses(c_bool(enable))
|
70 |
+
|
71 |
+
|
72 |
+
def report_and_reset_timings():
|
73 |
+
"""Returns the pass timings report and resets the LLVM internal timers.
|
74 |
+
|
75 |
+
Pass timers are enabled by ``set_time_passes()``. If the timers are not
|
76 |
+
enabled, this function will return an empty string.
|
77 |
+
|
78 |
+
Returns
|
79 |
+
-------
|
80 |
+
res : str
|
81 |
+
LLVM generated timing report.
|
82 |
+
"""
|
83 |
+
with ffi.OutputString() as buf:
|
84 |
+
ffi.lib.LLVMPY_ReportAndResetTimings(buf)
|
85 |
+
return str(buf)
|
86 |
+
|
87 |
+
|
88 |
+
def create_module_pass_manager():
|
89 |
+
return ModulePassManager()
|
90 |
+
|
91 |
+
|
92 |
+
def create_function_pass_manager(module):
|
93 |
+
return FunctionPassManager(module)
|
94 |
+
|
95 |
+
|
96 |
+
class RefPruneSubpasses(IntFlag):
|
97 |
+
PER_BB = 0b0001 # noqa: E221
|
98 |
+
DIAMOND = 0b0010 # noqa: E221
|
99 |
+
FANOUT = 0b0100 # noqa: E221
|
100 |
+
FANOUT_RAISE = 0b1000
|
101 |
+
ALL = PER_BB | DIAMOND | FANOUT | FANOUT_RAISE
|
102 |
+
|
103 |
+
|
104 |
+
class PassManager(ffi.ObjectRef):
|
105 |
+
"""PassManager
|
106 |
+
"""
|
107 |
+
|
108 |
+
def _dispose(self):
|
109 |
+
self._capi.LLVMPY_DisposePassManager(self)
|
110 |
+
|
111 |
+
def add_aa_eval_pass(self):
|
112 |
+
"""
|
113 |
+
See https://llvm.org/docs/Passes.html#aa-eval-exhaustive-alias-analysis-precision-evaluator
|
114 |
+
|
115 |
+
LLVM 14: `llvm::createAAEvalPass`
|
116 |
+
""" # noqa E501
|
117 |
+
ffi.lib.LLVMPY_AddAAEvalPass(self)
|
118 |
+
|
119 |
+
def add_basic_aa_pass(self):
|
120 |
+
"""
|
121 |
+
See https://llvm.org/docs/Passes.html#basic-aa-basic-alias-analysis-stateless-aa-impl
|
122 |
+
|
123 |
+
LLVM 14: `llvm::createBasicAAWrapperPass`
|
124 |
+
""" # noqa E501
|
125 |
+
ffi.lib.LLVMPY_AddBasicAAWrapperPass(self)
|
126 |
+
|
127 |
+
def add_constant_merge_pass(self):
|
128 |
+
"""
|
129 |
+
See http://llvm.org/docs/Passes.html#constmerge-merge-duplicate-global-constants
|
130 |
+
|
131 |
+
LLVM 14: `LLVMAddConstantMergePass`
|
132 |
+
""" # noqa E501
|
133 |
+
ffi.lib.LLVMPY_AddConstantMergePass(self)
|
134 |
+
|
135 |
+
def add_dead_arg_elimination_pass(self):
|
136 |
+
"""
|
137 |
+
See http://llvm.org/docs/Passes.html#deadargelim-dead-argument-elimination
|
138 |
+
|
139 |
+
LLVM 14: `LLVMAddDeadArgEliminationPass`
|
140 |
+
""" # noqa E501
|
141 |
+
ffi.lib.LLVMPY_AddDeadArgEliminationPass(self)
|
142 |
+
|
143 |
+
def add_dependence_analysis_pass(self):
|
144 |
+
"""
|
145 |
+
See https://llvm.org/docs/Passes.html#da-dependence-analysis
|
146 |
+
|
147 |
+
LLVM 14: `llvm::createDependenceAnalysisWrapperPass`
|
148 |
+
""" # noqa E501
|
149 |
+
ffi.lib.LLVMPY_AddDependenceAnalysisPass(self)
|
150 |
+
|
151 |
+
def add_dot_call_graph_pass(self):
|
152 |
+
"""
|
153 |
+
See https://llvm.org/docs/Passes.html#dot-callgraph-print-call-graph-to-dot-file
|
154 |
+
|
155 |
+
LLVM 14: `llvm::createCallGraphDOTPrinterPass`
|
156 |
+
""" # noqa E501
|
157 |
+
ffi.lib.LLVMPY_AddCallGraphDOTPrinterPass(self)
|
158 |
+
|
159 |
+
def add_dot_cfg_printer_pass(self):
|
160 |
+
"""
|
161 |
+
See https://llvm.org/docs/Passes.html#dot-cfg-print-cfg-of-function-to-dot-file
|
162 |
+
|
163 |
+
LLVM 14: `llvm::createCFGPrinterLegacyPassPass`
|
164 |
+
""" # noqa E501
|
165 |
+
ffi.lib.LLVMPY_AddCFGPrinterPass(self)
|
166 |
+
|
167 |
+
def add_dot_dom_printer_pass(self, show_body=False):
|
168 |
+
"""
|
169 |
+
See https://llvm.org/docs/Passes.html#dot-dom-print-dominance-tree-of-function-to-dot-file
|
170 |
+
|
171 |
+
LLVM 14: `llvm::createDomPrinterPass` and `llvm::createDomOnlyPrinterPass`
|
172 |
+
""" # noqa E501
|
173 |
+
ffi.lib.LLVMPY_AddDotDomPrinterPass(self, show_body)
|
174 |
+
|
175 |
+
def add_dot_postdom_printer_pass(self, show_body=False):
|
176 |
+
"""
|
177 |
+
See https://llvm.org/docs/Passes.html#dot-postdom-print-postdominance-tree-of-function-to-dot-file
|
178 |
+
|
179 |
+
LLVM 14: `llvm::createPostDomPrinterPass` and `llvm::createPostDomOnlyPrinterPass`
|
180 |
+
""" # noqa E501
|
181 |
+
ffi.lib.LLVMPY_AddDotPostDomPrinterPass(self, show_body)
|
182 |
+
|
183 |
+
def add_globals_mod_ref_aa_pass(self):
|
184 |
+
"""
|
185 |
+
See https://llvm.org/docs/Passes.html#globalsmodref-aa-simple-mod-ref-analysis-for-globals
|
186 |
+
|
187 |
+
LLVM 14: `llvm::createGlobalsAAWrapperPass`
|
188 |
+
""" # noqa E501
|
189 |
+
ffi.lib.LLVMPY_AddGlobalsModRefAAPass(self)
|
190 |
+
|
191 |
+
def add_iv_users_pass(self):
|
192 |
+
"""
|
193 |
+
See https://llvm.org/docs/Passes.html#iv-users-induction-variable-users
|
194 |
+
|
195 |
+
LLVM 14: `llvm::createIVUsersPass`
|
196 |
+
""" # noqa E501
|
197 |
+
ffi.lib.LLVMPY_AddIVUsersPass(self)
|
198 |
+
|
199 |
+
def add_lint_pass(self):
|
200 |
+
"""
|
201 |
+
See https://llvm.org/docs/Passes.html#lint-statically-lint-checks-llvm-ir
|
202 |
+
|
203 |
+
LLVM 14: `llvm::createLintLegacyPassPass`
|
204 |
+
""" # noqa E501
|
205 |
+
ffi.lib.LLVMPY_AddLintPass(self)
|
206 |
+
|
207 |
+
def add_lazy_value_info_pass(self):
|
208 |
+
"""
|
209 |
+
See https://llvm.org/docs/Passes.html#lazy-value-info-lazy-value-information-analysis
|
210 |
+
|
211 |
+
LLVM 14: `llvm::createLazyValueInfoPass`
|
212 |
+
""" # noqa E501
|
213 |
+
ffi.lib.LLVMPY_AddLazyValueInfoPass(self)
|
214 |
+
|
215 |
+
def add_module_debug_info_pass(self):
|
216 |
+
"""
|
217 |
+
See https://llvm.org/docs/Passes.html#module-debuginfo-decodes-module-level-debug-info
|
218 |
+
|
219 |
+
LLVM 14: `llvm::createModuleDebugInfoPrinterPass`
|
220 |
+
""" # noqa E501
|
221 |
+
ffi.lib.LLVMPY_AddModuleDebugInfoPrinterPass(self)
|
222 |
+
|
223 |
+
def add_region_info_pass(self):
|
224 |
+
"""
|
225 |
+
See https://llvm.org/docs/Passes.html#regions-detect-single-entry-single-exit-regions
|
226 |
+
|
227 |
+
LLVM 14: `llvm::createRegionInfoPass`
|
228 |
+
""" # noqa E501
|
229 |
+
ffi.lib.LLVMPY_AddRegionInfoPass(self)
|
230 |
+
|
231 |
+
def add_scalar_evolution_aa_pass(self):
|
232 |
+
"""
|
233 |
+
See https://llvm.org/docs/Passes.html#scev-aa-scalarevolution-based-alias-analysis
|
234 |
+
|
235 |
+
LLVM 14: `llvm::createSCEVAAWrapperPass`
|
236 |
+
""" # noqa E501
|
237 |
+
ffi.lib.LLVMPY_AddScalarEvolutionAAPass(self)
|
238 |
+
|
239 |
+
def add_aggressive_dead_code_elimination_pass(self):
|
240 |
+
"""
|
241 |
+
See https://llvm.org/docs/Passes.html#adce-aggressive-dead-code-elimination
|
242 |
+
|
243 |
+
LLVM 14: `llvm::createAggressiveDCEPass`
|
244 |
+
""" # noqa E501
|
245 |
+
ffi.lib.LLVMPY_AddAggressiveDCEPass(self)
|
246 |
+
|
247 |
+
def add_always_inliner_pass(self, insert_lifetime=True):
|
248 |
+
"""
|
249 |
+
See https://llvm.org/docs/Passes.html#always-inline-inliner-for-always-inline-functions
|
250 |
+
|
251 |
+
LLVM 14: `llvm::createAlwaysInlinerLegacyPass`
|
252 |
+
""" # noqa E501
|
253 |
+
ffi.lib.LLVMPY_AddAlwaysInlinerPass(self, insert_lifetime)
|
254 |
+
|
255 |
+
def add_arg_promotion_pass(self, max_elements=3):
|
256 |
+
"""
|
257 |
+
See https://llvm.org/docs/Passes.html#argpromotion-promote-by-reference-arguments-to-scalars
|
258 |
+
|
259 |
+
LLVM 14: `llvm::createArgumentPromotionPass`
|
260 |
+
""" # noqa E501
|
261 |
+
ffi.lib.LLVMPY_AddArgPromotionPass(self, max_elements)
|
262 |
+
|
263 |
+
def add_break_critical_edges_pass(self):
|
264 |
+
"""
|
265 |
+
See https://llvm.org/docs/Passes.html#break-crit-edges-break-critical-edges-in-cfg
|
266 |
+
|
267 |
+
LLVM 14: `llvm::createBreakCriticalEdgesPass`
|
268 |
+
""" # noqa E501
|
269 |
+
ffi.lib.LLVMPY_AddBreakCriticalEdgesPass(self)
|
270 |
+
|
271 |
+
def add_dead_store_elimination_pass(self):
|
272 |
+
"""
|
273 |
+
See https://llvm.org/docs/Passes.html#dse-dead-store-elimination
|
274 |
+
|
275 |
+
LLVM 14: `llvm::createDeadStoreEliminationPass`
|
276 |
+
""" # noqa E501
|
277 |
+
ffi.lib.LLVMPY_AddDeadStoreEliminationPass(self)
|
278 |
+
|
279 |
+
def add_reverse_post_order_function_attrs_pass(self):
|
280 |
+
"""
|
281 |
+
See https://llvm.org/docs/Passes.html#function-attrs-deduce-function-attributes
|
282 |
+
|
283 |
+
LLVM 14: `llvm::createReversePostOrderFunctionAttrsPass`
|
284 |
+
""" # noqa E501
|
285 |
+
ffi.lib.LLVMPY_AddReversePostOrderFunctionAttrsPass(self)
|
286 |
+
|
287 |
+
def add_function_attrs_pass(self):
|
288 |
+
"""
|
289 |
+
See http://llvm.org/docs/Passes.html#functionattrs-deduce-function-attributes
|
290 |
+
|
291 |
+
LLVM 14: `LLVMAddFunctionAttrsPass`
|
292 |
+
""" # noqa E501
|
293 |
+
ffi.lib.LLVMPY_AddFunctionAttrsPass(self)
|
294 |
+
|
295 |
+
def add_function_inlining_pass(self, threshold):
|
296 |
+
"""
|
297 |
+
See http://llvm.org/docs/Passes.html#inline-function-integration-inlining
|
298 |
+
|
299 |
+
LLVM 14: `createFunctionInliningPass`
|
300 |
+
""" # noqa E501
|
301 |
+
ffi.lib.LLVMPY_AddFunctionInliningPass(self, threshold)
|
302 |
+
|
303 |
+
def add_global_dce_pass(self):
|
304 |
+
"""
|
305 |
+
See http://llvm.org/docs/Passes.html#globaldce-dead-global-elimination
|
306 |
+
|
307 |
+
LLVM 14: `LLVMAddGlobalDCEPass`
|
308 |
+
""" # noqa E501
|
309 |
+
ffi.lib.LLVMPY_AddGlobalDCEPass(self)
|
310 |
+
|
311 |
+
def add_global_optimizer_pass(self):
|
312 |
+
"""
|
313 |
+
See http://llvm.org/docs/Passes.html#globalopt-global-variable-optimizer
|
314 |
+
|
315 |
+
LLVM 14: `LLVMAddGlobalOptimizerPass`
|
316 |
+
""" # noqa E501
|
317 |
+
ffi.lib.LLVMPY_AddGlobalOptimizerPass(self)
|
318 |
+
|
319 |
+
def add_ipsccp_pass(self):
|
320 |
+
"""
|
321 |
+
See http://llvm.org/docs/Passes.html#ipsccp-interprocedural-sparse-conditional-constant-propagation
|
322 |
+
|
323 |
+
LLVM 14: `LLVMAddIPSCCPPass`
|
324 |
+
""" # noqa E501
|
325 |
+
ffi.lib.LLVMPY_AddIPSCCPPass(self)
|
326 |
+
|
327 |
+
def add_dead_code_elimination_pass(self):
|
328 |
+
"""
|
329 |
+
See http://llvm.org/docs/Passes.html#dce-dead-code-elimination
|
330 |
+
LLVM 14: `llvm::createDeadCodeEliminationPass`
|
331 |
+
"""
|
332 |
+
ffi.lib.LLVMPY_AddDeadCodeEliminationPass(self)
|
333 |
+
|
334 |
+
def add_aggressive_instruction_combining_pass(self):
|
335 |
+
"""
|
336 |
+
See https://llvm.org/docs/Passes.html#aggressive-instcombine-combine-expression-patterns
|
337 |
+
|
338 |
+
LLVM 14: `llvm::createAggressiveInstCombinerPass`
|
339 |
+
""" # noqa E501
|
340 |
+
ffi.lib.LLVMPY_AddAggressiveInstructionCombiningPass(self)
|
341 |
+
|
342 |
+
def add_internalize_pass(self):
|
343 |
+
"""
|
344 |
+
See https://llvm.org/docs/Passes.html#internalize-internalize-global-symbols
|
345 |
+
|
346 |
+
LLVM 14: `llvm::createInternalizePass`
|
347 |
+
""" # noqa E501
|
348 |
+
ffi.lib.LLVMPY_AddInternalizePass(self)
|
349 |
+
|
350 |
+
def add_cfg_simplification_pass(self):
|
351 |
+
"""
|
352 |
+
See http://llvm.org/docs/Passes.html#simplifycfg-simplify-the-cfg
|
353 |
+
|
354 |
+
LLVM 14: `LLVMAddCFGSimplificationPass`
|
355 |
+
"""
|
356 |
+
ffi.lib.LLVMPY_AddCFGSimplificationPass(self)
|
357 |
+
|
358 |
+
def add_jump_threading_pass(self, threshold=-1):
|
359 |
+
"""
|
360 |
+
See https://llvm.org/docs/Passes.html#jump-threading-jump-threading
|
361 |
+
|
362 |
+
LLVM 14: `llvm::createJumpThreadingPass`
|
363 |
+
""" # noqa E501
|
364 |
+
ffi.lib.LLVMPY_AddJumpThreadingPass(self, threshold)
|
365 |
+
|
366 |
+
def add_lcssa_pass(self):
|
367 |
+
"""
|
368 |
+
See https://llvm.org/docs/Passes.html#lcssa-loop-closed-ssa-form-pass
|
369 |
+
|
370 |
+
LLVM 14: `llvm::createLCSSAPass`
|
371 |
+
""" # noqa E501
|
372 |
+
ffi.lib.LLVMPY_AddLCSSAPass(self)
|
373 |
+
|
374 |
+
def add_gvn_pass(self):
|
375 |
+
"""
|
376 |
+
See http://llvm.org/docs/Passes.html#gvn-global-value-numbering
|
377 |
+
|
378 |
+
LLVM 14: `LLVMAddGVNPass`
|
379 |
+
"""
|
380 |
+
ffi.lib.LLVMPY_AddGVNPass(self)
|
381 |
+
|
382 |
+
def add_instruction_combining_pass(self):
|
383 |
+
"""
|
384 |
+
See http://llvm.org/docs/Passes.html#passes-instcombine
|
385 |
+
|
386 |
+
LLVM 14: `LLVMAddInstructionCombiningPass`
|
387 |
+
"""
|
388 |
+
ffi.lib.LLVMPY_AddInstructionCombiningPass(self)
|
389 |
+
|
390 |
+
def add_licm_pass(self):
|
391 |
+
"""
|
392 |
+
See http://llvm.org/docs/Passes.html#licm-loop-invariant-code-motion
|
393 |
+
|
394 |
+
LLVM 14: `LLVMAddLICMPass`
|
395 |
+
""" # noqa E501
|
396 |
+
ffi.lib.LLVMPY_AddLICMPass(self)
|
397 |
+
|
398 |
+
def add_loop_deletion_pass(self):
|
399 |
+
"""
|
400 |
+
See https://llvm.org/docs/Passes.html#loop-deletion-delete-dead-loops
|
401 |
+
|
402 |
+
LLVM 14: `llvm::createLoopDeletionPass`
|
403 |
+
""" # noqa E501
|
404 |
+
ffi.lib.LLVMPY_AddLoopDeletionPass(self)
|
405 |
+
|
406 |
+
def add_loop_extractor_pass(self):
|
407 |
+
"""
|
408 |
+
See https://llvm.org/docs/Passes.html#loop-extract-extract-loops-into-new-functions
|
409 |
+
|
410 |
+
LLVM 14: `llvm::createLoopExtractorPass`
|
411 |
+
""" # noqa E501
|
412 |
+
ffi.lib.LLVMPY_AddLoopExtractorPass(self)
|
413 |
+
|
414 |
+
def add_single_loop_extractor_pass(self):
|
415 |
+
"""
|
416 |
+
See https://llvm.org/docs/Passes.html#loop-extract-single-extract-at-most-one-loop-into-a-new-function
|
417 |
+
|
418 |
+
LLVM 14: `llvm::createSingleLoopExtractorPass`
|
419 |
+
""" # noqa E501
|
420 |
+
ffi.lib.LLVMPY_AddSingleLoopExtractorPass(self)
|
421 |
+
|
422 |
+
def add_sccp_pass(self):
|
423 |
+
"""
|
424 |
+
See http://llvm.org/docs/Passes.html#sccp-sparse-conditional-constant-propagation
|
425 |
+
|
426 |
+
LLVM 14: `LLVMAddSCCPPass`
|
427 |
+
""" # noqa E501
|
428 |
+
ffi.lib.LLVMPY_AddSCCPPass(self)
|
429 |
+
|
430 |
+
def add_loop_strength_reduce_pass(self):
|
431 |
+
"""
|
432 |
+
See https://llvm.org/docs/Passes.html#loop-reduce-loop-strength-reduction
|
433 |
+
|
434 |
+
LLVM 14: `llvm::createLoopStrengthReducePass`
|
435 |
+
""" # noqa E501
|
436 |
+
ffi.lib.LLVMPY_AddLoopStrengthReducePass(self)
|
437 |
+
|
438 |
+
def add_loop_simplification_pass(self):
|
439 |
+
"""
|
440 |
+
See https://llvm.org/docs/Passes.html#loop-simplify-canonicalize-natural-loops
|
441 |
+
|
442 |
+
LLVM 14: `llvm::createLoopSimplifyPass`
|
443 |
+
""" # noqa E501
|
444 |
+
ffi.lib.LLVMPY_AddLoopSimplificationPass(self)
|
445 |
+
|
446 |
+
def add_loop_unroll_pass(self):
|
447 |
+
"""
|
448 |
+
See https://llvm.org/docs/Passes.html#loop-unroll-unroll-loops
|
449 |
+
|
450 |
+
LLVM 14: `LLVMAddLoopUnrollPass`
|
451 |
+
""" # noqa E501
|
452 |
+
ffi.lib.LLVMPY_AddLoopUnrollPass(self)
|
453 |
+
|
454 |
+
def add_loop_unroll_and_jam_pass(self):
|
455 |
+
"""
|
456 |
+
See https://llvm.org/docs/Passes.html#loop-unroll-and-jam-unroll-and-jam-loops
|
457 |
+
|
458 |
+
LLVM 14: `LLVMAddLoopUnrollAndJamPass`
|
459 |
+
""" # noqa E501
|
460 |
+
ffi.lib.LLVMPY_AddLoopUnrollAndJamPass(self)
|
461 |
+
|
462 |
+
def add_loop_unswitch_pass(self,
|
463 |
+
optimize_for_size=False,
|
464 |
+
has_branch_divergence=False):
|
465 |
+
"""
|
466 |
+
See https://llvm.org/docs/Passes.html#loop-unswitch-unswitch-loops
|
467 |
+
|
468 |
+
LLVM 14: `llvm::createLoopUnswitchPass`
|
469 |
+
""" # noqa E501
|
470 |
+
ffi.lib.LLVMPY_AddLoopUnswitchPass(self,
|
471 |
+
optimize_for_size,
|
472 |
+
has_branch_divergence)
|
473 |
+
|
474 |
+
def add_lower_atomic_pass(self):
|
475 |
+
"""
|
476 |
+
See https://llvm.org/docs/Passes.html#loweratomic-lower-atomic-intrinsics-to-non-atomic-form
|
477 |
+
|
478 |
+
LLVM 14: `llvm::createLowerAtomicPass`
|
479 |
+
""" # noqa E501
|
480 |
+
ffi.lib.LLVMPY_AddLowerAtomicPass(self)
|
481 |
+
|
482 |
+
def add_lower_invoke_pass(self):
|
483 |
+
"""
|
484 |
+
See https://llvm.org/docs/Passes.html#lowerinvoke-lower-invokes-to-calls-for-unwindless-code-generators
|
485 |
+
|
486 |
+
LLVM 14: `llvm::createLowerInvokePass`
|
487 |
+
""" # noqa E501
|
488 |
+
ffi.lib.LLVMPY_AddLowerInvokePass(self)
|
489 |
+
|
490 |
+
def add_lower_switch_pass(self):
|
491 |
+
"""
|
492 |
+
See https://llvm.org/docs/Passes.html#lowerswitch-lower-switchinsts-to-branches
|
493 |
+
|
494 |
+
LLVM 14: `llvm::createLowerSwitchPass`
|
495 |
+
""" # noqa E501
|
496 |
+
ffi.lib.LLVMPY_AddLowerSwitchPass(self)
|
497 |
+
|
498 |
+
def add_memcpy_optimization_pass(self):
|
499 |
+
"""
|
500 |
+
See https://llvm.org/docs/Passes.html#memcpyopt-memcpy-optimization
|
501 |
+
|
502 |
+
LLVM 14: `llvm::createMemCpyOptPass`
|
503 |
+
""" # noqa E501
|
504 |
+
ffi.lib.LLVMPY_AddMemCpyOptimizationPass(self)
|
505 |
+
|
506 |
+
def add_merge_functions_pass(self):
|
507 |
+
"""
|
508 |
+
See https://llvm.org/docs/Passes.html#mergefunc-merge-functions
|
509 |
+
|
510 |
+
LLVM 14: `llvm::createMergeFunctionsPass`
|
511 |
+
""" # noqa E501
|
512 |
+
ffi.lib.LLVMPY_AddMergeFunctionsPass(self)
|
513 |
+
|
514 |
+
def add_merge_returns_pass(self):
|
515 |
+
"""
|
516 |
+
See https://llvm.org/docs/Passes.html#mergereturn-unify-function-exit-nodes
|
517 |
+
|
518 |
+
LLVM 14: `llvm::createUnifyFunctionExitNodesPass`
|
519 |
+
""" # noqa E501
|
520 |
+
ffi.lib.LLVMPY_AddMergeReturnsPass(self)
|
521 |
+
|
522 |
+
def add_partial_inlining_pass(self):
|
523 |
+
"""
|
524 |
+
See https://llvm.org/docs/Passes.html#partial-inliner-partial-inliner
|
525 |
+
|
526 |
+
LLVM 14: `llvm::createPartialInliningPass`
|
527 |
+
""" # noqa E501
|
528 |
+
ffi.lib.LLVMPY_AddPartialInliningPass(self)
|
529 |
+
|
530 |
+
def add_prune_exception_handling_pass(self):
|
531 |
+
"""
|
532 |
+
See https://llvm.org/docs/Passes.html#prune-eh-remove-unused-exception-handling-info
|
533 |
+
|
534 |
+
LLVM 14: `llvm::createPruneEHPass`
|
535 |
+
""" # noqa E501
|
536 |
+
ffi.lib.LLVMPY_AddPruneExceptionHandlingPass(self)
|
537 |
+
|
538 |
+
def add_reassociate_expressions_pass(self):
|
539 |
+
"""
|
540 |
+
See https://llvm.org/docs/Passes.html#reassociate-reassociate-expressions
|
541 |
+
|
542 |
+
LLVM 14: `llvm::createReassociatePass`
|
543 |
+
""" # noqa E501
|
544 |
+
ffi.lib.LLVMPY_AddReassociatePass(self)
|
545 |
+
|
546 |
+
def add_demote_register_to_memory_pass(self):
|
547 |
+
"""
|
548 |
+
See https://llvm.org/docs/Passes.html#rel-lookup-table-converter-relative-lookup-table-converter
|
549 |
+
|
550 |
+
LLVM 14: `llvm::createDemoteRegisterToMemoryPass`
|
551 |
+
""" # noqa E501
|
552 |
+
ffi.lib.LLVMPY_AddDemoteRegisterToMemoryPass(self)
|
553 |
+
|
554 |
+
def add_sroa_pass(self):
|
555 |
+
"""
|
556 |
+
See http://llvm.org/docs/Passes.html#scalarrepl-scalar-replacement-of-aggregates-dt
|
557 |
+
Note that this pass corresponds to the ``opt -sroa`` command-line option,
|
558 |
+
despite the link above.
|
559 |
+
|
560 |
+
LLVM 14: `llvm::createSROAPass`
|
561 |
+
""" # noqa E501
|
562 |
+
ffi.lib.LLVMPY_AddSROAPass(self)
|
563 |
+
|
564 |
+
def add_sink_pass(self):
|
565 |
+
"""
|
566 |
+
See https://llvm.org/docs/Passes.html#sink-code-sinking
|
567 |
+
|
568 |
+
LLVM 14: `llvm::createSinkingPass`
|
569 |
+
""" # noqa E501
|
570 |
+
ffi.lib.LLVMPY_AddSinkPass(self)
|
571 |
+
|
572 |
+
def add_strip_symbols_pass(self, only_debug=False):
|
573 |
+
"""
|
574 |
+
See https://llvm.org/docs/Passes.html#strip-strip-all-symbols-from-a-module
|
575 |
+
|
576 |
+
LLVM 14: `llvm::createStripSymbolsPass`
|
577 |
+
""" # noqa E501
|
578 |
+
ffi.lib.LLVMPY_AddStripSymbolsPass(self, only_debug)
|
579 |
+
|
580 |
+
def add_strip_dead_debug_info_pass(self):
|
581 |
+
"""
|
582 |
+
See https://llvm.org/docs/Passes.html#strip-dead-debug-info-strip-debug-info-for-unused-symbols
|
583 |
+
|
584 |
+
LLVM 14: `llvm::createStripDeadDebugInfoPass`
|
585 |
+
""" # noqa E501
|
586 |
+
ffi.lib.LLVMPY_AddStripDeadDebugInfoPass(self)
|
587 |
+
|
588 |
+
def add_strip_dead_prototypes_pass(self):
|
589 |
+
"""
|
590 |
+
See https://llvm.org/docs/Passes.html#strip-dead-prototypes-strip-unused-function-prototypes
|
591 |
+
|
592 |
+
LLVM 14: `llvm::createStripDeadPrototypesPass`
|
593 |
+
""" # noqa E501
|
594 |
+
ffi.lib.LLVMPY_AddStripDeadPrototypesPass(self)
|
595 |
+
|
596 |
+
def add_strip_debug_declare_pass(self):
|
597 |
+
"""
|
598 |
+
See https://llvm.org/docs/Passes.html#strip-debug-declare-strip-all-llvm-dbg-declare-intrinsics
|
599 |
+
|
600 |
+
LLVM 14: `llvm::createStripDebugDeclarePass`
|
601 |
+
""" # noqa E501
|
602 |
+
ffi.lib.LLVMPY_AddStripDebugDeclarePrototypesPass(self)
|
603 |
+
|
604 |
+
def add_strip_nondebug_symbols_pass(self):
|
605 |
+
"""
|
606 |
+
See https://llvm.org/docs/Passes.html#strip-nondebug-strip-all-symbols-except-dbg-symbols-from-a-module
|
607 |
+
|
608 |
+
LLVM 14: `llvm::createStripNonDebugSymbolsPass`
|
609 |
+
""" # noqa E501
|
610 |
+
ffi.lib.LLVMPY_AddStripNondebugSymbolsPass(self)
|
611 |
+
|
612 |
+
def add_tail_call_elimination_pass(self):
|
613 |
+
"""
|
614 |
+
See https://llvm.org/docs/Passes.html#tailcallelim-tail-call-elimination
|
615 |
+
|
616 |
+
LLVM 14: `llvm::createTailCallEliminationPass`
|
617 |
+
""" # noqa E501
|
618 |
+
ffi.lib.LLVMPY_AddTailCallEliminationPass(self)
|
619 |
+
|
620 |
+
def add_type_based_alias_analysis_pass(self):
|
621 |
+
"""
|
622 |
+
LLVM 14: `LLVMAddTypeBasedAliasAnalysisPass`
|
623 |
+
""" # noqa E501
|
624 |
+
ffi.lib.LLVMPY_AddTypeBasedAliasAnalysisPass(self)
|
625 |
+
|
626 |
+
def add_basic_alias_analysis_pass(self):
|
627 |
+
"""
|
628 |
+
See http://llvm.org/docs/AliasAnalysis.html#the-basicaa-pass
|
629 |
+
|
630 |
+
LLVM 14: `LLVMAddBasicAliasAnalysisPass`
|
631 |
+
"""
|
632 |
+
ffi.lib.LLVMPY_AddBasicAliasAnalysisPass(self)
|
633 |
+
|
634 |
+
def add_loop_rotate_pass(self):
|
635 |
+
"""http://llvm.org/docs/Passes.html#loop-rotate-rotate-loops."""
|
636 |
+
ffi.lib.LLVMPY_LLVMAddLoopRotatePass(self)
|
637 |
+
|
638 |
+
def add_target_library_info(self, triple):
|
639 |
+
ffi.lib.LLVMPY_AddTargetLibraryInfoPass(self, _encode_string(triple))
|
640 |
+
|
641 |
+
# Non-standard LLVM passes
|
642 |
+
|
643 |
+
def add_refprune_pass(self, subpasses_flags=RefPruneSubpasses.ALL,
|
644 |
+
subgraph_limit=1000):
|
645 |
+
"""Add Numba specific Reference count pruning pass.
|
646 |
+
|
647 |
+
Parameters
|
648 |
+
----------
|
649 |
+
subpasses_flags : RefPruneSubpasses
|
650 |
+
A bitmask to control the subpasses to be enabled.
|
651 |
+
subgraph_limit : int
|
652 |
+
Limit the fanout pruners to working on a subgraph no bigger than
|
653 |
+
this number of basic-blocks to avoid spending too much time in very
|
654 |
+
large graphs. Default is 1000. Subject to change in future
|
655 |
+
versions.
|
656 |
+
"""
|
657 |
+
iflags = RefPruneSubpasses(subpasses_flags)
|
658 |
+
ffi.lib.LLVMPY_AddRefPrunePass(self, iflags, subgraph_limit)
|
659 |
+
|
660 |
+
|
661 |
+
class ModulePassManager(PassManager):
|
662 |
+
|
663 |
+
def __init__(self, ptr=None):
|
664 |
+
if ptr is None:
|
665 |
+
ptr = ffi.lib.LLVMPY_CreatePassManager()
|
666 |
+
PassManager.__init__(self, ptr)
|
667 |
+
|
668 |
+
def run(self, module, remarks_file=None, remarks_format='yaml',
|
669 |
+
remarks_filter=''):
|
670 |
+
"""
|
671 |
+
Run optimization passes on the given module.
|
672 |
+
|
673 |
+
Parameters
|
674 |
+
----------
|
675 |
+
module : llvmlite.binding.ModuleRef
|
676 |
+
The module to be optimized inplace
|
677 |
+
remarks_file : str; optional
|
678 |
+
If not `None`, it is the file to store the optimization remarks.
|
679 |
+
remarks_format : str; optional
|
680 |
+
The format to write; YAML is default
|
681 |
+
remarks_filter : str; optional
|
682 |
+
The filter that should be applied to the remarks output.
|
683 |
+
"""
|
684 |
+
if remarks_file is None:
|
685 |
+
return ffi.lib.LLVMPY_RunPassManager(self, module)
|
686 |
+
else:
|
687 |
+
r = ffi.lib.LLVMPY_RunPassManagerWithRemarks(
|
688 |
+
self, module, _encode_string(remarks_format),
|
689 |
+
_encode_string(remarks_filter),
|
690 |
+
_encode_string(remarks_file))
|
691 |
+
if r == -1:
|
692 |
+
raise IOError("Failed to initialize remarks file.")
|
693 |
+
return r > 0
|
694 |
+
|
695 |
+
def run_with_remarks(self, module, remarks_format='yaml',
|
696 |
+
remarks_filter=''):
|
697 |
+
"""
|
698 |
+
Run optimization passes on the given module and returns the result and
|
699 |
+
the remarks data.
|
700 |
+
|
701 |
+
Parameters
|
702 |
+
----------
|
703 |
+
module : llvmlite.binding.ModuleRef
|
704 |
+
The module to be optimized
|
705 |
+
remarks_format : str
|
706 |
+
The remarks output; YAML is the default
|
707 |
+
remarks_filter : str; optional
|
708 |
+
The filter that should be applied to the remarks output.
|
709 |
+
"""
|
710 |
+
remarkdesc, remarkfile = mkstemp()
|
711 |
+
try:
|
712 |
+
with os.fdopen(remarkdesc, 'r'):
|
713 |
+
pass
|
714 |
+
r = self.run(module, remarkfile, remarks_format, remarks_filter)
|
715 |
+
if r == -1:
|
716 |
+
raise IOError("Failed to initialize remarks file.")
|
717 |
+
with open(remarkfile) as f:
|
718 |
+
return bool(r), f.read()
|
719 |
+
finally:
|
720 |
+
os.unlink(remarkfile)
|
721 |
+
|
722 |
+
|
723 |
+
class FunctionPassManager(PassManager):
|
724 |
+
|
725 |
+
def __init__(self, module):
|
726 |
+
ptr = ffi.lib.LLVMPY_CreateFunctionPassManager(module)
|
727 |
+
self._module = module
|
728 |
+
module._owned = True
|
729 |
+
PassManager.__init__(self, ptr)
|
730 |
+
|
731 |
+
def initialize(self):
|
732 |
+
"""
|
733 |
+
Initialize the FunctionPassManager. Returns True if it produced
|
734 |
+
any changes (?).
|
735 |
+
"""
|
736 |
+
return ffi.lib.LLVMPY_InitializeFunctionPassManager(self)
|
737 |
+
|
738 |
+
def finalize(self):
|
739 |
+
"""
|
740 |
+
Finalize the FunctionPassManager. Returns True if it produced
|
741 |
+
any changes (?).
|
742 |
+
"""
|
743 |
+
return ffi.lib.LLVMPY_FinalizeFunctionPassManager(self)
|
744 |
+
|
745 |
+
def run(self, function, remarks_file=None, remarks_format='yaml',
|
746 |
+
remarks_filter=''):
|
747 |
+
"""
|
748 |
+
Run optimization passes on the given function.
|
749 |
+
|
750 |
+
Parameters
|
751 |
+
----------
|
752 |
+
function : llvmlite.binding.FunctionRef
|
753 |
+
The function to be optimized inplace
|
754 |
+
remarks_file : str; optional
|
755 |
+
If not `None`, it is the file to store the optimization remarks.
|
756 |
+
remarks_format : str; optional
|
757 |
+
The format of the remarks file; the default is YAML
|
758 |
+
remarks_filter : str; optional
|
759 |
+
The filter that should be applied to the remarks output.
|
760 |
+
"""
|
761 |
+
if remarks_file is None:
|
762 |
+
return ffi.lib.LLVMPY_RunFunctionPassManager(self, function)
|
763 |
+
else:
|
764 |
+
r = ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks(
|
765 |
+
self, function, _encode_string(remarks_format),
|
766 |
+
_encode_string(remarks_filter),
|
767 |
+
_encode_string(remarks_file))
|
768 |
+
if r == -1:
|
769 |
+
raise IOError("Failed to initialize remarks file.")
|
770 |
+
return bool(r)
|
771 |
+
|
772 |
+
def run_with_remarks(self, function, remarks_format='yaml',
|
773 |
+
remarks_filter=''):
|
774 |
+
"""
|
775 |
+
Run optimization passes on the given function and returns the result
|
776 |
+
and the remarks data.
|
777 |
+
|
778 |
+
Parameters
|
779 |
+
----------
|
780 |
+
function : llvmlite.binding.FunctionRef
|
781 |
+
The function to be optimized inplace
|
782 |
+
remarks_format : str; optional
|
783 |
+
The format of the remarks file; the default is YAML
|
784 |
+
remarks_filter : str; optional
|
785 |
+
The filter that should be applied to the remarks output.
|
786 |
+
"""
|
787 |
+
# LLVM is going to need to close this file and then reopen it, so we
|
788 |
+
# can't use an unlinked temporary file.
|
789 |
+
remarkdesc, remarkfile = mkstemp()
|
790 |
+
try:
|
791 |
+
# We get an open handle, but we need LLVM to write first, so close
|
792 |
+
# it.
|
793 |
+
with os.fdopen(remarkdesc, 'r'):
|
794 |
+
pass
|
795 |
+
r = self.run(function, remarkfile, remarks_format, remarks_filter)
|
796 |
+
if r == -1:
|
797 |
+
raise IOError("Failed to initialize remarks file.")
|
798 |
+
with open(remarkfile) as f:
|
799 |
+
return bool(r), f.read()
|
800 |
+
finally:
|
801 |
+
os.unlink(remarkfile)
|
802 |
+
|
803 |
+
|
804 |
+
# ============================================================================
|
805 |
+
# FFI
|
806 |
+
|
807 |
+
ffi.lib.LLVMPY_CreatePassManager.restype = ffi.LLVMPassManagerRef
|
808 |
+
|
809 |
+
ffi.lib.LLVMPY_CreateFunctionPassManager.argtypes = [ffi.LLVMModuleRef]
|
810 |
+
ffi.lib.LLVMPY_CreateFunctionPassManager.restype = ffi.LLVMPassManagerRef
|
811 |
+
|
812 |
+
ffi.lib.LLVMPY_DisposePassManager.argtypes = [ffi.LLVMPassManagerRef]
|
813 |
+
|
814 |
+
ffi.lib.LLVMPY_RunPassManager.argtypes = [ffi.LLVMPassManagerRef,
|
815 |
+
ffi.LLVMModuleRef]
|
816 |
+
ffi.lib.LLVMPY_RunPassManager.restype = c_bool
|
817 |
+
|
818 |
+
ffi.lib.LLVMPY_RunPassManagerWithRemarks.argtypes = [ffi.LLVMPassManagerRef,
|
819 |
+
ffi.LLVMModuleRef,
|
820 |
+
c_char_p,
|
821 |
+
c_char_p,
|
822 |
+
c_char_p]
|
823 |
+
ffi.lib.LLVMPY_RunPassManagerWithRemarks.restype = c_int
|
824 |
+
|
825 |
+
ffi.lib.LLVMPY_InitializeFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef]
|
826 |
+
ffi.lib.LLVMPY_InitializeFunctionPassManager.restype = c_bool
|
827 |
+
|
828 |
+
ffi.lib.LLVMPY_FinalizeFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef]
|
829 |
+
ffi.lib.LLVMPY_FinalizeFunctionPassManager.restype = c_bool
|
830 |
+
|
831 |
+
ffi.lib.LLVMPY_RunFunctionPassManager.argtypes = [ffi.LLVMPassManagerRef,
|
832 |
+
ffi.LLVMValueRef]
|
833 |
+
ffi.lib.LLVMPY_RunFunctionPassManager.restype = c_bool
|
834 |
+
|
835 |
+
ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks.argtypes = [
|
836 |
+
ffi.LLVMPassManagerRef, ffi.LLVMValueRef, c_char_p, c_char_p, c_char_p
|
837 |
+
]
|
838 |
+
ffi.lib.LLVMPY_RunFunctionPassManagerWithRemarks.restype = c_int
|
839 |
+
|
840 |
+
ffi.lib.LLVMPY_AddAAEvalPass.argtypes = [ffi.LLVMPassManagerRef]
|
841 |
+
ffi.lib.LLVMPY_AddBasicAAWrapperPass.argtypes = [ffi.LLVMPassManagerRef]
|
842 |
+
ffi.lib.LLVMPY_AddConstantMergePass.argtypes = [ffi.LLVMPassManagerRef]
|
843 |
+
ffi.lib.LLVMPY_AddDeadArgEliminationPass.argtypes = [ffi.LLVMPassManagerRef]
|
844 |
+
ffi.lib.LLVMPY_AddDependenceAnalysisPass.argtypes = [ffi.LLVMPassManagerRef]
|
845 |
+
ffi.lib.LLVMPY_AddCallGraphDOTPrinterPass.argtypes = [ffi.LLVMPassManagerRef]
|
846 |
+
ffi.lib.LLVMPY_AddCFGPrinterPass.argtypes = [ffi.LLVMPassManagerRef]
|
847 |
+
ffi.lib.LLVMPY_AddDotDomPrinterPass.argtypes = [ffi.LLVMPassManagerRef, c_bool]
|
848 |
+
ffi.lib.LLVMPY_AddDotPostDomPrinterPass.argtypes = [
|
849 |
+
ffi.LLVMPassManagerRef,
|
850 |
+
c_bool]
|
851 |
+
ffi.lib.LLVMPY_AddGlobalsModRefAAPass.argtypes = [ffi.LLVMPassManagerRef]
|
852 |
+
ffi.lib.LLVMPY_AddInstructionCountPass.argtypes = [ffi.LLVMPassManagerRef]
|
853 |
+
ffi.lib.LLVMPY_AddIVUsersPass.argtypes = [ffi.LLVMPassManagerRef]
|
854 |
+
ffi.lib.LLVMPY_AddLazyValueInfoPass.argtypes = [ffi.LLVMPassManagerRef]
|
855 |
+
ffi.lib.LLVMPY_AddLintPass.argtypes = [ffi.LLVMPassManagerRef]
|
856 |
+
ffi.lib.LLVMPY_AddModuleDebugInfoPrinterPass.argtypes = [ffi.LLVMPassManagerRef]
|
857 |
+
ffi.lib.LLVMPY_AddRegionInfoPass.argtypes = [ffi.LLVMPassManagerRef]
|
858 |
+
ffi.lib.LLVMPY_AddScalarEvolutionAAPass.argtypes = [ffi.LLVMPassManagerRef]
|
859 |
+
ffi.lib.LLVMPY_AddAggressiveDCEPass.argtypes = [ffi.LLVMPassManagerRef]
|
860 |
+
ffi.lib.LLVMPY_AddAlwaysInlinerPass.argtypes = [ffi.LLVMPassManagerRef, c_bool]
|
861 |
+
ffi.lib.LLVMPY_AddArgPromotionPass.argtypes = [ffi.LLVMPassManagerRef, c_uint]
|
862 |
+
ffi.lib.LLVMPY_AddBreakCriticalEdgesPass.argtypes = [ffi.LLVMPassManagerRef]
|
863 |
+
ffi.lib.LLVMPY_AddDeadStoreEliminationPass.argtypes = [
|
864 |
+
ffi.LLVMPassManagerRef]
|
865 |
+
ffi.lib.LLVMPY_AddReversePostOrderFunctionAttrsPass.argtypes = [
|
866 |
+
ffi.LLVMPassManagerRef]
|
867 |
+
ffi.lib.LLVMPY_AddAggressiveInstructionCombiningPass.argtypes = [
|
868 |
+
ffi.LLVMPassManagerRef]
|
869 |
+
ffi.lib.LLVMPY_AddInternalizePass.argtypes = [ffi.LLVMPassManagerRef]
|
870 |
+
ffi.lib.LLVMPY_AddLCSSAPass.argtypes = [ffi.LLVMPassManagerRef]
|
871 |
+
ffi.lib.LLVMPY_AddLoopDeletionPass.argtypes = [ffi.LLVMPassManagerRef]
|
872 |
+
ffi.lib.LLVMPY_AddLoopExtractorPass.argtypes = [ffi.LLVMPassManagerRef]
|
873 |
+
ffi.lib.LLVMPY_AddSingleLoopExtractorPass.argtypes = [ffi.LLVMPassManagerRef]
|
874 |
+
ffi.lib.LLVMPY_AddLoopStrengthReducePass.argtypes = [ffi.LLVMPassManagerRef]
|
875 |
+
ffi.lib.LLVMPY_AddLoopSimplificationPass.argtypes = [ffi.LLVMPassManagerRef]
|
876 |
+
ffi.lib.LLVMPY_AddLoopUnrollPass.argtypes = [ffi.LLVMPassManagerRef]
|
877 |
+
ffi.lib.LLVMPY_AddLoopUnrollAndJamPass.argtypes = [ffi.LLVMPassManagerRef]
|
878 |
+
ffi.lib.LLVMPY_AddLoopUnswitchPass.argtypes = [
|
879 |
+
ffi.LLVMPassManagerRef,
|
880 |
+
c_bool,
|
881 |
+
c_bool]
|
882 |
+
ffi.lib.LLVMPY_AddLowerAtomicPass.argtypes = [ffi.LLVMPassManagerRef]
|
883 |
+
ffi.lib.LLVMPY_AddLowerInvokePass.argtypes = [ffi.LLVMPassManagerRef]
|
884 |
+
ffi.lib.LLVMPY_AddLowerSwitchPass.argtypes = [ffi.LLVMPassManagerRef]
|
885 |
+
ffi.lib.LLVMPY_AddMemCpyOptimizationPass.argtypes = [ffi.LLVMPassManagerRef]
|
886 |
+
ffi.lib.LLVMPY_AddMergeFunctionsPass.argtypes = [ffi.LLVMPassManagerRef]
|
887 |
+
ffi.lib.LLVMPY_AddMergeReturnsPass.argtypes = [ffi.LLVMPassManagerRef]
|
888 |
+
ffi.lib.LLVMPY_AddPartialInliningPass.argtypes = [ffi.LLVMPassManagerRef]
|
889 |
+
ffi.lib.LLVMPY_AddPruneExceptionHandlingPass.argtypes = [ffi.LLVMPassManagerRef]
|
890 |
+
ffi.lib.LLVMPY_AddReassociatePass.argtypes = [ffi.LLVMPassManagerRef]
|
891 |
+
ffi.lib.LLVMPY_AddDemoteRegisterToMemoryPass.argtypes = [ffi.LLVMPassManagerRef]
|
892 |
+
ffi.lib.LLVMPY_AddSinkPass.argtypes = [ffi.LLVMPassManagerRef]
|
893 |
+
ffi.lib.LLVMPY_AddStripSymbolsPass.argtypes = [ffi.LLVMPassManagerRef, c_bool]
|
894 |
+
ffi.lib.LLVMPY_AddStripDeadDebugInfoPass.argtypes = [ffi.LLVMPassManagerRef]
|
895 |
+
ffi.lib.LLVMPY_AddStripDeadPrototypesPass.argtypes = [ffi.LLVMPassManagerRef]
|
896 |
+
ffi.lib.LLVMPY_AddStripDebugDeclarePrototypesPass.argtypes = [
|
897 |
+
ffi.LLVMPassManagerRef]
|
898 |
+
ffi.lib.LLVMPY_AddStripNondebugSymbolsPass.argtypes = [ffi.LLVMPassManagerRef]
|
899 |
+
ffi.lib.LLVMPY_AddTailCallEliminationPass.argtypes = [ffi.LLVMPassManagerRef]
|
900 |
+
ffi.lib.LLVMPY_AddJumpThreadingPass.argtypes = [ffi.LLVMPassManagerRef, c_int]
|
901 |
+
ffi.lib.LLVMPY_AddFunctionAttrsPass.argtypes = [ffi.LLVMPassManagerRef]
|
902 |
+
ffi.lib.LLVMPY_AddFunctionInliningPass.argtypes = [
|
903 |
+
ffi.LLVMPassManagerRef, c_int]
|
904 |
+
ffi.lib.LLVMPY_AddGlobalDCEPass.argtypes = [ffi.LLVMPassManagerRef]
|
905 |
+
ffi.lib.LLVMPY_AddGlobalOptimizerPass.argtypes = [ffi.LLVMPassManagerRef]
|
906 |
+
ffi.lib.LLVMPY_AddIPSCCPPass.argtypes = [ffi.LLVMPassManagerRef]
|
907 |
+
|
908 |
+
ffi.lib.LLVMPY_AddDeadCodeEliminationPass.argtypes = [ffi.LLVMPassManagerRef]
|
909 |
+
ffi.lib.LLVMPY_AddCFGSimplificationPass.argtypes = [ffi.LLVMPassManagerRef]
|
910 |
+
ffi.lib.LLVMPY_AddGVNPass.argtypes = [ffi.LLVMPassManagerRef]
|
911 |
+
ffi.lib.LLVMPY_AddInstructionCombiningPass.argtypes = [ffi.LLVMPassManagerRef]
|
912 |
+
ffi.lib.LLVMPY_AddLICMPass.argtypes = [ffi.LLVMPassManagerRef]
|
913 |
+
ffi.lib.LLVMPY_AddSCCPPass.argtypes = [ffi.LLVMPassManagerRef]
|
914 |
+
ffi.lib.LLVMPY_AddSROAPass.argtypes = [ffi.LLVMPassManagerRef]
|
915 |
+
ffi.lib.LLVMPY_AddTypeBasedAliasAnalysisPass.argtypes = [ffi.LLVMPassManagerRef]
|
916 |
+
ffi.lib.LLVMPY_AddBasicAliasAnalysisPass.argtypes = [ffi.LLVMPassManagerRef]
|
917 |
+
ffi.lib.LLVMPY_AddTargetLibraryInfoPass.argtypes = [ffi.LLVMPassManagerRef,
|
918 |
+
c_char_p]
|
919 |
+
|
920 |
+
ffi.lib.LLVMPY_AddRefPrunePass.argtypes = [ffi.LLVMPassManagerRef, c_int,
|
921 |
+
c_size_t]
|
922 |
+
|
923 |
+
ffi.lib.LLVMPY_DumpRefPruneStats.argtypes = [POINTER(_c_PruneStats), c_bool]
|
lib/python3.11/site-packages/llvmlite/binding/targets.py
ADDED
@@ -0,0 +1,450 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from ctypes import (POINTER, c_char_p, c_longlong, c_int, c_size_t,
|
3 |
+
c_void_p, string_at)
|
4 |
+
|
5 |
+
from llvmlite.binding import ffi
|
6 |
+
from llvmlite.binding.common import _decode_string, _encode_string
|
7 |
+
|
8 |
+
|
9 |
+
def get_process_triple():
|
10 |
+
"""
|
11 |
+
Return a target triple suitable for generating code for the current process.
|
12 |
+
An example when the default triple from ``get_default_triple()`` is not be
|
13 |
+
suitable is when LLVM is compiled for 32-bit but the process is executing
|
14 |
+
in 64-bit mode.
|
15 |
+
"""
|
16 |
+
with ffi.OutputString() as out:
|
17 |
+
ffi.lib.LLVMPY_GetProcessTriple(out)
|
18 |
+
return str(out)
|
19 |
+
|
20 |
+
|
21 |
+
class FeatureMap(dict):
|
22 |
+
"""
|
23 |
+
Maps feature name to a boolean indicating the availability of the feature.
|
24 |
+
Extends ``dict`` to add `.flatten()` method.
|
25 |
+
"""
|
26 |
+
|
27 |
+
def flatten(self, sort=True):
|
28 |
+
"""
|
29 |
+
Args
|
30 |
+
----
|
31 |
+
sort: bool
|
32 |
+
Optional. If True, the features are sorted by name; otherwise,
|
33 |
+
the ordering is unstable between python session due to hash
|
34 |
+
randomization. Defaults to True.
|
35 |
+
|
36 |
+
Returns a string suitable for use as the ``features`` argument to
|
37 |
+
``Target.create_target_machine()``.
|
38 |
+
|
39 |
+
"""
|
40 |
+
iterator = sorted(self.items()) if sort else iter(self.items())
|
41 |
+
flag_map = {True: '+', False: '-'}
|
42 |
+
return ','.join('{0}{1}'.format(flag_map[v], k)
|
43 |
+
for k, v in iterator)
|
44 |
+
|
45 |
+
|
46 |
+
def get_host_cpu_features():
|
47 |
+
"""
|
48 |
+
Returns a dictionary-like object indicating the CPU features for current
|
49 |
+
architecture and whether they are enabled for this CPU. The key-value pairs
|
50 |
+
are the feature name as string and a boolean indicating whether the feature
|
51 |
+
is available. The returned value is an instance of ``FeatureMap`` class,
|
52 |
+
which adds a new method ``.flatten()`` for returning a string suitable for
|
53 |
+
use as the "features" argument to ``Target.create_target_machine()``.
|
54 |
+
|
55 |
+
If LLVM has not implemented this feature or it fails to get the information,
|
56 |
+
this function will raise a RuntimeError exception.
|
57 |
+
"""
|
58 |
+
with ffi.OutputString() as out:
|
59 |
+
outdict = FeatureMap()
|
60 |
+
if not ffi.lib.LLVMPY_GetHostCPUFeatures(out):
|
61 |
+
return outdict
|
62 |
+
flag_map = {'+': True, '-': False}
|
63 |
+
content = str(out)
|
64 |
+
if content: # protect against empty string
|
65 |
+
for feat in content.split(','):
|
66 |
+
if feat: # protect against empty feature
|
67 |
+
outdict[feat[1:]] = flag_map[feat[0]]
|
68 |
+
return outdict
|
69 |
+
|
70 |
+
|
71 |
+
def get_default_triple():
|
72 |
+
"""
|
73 |
+
Return the default target triple LLVM is configured to produce code for.
|
74 |
+
"""
|
75 |
+
with ffi.OutputString() as out:
|
76 |
+
ffi.lib.LLVMPY_GetDefaultTargetTriple(out)
|
77 |
+
return str(out)
|
78 |
+
|
79 |
+
|
80 |
+
def get_host_cpu_name():
|
81 |
+
"""
|
82 |
+
Get the name of the host's CPU, suitable for using with
|
83 |
+
:meth:`Target.create_target_machine()`.
|
84 |
+
"""
|
85 |
+
with ffi.OutputString() as out:
|
86 |
+
ffi.lib.LLVMPY_GetHostCPUName(out)
|
87 |
+
return str(out)
|
88 |
+
|
89 |
+
|
90 |
+
_object_formats = {
|
91 |
+
1: "COFF",
|
92 |
+
2: "ELF",
|
93 |
+
3: "MachO",
|
94 |
+
}
|
95 |
+
|
96 |
+
|
97 |
+
def get_object_format(triple=None):
|
98 |
+
"""
|
99 |
+
Get the object format for the given *triple* string (or the default
|
100 |
+
triple if omitted).
|
101 |
+
A string is returned
|
102 |
+
"""
|
103 |
+
if triple is None:
|
104 |
+
triple = get_default_triple()
|
105 |
+
res = ffi.lib.LLVMPY_GetTripleObjectFormat(_encode_string(triple))
|
106 |
+
return _object_formats[res]
|
107 |
+
|
108 |
+
|
109 |
+
def create_target_data(layout):
|
110 |
+
"""
|
111 |
+
Create a TargetData instance for the given *layout* string.
|
112 |
+
"""
|
113 |
+
return TargetData(ffi.lib.LLVMPY_CreateTargetData(_encode_string(layout)))
|
114 |
+
|
115 |
+
|
116 |
+
class TargetData(ffi.ObjectRef):
|
117 |
+
"""
|
118 |
+
A TargetData provides structured access to a data layout.
|
119 |
+
Use :func:`create_target_data` to create instances.
|
120 |
+
"""
|
121 |
+
|
122 |
+
def __str__(self):
|
123 |
+
if self._closed:
|
124 |
+
return "<dead TargetData>"
|
125 |
+
with ffi.OutputString() as out:
|
126 |
+
ffi.lib.LLVMPY_CopyStringRepOfTargetData(self, out)
|
127 |
+
return str(out)
|
128 |
+
|
129 |
+
def _dispose(self):
|
130 |
+
self._capi.LLVMPY_DisposeTargetData(self)
|
131 |
+
|
132 |
+
def get_abi_size(self, ty):
|
133 |
+
"""
|
134 |
+
Get ABI size of LLVM type *ty*.
|
135 |
+
"""
|
136 |
+
return ffi.lib.LLVMPY_ABISizeOfType(self, ty)
|
137 |
+
|
138 |
+
def get_element_offset(self, ty, position):
|
139 |
+
"""
|
140 |
+
Get byte offset of type's ty element at the given position
|
141 |
+
"""
|
142 |
+
|
143 |
+
offset = ffi.lib.LLVMPY_OffsetOfElement(self, ty, position)
|
144 |
+
if offset == -1:
|
145 |
+
raise ValueError("Could not determined offset of {}th "
|
146 |
+
"element of the type '{}'. Is it a struct"
|
147 |
+
"type?".format(position, str(ty)))
|
148 |
+
return offset
|
149 |
+
|
150 |
+
def get_pointee_abi_size(self, ty):
|
151 |
+
"""
|
152 |
+
Get ABI size of pointee type of LLVM pointer type *ty*.
|
153 |
+
"""
|
154 |
+
size = ffi.lib.LLVMPY_ABISizeOfElementType(self, ty)
|
155 |
+
if size == -1:
|
156 |
+
raise RuntimeError("Not a pointer type: %s" % (ty,))
|
157 |
+
return size
|
158 |
+
|
159 |
+
def get_pointee_abi_alignment(self, ty):
|
160 |
+
"""
|
161 |
+
Get minimum ABI alignment of pointee type of LLVM pointer type *ty*.
|
162 |
+
"""
|
163 |
+
size = ffi.lib.LLVMPY_ABIAlignmentOfElementType(self, ty)
|
164 |
+
if size == -1:
|
165 |
+
raise RuntimeError("Not a pointer type: %s" % (ty,))
|
166 |
+
return size
|
167 |
+
|
168 |
+
|
169 |
+
RELOC = frozenset(['default', 'static', 'pic', 'dynamicnopic'])
|
170 |
+
CODEMODEL = frozenset(['default', 'jitdefault', 'small', 'kernel', 'medium',
|
171 |
+
'large'])
|
172 |
+
|
173 |
+
|
174 |
+
class Target(ffi.ObjectRef):
|
175 |
+
_triple = ''
|
176 |
+
|
177 |
+
# No _dispose() method since LLVMGetTargetFromTriple() returns a
|
178 |
+
# persistent object.
|
179 |
+
|
180 |
+
@classmethod
|
181 |
+
def from_default_triple(cls):
|
182 |
+
"""
|
183 |
+
Create a Target instance for the default triple.
|
184 |
+
"""
|
185 |
+
triple = get_default_triple()
|
186 |
+
return cls.from_triple(triple)
|
187 |
+
|
188 |
+
@classmethod
|
189 |
+
def from_triple(cls, triple):
|
190 |
+
"""
|
191 |
+
Create a Target instance for the given triple (a string).
|
192 |
+
"""
|
193 |
+
with ffi.OutputString() as outerr:
|
194 |
+
target = ffi.lib.LLVMPY_GetTargetFromTriple(triple.encode('utf8'),
|
195 |
+
outerr)
|
196 |
+
if not target:
|
197 |
+
raise RuntimeError(str(outerr))
|
198 |
+
target = cls(target)
|
199 |
+
target._triple = triple
|
200 |
+
return target
|
201 |
+
|
202 |
+
@property
|
203 |
+
def name(self):
|
204 |
+
s = ffi.lib.LLVMPY_GetTargetName(self)
|
205 |
+
return _decode_string(s)
|
206 |
+
|
207 |
+
@property
|
208 |
+
def description(self):
|
209 |
+
s = ffi.lib.LLVMPY_GetTargetDescription(self)
|
210 |
+
return _decode_string(s)
|
211 |
+
|
212 |
+
@property
|
213 |
+
def triple(self):
|
214 |
+
return self._triple
|
215 |
+
|
216 |
+
def __str__(self):
|
217 |
+
return "<Target {0} ({1})>".format(self.name, self.description)
|
218 |
+
|
219 |
+
def create_target_machine(self, cpu='', features='',
|
220 |
+
opt=2, reloc='default', codemodel='jitdefault',
|
221 |
+
printmc=False, jit=False, abiname=''):
|
222 |
+
"""
|
223 |
+
Create a new TargetMachine for this target and the given options.
|
224 |
+
|
225 |
+
Specifying codemodel='default' will result in the use of the "small"
|
226 |
+
code model. Specifying codemodel='jitdefault' will result in the code
|
227 |
+
model being picked based on platform bitness (32="small", 64="large").
|
228 |
+
|
229 |
+
The `printmc` option corresponds to llvm's `-print-machineinstrs`.
|
230 |
+
|
231 |
+
The `jit` option should be set when the target-machine is to be used
|
232 |
+
in a JIT engine.
|
233 |
+
|
234 |
+
The `abiname` option specifies the ABI. RISC-V targets with hard-float
|
235 |
+
needs to pass the ABI name to LLVM.
|
236 |
+
"""
|
237 |
+
assert 0 <= opt <= 3
|
238 |
+
assert reloc in RELOC
|
239 |
+
assert codemodel in CODEMODEL
|
240 |
+
triple = self._triple
|
241 |
+
# MCJIT under Windows only supports ELF objects, see
|
242 |
+
# http://lists.llvm.org/pipermail/llvm-dev/2013-December/068341.html
|
243 |
+
# Note we still want to produce regular COFF files in AOT mode.
|
244 |
+
if os.name == 'nt' and codemodel == 'jitdefault':
|
245 |
+
triple += '-elf'
|
246 |
+
tm = ffi.lib.LLVMPY_CreateTargetMachine(self,
|
247 |
+
_encode_string(triple),
|
248 |
+
_encode_string(cpu),
|
249 |
+
_encode_string(features),
|
250 |
+
opt,
|
251 |
+
_encode_string(reloc),
|
252 |
+
_encode_string(codemodel),
|
253 |
+
int(printmc),
|
254 |
+
int(jit),
|
255 |
+
_encode_string(abiname),
|
256 |
+
)
|
257 |
+
if tm:
|
258 |
+
return TargetMachine(tm)
|
259 |
+
else:
|
260 |
+
raise RuntimeError("Cannot create target machine")
|
261 |
+
|
262 |
+
|
263 |
+
class TargetMachine(ffi.ObjectRef):
|
264 |
+
|
265 |
+
def _dispose(self):
|
266 |
+
self._capi.LLVMPY_DisposeTargetMachine(self)
|
267 |
+
|
268 |
+
def add_analysis_passes(self, pm):
|
269 |
+
"""
|
270 |
+
Register analysis passes for this target machine with a pass manager.
|
271 |
+
"""
|
272 |
+
ffi.lib.LLVMPY_AddAnalysisPasses(self, pm)
|
273 |
+
|
274 |
+
def set_asm_verbosity(self, verbose):
|
275 |
+
"""
|
276 |
+
Set whether this target machine will emit assembly with human-readable
|
277 |
+
comments describing control flow, debug information, and so on.
|
278 |
+
"""
|
279 |
+
ffi.lib.LLVMPY_SetTargetMachineAsmVerbosity(self, verbose)
|
280 |
+
|
281 |
+
def emit_object(self, module):
|
282 |
+
"""
|
283 |
+
Represent the module as a code object, suitable for use with
|
284 |
+
the platform's linker. Returns a byte string.
|
285 |
+
"""
|
286 |
+
return self._emit_to_memory(module, use_object=True)
|
287 |
+
|
288 |
+
def emit_assembly(self, module):
|
289 |
+
"""
|
290 |
+
Return the raw assembler of the module, as a string.
|
291 |
+
|
292 |
+
llvm.initialize_native_asmprinter() must have been called first.
|
293 |
+
"""
|
294 |
+
return _decode_string(self._emit_to_memory(module, use_object=False))
|
295 |
+
|
296 |
+
def _emit_to_memory(self, module, use_object=False):
|
297 |
+
"""Returns bytes of object code of the module.
|
298 |
+
|
299 |
+
Args
|
300 |
+
----
|
301 |
+
use_object : bool
|
302 |
+
Emit object code or (if False) emit assembly code.
|
303 |
+
"""
|
304 |
+
with ffi.OutputString() as outerr:
|
305 |
+
mb = ffi.lib.LLVMPY_TargetMachineEmitToMemory(self, module,
|
306 |
+
int(use_object),
|
307 |
+
outerr)
|
308 |
+
if not mb:
|
309 |
+
raise RuntimeError(str(outerr))
|
310 |
+
|
311 |
+
bufptr = ffi.lib.LLVMPY_GetBufferStart(mb)
|
312 |
+
bufsz = ffi.lib.LLVMPY_GetBufferSize(mb)
|
313 |
+
try:
|
314 |
+
return string_at(bufptr, bufsz)
|
315 |
+
finally:
|
316 |
+
ffi.lib.LLVMPY_DisposeMemoryBuffer(mb)
|
317 |
+
|
318 |
+
@property
|
319 |
+
def target_data(self):
|
320 |
+
return TargetData(ffi.lib.LLVMPY_CreateTargetMachineData(self))
|
321 |
+
|
322 |
+
@property
|
323 |
+
def triple(self):
|
324 |
+
with ffi.OutputString() as out:
|
325 |
+
ffi.lib.LLVMPY_GetTargetMachineTriple(self, out)
|
326 |
+
return str(out)
|
327 |
+
|
328 |
+
|
329 |
+
def has_svml():
|
330 |
+
"""
|
331 |
+
Returns True if SVML was enabled at FFI support compile time.
|
332 |
+
"""
|
333 |
+
if ffi.lib.LLVMPY_HasSVMLSupport() == 0:
|
334 |
+
return False
|
335 |
+
else:
|
336 |
+
return True
|
337 |
+
|
338 |
+
|
339 |
+
# ============================================================================
|
340 |
+
# FFI
|
341 |
+
|
342 |
+
ffi.lib.LLVMPY_GetProcessTriple.argtypes = [POINTER(c_char_p)]
|
343 |
+
|
344 |
+
ffi.lib.LLVMPY_GetHostCPUFeatures.argtypes = [POINTER(c_char_p)]
|
345 |
+
ffi.lib.LLVMPY_GetHostCPUFeatures.restype = c_int
|
346 |
+
|
347 |
+
ffi.lib.LLVMPY_GetDefaultTargetTriple.argtypes = [POINTER(c_char_p)]
|
348 |
+
|
349 |
+
ffi.lib.LLVMPY_GetHostCPUName.argtypes = [POINTER(c_char_p)]
|
350 |
+
|
351 |
+
ffi.lib.LLVMPY_GetTripleObjectFormat.argtypes = [c_char_p]
|
352 |
+
ffi.lib.LLVMPY_GetTripleObjectFormat.restype = c_int
|
353 |
+
|
354 |
+
ffi.lib.LLVMPY_CreateTargetData.argtypes = [c_char_p]
|
355 |
+
ffi.lib.LLVMPY_CreateTargetData.restype = ffi.LLVMTargetDataRef
|
356 |
+
|
357 |
+
ffi.lib.LLVMPY_CopyStringRepOfTargetData.argtypes = [
|
358 |
+
ffi.LLVMTargetDataRef,
|
359 |
+
POINTER(c_char_p),
|
360 |
+
]
|
361 |
+
|
362 |
+
ffi.lib.LLVMPY_DisposeTargetData.argtypes = [
|
363 |
+
ffi.LLVMTargetDataRef,
|
364 |
+
]
|
365 |
+
|
366 |
+
ffi.lib.LLVMPY_ABISizeOfType.argtypes = [ffi.LLVMTargetDataRef,
|
367 |
+
ffi.LLVMTypeRef]
|
368 |
+
ffi.lib.LLVMPY_ABISizeOfType.restype = c_longlong
|
369 |
+
|
370 |
+
ffi.lib.LLVMPY_OffsetOfElement.argtypes = [ffi.LLVMTargetDataRef,
|
371 |
+
ffi.LLVMTypeRef,
|
372 |
+
c_int]
|
373 |
+
ffi.lib.LLVMPY_OffsetOfElement.restype = c_longlong
|
374 |
+
|
375 |
+
ffi.lib.LLVMPY_ABISizeOfElementType.argtypes = [ffi.LLVMTargetDataRef,
|
376 |
+
ffi.LLVMTypeRef]
|
377 |
+
ffi.lib.LLVMPY_ABISizeOfElementType.restype = c_longlong
|
378 |
+
|
379 |
+
ffi.lib.LLVMPY_ABIAlignmentOfElementType.argtypes = [ffi.LLVMTargetDataRef,
|
380 |
+
ffi.LLVMTypeRef]
|
381 |
+
ffi.lib.LLVMPY_ABIAlignmentOfElementType.restype = c_longlong
|
382 |
+
|
383 |
+
ffi.lib.LLVMPY_GetTargetFromTriple.argtypes = [c_char_p, POINTER(c_char_p)]
|
384 |
+
ffi.lib.LLVMPY_GetTargetFromTriple.restype = ffi.LLVMTargetRef
|
385 |
+
|
386 |
+
ffi.lib.LLVMPY_GetTargetName.argtypes = [ffi.LLVMTargetRef]
|
387 |
+
ffi.lib.LLVMPY_GetTargetName.restype = c_char_p
|
388 |
+
|
389 |
+
ffi.lib.LLVMPY_GetTargetDescription.argtypes = [ffi.LLVMTargetRef]
|
390 |
+
ffi.lib.LLVMPY_GetTargetDescription.restype = c_char_p
|
391 |
+
|
392 |
+
ffi.lib.LLVMPY_CreateTargetMachine.argtypes = [
|
393 |
+
ffi.LLVMTargetRef,
|
394 |
+
# Triple
|
395 |
+
c_char_p,
|
396 |
+
# CPU
|
397 |
+
c_char_p,
|
398 |
+
# Features
|
399 |
+
c_char_p,
|
400 |
+
# OptLevel
|
401 |
+
c_int,
|
402 |
+
# Reloc
|
403 |
+
c_char_p,
|
404 |
+
# CodeModel
|
405 |
+
c_char_p,
|
406 |
+
# PrintMC
|
407 |
+
c_int,
|
408 |
+
# JIT
|
409 |
+
c_int,
|
410 |
+
# ABIName
|
411 |
+
c_char_p,
|
412 |
+
]
|
413 |
+
ffi.lib.LLVMPY_CreateTargetMachine.restype = ffi.LLVMTargetMachineRef
|
414 |
+
|
415 |
+
ffi.lib.LLVMPY_DisposeTargetMachine.argtypes = [ffi.LLVMTargetMachineRef]
|
416 |
+
|
417 |
+
ffi.lib.LLVMPY_GetTargetMachineTriple.argtypes = [ffi.LLVMTargetMachineRef,
|
418 |
+
POINTER(c_char_p)]
|
419 |
+
|
420 |
+
ffi.lib.LLVMPY_SetTargetMachineAsmVerbosity.argtypes = [
|
421 |
+
ffi.LLVMTargetMachineRef, c_int]
|
422 |
+
|
423 |
+
ffi.lib.LLVMPY_AddAnalysisPasses.argtypes = [
|
424 |
+
ffi.LLVMTargetMachineRef,
|
425 |
+
ffi.LLVMPassManagerRef,
|
426 |
+
]
|
427 |
+
|
428 |
+
ffi.lib.LLVMPY_TargetMachineEmitToMemory.argtypes = [
|
429 |
+
ffi.LLVMTargetMachineRef,
|
430 |
+
ffi.LLVMModuleRef,
|
431 |
+
c_int,
|
432 |
+
POINTER(c_char_p),
|
433 |
+
]
|
434 |
+
ffi.lib.LLVMPY_TargetMachineEmitToMemory.restype = ffi.LLVMMemoryBufferRef
|
435 |
+
|
436 |
+
ffi.lib.LLVMPY_GetBufferStart.argtypes = [ffi.LLVMMemoryBufferRef]
|
437 |
+
ffi.lib.LLVMPY_GetBufferStart.restype = c_void_p
|
438 |
+
|
439 |
+
ffi.lib.LLVMPY_GetBufferSize.argtypes = [ffi.LLVMMemoryBufferRef]
|
440 |
+
ffi.lib.LLVMPY_GetBufferSize.restype = c_size_t
|
441 |
+
|
442 |
+
ffi.lib.LLVMPY_DisposeMemoryBuffer.argtypes = [ffi.LLVMMemoryBufferRef]
|
443 |
+
|
444 |
+
ffi.lib.LLVMPY_CreateTargetMachineData.argtypes = [
|
445 |
+
ffi.LLVMTargetMachineRef,
|
446 |
+
]
|
447 |
+
ffi.lib.LLVMPY_CreateTargetMachineData.restype = ffi.LLVMTargetDataRef
|
448 |
+
|
449 |
+
ffi.lib.LLVMPY_HasSVMLSupport.argtypes = []
|
450 |
+
ffi.lib.LLVMPY_HasSVMLSupport.restype = c_int
|
lib/python3.11/site-packages/llvmlite/binding/transforms.py
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ctypes import c_uint, c_bool
|
2 |
+
from llvmlite.binding import ffi
|
3 |
+
from llvmlite.binding import passmanagers
|
4 |
+
|
5 |
+
|
6 |
+
def create_pass_manager_builder():
|
7 |
+
return PassManagerBuilder()
|
8 |
+
|
9 |
+
|
10 |
+
class PassManagerBuilder(ffi.ObjectRef):
|
11 |
+
__slots__ = ()
|
12 |
+
|
13 |
+
def __init__(self, ptr=None):
|
14 |
+
if ptr is None:
|
15 |
+
ptr = ffi.lib.LLVMPY_PassManagerBuilderCreate()
|
16 |
+
ffi.ObjectRef.__init__(self, ptr)
|
17 |
+
|
18 |
+
@property
|
19 |
+
def opt_level(self):
|
20 |
+
"""
|
21 |
+
The general optimization level as an integer between 0 and 3.
|
22 |
+
"""
|
23 |
+
return ffi.lib.LLVMPY_PassManagerBuilderGetOptLevel(self)
|
24 |
+
|
25 |
+
@opt_level.setter
|
26 |
+
def opt_level(self, level):
|
27 |
+
ffi.lib.LLVMPY_PassManagerBuilderSetOptLevel(self, level)
|
28 |
+
|
29 |
+
@property
|
30 |
+
def size_level(self):
|
31 |
+
"""
|
32 |
+
Whether and how much to optimize for size. An integer between 0 and 2.
|
33 |
+
"""
|
34 |
+
return ffi.lib.LLVMPY_PassManagerBuilderGetSizeLevel(self)
|
35 |
+
|
36 |
+
@size_level.setter
|
37 |
+
def size_level(self, size):
|
38 |
+
ffi.lib.LLVMPY_PassManagerBuilderSetSizeLevel(self, size)
|
39 |
+
|
40 |
+
@property
|
41 |
+
def inlining_threshold(self):
|
42 |
+
"""
|
43 |
+
The integer threshold for inlining a function into another. The higher,
|
44 |
+
the more likely inlining a function is. This attribute is write-only.
|
45 |
+
"""
|
46 |
+
raise NotImplementedError("inlining_threshold is write-only")
|
47 |
+
|
48 |
+
@inlining_threshold.setter
|
49 |
+
def inlining_threshold(self, threshold):
|
50 |
+
ffi.lib.LLVMPY_PassManagerBuilderUseInlinerWithThreshold(
|
51 |
+
self, threshold)
|
52 |
+
|
53 |
+
@property
|
54 |
+
def disable_unroll_loops(self):
|
55 |
+
"""
|
56 |
+
If true, disable loop unrolling.
|
57 |
+
"""
|
58 |
+
return ffi.lib.LLVMPY_PassManagerBuilderGetDisableUnrollLoops(self)
|
59 |
+
|
60 |
+
@disable_unroll_loops.setter
|
61 |
+
def disable_unroll_loops(self, disable=True):
|
62 |
+
ffi.lib.LLVMPY_PassManagerBuilderSetDisableUnrollLoops(self, disable)
|
63 |
+
|
64 |
+
@property
|
65 |
+
def loop_vectorize(self):
|
66 |
+
"""
|
67 |
+
If true, allow vectorizing loops.
|
68 |
+
"""
|
69 |
+
return ffi.lib.LLVMPY_PassManagerBuilderGetLoopVectorize(self)
|
70 |
+
|
71 |
+
@loop_vectorize.setter
|
72 |
+
def loop_vectorize(self, enable=True):
|
73 |
+
return ffi.lib.LLVMPY_PassManagerBuilderSetLoopVectorize(self, enable)
|
74 |
+
|
75 |
+
@property
|
76 |
+
def slp_vectorize(self):
|
77 |
+
"""
|
78 |
+
If true, enable the "SLP vectorizer", which uses a different algorithm
|
79 |
+
from the loop vectorizer. Both may be enabled at the same time.
|
80 |
+
"""
|
81 |
+
return ffi.lib.LLVMPY_PassManagerBuilderGetSLPVectorize(self)
|
82 |
+
|
83 |
+
@slp_vectorize.setter
|
84 |
+
def slp_vectorize(self, enable=True):
|
85 |
+
return ffi.lib.LLVMPY_PassManagerBuilderSetSLPVectorize(self, enable)
|
86 |
+
|
87 |
+
def _populate_module_pm(self, pm):
|
88 |
+
ffi.lib.LLVMPY_PassManagerBuilderPopulateModulePassManager(self, pm)
|
89 |
+
|
90 |
+
def _populate_function_pm(self, pm):
|
91 |
+
ffi.lib.LLVMPY_PassManagerBuilderPopulateFunctionPassManager(self, pm)
|
92 |
+
|
93 |
+
def populate(self, pm):
|
94 |
+
if isinstance(pm, passmanagers.ModulePassManager):
|
95 |
+
self._populate_module_pm(pm)
|
96 |
+
elif isinstance(pm, passmanagers.FunctionPassManager):
|
97 |
+
self._populate_function_pm(pm)
|
98 |
+
else:
|
99 |
+
raise TypeError(pm)
|
100 |
+
|
101 |
+
def _dispose(self):
|
102 |
+
self._capi.LLVMPY_PassManagerBuilderDispose(self)
|
103 |
+
|
104 |
+
|
105 |
+
# ============================================================================
|
106 |
+
# FFI
|
107 |
+
|
108 |
+
ffi.lib.LLVMPY_PassManagerBuilderCreate.restype = ffi.LLVMPassManagerBuilderRef
|
109 |
+
|
110 |
+
ffi.lib.LLVMPY_PassManagerBuilderDispose.argtypes = [
|
111 |
+
ffi.LLVMPassManagerBuilderRef,
|
112 |
+
]
|
113 |
+
|
114 |
+
ffi.lib.LLVMPY_PassManagerBuilderPopulateModulePassManager.argtypes = [
|
115 |
+
ffi.LLVMPassManagerBuilderRef,
|
116 |
+
ffi.LLVMPassManagerRef,
|
117 |
+
]
|
118 |
+
|
119 |
+
ffi.lib.LLVMPY_PassManagerBuilderPopulateFunctionPassManager.argtypes = [
|
120 |
+
ffi.LLVMPassManagerBuilderRef,
|
121 |
+
ffi.LLVMPassManagerRef,
|
122 |
+
]
|
123 |
+
|
124 |
+
# Unsigned int PassManagerBuilder properties
|
125 |
+
|
126 |
+
for _func in (ffi.lib.LLVMPY_PassManagerBuilderSetOptLevel,
|
127 |
+
ffi.lib.LLVMPY_PassManagerBuilderSetSizeLevel,
|
128 |
+
ffi.lib.LLVMPY_PassManagerBuilderUseInlinerWithThreshold,
|
129 |
+
):
|
130 |
+
_func.argtypes = [ffi.LLVMPassManagerBuilderRef, c_uint]
|
131 |
+
|
132 |
+
for _func in (ffi.lib.LLVMPY_PassManagerBuilderGetOptLevel,
|
133 |
+
ffi.lib.LLVMPY_PassManagerBuilderGetSizeLevel,
|
134 |
+
):
|
135 |
+
_func.argtypes = [ffi.LLVMPassManagerBuilderRef]
|
136 |
+
_func.restype = c_uint
|
137 |
+
|
138 |
+
# Boolean PassManagerBuilder properties
|
139 |
+
|
140 |
+
for _func in (ffi.lib.LLVMPY_PassManagerBuilderSetDisableUnrollLoops,
|
141 |
+
ffi.lib.LLVMPY_PassManagerBuilderSetLoopVectorize,
|
142 |
+
ffi.lib.LLVMPY_PassManagerBuilderSetSLPVectorize,
|
143 |
+
):
|
144 |
+
_func.argtypes = [ffi.LLVMPassManagerBuilderRef, c_bool]
|
145 |
+
|
146 |
+
for _func in (ffi.lib.LLVMPY_PassManagerBuilderGetDisableUnrollLoops,
|
147 |
+
ffi.lib.LLVMPY_PassManagerBuilderGetLoopVectorize,
|
148 |
+
ffi.lib.LLVMPY_PassManagerBuilderGetSLPVectorize,
|
149 |
+
):
|
150 |
+
_func.argtypes = [ffi.LLVMPassManagerBuilderRef]
|
151 |
+
_func.restype = c_bool
|
lib/python3.11/site-packages/llvmlite/binding/value.py
ADDED
@@ -0,0 +1,624 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ctypes import (POINTER, byref, cast, c_char_p, c_double, c_int, c_size_t,
|
2 |
+
c_uint, c_uint64, c_bool, c_void_p)
|
3 |
+
import enum
|
4 |
+
|
5 |
+
from llvmlite.binding import ffi
|
6 |
+
from llvmlite.binding.common import _decode_string, _encode_string
|
7 |
+
|
8 |
+
|
9 |
+
class Linkage(enum.IntEnum):
|
10 |
+
# The LLVMLinkage enum from llvm-c/Core.h
|
11 |
+
|
12 |
+
external = 0
|
13 |
+
available_externally = 1
|
14 |
+
linkonce_any = 2
|
15 |
+
linkonce_odr = 3
|
16 |
+
linkonce_odr_autohide = 4
|
17 |
+
weak_any = 5
|
18 |
+
weak_odr = 6
|
19 |
+
appending = 7
|
20 |
+
internal = 8
|
21 |
+
private = 9
|
22 |
+
dllimport = 10
|
23 |
+
dllexport = 11
|
24 |
+
external_weak = 12
|
25 |
+
ghost = 13
|
26 |
+
common = 14
|
27 |
+
linker_private = 15
|
28 |
+
linker_private_weak = 16
|
29 |
+
|
30 |
+
|
31 |
+
class Visibility(enum.IntEnum):
|
32 |
+
# The LLVMVisibility enum from llvm-c/Core.h
|
33 |
+
|
34 |
+
default = 0
|
35 |
+
hidden = 1
|
36 |
+
protected = 2
|
37 |
+
|
38 |
+
|
39 |
+
class StorageClass(enum.IntEnum):
|
40 |
+
# The LLVMDLLStorageClass enum from llvm-c/Core.h
|
41 |
+
|
42 |
+
default = 0
|
43 |
+
dllimport = 1
|
44 |
+
dllexport = 2
|
45 |
+
|
46 |
+
|
47 |
+
class ValueKind(enum.IntEnum):
|
48 |
+
# The LLVMValueKind enum from llvm-c/Core.h
|
49 |
+
|
50 |
+
argument = 0
|
51 |
+
basic_block = 1
|
52 |
+
memory_use = 2
|
53 |
+
memory_def = 3
|
54 |
+
memory_phi = 4
|
55 |
+
|
56 |
+
function = 5
|
57 |
+
global_alias = 6
|
58 |
+
global_ifunc = 7
|
59 |
+
global_variable = 8
|
60 |
+
block_address = 9
|
61 |
+
constant_expr = 10
|
62 |
+
constant_array = 11
|
63 |
+
constant_struct = 12
|
64 |
+
constant_vector = 13
|
65 |
+
|
66 |
+
undef_value = 14
|
67 |
+
constant_aggregate_zero = 15
|
68 |
+
constant_data_array = 16
|
69 |
+
constant_data_vector = 17
|
70 |
+
constant_int = 18
|
71 |
+
constant_fp = 19
|
72 |
+
constant_pointer_null = 20
|
73 |
+
constant_token_none = 21
|
74 |
+
|
75 |
+
metadata_as_value = 22
|
76 |
+
inline_asm = 23
|
77 |
+
|
78 |
+
instruction = 24
|
79 |
+
poison_value = 25
|
80 |
+
|
81 |
+
|
82 |
+
class TypeRef(ffi.ObjectRef):
|
83 |
+
"""A weak reference to a LLVM type
|
84 |
+
"""
|
85 |
+
@property
|
86 |
+
def name(self):
|
87 |
+
"""
|
88 |
+
Get type name
|
89 |
+
"""
|
90 |
+
return ffi.ret_string(ffi.lib.LLVMPY_GetTypeName(self))
|
91 |
+
|
92 |
+
@property
|
93 |
+
def is_pointer(self):
|
94 |
+
"""
|
95 |
+
Returns true is the type is a pointer type.
|
96 |
+
"""
|
97 |
+
return ffi.lib.LLVMPY_TypeIsPointer(self)
|
98 |
+
|
99 |
+
@property
|
100 |
+
def element_type(self):
|
101 |
+
"""
|
102 |
+
Returns the pointed-to type. When the type is not a pointer,
|
103 |
+
raises exception.
|
104 |
+
"""
|
105 |
+
if not self.is_pointer:
|
106 |
+
raise ValueError("Type {} is not a pointer".format(self))
|
107 |
+
return TypeRef(ffi.lib.LLVMPY_GetElementType(self))
|
108 |
+
|
109 |
+
def __str__(self):
|
110 |
+
return ffi.ret_string(ffi.lib.LLVMPY_PrintType(self))
|
111 |
+
|
112 |
+
|
113 |
+
class ValueRef(ffi.ObjectRef):
|
114 |
+
"""A weak reference to a LLVM value.
|
115 |
+
"""
|
116 |
+
|
117 |
+
def __init__(self, ptr, kind, parents):
|
118 |
+
self._kind = kind
|
119 |
+
self._parents = parents
|
120 |
+
ffi.ObjectRef.__init__(self, ptr)
|
121 |
+
|
122 |
+
def __str__(self):
|
123 |
+
with ffi.OutputString() as outstr:
|
124 |
+
ffi.lib.LLVMPY_PrintValueToString(self, outstr)
|
125 |
+
return str(outstr)
|
126 |
+
|
127 |
+
@property
|
128 |
+
def module(self):
|
129 |
+
"""
|
130 |
+
The module this function or global variable value was obtained from.
|
131 |
+
"""
|
132 |
+
return self._parents.get('module')
|
133 |
+
|
134 |
+
@property
|
135 |
+
def function(self):
|
136 |
+
"""
|
137 |
+
The function this argument or basic block value was obtained from.
|
138 |
+
"""
|
139 |
+
return self._parents.get('function')
|
140 |
+
|
141 |
+
@property
|
142 |
+
def block(self):
|
143 |
+
"""
|
144 |
+
The block this instruction value was obtained from.
|
145 |
+
"""
|
146 |
+
return self._parents.get('block')
|
147 |
+
|
148 |
+
@property
|
149 |
+
def instruction(self):
|
150 |
+
"""
|
151 |
+
The instruction this operand value was obtained from.
|
152 |
+
"""
|
153 |
+
return self._parents.get('instruction')
|
154 |
+
|
155 |
+
@property
|
156 |
+
def is_global(self):
|
157 |
+
return self._kind == 'global'
|
158 |
+
|
159 |
+
@property
|
160 |
+
def is_function(self):
|
161 |
+
return self._kind == 'function'
|
162 |
+
|
163 |
+
@property
|
164 |
+
def is_block(self):
|
165 |
+
return self._kind == 'block'
|
166 |
+
|
167 |
+
@property
|
168 |
+
def is_argument(self):
|
169 |
+
return self._kind == 'argument'
|
170 |
+
|
171 |
+
@property
|
172 |
+
def is_instruction(self):
|
173 |
+
return self._kind == 'instruction'
|
174 |
+
|
175 |
+
@property
|
176 |
+
def is_operand(self):
|
177 |
+
return self._kind == 'operand'
|
178 |
+
|
179 |
+
@property
|
180 |
+
def is_constant(self):
|
181 |
+
return bool(ffi.lib.LLVMPY_IsConstant(self))
|
182 |
+
|
183 |
+
@property
|
184 |
+
def value_kind(self):
|
185 |
+
return ValueKind(ffi.lib.LLVMPY_GetValueKind(self))
|
186 |
+
|
187 |
+
@property
|
188 |
+
def name(self):
|
189 |
+
return _decode_string(ffi.lib.LLVMPY_GetValueName(self))
|
190 |
+
|
191 |
+
@name.setter
|
192 |
+
def name(self, val):
|
193 |
+
ffi.lib.LLVMPY_SetValueName(self, _encode_string(val))
|
194 |
+
|
195 |
+
@property
|
196 |
+
def linkage(self):
|
197 |
+
return Linkage(ffi.lib.LLVMPY_GetLinkage(self))
|
198 |
+
|
199 |
+
@linkage.setter
|
200 |
+
def linkage(self, value):
|
201 |
+
if not isinstance(value, Linkage):
|
202 |
+
value = Linkage[value]
|
203 |
+
ffi.lib.LLVMPY_SetLinkage(self, value)
|
204 |
+
|
205 |
+
@property
|
206 |
+
def visibility(self):
|
207 |
+
return Visibility(ffi.lib.LLVMPY_GetVisibility(self))
|
208 |
+
|
209 |
+
@visibility.setter
|
210 |
+
def visibility(self, value):
|
211 |
+
if not isinstance(value, Visibility):
|
212 |
+
value = Visibility[value]
|
213 |
+
ffi.lib.LLVMPY_SetVisibility(self, value)
|
214 |
+
|
215 |
+
@property
|
216 |
+
def storage_class(self):
|
217 |
+
return StorageClass(ffi.lib.LLVMPY_GetDLLStorageClass(self))
|
218 |
+
|
219 |
+
@storage_class.setter
|
220 |
+
def storage_class(self, value):
|
221 |
+
if not isinstance(value, StorageClass):
|
222 |
+
value = StorageClass[value]
|
223 |
+
ffi.lib.LLVMPY_SetDLLStorageClass(self, value)
|
224 |
+
|
225 |
+
def add_function_attribute(self, attr):
|
226 |
+
"""Only works on function value
|
227 |
+
|
228 |
+
Parameters
|
229 |
+
-----------
|
230 |
+
attr : str
|
231 |
+
attribute name
|
232 |
+
"""
|
233 |
+
if not self.is_function:
|
234 |
+
raise ValueError('expected function value, got %s' % (self._kind,))
|
235 |
+
attrname = str(attr)
|
236 |
+
attrval = ffi.lib.LLVMPY_GetEnumAttributeKindForName(
|
237 |
+
_encode_string(attrname), len(attrname))
|
238 |
+
if attrval == 0:
|
239 |
+
raise ValueError('no such attribute {!r}'.format(attrname))
|
240 |
+
ffi.lib.LLVMPY_AddFunctionAttr(self, attrval)
|
241 |
+
|
242 |
+
@property
|
243 |
+
def type(self):
|
244 |
+
"""
|
245 |
+
This value's LLVM type.
|
246 |
+
"""
|
247 |
+
# XXX what does this return?
|
248 |
+
return TypeRef(ffi.lib.LLVMPY_TypeOf(self))
|
249 |
+
|
250 |
+
@property
|
251 |
+
def is_declaration(self):
|
252 |
+
"""
|
253 |
+
Whether this value (presumably global) is defined in the current
|
254 |
+
module.
|
255 |
+
"""
|
256 |
+
if not (self.is_global or self.is_function):
|
257 |
+
raise ValueError('expected global or function value, got %s'
|
258 |
+
% (self._kind,))
|
259 |
+
return ffi.lib.LLVMPY_IsDeclaration(self)
|
260 |
+
|
261 |
+
@property
|
262 |
+
def attributes(self):
|
263 |
+
"""
|
264 |
+
Return an iterator over this value's attributes.
|
265 |
+
The iterator will yield a string for each attribute.
|
266 |
+
"""
|
267 |
+
itr = iter(())
|
268 |
+
if self.is_function:
|
269 |
+
it = ffi.lib.LLVMPY_FunctionAttributesIter(self)
|
270 |
+
itr = _AttributeListIterator(it)
|
271 |
+
elif self.is_instruction:
|
272 |
+
if self.opcode == 'call':
|
273 |
+
it = ffi.lib.LLVMPY_CallInstAttributesIter(self)
|
274 |
+
itr = _AttributeListIterator(it)
|
275 |
+
elif self.opcode == 'invoke':
|
276 |
+
it = ffi.lib.LLVMPY_InvokeInstAttributesIter(self)
|
277 |
+
itr = _AttributeListIterator(it)
|
278 |
+
elif self.is_global:
|
279 |
+
it = ffi.lib.LLVMPY_GlobalAttributesIter(self)
|
280 |
+
itr = _AttributeSetIterator(it)
|
281 |
+
elif self.is_argument:
|
282 |
+
it = ffi.lib.LLVMPY_ArgumentAttributesIter(self)
|
283 |
+
itr = _AttributeSetIterator(it)
|
284 |
+
return itr
|
285 |
+
|
286 |
+
@property
|
287 |
+
def blocks(self):
|
288 |
+
"""
|
289 |
+
Return an iterator over this function's blocks.
|
290 |
+
The iterator will yield a ValueRef for each block.
|
291 |
+
"""
|
292 |
+
if not self.is_function:
|
293 |
+
raise ValueError('expected function value, got %s' % (self._kind,))
|
294 |
+
it = ffi.lib.LLVMPY_FunctionBlocksIter(self)
|
295 |
+
parents = self._parents.copy()
|
296 |
+
parents.update(function=self)
|
297 |
+
return _BlocksIterator(it, parents)
|
298 |
+
|
299 |
+
@property
|
300 |
+
def arguments(self):
|
301 |
+
"""
|
302 |
+
Return an iterator over this function's arguments.
|
303 |
+
The iterator will yield a ValueRef for each argument.
|
304 |
+
"""
|
305 |
+
if not self.is_function:
|
306 |
+
raise ValueError('expected function value, got %s' % (self._kind,))
|
307 |
+
it = ffi.lib.LLVMPY_FunctionArgumentsIter(self)
|
308 |
+
parents = self._parents.copy()
|
309 |
+
parents.update(function=self)
|
310 |
+
return _ArgumentsIterator(it, parents)
|
311 |
+
|
312 |
+
@property
|
313 |
+
def instructions(self):
|
314 |
+
"""
|
315 |
+
Return an iterator over this block's instructions.
|
316 |
+
The iterator will yield a ValueRef for each instruction.
|
317 |
+
"""
|
318 |
+
if not self.is_block:
|
319 |
+
raise ValueError('expected block value, got %s' % (self._kind,))
|
320 |
+
it = ffi.lib.LLVMPY_BlockInstructionsIter(self)
|
321 |
+
parents = self._parents.copy()
|
322 |
+
parents.update(block=self)
|
323 |
+
return _InstructionsIterator(it, parents)
|
324 |
+
|
325 |
+
@property
|
326 |
+
def operands(self):
|
327 |
+
"""
|
328 |
+
Return an iterator over this instruction's operands.
|
329 |
+
The iterator will yield a ValueRef for each operand.
|
330 |
+
"""
|
331 |
+
if not self.is_instruction:
|
332 |
+
raise ValueError('expected instruction value, got %s'
|
333 |
+
% (self._kind,))
|
334 |
+
it = ffi.lib.LLVMPY_InstructionOperandsIter(self)
|
335 |
+
parents = self._parents.copy()
|
336 |
+
parents.update(instruction=self)
|
337 |
+
return _OperandsIterator(it, parents)
|
338 |
+
|
339 |
+
@property
|
340 |
+
def opcode(self):
|
341 |
+
if not self.is_instruction:
|
342 |
+
raise ValueError('expected instruction value, got %s'
|
343 |
+
% (self._kind,))
|
344 |
+
return ffi.ret_string(ffi.lib.LLVMPY_GetOpcodeName(self))
|
345 |
+
|
346 |
+
def get_constant_value(self, signed_int=False, round_fp=False):
|
347 |
+
"""
|
348 |
+
Return the constant value, either as a literal (when supported)
|
349 |
+
or as a string.
|
350 |
+
|
351 |
+
Parameters
|
352 |
+
-----------
|
353 |
+
signed_int : bool
|
354 |
+
if True and the constant is an integer, returns a signed version
|
355 |
+
round_fp : bool
|
356 |
+
if True and the constant is a floating point value, rounds the
|
357 |
+
result upon accuracy loss (e.g., when querying an fp128 value).
|
358 |
+
By default, raises an exception on accuracy loss
|
359 |
+
"""
|
360 |
+
if not self.is_constant:
|
361 |
+
raise ValueError('expected constant value, got %s'
|
362 |
+
% (self._kind,))
|
363 |
+
|
364 |
+
if self.value_kind == ValueKind.constant_int:
|
365 |
+
# Python integers are also arbitrary-precision
|
366 |
+
little_endian = c_bool(False)
|
367 |
+
words = ffi.lib.LLVMPY_GetConstantIntNumWords(self)
|
368 |
+
ptr = ffi.lib.LLVMPY_GetConstantIntRawValue(
|
369 |
+
self, byref(little_endian))
|
370 |
+
asbytes = bytes(cast(ptr, POINTER(c_uint64 * words)).contents)
|
371 |
+
return int.from_bytes(
|
372 |
+
asbytes,
|
373 |
+
('little' if little_endian.value else 'big'),
|
374 |
+
signed=signed_int,
|
375 |
+
)
|
376 |
+
elif self.value_kind == ValueKind.constant_fp:
|
377 |
+
# Convert floating-point values to double-precision (Python float)
|
378 |
+
accuracy_loss = c_bool(False)
|
379 |
+
value = ffi.lib.LLVMPY_GetConstantFPValue(self,
|
380 |
+
byref(accuracy_loss))
|
381 |
+
if accuracy_loss.value and not round_fp:
|
382 |
+
raise ValueError(
|
383 |
+
'Accuracy loss encountered in conversion of constant '
|
384 |
+
f'value {str(self)}')
|
385 |
+
|
386 |
+
return value
|
387 |
+
|
388 |
+
# Otherwise, return the IR string
|
389 |
+
return str(self)
|
390 |
+
|
391 |
+
|
392 |
+
class _ValueIterator(ffi.ObjectRef):
|
393 |
+
|
394 |
+
kind = None # derived classes must specify the Value kind value
|
395 |
+
# as class attribute
|
396 |
+
|
397 |
+
def __init__(self, ptr, parents):
|
398 |
+
ffi.ObjectRef.__init__(self, ptr)
|
399 |
+
# Keep parent objects (module, function, etc) alive
|
400 |
+
self._parents = parents
|
401 |
+
if self.kind is None:
|
402 |
+
raise NotImplementedError('%s must specify kind attribute'
|
403 |
+
% (type(self).__name__,))
|
404 |
+
|
405 |
+
def __next__(self):
|
406 |
+
vp = self._next()
|
407 |
+
if vp:
|
408 |
+
return ValueRef(vp, self.kind, self._parents)
|
409 |
+
else:
|
410 |
+
raise StopIteration
|
411 |
+
|
412 |
+
next = __next__
|
413 |
+
|
414 |
+
def __iter__(self):
|
415 |
+
return self
|
416 |
+
|
417 |
+
|
418 |
+
class _AttributeIterator(ffi.ObjectRef):
|
419 |
+
|
420 |
+
def __next__(self):
|
421 |
+
vp = self._next()
|
422 |
+
if vp:
|
423 |
+
return vp
|
424 |
+
else:
|
425 |
+
raise StopIteration
|
426 |
+
|
427 |
+
next = __next__
|
428 |
+
|
429 |
+
def __iter__(self):
|
430 |
+
return self
|
431 |
+
|
432 |
+
|
433 |
+
class _AttributeListIterator(_AttributeIterator):
|
434 |
+
|
435 |
+
def _dispose(self):
|
436 |
+
self._capi.LLVMPY_DisposeAttributeListIter(self)
|
437 |
+
|
438 |
+
def _next(self):
|
439 |
+
return ffi.ret_bytes(ffi.lib.LLVMPY_AttributeListIterNext(self))
|
440 |
+
|
441 |
+
|
442 |
+
class _AttributeSetIterator(_AttributeIterator):
|
443 |
+
|
444 |
+
def _dispose(self):
|
445 |
+
self._capi.LLVMPY_DisposeAttributeSetIter(self)
|
446 |
+
|
447 |
+
def _next(self):
|
448 |
+
return ffi.ret_bytes(ffi.lib.LLVMPY_AttributeSetIterNext(self))
|
449 |
+
|
450 |
+
|
451 |
+
class _BlocksIterator(_ValueIterator):
|
452 |
+
|
453 |
+
kind = 'block'
|
454 |
+
|
455 |
+
def _dispose(self):
|
456 |
+
self._capi.LLVMPY_DisposeBlocksIter(self)
|
457 |
+
|
458 |
+
def _next(self):
|
459 |
+
return ffi.lib.LLVMPY_BlocksIterNext(self)
|
460 |
+
|
461 |
+
|
462 |
+
class _ArgumentsIterator(_ValueIterator):
|
463 |
+
|
464 |
+
kind = 'argument'
|
465 |
+
|
466 |
+
def _dispose(self):
|
467 |
+
self._capi.LLVMPY_DisposeArgumentsIter(self)
|
468 |
+
|
469 |
+
def _next(self):
|
470 |
+
return ffi.lib.LLVMPY_ArgumentsIterNext(self)
|
471 |
+
|
472 |
+
|
473 |
+
class _InstructionsIterator(_ValueIterator):
|
474 |
+
|
475 |
+
kind = 'instruction'
|
476 |
+
|
477 |
+
def _dispose(self):
|
478 |
+
self._capi.LLVMPY_DisposeInstructionsIter(self)
|
479 |
+
|
480 |
+
def _next(self):
|
481 |
+
return ffi.lib.LLVMPY_InstructionsIterNext(self)
|
482 |
+
|
483 |
+
|
484 |
+
class _OperandsIterator(_ValueIterator):
|
485 |
+
|
486 |
+
kind = 'operand'
|
487 |
+
|
488 |
+
def _dispose(self):
|
489 |
+
self._capi.LLVMPY_DisposeOperandsIter(self)
|
490 |
+
|
491 |
+
def _next(self):
|
492 |
+
return ffi.lib.LLVMPY_OperandsIterNext(self)
|
493 |
+
|
494 |
+
|
495 |
+
# FFI
|
496 |
+
|
497 |
+
ffi.lib.LLVMPY_PrintValueToString.argtypes = [
|
498 |
+
ffi.LLVMValueRef,
|
499 |
+
POINTER(c_char_p)
|
500 |
+
]
|
501 |
+
|
502 |
+
ffi.lib.LLVMPY_GetGlobalParent.argtypes = [ffi.LLVMValueRef]
|
503 |
+
ffi.lib.LLVMPY_GetGlobalParent.restype = ffi.LLVMModuleRef
|
504 |
+
|
505 |
+
ffi.lib.LLVMPY_GetValueName.argtypes = [ffi.LLVMValueRef]
|
506 |
+
ffi.lib.LLVMPY_GetValueName.restype = c_char_p
|
507 |
+
|
508 |
+
ffi.lib.LLVMPY_SetValueName.argtypes = [ffi.LLVMValueRef, c_char_p]
|
509 |
+
|
510 |
+
ffi.lib.LLVMPY_TypeOf.argtypes = [ffi.LLVMValueRef]
|
511 |
+
ffi.lib.LLVMPY_TypeOf.restype = ffi.LLVMTypeRef
|
512 |
+
|
513 |
+
|
514 |
+
ffi.lib.LLVMPY_PrintType.argtypes = [ffi.LLVMTypeRef]
|
515 |
+
ffi.lib.LLVMPY_PrintType.restype = c_void_p
|
516 |
+
|
517 |
+
ffi.lib.LLVMPY_TypeIsPointer.argtypes = [ffi.LLVMTypeRef]
|
518 |
+
ffi.lib.LLVMPY_TypeIsPointer.restype = c_bool
|
519 |
+
|
520 |
+
ffi.lib.LLVMPY_GetElementType.argtypes = [ffi.LLVMTypeRef]
|
521 |
+
ffi.lib.LLVMPY_GetElementType.restype = ffi.LLVMTypeRef
|
522 |
+
|
523 |
+
|
524 |
+
ffi.lib.LLVMPY_GetTypeName.argtypes = [ffi.LLVMTypeRef]
|
525 |
+
ffi.lib.LLVMPY_GetTypeName.restype = c_void_p
|
526 |
+
|
527 |
+
ffi.lib.LLVMPY_GetLinkage.argtypes = [ffi.LLVMValueRef]
|
528 |
+
ffi.lib.LLVMPY_GetLinkage.restype = c_int
|
529 |
+
|
530 |
+
ffi.lib.LLVMPY_SetLinkage.argtypes = [ffi.LLVMValueRef, c_int]
|
531 |
+
|
532 |
+
ffi.lib.LLVMPY_GetVisibility.argtypes = [ffi.LLVMValueRef]
|
533 |
+
ffi.lib.LLVMPY_GetVisibility.restype = c_int
|
534 |
+
|
535 |
+
ffi.lib.LLVMPY_SetVisibility.argtypes = [ffi.LLVMValueRef, c_int]
|
536 |
+
|
537 |
+
ffi.lib.LLVMPY_GetDLLStorageClass.argtypes = [ffi.LLVMValueRef]
|
538 |
+
ffi.lib.LLVMPY_GetDLLStorageClass.restype = c_int
|
539 |
+
|
540 |
+
ffi.lib.LLVMPY_SetDLLStorageClass.argtypes = [ffi.LLVMValueRef, c_int]
|
541 |
+
|
542 |
+
ffi.lib.LLVMPY_GetEnumAttributeKindForName.argtypes = [c_char_p, c_size_t]
|
543 |
+
ffi.lib.LLVMPY_GetEnumAttributeKindForName.restype = c_uint
|
544 |
+
|
545 |
+
ffi.lib.LLVMPY_AddFunctionAttr.argtypes = [ffi.LLVMValueRef, c_uint]
|
546 |
+
|
547 |
+
ffi.lib.LLVMPY_IsDeclaration.argtypes = [ffi.LLVMValueRef]
|
548 |
+
ffi.lib.LLVMPY_IsDeclaration.restype = c_int
|
549 |
+
|
550 |
+
ffi.lib.LLVMPY_FunctionAttributesIter.argtypes = [ffi.LLVMValueRef]
|
551 |
+
ffi.lib.LLVMPY_FunctionAttributesIter.restype = ffi.LLVMAttributeListIterator
|
552 |
+
|
553 |
+
ffi.lib.LLVMPY_CallInstAttributesIter.argtypes = [ffi.LLVMValueRef]
|
554 |
+
ffi.lib.LLVMPY_CallInstAttributesIter.restype = ffi.LLVMAttributeListIterator
|
555 |
+
|
556 |
+
ffi.lib.LLVMPY_InvokeInstAttributesIter.argtypes = [ffi.LLVMValueRef]
|
557 |
+
ffi.lib.LLVMPY_InvokeInstAttributesIter.restype = ffi.LLVMAttributeListIterator
|
558 |
+
|
559 |
+
ffi.lib.LLVMPY_GlobalAttributesIter.argtypes = [ffi.LLVMValueRef]
|
560 |
+
ffi.lib.LLVMPY_GlobalAttributesIter.restype = ffi.LLVMAttributeSetIterator
|
561 |
+
|
562 |
+
ffi.lib.LLVMPY_ArgumentAttributesIter.argtypes = [ffi.LLVMValueRef]
|
563 |
+
ffi.lib.LLVMPY_ArgumentAttributesIter.restype = ffi.LLVMAttributeSetIterator
|
564 |
+
|
565 |
+
ffi.lib.LLVMPY_FunctionBlocksIter.argtypes = [ffi.LLVMValueRef]
|
566 |
+
ffi.lib.LLVMPY_FunctionBlocksIter.restype = ffi.LLVMBlocksIterator
|
567 |
+
|
568 |
+
ffi.lib.LLVMPY_FunctionArgumentsIter.argtypes = [ffi.LLVMValueRef]
|
569 |
+
ffi.lib.LLVMPY_FunctionArgumentsIter.restype = ffi.LLVMArgumentsIterator
|
570 |
+
|
571 |
+
ffi.lib.LLVMPY_BlockInstructionsIter.argtypes = [ffi.LLVMValueRef]
|
572 |
+
ffi.lib.LLVMPY_BlockInstructionsIter.restype = ffi.LLVMInstructionsIterator
|
573 |
+
|
574 |
+
ffi.lib.LLVMPY_InstructionOperandsIter.argtypes = [ffi.LLVMValueRef]
|
575 |
+
ffi.lib.LLVMPY_InstructionOperandsIter.restype = ffi.LLVMOperandsIterator
|
576 |
+
|
577 |
+
ffi.lib.LLVMPY_DisposeAttributeListIter.argtypes = [
|
578 |
+
ffi.LLVMAttributeListIterator]
|
579 |
+
|
580 |
+
ffi.lib.LLVMPY_DisposeAttributeSetIter.argtypes = [ffi.LLVMAttributeSetIterator]
|
581 |
+
|
582 |
+
ffi.lib.LLVMPY_DisposeBlocksIter.argtypes = [ffi.LLVMBlocksIterator]
|
583 |
+
|
584 |
+
ffi.lib.LLVMPY_DisposeInstructionsIter.argtypes = [ffi.LLVMInstructionsIterator]
|
585 |
+
|
586 |
+
ffi.lib.LLVMPY_DisposeOperandsIter.argtypes = [ffi.LLVMOperandsIterator]
|
587 |
+
|
588 |
+
ffi.lib.LLVMPY_AttributeListIterNext.argtypes = [ffi.LLVMAttributeListIterator]
|
589 |
+
ffi.lib.LLVMPY_AttributeListIterNext.restype = c_void_p
|
590 |
+
|
591 |
+
ffi.lib.LLVMPY_AttributeSetIterNext.argtypes = [ffi.LLVMAttributeSetIterator]
|
592 |
+
ffi.lib.LLVMPY_AttributeSetIterNext.restype = c_void_p
|
593 |
+
|
594 |
+
ffi.lib.LLVMPY_BlocksIterNext.argtypes = [ffi.LLVMBlocksIterator]
|
595 |
+
ffi.lib.LLVMPY_BlocksIterNext.restype = ffi.LLVMValueRef
|
596 |
+
|
597 |
+
ffi.lib.LLVMPY_ArgumentsIterNext.argtypes = [ffi.LLVMArgumentsIterator]
|
598 |
+
ffi.lib.LLVMPY_ArgumentsIterNext.restype = ffi.LLVMValueRef
|
599 |
+
|
600 |
+
ffi.lib.LLVMPY_InstructionsIterNext.argtypes = [ffi.LLVMInstructionsIterator]
|
601 |
+
ffi.lib.LLVMPY_InstructionsIterNext.restype = ffi.LLVMValueRef
|
602 |
+
|
603 |
+
ffi.lib.LLVMPY_OperandsIterNext.argtypes = [ffi.LLVMOperandsIterator]
|
604 |
+
ffi.lib.LLVMPY_OperandsIterNext.restype = ffi.LLVMValueRef
|
605 |
+
|
606 |
+
ffi.lib.LLVMPY_GetOpcodeName.argtypes = [ffi.LLVMValueRef]
|
607 |
+
ffi.lib.LLVMPY_GetOpcodeName.restype = c_void_p
|
608 |
+
|
609 |
+
ffi.lib.LLVMPY_IsConstant.argtypes = [ffi.LLVMValueRef]
|
610 |
+
ffi.lib.LLVMPY_IsConstant.restype = c_bool
|
611 |
+
|
612 |
+
ffi.lib.LLVMPY_GetValueKind.argtypes = [ffi.LLVMValueRef]
|
613 |
+
ffi.lib.LLVMPY_GetValueKind.restype = c_int
|
614 |
+
|
615 |
+
ffi.lib.LLVMPY_GetConstantIntRawValue.argtypes = [ffi.LLVMValueRef,
|
616 |
+
POINTER(c_bool)]
|
617 |
+
ffi.lib.LLVMPY_GetConstantIntRawValue.restype = POINTER(c_uint64)
|
618 |
+
|
619 |
+
ffi.lib.LLVMPY_GetConstantIntNumWords.argtypes = [ffi.LLVMValueRef]
|
620 |
+
ffi.lib.LLVMPY_GetConstantIntNumWords.restype = c_uint
|
621 |
+
|
622 |
+
ffi.lib.LLVMPY_GetConstantFPValue.argtypes = [ffi.LLVMValueRef,
|
623 |
+
POINTER(c_bool)]
|
624 |
+
ffi.lib.LLVMPY_GetConstantFPValue.restype = c_double
|
lib/python3.11/site-packages/llvmlite/ir/__init__.py
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
This subpackage implements the LLVM IR classes in pure python
|
3 |
+
"""
|
4 |
+
|
5 |
+
from .types import *
|
6 |
+
from .values import *
|
7 |
+
from .module import *
|
8 |
+
from .builder import *
|
9 |
+
from .instructions import *
|
10 |
+
from .transforms import *
|
11 |
+
from .context import Context, global_context
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (583 Bytes). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/_utils.cpython-311.pyc
ADDED
Binary file (5.17 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/builder.cpython-311.pyc
ADDED
Binary file (53.2 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/context.cpython-311.pyc
ADDED
Binary file (1.32 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/instructions.cpython-311.pyc
ADDED
Binary file (62.2 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/module.cpython-311.pyc
ADDED
Binary file (14.5 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/transforms.cpython-311.pyc
ADDED
Binary file (4.24 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/types.cpython-311.pyc
ADDED
Binary file (34.1 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/__pycache__/values.cpython-311.pyc
ADDED
Binary file (65.2 kB). View file
|
|
lib/python3.11/site-packages/llvmlite/ir/_utils.py
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections import defaultdict
|
2 |
+
|
3 |
+
|
4 |
+
class DuplicatedNameError(NameError):
|
5 |
+
pass
|
6 |
+
|
7 |
+
|
8 |
+
class NameScope(object):
|
9 |
+
def __init__(self):
|
10 |
+
self._useset = set([''])
|
11 |
+
self._basenamemap = defaultdict(int)
|
12 |
+
|
13 |
+
def is_used(self, name):
|
14 |
+
return name in self._useset
|
15 |
+
|
16 |
+
def register(self, name, deduplicate=False):
|
17 |
+
if deduplicate:
|
18 |
+
name = self.deduplicate(name)
|
19 |
+
elif self.is_used(name):
|
20 |
+
raise DuplicatedNameError(name)
|
21 |
+
self._useset.add(name)
|
22 |
+
return name
|
23 |
+
|
24 |
+
def deduplicate(self, name):
|
25 |
+
basename = name
|
26 |
+
while self.is_used(name):
|
27 |
+
ident = self._basenamemap[basename] + 1
|
28 |
+
self._basenamemap[basename] = ident
|
29 |
+
name = "{0}.{1}".format(basename, ident)
|
30 |
+
return name
|
31 |
+
|
32 |
+
def get_child(self):
|
33 |
+
return type(self)(parent=self)
|
34 |
+
|
35 |
+
|
36 |
+
class _StrCaching(object):
|
37 |
+
|
38 |
+
def _clear_string_cache(self):
|
39 |
+
try:
|
40 |
+
del self.__cached_str
|
41 |
+
except AttributeError:
|
42 |
+
pass
|
43 |
+
|
44 |
+
def __str__(self):
|
45 |
+
try:
|
46 |
+
return self.__cached_str
|
47 |
+
except AttributeError:
|
48 |
+
s = self.__cached_str = self._to_string()
|
49 |
+
return s
|
50 |
+
|
51 |
+
|
52 |
+
class _StringReferenceCaching(object):
|
53 |
+
|
54 |
+
def get_reference(self):
|
55 |
+
try:
|
56 |
+
return self.__cached_refstr
|
57 |
+
except AttributeError:
|
58 |
+
s = self.__cached_refstr = self._get_reference()
|
59 |
+
return s
|
60 |
+
|
61 |
+
|
62 |
+
class _HasMetadata(object):
|
63 |
+
|
64 |
+
def set_metadata(self, name, node):
|
65 |
+
"""
|
66 |
+
Attach unnamed metadata *node* to the metadata slot *name* of this
|
67 |
+
value.
|
68 |
+
"""
|
69 |
+
self.metadata[name] = node
|
70 |
+
|
71 |
+
def _stringify_metadata(self, leading_comma=False):
|
72 |
+
if self.metadata:
|
73 |
+
buf = []
|
74 |
+
if leading_comma:
|
75 |
+
buf.append("")
|
76 |
+
buf += ["!{0} {1}".format(k, v.get_reference())
|
77 |
+
for k, v in self.metadata.items()]
|
78 |
+
return ', '.join(buf)
|
79 |
+
else:
|
80 |
+
return ''
|
lib/python3.11/site-packages/llvmlite/ir/builder.py
ADDED
@@ -0,0 +1,1119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import contextlib
|
2 |
+
import functools
|
3 |
+
|
4 |
+
from llvmlite.ir import instructions, types, values
|
5 |
+
|
6 |
+
_CMP_MAP = {
|
7 |
+
'>': 'gt',
|
8 |
+
'<': 'lt',
|
9 |
+
'==': 'eq',
|
10 |
+
'!=': 'ne',
|
11 |
+
'>=': 'ge',
|
12 |
+
'<=': 'le',
|
13 |
+
}
|
14 |
+
|
15 |
+
|
16 |
+
def _unop(opname, cls=instructions.Instruction):
|
17 |
+
def wrap(fn):
|
18 |
+
@functools.wraps(fn)
|
19 |
+
def wrapped(self, arg, name='', flags=()):
|
20 |
+
instr = cls(self.block, arg.type, opname, [arg], name, flags)
|
21 |
+
self._insert(instr)
|
22 |
+
return instr
|
23 |
+
|
24 |
+
return wrapped
|
25 |
+
|
26 |
+
return wrap
|
27 |
+
|
28 |
+
|
29 |
+
def _binop(opname, cls=instructions.Instruction):
|
30 |
+
def wrap(fn):
|
31 |
+
@functools.wraps(fn)
|
32 |
+
def wrapped(self, lhs, rhs, name='', flags=()):
|
33 |
+
if lhs.type != rhs.type:
|
34 |
+
raise ValueError("Operands must be the same type, got (%s, %s)"
|
35 |
+
% (lhs.type, rhs.type))
|
36 |
+
instr = cls(self.block, lhs.type, opname, (lhs, rhs), name, flags)
|
37 |
+
self._insert(instr)
|
38 |
+
return instr
|
39 |
+
|
40 |
+
return wrapped
|
41 |
+
|
42 |
+
return wrap
|
43 |
+
|
44 |
+
|
45 |
+
def _binop_with_overflow(opname, cls=instructions.Instruction):
|
46 |
+
def wrap(fn):
|
47 |
+
@functools.wraps(fn)
|
48 |
+
def wrapped(self, lhs, rhs, name=''):
|
49 |
+
if lhs.type != rhs.type:
|
50 |
+
raise ValueError("Operands must be the same type, got (%s, %s)"
|
51 |
+
% (lhs.type, rhs.type))
|
52 |
+
ty = lhs.type
|
53 |
+
if not isinstance(ty, types.IntType):
|
54 |
+
raise TypeError("expected an integer type, got %s" % (ty,))
|
55 |
+
bool_ty = types.IntType(1)
|
56 |
+
|
57 |
+
mod = self.module
|
58 |
+
fnty = types.FunctionType(types.LiteralStructType([ty, bool_ty]),
|
59 |
+
[ty, ty])
|
60 |
+
fn = mod.declare_intrinsic("llvm.%s.with.overflow" % (opname,),
|
61 |
+
[ty], fnty)
|
62 |
+
ret = self.call(fn, [lhs, rhs], name=name)
|
63 |
+
return ret
|
64 |
+
|
65 |
+
return wrapped
|
66 |
+
|
67 |
+
return wrap
|
68 |
+
|
69 |
+
|
70 |
+
def _uniop(opname, cls=instructions.Instruction):
|
71 |
+
def wrap(fn):
|
72 |
+
@functools.wraps(fn)
|
73 |
+
def wrapped(self, operand, name=''):
|
74 |
+
instr = cls(self.block, operand.type, opname, [operand], name)
|
75 |
+
self._insert(instr)
|
76 |
+
return instr
|
77 |
+
|
78 |
+
return wrapped
|
79 |
+
|
80 |
+
return wrap
|
81 |
+
|
82 |
+
|
83 |
+
def _uniop_intrinsic_int(opname):
|
84 |
+
def wrap(fn):
|
85 |
+
@functools.wraps(fn)
|
86 |
+
def wrapped(self, operand, name=''):
|
87 |
+
if not isinstance(operand.type, types.IntType):
|
88 |
+
raise TypeError(
|
89 |
+
"expected an integer type, got %s" %
|
90 |
+
operand.type)
|
91 |
+
fn = self.module.declare_intrinsic(opname, [operand.type])
|
92 |
+
return self.call(fn, [operand], name)
|
93 |
+
|
94 |
+
return wrapped
|
95 |
+
|
96 |
+
return wrap
|
97 |
+
|
98 |
+
|
99 |
+
def _uniop_intrinsic_float(opname):
|
100 |
+
def wrap(fn):
|
101 |
+
@functools.wraps(fn)
|
102 |
+
def wrapped(self, operand, name=''):
|
103 |
+
if not isinstance(
|
104 |
+
operand.type, (types.FloatType, types.DoubleType)):
|
105 |
+
raise TypeError("expected a float type, got %s" % operand.type)
|
106 |
+
fn = self.module.declare_intrinsic(opname, [operand.type])
|
107 |
+
return self.call(fn, [operand], name)
|
108 |
+
|
109 |
+
return wrapped
|
110 |
+
|
111 |
+
return wrap
|
112 |
+
|
113 |
+
|
114 |
+
def _uniop_intrinsic_with_flag(opname):
|
115 |
+
def wrap(fn):
|
116 |
+
@functools.wraps(fn)
|
117 |
+
def wrapped(self, operand, flag, name=''):
|
118 |
+
if not isinstance(operand.type, types.IntType):
|
119 |
+
raise TypeError(
|
120 |
+
"expected an integer type, got %s" %
|
121 |
+
operand.type)
|
122 |
+
if not (isinstance(flag.type, types.IntType) and
|
123 |
+
flag.type.width == 1):
|
124 |
+
raise TypeError("expected an i1 type, got %s" % flag.type)
|
125 |
+
fn = self.module.declare_intrinsic(
|
126 |
+
opname, [operand.type, flag.type])
|
127 |
+
return self.call(fn, [operand, flag], name)
|
128 |
+
|
129 |
+
return wrapped
|
130 |
+
|
131 |
+
return wrap
|
132 |
+
|
133 |
+
|
134 |
+
def _triop_intrinsic(opname):
|
135 |
+
def wrap(fn):
|
136 |
+
@functools.wraps(fn)
|
137 |
+
def wrapped(self, a, b, c, name=''):
|
138 |
+
if a.type != b.type or b.type != c.type:
|
139 |
+
raise TypeError(
|
140 |
+
"expected types to be the same, got %s, %s, %s" % (
|
141 |
+
a.type,
|
142 |
+
b.type,
|
143 |
+
c.type))
|
144 |
+
elif not isinstance(
|
145 |
+
a.type,
|
146 |
+
(types.HalfType, types.FloatType, types.DoubleType)):
|
147 |
+
raise TypeError(
|
148 |
+
"expected an floating point type, got %s" %
|
149 |
+
a.type)
|
150 |
+
fn = self.module.declare_intrinsic(opname, [a.type, b.type, c.type])
|
151 |
+
return self.call(fn, [a, b, c], name)
|
152 |
+
|
153 |
+
return wrapped
|
154 |
+
|
155 |
+
return wrap
|
156 |
+
|
157 |
+
|
158 |
+
def _castop(opname, cls=instructions.CastInstr):
|
159 |
+
def wrap(fn):
|
160 |
+
@functools.wraps(fn)
|
161 |
+
def wrapped(self, val, typ, name=''):
|
162 |
+
if val.type == typ:
|
163 |
+
return val
|
164 |
+
instr = cls(self.block, opname, val, typ, name)
|
165 |
+
self._insert(instr)
|
166 |
+
return instr
|
167 |
+
|
168 |
+
return wrapped
|
169 |
+
|
170 |
+
return wrap
|
171 |
+
|
172 |
+
|
173 |
+
def _label_suffix(label, suffix):
|
174 |
+
"""Returns (label + suffix) or a truncated version if it's too long.
|
175 |
+
Parameters
|
176 |
+
----------
|
177 |
+
label : str
|
178 |
+
Label name
|
179 |
+
suffix : str
|
180 |
+
Label suffix
|
181 |
+
"""
|
182 |
+
if len(label) > 50:
|
183 |
+
nhead = 25
|
184 |
+
return ''.join([label[:nhead], '..', suffix])
|
185 |
+
else:
|
186 |
+
return label + suffix
|
187 |
+
|
188 |
+
|
189 |
+
class IRBuilder(object):
|
190 |
+
def __init__(self, block=None):
|
191 |
+
self._block = block
|
192 |
+
self._anchor = len(block.instructions) if block else 0
|
193 |
+
self.debug_metadata = None
|
194 |
+
|
195 |
+
@property
|
196 |
+
def block(self):
|
197 |
+
"""
|
198 |
+
The current basic block.
|
199 |
+
"""
|
200 |
+
return self._block
|
201 |
+
|
202 |
+
basic_block = block
|
203 |
+
|
204 |
+
@property
|
205 |
+
def function(self):
|
206 |
+
"""
|
207 |
+
The current function.
|
208 |
+
"""
|
209 |
+
return self.block.parent
|
210 |
+
|
211 |
+
@property
|
212 |
+
def module(self):
|
213 |
+
"""
|
214 |
+
The current module.
|
215 |
+
"""
|
216 |
+
return self.block.parent.module
|
217 |
+
|
218 |
+
def position_before(self, instr):
|
219 |
+
"""
|
220 |
+
Position immediately before the given instruction. The current block
|
221 |
+
is also changed to the instruction's basic block.
|
222 |
+
"""
|
223 |
+
self._block = instr.parent
|
224 |
+
self._anchor = self._block.instructions.index(instr)
|
225 |
+
|
226 |
+
def position_after(self, instr):
|
227 |
+
"""
|
228 |
+
Position immediately after the given instruction. The current block
|
229 |
+
is also changed to the instruction's basic block.
|
230 |
+
"""
|
231 |
+
self._block = instr.parent
|
232 |
+
self._anchor = self._block.instructions.index(instr) + 1
|
233 |
+
|
234 |
+
def position_at_start(self, block):
|
235 |
+
"""
|
236 |
+
Position at the start of the basic *block*.
|
237 |
+
"""
|
238 |
+
self._block = block
|
239 |
+
self._anchor = 0
|
240 |
+
|
241 |
+
def position_at_end(self, block):
|
242 |
+
"""
|
243 |
+
Position at the end of the basic *block*.
|
244 |
+
"""
|
245 |
+
self._block = block
|
246 |
+
self._anchor = len(block.instructions)
|
247 |
+
|
248 |
+
def append_basic_block(self, name=''):
|
249 |
+
"""
|
250 |
+
Append a basic block, with the given optional *name*, to the current
|
251 |
+
function. The current block is not changed. The new block is returned.
|
252 |
+
"""
|
253 |
+
return self.function.append_basic_block(name)
|
254 |
+
|
255 |
+
def remove(self, instr):
|
256 |
+
"""Remove the given instruction."""
|
257 |
+
idx = self._block.instructions.index(instr)
|
258 |
+
del self._block.instructions[idx]
|
259 |
+
if self._block.terminator == instr:
|
260 |
+
self._block.terminator = None
|
261 |
+
if self._anchor > idx:
|
262 |
+
self._anchor -= 1
|
263 |
+
|
264 |
+
@contextlib.contextmanager
|
265 |
+
def goto_block(self, block):
|
266 |
+
"""
|
267 |
+
A context manager which temporarily positions the builder at the end
|
268 |
+
of basic block *bb* (but before any terminator).
|
269 |
+
"""
|
270 |
+
old_block = self.basic_block
|
271 |
+
term = block.terminator
|
272 |
+
if term is not None:
|
273 |
+
self.position_before(term)
|
274 |
+
else:
|
275 |
+
self.position_at_end(block)
|
276 |
+
try:
|
277 |
+
yield
|
278 |
+
finally:
|
279 |
+
self.position_at_end(old_block)
|
280 |
+
|
281 |
+
@contextlib.contextmanager
|
282 |
+
def goto_entry_block(self):
|
283 |
+
"""
|
284 |
+
A context manager which temporarily positions the builder at the
|
285 |
+
end of the function's entry block.
|
286 |
+
"""
|
287 |
+
with self.goto_block(self.function.entry_basic_block):
|
288 |
+
yield
|
289 |
+
|
290 |
+
@contextlib.contextmanager
|
291 |
+
def _branch_helper(self, bbenter, bbexit):
|
292 |
+
self.position_at_end(bbenter)
|
293 |
+
yield bbexit
|
294 |
+
if self.basic_block.terminator is None:
|
295 |
+
self.branch(bbexit)
|
296 |
+
|
297 |
+
@contextlib.contextmanager
|
298 |
+
def if_then(self, pred, likely=None):
|
299 |
+
"""
|
300 |
+
A context manager which sets up a conditional basic block based
|
301 |
+
on the given predicate (a i1 value). If the conditional block
|
302 |
+
is not explicitly terminated, a branch will be added to the next
|
303 |
+
block.
|
304 |
+
If *likely* is given, its boolean value indicates whether the
|
305 |
+
predicate is likely to be true or not, and metadata is issued
|
306 |
+
for LLVM's optimizers to account for that.
|
307 |
+
"""
|
308 |
+
bb = self.basic_block
|
309 |
+
bbif = self.append_basic_block(name=_label_suffix(bb.name, '.if'))
|
310 |
+
bbend = self.append_basic_block(name=_label_suffix(bb.name, '.endif'))
|
311 |
+
br = self.cbranch(pred, bbif, bbend)
|
312 |
+
if likely is not None:
|
313 |
+
br.set_weights([99, 1] if likely else [1, 99])
|
314 |
+
|
315 |
+
with self._branch_helper(bbif, bbend):
|
316 |
+
yield bbend
|
317 |
+
|
318 |
+
self.position_at_end(bbend)
|
319 |
+
|
320 |
+
@contextlib.contextmanager
|
321 |
+
def if_else(self, pred, likely=None):
|
322 |
+
"""
|
323 |
+
A context manager which sets up two conditional basic blocks based
|
324 |
+
on the given predicate (a i1 value).
|
325 |
+
A tuple of context managers is yield'ed. Each context manager
|
326 |
+
acts as a if_then() block.
|
327 |
+
*likely* has the same meaning as in if_then().
|
328 |
+
|
329 |
+
Typical use::
|
330 |
+
with builder.if_else(pred) as (then, otherwise):
|
331 |
+
with then:
|
332 |
+
# emit instructions for when the predicate is true
|
333 |
+
with otherwise:
|
334 |
+
# emit instructions for when the predicate is false
|
335 |
+
"""
|
336 |
+
bb = self.basic_block
|
337 |
+
bbif = self.append_basic_block(name=_label_suffix(bb.name, '.if'))
|
338 |
+
bbelse = self.append_basic_block(name=_label_suffix(bb.name, '.else'))
|
339 |
+
bbend = self.append_basic_block(name=_label_suffix(bb.name, '.endif'))
|
340 |
+
br = self.cbranch(pred, bbif, bbelse)
|
341 |
+
if likely is not None:
|
342 |
+
br.set_weights([99, 1] if likely else [1, 99])
|
343 |
+
|
344 |
+
then = self._branch_helper(bbif, bbend)
|
345 |
+
otherwise = self._branch_helper(bbelse, bbend)
|
346 |
+
|
347 |
+
yield then, otherwise
|
348 |
+
|
349 |
+
self.position_at_end(bbend)
|
350 |
+
|
351 |
+
def _insert(self, instr):
|
352 |
+
if self.debug_metadata is not None and 'dbg' not in instr.metadata:
|
353 |
+
instr.metadata['dbg'] = self.debug_metadata
|
354 |
+
self._block.instructions.insert(self._anchor, instr)
|
355 |
+
self._anchor += 1
|
356 |
+
|
357 |
+
def _set_terminator(self, term):
|
358 |
+
assert not self.block.is_terminated
|
359 |
+
self._insert(term)
|
360 |
+
self.block.terminator = term
|
361 |
+
return term
|
362 |
+
|
363 |
+
#
|
364 |
+
# Arithmetic APIs
|
365 |
+
#
|
366 |
+
|
367 |
+
@_binop('shl')
|
368 |
+
def shl(self, lhs, rhs, name=''):
|
369 |
+
"""
|
370 |
+
Left integer shift:
|
371 |
+
name = lhs << rhs
|
372 |
+
"""
|
373 |
+
|
374 |
+
@_binop('lshr')
|
375 |
+
def lshr(self, lhs, rhs, name=''):
|
376 |
+
"""
|
377 |
+
Logical (unsigned) right integer shift:
|
378 |
+
name = lhs >> rhs
|
379 |
+
"""
|
380 |
+
|
381 |
+
@_binop('ashr')
|
382 |
+
def ashr(self, lhs, rhs, name=''):
|
383 |
+
"""
|
384 |
+
Arithmetic (signed) right integer shift:
|
385 |
+
name = lhs >> rhs
|
386 |
+
"""
|
387 |
+
|
388 |
+
@_binop('add')
|
389 |
+
def add(self, lhs, rhs, name=''):
|
390 |
+
"""
|
391 |
+
Integer addition:
|
392 |
+
name = lhs + rhs
|
393 |
+
"""
|
394 |
+
|
395 |
+
@_binop('fadd')
|
396 |
+
def fadd(self, lhs, rhs, name=''):
|
397 |
+
"""
|
398 |
+
Floating-point addition:
|
399 |
+
name = lhs + rhs
|
400 |
+
"""
|
401 |
+
|
402 |
+
@_binop('sub')
|
403 |
+
def sub(self, lhs, rhs, name=''):
|
404 |
+
"""
|
405 |
+
Integer subtraction:
|
406 |
+
name = lhs - rhs
|
407 |
+
"""
|
408 |
+
|
409 |
+
@_binop('fsub')
|
410 |
+
def fsub(self, lhs, rhs, name=''):
|
411 |
+
"""
|
412 |
+
Floating-point subtraction:
|
413 |
+
name = lhs - rhs
|
414 |
+
"""
|
415 |
+
|
416 |
+
@_binop('mul')
|
417 |
+
def mul(self, lhs, rhs, name=''):
|
418 |
+
"""
|
419 |
+
Integer multiplication:
|
420 |
+
name = lhs * rhs
|
421 |
+
"""
|
422 |
+
|
423 |
+
@_binop('fmul')
|
424 |
+
def fmul(self, lhs, rhs, name=''):
|
425 |
+
"""
|
426 |
+
Floating-point multiplication:
|
427 |
+
name = lhs * rhs
|
428 |
+
"""
|
429 |
+
|
430 |
+
@_binop('udiv')
|
431 |
+
def udiv(self, lhs, rhs, name=''):
|
432 |
+
"""
|
433 |
+
Unsigned integer division:
|
434 |
+
name = lhs / rhs
|
435 |
+
"""
|
436 |
+
|
437 |
+
@_binop('sdiv')
|
438 |
+
def sdiv(self, lhs, rhs, name=''):
|
439 |
+
"""
|
440 |
+
Signed integer division:
|
441 |
+
name = lhs / rhs
|
442 |
+
"""
|
443 |
+
|
444 |
+
@_binop('fdiv')
|
445 |
+
def fdiv(self, lhs, rhs, name=''):
|
446 |
+
"""
|
447 |
+
Floating-point division:
|
448 |
+
name = lhs / rhs
|
449 |
+
"""
|
450 |
+
|
451 |
+
@_binop('urem')
|
452 |
+
def urem(self, lhs, rhs, name=''):
|
453 |
+
"""
|
454 |
+
Unsigned integer remainder:
|
455 |
+
name = lhs % rhs
|
456 |
+
"""
|
457 |
+
|
458 |
+
@_binop('srem')
|
459 |
+
def srem(self, lhs, rhs, name=''):
|
460 |
+
"""
|
461 |
+
Signed integer remainder:
|
462 |
+
name = lhs % rhs
|
463 |
+
"""
|
464 |
+
|
465 |
+
@_binop('frem')
|
466 |
+
def frem(self, lhs, rhs, name=''):
|
467 |
+
"""
|
468 |
+
Floating-point remainder:
|
469 |
+
name = lhs % rhs
|
470 |
+
"""
|
471 |
+
|
472 |
+
@_binop('or')
|
473 |
+
def or_(self, lhs, rhs, name=''):
|
474 |
+
"""
|
475 |
+
Bitwise integer OR:
|
476 |
+
name = lhs | rhs
|
477 |
+
"""
|
478 |
+
|
479 |
+
@_binop('and')
|
480 |
+
def and_(self, lhs, rhs, name=''):
|
481 |
+
"""
|
482 |
+
Bitwise integer AND:
|
483 |
+
name = lhs & rhs
|
484 |
+
"""
|
485 |
+
|
486 |
+
@_binop('xor')
|
487 |
+
def xor(self, lhs, rhs, name=''):
|
488 |
+
"""
|
489 |
+
Bitwise integer XOR:
|
490 |
+
name = lhs ^ rhs
|
491 |
+
"""
|
492 |
+
|
493 |
+
@_binop_with_overflow('sadd')
|
494 |
+
def sadd_with_overflow(self, lhs, rhs, name=''):
|
495 |
+
"""
|
496 |
+
Signed integer addition with overflow:
|
497 |
+
name = {result, overflow bit} = lhs + rhs
|
498 |
+
"""
|
499 |
+
|
500 |
+
@_binop_with_overflow('smul')
|
501 |
+
def smul_with_overflow(self, lhs, rhs, name=''):
|
502 |
+
"""
|
503 |
+
Signed integer multiplication with overflow:
|
504 |
+
name = {result, overflow bit} = lhs * rhs
|
505 |
+
"""
|
506 |
+
|
507 |
+
@_binop_with_overflow('ssub')
|
508 |
+
def ssub_with_overflow(self, lhs, rhs, name=''):
|
509 |
+
"""
|
510 |
+
Signed integer subtraction with overflow:
|
511 |
+
name = {result, overflow bit} = lhs - rhs
|
512 |
+
"""
|
513 |
+
|
514 |
+
@_binop_with_overflow('uadd')
|
515 |
+
def uadd_with_overflow(self, lhs, rhs, name=''):
|
516 |
+
"""
|
517 |
+
Unsigned integer addition with overflow:
|
518 |
+
name = {result, overflow bit} = lhs + rhs
|
519 |
+
"""
|
520 |
+
|
521 |
+
@_binop_with_overflow('umul')
|
522 |
+
def umul_with_overflow(self, lhs, rhs, name=''):
|
523 |
+
"""
|
524 |
+
Unsigned integer multiplication with overflow:
|
525 |
+
name = {result, overflow bit} = lhs * rhs
|
526 |
+
"""
|
527 |
+
|
528 |
+
@_binop_with_overflow('usub')
|
529 |
+
def usub_with_overflow(self, lhs, rhs, name=''):
|
530 |
+
"""
|
531 |
+
Unsigned integer subtraction with overflow:
|
532 |
+
name = {result, overflow bit} = lhs - rhs
|
533 |
+
"""
|
534 |
+
|
535 |
+
#
|
536 |
+
# Unary APIs
|
537 |
+
#
|
538 |
+
|
539 |
+
def not_(self, value, name=''):
|
540 |
+
"""
|
541 |
+
Bitwise integer complement:
|
542 |
+
name = ~value
|
543 |
+
"""
|
544 |
+
if isinstance(value.type, types.VectorType):
|
545 |
+
rhs = values.Constant(value.type, (-1,) * value.type.count)
|
546 |
+
else:
|
547 |
+
rhs = values.Constant(value.type, -1)
|
548 |
+
return self.xor(value, rhs, name=name)
|
549 |
+
|
550 |
+
def neg(self, value, name=''):
|
551 |
+
"""
|
552 |
+
Integer negative:
|
553 |
+
name = -value
|
554 |
+
"""
|
555 |
+
return self.sub(values.Constant(value.type, 0), value, name=name)
|
556 |
+
|
557 |
+
@_unop('fneg')
|
558 |
+
def fneg(self, arg, name='', flags=()):
|
559 |
+
"""
|
560 |
+
Floating-point negative:
|
561 |
+
name = -arg
|
562 |
+
"""
|
563 |
+
|
564 |
+
#
|
565 |
+
# Comparison APIs
|
566 |
+
#
|
567 |
+
|
568 |
+
def _icmp(self, prefix, cmpop, lhs, rhs, name):
|
569 |
+
try:
|
570 |
+
op = _CMP_MAP[cmpop]
|
571 |
+
except KeyError:
|
572 |
+
raise ValueError("invalid comparison %r for icmp" % (cmpop,))
|
573 |
+
if cmpop not in ('==', '!='):
|
574 |
+
op = prefix + op
|
575 |
+
instr = instructions.ICMPInstr(self.block, op, lhs, rhs, name=name)
|
576 |
+
self._insert(instr)
|
577 |
+
return instr
|
578 |
+
|
579 |
+
def icmp_signed(self, cmpop, lhs, rhs, name=''):
|
580 |
+
"""
|
581 |
+
Signed integer comparison:
|
582 |
+
name = lhs <cmpop> rhs
|
583 |
+
|
584 |
+
where cmpop can be '==', '!=', '<', '<=', '>', '>='
|
585 |
+
"""
|
586 |
+
return self._icmp('s', cmpop, lhs, rhs, name)
|
587 |
+
|
588 |
+
def icmp_unsigned(self, cmpop, lhs, rhs, name=''):
|
589 |
+
"""
|
590 |
+
Unsigned integer (or pointer) comparison:
|
591 |
+
name = lhs <cmpop> rhs
|
592 |
+
|
593 |
+
where cmpop can be '==', '!=', '<', '<=', '>', '>='
|
594 |
+
"""
|
595 |
+
return self._icmp('u', cmpop, lhs, rhs, name)
|
596 |
+
|
597 |
+
def fcmp_ordered(self, cmpop, lhs, rhs, name='', flags=()):
|
598 |
+
"""
|
599 |
+
Floating-point ordered comparison:
|
600 |
+
name = lhs <cmpop> rhs
|
601 |
+
|
602 |
+
where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno'
|
603 |
+
"""
|
604 |
+
if cmpop in _CMP_MAP:
|
605 |
+
op = 'o' + _CMP_MAP[cmpop]
|
606 |
+
else:
|
607 |
+
op = cmpop
|
608 |
+
instr = instructions.FCMPInstr(
|
609 |
+
self.block, op, lhs, rhs, name=name, flags=flags)
|
610 |
+
self._insert(instr)
|
611 |
+
return instr
|
612 |
+
|
613 |
+
def fcmp_unordered(self, cmpop, lhs, rhs, name='', flags=()):
|
614 |
+
"""
|
615 |
+
Floating-point unordered comparison:
|
616 |
+
name = lhs <cmpop> rhs
|
617 |
+
|
618 |
+
where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno'
|
619 |
+
"""
|
620 |
+
if cmpop in _CMP_MAP:
|
621 |
+
op = 'u' + _CMP_MAP[cmpop]
|
622 |
+
else:
|
623 |
+
op = cmpop
|
624 |
+
instr = instructions.FCMPInstr(
|
625 |
+
self.block, op, lhs, rhs, name=name, flags=flags)
|
626 |
+
self._insert(instr)
|
627 |
+
return instr
|
628 |
+
|
629 |
+
def select(self, cond, lhs, rhs, name='', flags=()):
|
630 |
+
"""
|
631 |
+
Ternary select operator:
|
632 |
+
name = cond ? lhs : rhs
|
633 |
+
"""
|
634 |
+
instr = instructions.SelectInstr(self.block, cond, lhs, rhs, name=name,
|
635 |
+
flags=flags)
|
636 |
+
self._insert(instr)
|
637 |
+
return instr
|
638 |
+
|
639 |
+
#
|
640 |
+
# Cast APIs
|
641 |
+
#
|
642 |
+
|
643 |
+
@_castop('trunc')
|
644 |
+
def trunc(self, value, typ, name=''):
|
645 |
+
"""
|
646 |
+
Truncating integer downcast to a smaller type:
|
647 |
+
name = (typ) value
|
648 |
+
"""
|
649 |
+
|
650 |
+
@_castop('zext')
|
651 |
+
def zext(self, value, typ, name=''):
|
652 |
+
"""
|
653 |
+
Zero-extending integer upcast to a larger type:
|
654 |
+
name = (typ) value
|
655 |
+
"""
|
656 |
+
|
657 |
+
@_castop('sext')
|
658 |
+
def sext(self, value, typ, name=''):
|
659 |
+
"""
|
660 |
+
Sign-extending integer upcast to a larger type:
|
661 |
+
name = (typ) value
|
662 |
+
"""
|
663 |
+
|
664 |
+
@_castop('fptrunc')
|
665 |
+
def fptrunc(self, value, typ, name=''):
|
666 |
+
"""
|
667 |
+
Floating-point downcast to a less precise type:
|
668 |
+
name = (typ) value
|
669 |
+
"""
|
670 |
+
|
671 |
+
@_castop('fpext')
|
672 |
+
def fpext(self, value, typ, name=''):
|
673 |
+
"""
|
674 |
+
Floating-point upcast to a more precise type:
|
675 |
+
name = (typ) value
|
676 |
+
"""
|
677 |
+
|
678 |
+
@_castop('bitcast')
|
679 |
+
def bitcast(self, value, typ, name=''):
|
680 |
+
"""
|
681 |
+
Pointer cast to a different pointer type:
|
682 |
+
name = (typ) value
|
683 |
+
"""
|
684 |
+
|
685 |
+
@_castop('addrspacecast')
|
686 |
+
def addrspacecast(self, value, typ, name=''):
|
687 |
+
"""
|
688 |
+
Pointer cast to a different address space:
|
689 |
+
name = (typ) value
|
690 |
+
"""
|
691 |
+
|
692 |
+
@_castop('fptoui')
|
693 |
+
def fptoui(self, value, typ, name=''):
|
694 |
+
"""
|
695 |
+
Convert floating-point to unsigned integer:
|
696 |
+
name = (typ) value
|
697 |
+
"""
|
698 |
+
|
699 |
+
@_castop('uitofp')
|
700 |
+
def uitofp(self, value, typ, name=''):
|
701 |
+
"""
|
702 |
+
Convert unsigned integer to floating-point:
|
703 |
+
name = (typ) value
|
704 |
+
"""
|
705 |
+
|
706 |
+
@_castop('fptosi')
|
707 |
+
def fptosi(self, value, typ, name=''):
|
708 |
+
"""
|
709 |
+
Convert floating-point to signed integer:
|
710 |
+
name = (typ) value
|
711 |
+
"""
|
712 |
+
|
713 |
+
@_castop('sitofp')
|
714 |
+
def sitofp(self, value, typ, name=''):
|
715 |
+
"""
|
716 |
+
Convert signed integer to floating-point:
|
717 |
+
name = (typ) value
|
718 |
+
"""
|
719 |
+
|
720 |
+
@_castop('ptrtoint')
|
721 |
+
def ptrtoint(self, value, typ, name=''):
|
722 |
+
"""
|
723 |
+
Cast pointer to integer:
|
724 |
+
name = (typ) value
|
725 |
+
"""
|
726 |
+
|
727 |
+
@_castop('inttoptr')
|
728 |
+
def inttoptr(self, value, typ, name=''):
|
729 |
+
"""
|
730 |
+
Cast integer to pointer:
|
731 |
+
name = (typ) value
|
732 |
+
"""
|
733 |
+
|
734 |
+
#
|
735 |
+
# Memory APIs
|
736 |
+
#
|
737 |
+
|
738 |
+
def alloca(self, typ, size=None, name=''):
|
739 |
+
"""
|
740 |
+
Stack-allocate a slot for *size* elements of the given type.
|
741 |
+
(default one element)
|
742 |
+
"""
|
743 |
+
if size is None:
|
744 |
+
pass
|
745 |
+
elif isinstance(size, (values.Value, values.Constant)):
|
746 |
+
assert isinstance(size.type, types.IntType)
|
747 |
+
else:
|
748 |
+
# If it is not a Value instance,
|
749 |
+
# assume to be a Python integer.
|
750 |
+
size = values.Constant(types.IntType(32), size)
|
751 |
+
|
752 |
+
al = instructions.AllocaInstr(self.block, typ, size, name)
|
753 |
+
self._insert(al)
|
754 |
+
return al
|
755 |
+
|
756 |
+
def load(self, ptr, name='', align=None):
|
757 |
+
"""
|
758 |
+
Load value from pointer, with optional guaranteed alignment:
|
759 |
+
name = *ptr
|
760 |
+
"""
|
761 |
+
if not isinstance(ptr.type, types.PointerType):
|
762 |
+
msg = "cannot load from value of type %s (%r): not a pointer"
|
763 |
+
raise TypeError(msg % (ptr.type, str(ptr)))
|
764 |
+
ld = instructions.LoadInstr(self.block, ptr, name)
|
765 |
+
ld.align = align
|
766 |
+
self._insert(ld)
|
767 |
+
return ld
|
768 |
+
|
769 |
+
def store(self, value, ptr, align=None):
|
770 |
+
"""
|
771 |
+
Store value to pointer, with optional guaranteed alignment:
|
772 |
+
*ptr = name
|
773 |
+
"""
|
774 |
+
if not isinstance(ptr.type, types.PointerType):
|
775 |
+
msg = "cannot store to value of type %s (%r): not a pointer"
|
776 |
+
raise TypeError(msg % (ptr.type, str(ptr)))
|
777 |
+
if ptr.type.pointee != value.type:
|
778 |
+
raise TypeError("cannot store %s to %s: mismatching types"
|
779 |
+
% (value.type, ptr.type))
|
780 |
+
st = instructions.StoreInstr(self.block, value, ptr)
|
781 |
+
st.align = align
|
782 |
+
self._insert(st)
|
783 |
+
return st
|
784 |
+
|
785 |
+
def load_atomic(self, ptr, ordering, align, name=''):
|
786 |
+
"""
|
787 |
+
Load value from pointer, with optional guaranteed alignment:
|
788 |
+
name = *ptr
|
789 |
+
"""
|
790 |
+
if not isinstance(ptr.type, types.PointerType):
|
791 |
+
msg = "cannot load from value of type %s (%r): not a pointer"
|
792 |
+
raise TypeError(msg % (ptr.type, str(ptr)))
|
793 |
+
ld = instructions.LoadAtomicInstr(
|
794 |
+
self.block, ptr, ordering, align, name)
|
795 |
+
self._insert(ld)
|
796 |
+
return ld
|
797 |
+
|
798 |
+
def store_atomic(self, value, ptr, ordering, align):
|
799 |
+
"""
|
800 |
+
Store value to pointer, with optional guaranteed alignment:
|
801 |
+
*ptr = name
|
802 |
+
"""
|
803 |
+
if not isinstance(ptr.type, types.PointerType):
|
804 |
+
msg = "cannot store to value of type %s (%r): not a pointer"
|
805 |
+
raise TypeError(msg % (ptr.type, str(ptr)))
|
806 |
+
if ptr.type.pointee != value.type:
|
807 |
+
raise TypeError("cannot store %s to %s: mismatching types"
|
808 |
+
% (value.type, ptr.type))
|
809 |
+
st = instructions.StoreAtomicInstr(
|
810 |
+
self.block, value, ptr, ordering, align)
|
811 |
+
self._insert(st)
|
812 |
+
return st
|
813 |
+
|
814 |
+
#
|
815 |
+
# Terminators APIs
|
816 |
+
#
|
817 |
+
|
818 |
+
def switch(self, value, default):
|
819 |
+
"""
|
820 |
+
Create a switch-case with a single *default* target.
|
821 |
+
"""
|
822 |
+
swt = instructions.SwitchInstr(self.block, 'switch', value, default)
|
823 |
+
self._set_terminator(swt)
|
824 |
+
return swt
|
825 |
+
|
826 |
+
def branch(self, target):
|
827 |
+
"""
|
828 |
+
Unconditional branch to *target*.
|
829 |
+
"""
|
830 |
+
br = instructions.Branch(self.block, "br", [target])
|
831 |
+
self._set_terminator(br)
|
832 |
+
return br
|
833 |
+
|
834 |
+
def cbranch(self, cond, truebr, falsebr):
|
835 |
+
"""
|
836 |
+
Conditional branch to *truebr* if *cond* is true, else to *falsebr*.
|
837 |
+
"""
|
838 |
+
br = instructions.ConditionalBranch(self.block, "br",
|
839 |
+
[cond, truebr, falsebr])
|
840 |
+
self._set_terminator(br)
|
841 |
+
return br
|
842 |
+
|
843 |
+
def branch_indirect(self, addr):
|
844 |
+
"""
|
845 |
+
Indirect branch to target *addr*.
|
846 |
+
"""
|
847 |
+
br = instructions.IndirectBranch(self.block, "indirectbr", addr)
|
848 |
+
self._set_terminator(br)
|
849 |
+
return br
|
850 |
+
|
851 |
+
def ret_void(self):
|
852 |
+
"""
|
853 |
+
Return from function without a value.
|
854 |
+
"""
|
855 |
+
return self._set_terminator(
|
856 |
+
instructions.Ret(self.block, "ret void"))
|
857 |
+
|
858 |
+
def ret(self, value):
|
859 |
+
"""
|
860 |
+
Return from function with the given *value*.
|
861 |
+
"""
|
862 |
+
return self._set_terminator(
|
863 |
+
instructions.Ret(self.block, "ret", value))
|
864 |
+
|
865 |
+
def resume(self, landingpad):
|
866 |
+
"""
|
867 |
+
Resume an in-flight exception.
|
868 |
+
"""
|
869 |
+
br = instructions.Branch(self.block, "resume", [landingpad])
|
870 |
+
self._set_terminator(br)
|
871 |
+
return br
|
872 |
+
|
873 |
+
# Call APIs
|
874 |
+
|
875 |
+
def call(self, fn, args, name='', cconv=None, tail=False, fastmath=(),
|
876 |
+
attrs=(), arg_attrs=None):
|
877 |
+
"""
|
878 |
+
Call function *fn* with *args*:
|
879 |
+
name = fn(args...)
|
880 |
+
"""
|
881 |
+
inst = instructions.CallInstr(self.block, fn, args, name=name,
|
882 |
+
cconv=cconv, tail=tail, fastmath=fastmath,
|
883 |
+
attrs=attrs, arg_attrs=arg_attrs)
|
884 |
+
self._insert(inst)
|
885 |
+
return inst
|
886 |
+
|
887 |
+
def asm(self, ftype, asm, constraint, args, side_effect, name=''):
|
888 |
+
"""
|
889 |
+
Inline assembler.
|
890 |
+
"""
|
891 |
+
asm = instructions.InlineAsm(ftype, asm, constraint, side_effect)
|
892 |
+
return self.call(asm, args, name)
|
893 |
+
|
894 |
+
def load_reg(self, reg_type, reg_name, name=''):
|
895 |
+
"""
|
896 |
+
Load a register value into an LLVM value.
|
897 |
+
Example: v = load_reg(IntType(32), "eax")
|
898 |
+
"""
|
899 |
+
ftype = types.FunctionType(reg_type, [])
|
900 |
+
return self.asm(ftype, "", "={%s}" % reg_name, [], False, name)
|
901 |
+
|
902 |
+
def store_reg(self, value, reg_type, reg_name, name=''):
|
903 |
+
"""
|
904 |
+
Store an LLVM value inside a register
|
905 |
+
Example:
|
906 |
+
store_reg(Constant(IntType(32), 0xAAAAAAAA), IntType(32), "eax")
|
907 |
+
"""
|
908 |
+
ftype = types.FunctionType(types.VoidType(), [reg_type])
|
909 |
+
return self.asm(ftype, "", "{%s}" % reg_name, [value], True, name)
|
910 |
+
|
911 |
+
def invoke(self, fn, args, normal_to, unwind_to,
|
912 |
+
name='', cconv=None, fastmath=(), attrs=(), arg_attrs=None):
|
913 |
+
inst = instructions.InvokeInstr(self.block, fn, args, normal_to,
|
914 |
+
unwind_to, name=name, cconv=cconv,
|
915 |
+
fastmath=fastmath, attrs=attrs,
|
916 |
+
arg_attrs=arg_attrs)
|
917 |
+
self._set_terminator(inst)
|
918 |
+
return inst
|
919 |
+
|
920 |
+
# GEP APIs
|
921 |
+
|
922 |
+
def gep(self, ptr, indices, inbounds=False, name=''):
|
923 |
+
"""
|
924 |
+
Compute effective address (getelementptr):
|
925 |
+
name = getelementptr ptr, <indices...>
|
926 |
+
"""
|
927 |
+
instr = instructions.GEPInstr(self.block, ptr, indices,
|
928 |
+
inbounds=inbounds, name=name)
|
929 |
+
self._insert(instr)
|
930 |
+
return instr
|
931 |
+
|
932 |
+
# Vector Operations APIs
|
933 |
+
|
934 |
+
def extract_element(self, vector, idx, name=''):
|
935 |
+
"""
|
936 |
+
Returns the value at position idx.
|
937 |
+
"""
|
938 |
+
instr = instructions.ExtractElement(self.block, vector, idx, name=name)
|
939 |
+
self._insert(instr)
|
940 |
+
return instr
|
941 |
+
|
942 |
+
def insert_element(self, vector, value, idx, name=''):
|
943 |
+
"""
|
944 |
+
Returns vector with vector[idx] replaced by value.
|
945 |
+
The result is undefined if the idx is larger or equal the vector length.
|
946 |
+
"""
|
947 |
+
instr = instructions.InsertElement(self.block, vector, value, idx,
|
948 |
+
name=name)
|
949 |
+
self._insert(instr)
|
950 |
+
return instr
|
951 |
+
|
952 |
+
def shuffle_vector(self, vector1, vector2, mask, name=''):
|
953 |
+
"""
|
954 |
+
Constructs a permutation of elements from *vector1* and *vector2*.
|
955 |
+
Returns a new vector in the same length of *mask*.
|
956 |
+
|
957 |
+
* *vector1* and *vector2* must have the same element type.
|
958 |
+
* *mask* must be a constant vector of integer types.
|
959 |
+
"""
|
960 |
+
instr = instructions.ShuffleVector(self.block, vector1, vector2, mask,
|
961 |
+
name=name)
|
962 |
+
self._insert(instr)
|
963 |
+
return instr
|
964 |
+
|
965 |
+
# Aggregate APIs
|
966 |
+
|
967 |
+
def extract_value(self, agg, idx, name=''):
|
968 |
+
"""
|
969 |
+
Extract member number *idx* from aggregate.
|
970 |
+
"""
|
971 |
+
if not isinstance(idx, (tuple, list)):
|
972 |
+
idx = [idx]
|
973 |
+
instr = instructions.ExtractValue(self.block, agg, idx, name=name)
|
974 |
+
self._insert(instr)
|
975 |
+
return instr
|
976 |
+
|
977 |
+
def insert_value(self, agg, value, idx, name=''):
|
978 |
+
"""
|
979 |
+
Insert *value* into member number *idx* from aggregate.
|
980 |
+
"""
|
981 |
+
if not isinstance(idx, (tuple, list)):
|
982 |
+
idx = [idx]
|
983 |
+
instr = instructions.InsertValue(self.block, agg, value, idx, name=name)
|
984 |
+
self._insert(instr)
|
985 |
+
return instr
|
986 |
+
|
987 |
+
# PHI APIs
|
988 |
+
|
989 |
+
def phi(self, typ, name='', flags=()):
|
990 |
+
inst = instructions.PhiInstr(self.block, typ, name=name, flags=flags)
|
991 |
+
self._insert(inst)
|
992 |
+
return inst
|
993 |
+
|
994 |
+
# Special API
|
995 |
+
|
996 |
+
def unreachable(self):
|
997 |
+
inst = instructions.Unreachable(self.block)
|
998 |
+
self._set_terminator(inst)
|
999 |
+
return inst
|
1000 |
+
|
1001 |
+
def atomic_rmw(self, op, ptr, val, ordering, name=''):
|
1002 |
+
inst = instructions.AtomicRMW(
|
1003 |
+
self.block, op, ptr, val, ordering, name=name)
|
1004 |
+
self._insert(inst)
|
1005 |
+
return inst
|
1006 |
+
|
1007 |
+
def cmpxchg(self, ptr, cmp, val, ordering, failordering=None, name=''):
|
1008 |
+
"""
|
1009 |
+
Atomic compared-and-set:
|
1010 |
+
atomic {
|
1011 |
+
old = *ptr
|
1012 |
+
success = (old == cmp)
|
1013 |
+
if (success)
|
1014 |
+
*ptr = val
|
1015 |
+
}
|
1016 |
+
name = { old, success }
|
1017 |
+
|
1018 |
+
If failordering is `None`, the value of `ordering` is used.
|
1019 |
+
"""
|
1020 |
+
failordering = ordering if failordering is None else failordering
|
1021 |
+
inst = instructions.CmpXchg(self.block, ptr, cmp, val, ordering,
|
1022 |
+
failordering, name=name)
|
1023 |
+
self._insert(inst)
|
1024 |
+
return inst
|
1025 |
+
|
1026 |
+
def landingpad(self, typ, name='', cleanup=False):
|
1027 |
+
inst = instructions.LandingPadInstr(self.block, typ, name, cleanup)
|
1028 |
+
self._insert(inst)
|
1029 |
+
return inst
|
1030 |
+
|
1031 |
+
def assume(self, cond):
|
1032 |
+
"""
|
1033 |
+
Optimizer hint: assume *cond* is always true.
|
1034 |
+
"""
|
1035 |
+
fn = self.module.declare_intrinsic("llvm.assume")
|
1036 |
+
return self.call(fn, [cond])
|
1037 |
+
|
1038 |
+
def fence(self, ordering, targetscope=None, name=''):
|
1039 |
+
"""
|
1040 |
+
Add a memory barrier, preventing certain reorderings of load and/or
|
1041 |
+
store accesses with
|
1042 |
+
respect to other processors and devices.
|
1043 |
+
"""
|
1044 |
+
inst = instructions.Fence(self.block, ordering, targetscope, name=name)
|
1045 |
+
self._insert(inst)
|
1046 |
+
return inst
|
1047 |
+
|
1048 |
+
def comment(self, text):
|
1049 |
+
"""
|
1050 |
+
Puts a single-line comment into the generated IR. This will be ignored
|
1051 |
+
by LLVM, but can be useful for debugging the output of a compiler. Adds
|
1052 |
+
a comment to the source file.
|
1053 |
+
|
1054 |
+
* *text* is a string that does not contain new line characters.
|
1055 |
+
"""
|
1056 |
+
inst = instructions.Comment(self.block, text)
|
1057 |
+
self._insert(inst)
|
1058 |
+
return inst
|
1059 |
+
|
1060 |
+
@_uniop_intrinsic_int("llvm.bswap")
|
1061 |
+
def bswap(self, cond):
|
1062 |
+
"""
|
1063 |
+
Used to byte swap integer values with an even number of bytes (positive
|
1064 |
+
multiple of 16 bits)
|
1065 |
+
"""
|
1066 |
+
|
1067 |
+
@_uniop_intrinsic_int("llvm.bitreverse")
|
1068 |
+
def bitreverse(self, cond):
|
1069 |
+
"""
|
1070 |
+
Reverse the bitpattern of an integer value; for example 0b10110110
|
1071 |
+
becomes 0b01101101.
|
1072 |
+
"""
|
1073 |
+
|
1074 |
+
@_uniop_intrinsic_int("llvm.ctpop")
|
1075 |
+
def ctpop(self, cond):
|
1076 |
+
"""
|
1077 |
+
Counts the number of bits set in a value.
|
1078 |
+
"""
|
1079 |
+
|
1080 |
+
@_uniop_intrinsic_with_flag("llvm.ctlz")
|
1081 |
+
def ctlz(self, cond, flag):
|
1082 |
+
"""
|
1083 |
+
Counts leading zero bits in *value*. Boolean *flag* indicates whether
|
1084 |
+
the result is defined for ``0``.
|
1085 |
+
"""
|
1086 |
+
|
1087 |
+
@_uniop_intrinsic_with_flag("llvm.cttz")
|
1088 |
+
def cttz(self, cond, flag):
|
1089 |
+
"""
|
1090 |
+
Counts trailing zero bits in *value*. Boolean *flag* indicates whether
|
1091 |
+
the result is defined for ``0``.
|
1092 |
+
"""
|
1093 |
+
|
1094 |
+
@_triop_intrinsic("llvm.fma")
|
1095 |
+
def fma(self, a, b, c):
|
1096 |
+
"""
|
1097 |
+
Perform the fused multiply-add operation.
|
1098 |
+
"""
|
1099 |
+
|
1100 |
+
def convert_from_fp16(self, a, to=None, name=''):
|
1101 |
+
"""
|
1102 |
+
Convert from an i16 to the given FP type
|
1103 |
+
"""
|
1104 |
+
if not to:
|
1105 |
+
raise TypeError("expected a float return type")
|
1106 |
+
if not isinstance(to, (types.FloatType, types.DoubleType)):
|
1107 |
+
raise TypeError("expected a float type, got %s" % to)
|
1108 |
+
if not (isinstance(a.type, types.IntType) and a.type.width == 16):
|
1109 |
+
raise TypeError("expected an i16 type, got %s" % a.type)
|
1110 |
+
|
1111 |
+
opname = 'llvm.convert.from.fp16'
|
1112 |
+
fn = self.module.declare_intrinsic(opname, [to])
|
1113 |
+
return self.call(fn, [a], name)
|
1114 |
+
|
1115 |
+
@_uniop_intrinsic_float("llvm.convert.to.fp16")
|
1116 |
+
def convert_to_fp16(self, a):
|
1117 |
+
"""
|
1118 |
+
Convert the given FP number to an i16
|
1119 |
+
"""
|
lib/python3.11/site-packages/llvmlite/ir/context.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llvmlite.ir import _utils
|
2 |
+
from llvmlite.ir import types
|
3 |
+
|
4 |
+
|
5 |
+
class Context(object):
|
6 |
+
def __init__(self):
|
7 |
+
self.scope = _utils.NameScope()
|
8 |
+
self.identified_types = {}
|
9 |
+
|
10 |
+
def get_identified_type(self, name):
|
11 |
+
if name not in self.identified_types:
|
12 |
+
self.scope.register(name)
|
13 |
+
ty = types.IdentifiedStructType(self, name)
|
14 |
+
self.identified_types[name] = ty
|
15 |
+
else:
|
16 |
+
ty = self.identified_types[name]
|
17 |
+
return ty
|
18 |
+
|
19 |
+
|
20 |
+
global_context = Context()
|
lib/python3.11/site-packages/llvmlite/ir/instructions.py
ADDED
@@ -0,0 +1,893 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Implementation of LLVM IR instructions.
|
3 |
+
"""
|
4 |
+
|
5 |
+
from llvmlite.ir import types
|
6 |
+
from llvmlite.ir.values import (Block, Function, Value, NamedValue, Constant,
|
7 |
+
MetaDataArgument, MetaDataString, AttributeSet,
|
8 |
+
Undefined, ArgumentAttributes)
|
9 |
+
from llvmlite.ir._utils import _HasMetadata
|
10 |
+
|
11 |
+
|
12 |
+
class Instruction(NamedValue, _HasMetadata):
|
13 |
+
def __init__(self, parent, typ, opname, operands, name='', flags=()):
|
14 |
+
super(Instruction, self).__init__(parent, typ, name=name)
|
15 |
+
assert isinstance(parent, Block)
|
16 |
+
assert isinstance(flags, (tuple, list))
|
17 |
+
self.opname = opname
|
18 |
+
self.operands = operands
|
19 |
+
self.flags = list(flags)
|
20 |
+
self.metadata = {}
|
21 |
+
|
22 |
+
@property
|
23 |
+
def function(self):
|
24 |
+
return self.parent.function
|
25 |
+
|
26 |
+
@property
|
27 |
+
def module(self):
|
28 |
+
return self.parent.function.module
|
29 |
+
|
30 |
+
def descr(self, buf):
|
31 |
+
opname = self.opname
|
32 |
+
if self.flags:
|
33 |
+
opname = ' '.join([opname] + self.flags)
|
34 |
+
operands = ', '.join([op.get_reference() for op in self.operands])
|
35 |
+
typ = self.type
|
36 |
+
metadata = self._stringify_metadata(leading_comma=True)
|
37 |
+
buf.append("{0} {1} {2}{3}\n"
|
38 |
+
.format(opname, typ, operands, metadata))
|
39 |
+
|
40 |
+
def replace_usage(self, old, new):
|
41 |
+
if old in self.operands:
|
42 |
+
ops = []
|
43 |
+
for op in self.operands:
|
44 |
+
ops.append(new if op is old else op)
|
45 |
+
self.operands = tuple(ops)
|
46 |
+
self._clear_string_cache()
|
47 |
+
|
48 |
+
def __repr__(self):
|
49 |
+
return "<ir.%s %r of type '%s', opname %r, operands %r>" % (
|
50 |
+
self.__class__.__name__, self.name, self.type,
|
51 |
+
self.opname, self.operands)
|
52 |
+
|
53 |
+
|
54 |
+
class CallInstrAttributes(AttributeSet):
|
55 |
+
_known = frozenset(['noreturn', 'nounwind', 'readonly', 'readnone',
|
56 |
+
'noinline', 'alwaysinline'])
|
57 |
+
|
58 |
+
|
59 |
+
TailMarkerOptions = frozenset(['tail', 'musttail', 'notail'])
|
60 |
+
|
61 |
+
|
62 |
+
class FastMathFlags(AttributeSet):
|
63 |
+
_known = frozenset(['fast', 'nnan', 'ninf', 'nsz', 'arcp', 'contract',
|
64 |
+
'afn', 'reassoc'])
|
65 |
+
|
66 |
+
|
67 |
+
class CallInstr(Instruction):
|
68 |
+
def __init__(self, parent, func, args, name='', cconv=None, tail=None,
|
69 |
+
fastmath=(), attrs=(), arg_attrs=None):
|
70 |
+
self.cconv = (func.calling_convention
|
71 |
+
if cconv is None and isinstance(func, Function)
|
72 |
+
else cconv)
|
73 |
+
|
74 |
+
# For backwards compatibility with previous API of accepting a "truthy"
|
75 |
+
# value for a hint to the optimizer to potentially tail optimize.
|
76 |
+
if isinstance(tail, str) and tail in TailMarkerOptions:
|
77 |
+
pass
|
78 |
+
elif tail:
|
79 |
+
tail = "tail"
|
80 |
+
else:
|
81 |
+
tail = ""
|
82 |
+
|
83 |
+
self.tail = tail
|
84 |
+
self.fastmath = FastMathFlags(fastmath)
|
85 |
+
self.attributes = CallInstrAttributes(attrs)
|
86 |
+
self.arg_attributes = {}
|
87 |
+
if arg_attrs:
|
88 |
+
for idx, attrs in arg_attrs.items():
|
89 |
+
if not (0 <= idx < len(args)):
|
90 |
+
raise ValueError("Invalid argument index {}"
|
91 |
+
.format(idx))
|
92 |
+
self.arg_attributes[idx] = ArgumentAttributes(attrs)
|
93 |
+
|
94 |
+
# Fix and validate arguments
|
95 |
+
args = list(args)
|
96 |
+
for i in range(len(func.function_type.args)):
|
97 |
+
arg = args[i]
|
98 |
+
expected_type = func.function_type.args[i]
|
99 |
+
if (isinstance(expected_type, types.MetaDataType) and
|
100 |
+
arg.type != expected_type):
|
101 |
+
arg = MetaDataArgument(arg)
|
102 |
+
if arg.type != expected_type:
|
103 |
+
msg = ("Type of #{0} arg mismatch: {1} != {2}"
|
104 |
+
.format(1 + i, expected_type, arg.type))
|
105 |
+
raise TypeError(msg)
|
106 |
+
args[i] = arg
|
107 |
+
|
108 |
+
super(CallInstr, self).__init__(parent, func.function_type.return_type,
|
109 |
+
"call", [func] + list(args), name=name)
|
110 |
+
|
111 |
+
@property
|
112 |
+
def callee(self):
|
113 |
+
return self.operands[0]
|
114 |
+
|
115 |
+
@callee.setter
|
116 |
+
def callee(self, newcallee):
|
117 |
+
self.operands[0] = newcallee
|
118 |
+
|
119 |
+
@property
|
120 |
+
def args(self):
|
121 |
+
return self.operands[1:]
|
122 |
+
|
123 |
+
def replace_callee(self, newfunc):
|
124 |
+
if newfunc.function_type != self.callee.function_type:
|
125 |
+
raise TypeError("New function has incompatible type")
|
126 |
+
self.callee = newfunc
|
127 |
+
|
128 |
+
@property
|
129 |
+
def called_function(self):
|
130 |
+
"""The callee function"""
|
131 |
+
return self.callee
|
132 |
+
|
133 |
+
def _descr(self, buf, add_metadata):
|
134 |
+
def descr_arg(i, a):
|
135 |
+
if i in self.arg_attributes:
|
136 |
+
attrs = ' '.join(self.arg_attributes[i]._to_list(a.type)) + ' '
|
137 |
+
else:
|
138 |
+
attrs = ''
|
139 |
+
return '{0} {1}{2}'.format(a.type, attrs, a.get_reference())
|
140 |
+
args = ', '.join([descr_arg(i, a) for i, a in enumerate(self.args)])
|
141 |
+
|
142 |
+
fnty = self.callee.function_type
|
143 |
+
# Only print function type if variable-argument
|
144 |
+
if fnty.var_arg:
|
145 |
+
ty = fnty
|
146 |
+
# Otherwise, just print the return type.
|
147 |
+
else:
|
148 |
+
# Fastmath flag work only in this case
|
149 |
+
ty = fnty.return_type
|
150 |
+
callee_ref = "{0} {1}".format(ty, self.callee.get_reference())
|
151 |
+
if self.cconv:
|
152 |
+
callee_ref = "{0} {1}".format(self.cconv, callee_ref)
|
153 |
+
|
154 |
+
tail_marker = ""
|
155 |
+
if self.tail:
|
156 |
+
tail_marker = "{0} ".format(self.tail)
|
157 |
+
|
158 |
+
fn_attrs = ' ' + ' '.join(self.attributes._to_list(fnty.return_type))\
|
159 |
+
if self.attributes else ''
|
160 |
+
|
161 |
+
fm_attrs = ' ' + ' '.join(self.fastmath._to_list(fnty.return_type))\
|
162 |
+
if self.fastmath else ''
|
163 |
+
|
164 |
+
buf.append("{tail}{op}{fastmath} {callee}({args}){attr}{meta}\n".format(
|
165 |
+
tail=tail_marker,
|
166 |
+
op=self.opname,
|
167 |
+
callee=callee_ref,
|
168 |
+
fastmath=fm_attrs,
|
169 |
+
args=args,
|
170 |
+
attr=fn_attrs,
|
171 |
+
meta=(self._stringify_metadata(leading_comma=True)
|
172 |
+
if add_metadata else ""),
|
173 |
+
))
|
174 |
+
|
175 |
+
def descr(self, buf):
|
176 |
+
self._descr(buf, add_metadata=True)
|
177 |
+
|
178 |
+
|
179 |
+
class InvokeInstr(CallInstr):
|
180 |
+
def __init__(self, parent, func, args, normal_to, unwind_to, name='',
|
181 |
+
cconv=None, fastmath=(), attrs=(), arg_attrs=None):
|
182 |
+
assert isinstance(normal_to, Block)
|
183 |
+
assert isinstance(unwind_to, Block)
|
184 |
+
super(InvokeInstr, self).__init__(parent, func, args, name, cconv,
|
185 |
+
tail=False, fastmath=fastmath,
|
186 |
+
attrs=attrs, arg_attrs=arg_attrs)
|
187 |
+
self.opname = "invoke"
|
188 |
+
self.normal_to = normal_to
|
189 |
+
self.unwind_to = unwind_to
|
190 |
+
|
191 |
+
def descr(self, buf):
|
192 |
+
super(InvokeInstr, self)._descr(buf, add_metadata=False)
|
193 |
+
buf.append(" to label {0} unwind label {1}{metadata}\n".format(
|
194 |
+
self.normal_to.get_reference(),
|
195 |
+
self.unwind_to.get_reference(),
|
196 |
+
metadata=self._stringify_metadata(leading_comma=True),
|
197 |
+
))
|
198 |
+
|
199 |
+
|
200 |
+
class Terminator(Instruction):
|
201 |
+
def __init__(self, parent, opname, operands):
|
202 |
+
super(Terminator, self).__init__(parent, types.VoidType(), opname,
|
203 |
+
operands)
|
204 |
+
|
205 |
+
def descr(self, buf):
|
206 |
+
opname = self.opname
|
207 |
+
operands = ', '.join(["{0} {1}".format(op.type, op.get_reference())
|
208 |
+
for op in self.operands])
|
209 |
+
metadata = self._stringify_metadata(leading_comma=True)
|
210 |
+
buf.append("{0} {1}{2}".format(opname, operands, metadata))
|
211 |
+
|
212 |
+
|
213 |
+
class PredictableInstr(Instruction):
|
214 |
+
|
215 |
+
def set_weights(self, weights):
|
216 |
+
operands = [MetaDataString(self.module, "branch_weights")]
|
217 |
+
for w in weights:
|
218 |
+
if w < 0:
|
219 |
+
raise ValueError("branch weight must be a positive integer")
|
220 |
+
operands.append(Constant(types.IntType(32), w))
|
221 |
+
md = self.module.add_metadata(operands)
|
222 |
+
self.set_metadata("prof", md)
|
223 |
+
|
224 |
+
|
225 |
+
class Ret(Terminator):
|
226 |
+
def __init__(self, parent, opname, return_value=None):
|
227 |
+
operands = [return_value] if return_value is not None else []
|
228 |
+
super(Ret, self).__init__(parent, opname, operands)
|
229 |
+
|
230 |
+
@property
|
231 |
+
def return_value(self):
|
232 |
+
if self.operands:
|
233 |
+
return self.operands[0]
|
234 |
+
else:
|
235 |
+
return None
|
236 |
+
|
237 |
+
def descr(self, buf):
|
238 |
+
return_value = self.return_value
|
239 |
+
metadata = self._stringify_metadata(leading_comma=True)
|
240 |
+
if return_value is not None:
|
241 |
+
buf.append("{0} {1} {2}{3}\n"
|
242 |
+
.format(self.opname, return_value.type,
|
243 |
+
return_value.get_reference(),
|
244 |
+
metadata))
|
245 |
+
else:
|
246 |
+
buf.append("{0}{1}\n".format(self.opname, metadata))
|
247 |
+
|
248 |
+
|
249 |
+
class Branch(Terminator):
|
250 |
+
pass
|
251 |
+
|
252 |
+
|
253 |
+
class ConditionalBranch(PredictableInstr, Terminator):
|
254 |
+
pass
|
255 |
+
|
256 |
+
|
257 |
+
class IndirectBranch(PredictableInstr, Terminator):
|
258 |
+
def __init__(self, parent, opname, addr):
|
259 |
+
super(IndirectBranch, self).__init__(parent, opname, [addr])
|
260 |
+
self.destinations = []
|
261 |
+
|
262 |
+
@property
|
263 |
+
def address(self):
|
264 |
+
return self.operands[0]
|
265 |
+
|
266 |
+
def add_destination(self, block):
|
267 |
+
assert isinstance(block, Block)
|
268 |
+
self.destinations.append(block)
|
269 |
+
|
270 |
+
def descr(self, buf):
|
271 |
+
destinations = ["label {0}".format(blk.get_reference())
|
272 |
+
for blk in self.destinations]
|
273 |
+
buf.append("indirectbr {0} {1}, [{2}] {3}\n".format(
|
274 |
+
self.address.type,
|
275 |
+
self.address.get_reference(),
|
276 |
+
', '.join(destinations),
|
277 |
+
self._stringify_metadata(leading_comma=True),
|
278 |
+
))
|
279 |
+
|
280 |
+
|
281 |
+
class SwitchInstr(PredictableInstr, Terminator):
|
282 |
+
|
283 |
+
def __init__(self, parent, opname, val, default):
|
284 |
+
super(SwitchInstr, self).__init__(parent, opname, [val])
|
285 |
+
self.default = default
|
286 |
+
self.cases = []
|
287 |
+
|
288 |
+
@property
|
289 |
+
def value(self):
|
290 |
+
return self.operands[0]
|
291 |
+
|
292 |
+
def add_case(self, val, block):
|
293 |
+
assert isinstance(block, Block)
|
294 |
+
if not isinstance(val, Value):
|
295 |
+
val = Constant(self.value.type, val)
|
296 |
+
self.cases.append((val, block))
|
297 |
+
|
298 |
+
def descr(self, buf):
|
299 |
+
cases = ["{0} {1}, label {2}".format(val.type, val.get_reference(),
|
300 |
+
blk.get_reference())
|
301 |
+
for val, blk in self.cases]
|
302 |
+
buf.append("switch {0} {1}, label {2} [{3}] {4}\n".format(
|
303 |
+
self.value.type,
|
304 |
+
self.value.get_reference(),
|
305 |
+
self.default.get_reference(),
|
306 |
+
' '.join(cases),
|
307 |
+
self._stringify_metadata(leading_comma=True),
|
308 |
+
))
|
309 |
+
|
310 |
+
|
311 |
+
class Resume(Terminator):
|
312 |
+
pass
|
313 |
+
|
314 |
+
|
315 |
+
class SelectInstr(Instruction):
|
316 |
+
def __init__(self, parent, cond, lhs, rhs, name='', flags=()):
|
317 |
+
assert lhs.type == rhs.type
|
318 |
+
super(SelectInstr, self).__init__(parent, lhs.type, "select",
|
319 |
+
[cond, lhs, rhs], name=name,
|
320 |
+
flags=flags)
|
321 |
+
|
322 |
+
@property
|
323 |
+
def cond(self):
|
324 |
+
return self.operands[0]
|
325 |
+
|
326 |
+
@property
|
327 |
+
def lhs(self):
|
328 |
+
return self.operands[1]
|
329 |
+
|
330 |
+
@property
|
331 |
+
def rhs(self):
|
332 |
+
return self.operands[2]
|
333 |
+
|
334 |
+
def descr(self, buf):
|
335 |
+
buf.append("select {0} {1} {2}, {3} {4}, {5} {6} {7}\n".format(
|
336 |
+
' '.join(self.flags),
|
337 |
+
self.cond.type, self.cond.get_reference(),
|
338 |
+
self.lhs.type, self.lhs.get_reference(),
|
339 |
+
self.rhs.type, self.rhs.get_reference(),
|
340 |
+
self._stringify_metadata(leading_comma=True),
|
341 |
+
))
|
342 |
+
|
343 |
+
|
344 |
+
class CompareInstr(Instruction):
|
345 |
+
# Define the following in subclasses
|
346 |
+
OPNAME = 'invalid-compare'
|
347 |
+
VALID_OP = {}
|
348 |
+
|
349 |
+
def __init__(self, parent, op, lhs, rhs, name='', flags=[]):
|
350 |
+
if op not in self.VALID_OP:
|
351 |
+
raise ValueError("invalid comparison %r for %s" % (op, self.OPNAME))
|
352 |
+
for flag in flags:
|
353 |
+
if flag not in self.VALID_FLAG:
|
354 |
+
raise ValueError("invalid flag %r for %s" % (flag, self.OPNAME))
|
355 |
+
opname = self.OPNAME
|
356 |
+
if isinstance(lhs.type, types.VectorType):
|
357 |
+
typ = types.VectorType(types.IntType(1), lhs.type.count)
|
358 |
+
else:
|
359 |
+
typ = types.IntType(1)
|
360 |
+
super(CompareInstr, self).__init__(parent, typ,
|
361 |
+
opname, [lhs, rhs], flags=flags,
|
362 |
+
name=name)
|
363 |
+
self.op = op
|
364 |
+
|
365 |
+
def descr(self, buf):
|
366 |
+
buf.append("{opname}{flags} {op} {ty} {lhs}, {rhs} {meta}\n".format(
|
367 |
+
opname=self.opname,
|
368 |
+
flags=''.join(' ' + it for it in self.flags),
|
369 |
+
op=self.op,
|
370 |
+
ty=self.operands[0].type,
|
371 |
+
lhs=self.operands[0].get_reference(),
|
372 |
+
rhs=self.operands[1].get_reference(),
|
373 |
+
meta=self._stringify_metadata(leading_comma=True),
|
374 |
+
))
|
375 |
+
|
376 |
+
|
377 |
+
class ICMPInstr(CompareInstr):
|
378 |
+
OPNAME = 'icmp'
|
379 |
+
VALID_OP = {
|
380 |
+
'eq': 'equal',
|
381 |
+
'ne': 'not equal',
|
382 |
+
'ugt': 'unsigned greater than',
|
383 |
+
'uge': 'unsigned greater or equal',
|
384 |
+
'ult': 'unsigned less than',
|
385 |
+
'ule': 'unsigned less or equal',
|
386 |
+
'sgt': 'signed greater than',
|
387 |
+
'sge': 'signed greater or equal',
|
388 |
+
'slt': 'signed less than',
|
389 |
+
'sle': 'signed less or equal',
|
390 |
+
}
|
391 |
+
VALID_FLAG = set()
|
392 |
+
|
393 |
+
|
394 |
+
class FCMPInstr(CompareInstr):
|
395 |
+
OPNAME = 'fcmp'
|
396 |
+
VALID_OP = {
|
397 |
+
'false': 'no comparison, always returns false',
|
398 |
+
'oeq': 'ordered and equal',
|
399 |
+
'ogt': 'ordered and greater than',
|
400 |
+
'oge': 'ordered and greater than or equal',
|
401 |
+
'olt': 'ordered and less than',
|
402 |
+
'ole': 'ordered and less than or equal',
|
403 |
+
'one': 'ordered and not equal',
|
404 |
+
'ord': 'ordered (no nans)',
|
405 |
+
'ueq': 'unordered or equal',
|
406 |
+
'ugt': 'unordered or greater than',
|
407 |
+
'uge': 'unordered or greater than or equal',
|
408 |
+
'ult': 'unordered or less than',
|
409 |
+
'ule': 'unordered or less than or equal',
|
410 |
+
'une': 'unordered or not equal',
|
411 |
+
'uno': 'unordered (either nans)',
|
412 |
+
'true': 'no comparison, always returns true',
|
413 |
+
}
|
414 |
+
VALID_FLAG = {'nnan', 'ninf', 'nsz', 'arcp', 'contract', 'afn', 'reassoc',
|
415 |
+
'fast'}
|
416 |
+
|
417 |
+
|
418 |
+
class CastInstr(Instruction):
|
419 |
+
def __init__(self, parent, op, val, typ, name=''):
|
420 |
+
super(CastInstr, self).__init__(parent, typ, op, [val], name=name)
|
421 |
+
|
422 |
+
def descr(self, buf):
|
423 |
+
buf.append("{0} {1} {2} to {3} {4}\n".format(
|
424 |
+
self.opname,
|
425 |
+
self.operands[0].type,
|
426 |
+
self.operands[0].get_reference(),
|
427 |
+
self.type,
|
428 |
+
self._stringify_metadata(leading_comma=True),
|
429 |
+
))
|
430 |
+
|
431 |
+
|
432 |
+
class LoadInstr(Instruction):
|
433 |
+
|
434 |
+
def __init__(self, parent, ptr, name=''):
|
435 |
+
super(LoadInstr, self).__init__(parent, ptr.type.pointee, "load",
|
436 |
+
[ptr], name=name)
|
437 |
+
self.align = None
|
438 |
+
|
439 |
+
def descr(self, buf):
|
440 |
+
[val] = self.operands
|
441 |
+
if self.align is not None:
|
442 |
+
align = ', align %d' % (self.align)
|
443 |
+
else:
|
444 |
+
align = ''
|
445 |
+
buf.append("load {0}, {1} {2}{3}{4}\n".format(
|
446 |
+
val.type.pointee,
|
447 |
+
val.type,
|
448 |
+
val.get_reference(),
|
449 |
+
align,
|
450 |
+
self._stringify_metadata(leading_comma=True),
|
451 |
+
))
|
452 |
+
|
453 |
+
|
454 |
+
class StoreInstr(Instruction):
|
455 |
+
def __init__(self, parent, val, ptr):
|
456 |
+
super(StoreInstr, self).__init__(parent, types.VoidType(), "store",
|
457 |
+
[val, ptr])
|
458 |
+
|
459 |
+
def descr(self, buf):
|
460 |
+
val, ptr = self.operands
|
461 |
+
if self.align is not None:
|
462 |
+
align = ', align %d' % (self.align)
|
463 |
+
else:
|
464 |
+
align = ''
|
465 |
+
buf.append("store {0} {1}, {2} {3}{4}{5}\n".format(
|
466 |
+
val.type,
|
467 |
+
val.get_reference(),
|
468 |
+
ptr.type,
|
469 |
+
ptr.get_reference(),
|
470 |
+
align,
|
471 |
+
self._stringify_metadata(leading_comma=True),
|
472 |
+
))
|
473 |
+
|
474 |
+
|
475 |
+
class LoadAtomicInstr(Instruction):
|
476 |
+
def __init__(self, parent, ptr, ordering, align, name=''):
|
477 |
+
super(LoadAtomicInstr, self).__init__(parent, ptr.type.pointee,
|
478 |
+
"load atomic", [ptr], name=name)
|
479 |
+
self.ordering = ordering
|
480 |
+
self.align = align
|
481 |
+
|
482 |
+
def descr(self, buf):
|
483 |
+
[val] = self.operands
|
484 |
+
buf.append("load atomic {0}, {1} {2} {3}, align {4}{5}\n".format(
|
485 |
+
val.type.pointee,
|
486 |
+
val.type,
|
487 |
+
val.get_reference(),
|
488 |
+
self.ordering,
|
489 |
+
self.align,
|
490 |
+
self._stringify_metadata(leading_comma=True),
|
491 |
+
))
|
492 |
+
|
493 |
+
|
494 |
+
class StoreAtomicInstr(Instruction):
|
495 |
+
def __init__(self, parent, val, ptr, ordering, align):
|
496 |
+
super(StoreAtomicInstr, self).__init__(parent, types.VoidType(),
|
497 |
+
"store atomic", [val, ptr])
|
498 |
+
self.ordering = ordering
|
499 |
+
self.align = align
|
500 |
+
|
501 |
+
def descr(self, buf):
|
502 |
+
val, ptr = self.operands
|
503 |
+
buf.append("store atomic {0} {1}, {2} {3} {4}, align {5}{6}\n".format(
|
504 |
+
val.type,
|
505 |
+
val.get_reference(),
|
506 |
+
ptr.type,
|
507 |
+
ptr.get_reference(),
|
508 |
+
self.ordering,
|
509 |
+
self.align,
|
510 |
+
self._stringify_metadata(leading_comma=True),
|
511 |
+
))
|
512 |
+
|
513 |
+
|
514 |
+
class AllocaInstr(Instruction):
|
515 |
+
def __init__(self, parent, typ, count, name):
|
516 |
+
operands = [count] if count else ()
|
517 |
+
super(AllocaInstr, self).__init__(parent, typ.as_pointer(), "alloca",
|
518 |
+
operands, name)
|
519 |
+
self.align = None
|
520 |
+
|
521 |
+
def descr(self, buf):
|
522 |
+
buf.append("{0} {1}".format(self.opname, self.type.pointee))
|
523 |
+
if self.operands:
|
524 |
+
op, = self.operands
|
525 |
+
buf.append(", {0} {1}".format(op.type, op.get_reference()))
|
526 |
+
if self.align is not None:
|
527 |
+
buf.append(", align {0}".format(self.align))
|
528 |
+
if self.metadata:
|
529 |
+
buf.append(self._stringify_metadata(leading_comma=True))
|
530 |
+
|
531 |
+
|
532 |
+
class GEPInstr(Instruction):
|
533 |
+
def __init__(self, parent, ptr, indices, inbounds, name):
|
534 |
+
typ = ptr.type
|
535 |
+
lasttyp = None
|
536 |
+
lastaddrspace = 0
|
537 |
+
for i in indices:
|
538 |
+
lasttyp, typ = typ, typ.gep(i)
|
539 |
+
# inherit the addrspace from the last seen pointer
|
540 |
+
if isinstance(lasttyp, types.PointerType):
|
541 |
+
lastaddrspace = lasttyp.addrspace
|
542 |
+
|
543 |
+
if (not isinstance(typ, types.PointerType) and
|
544 |
+
isinstance(lasttyp, types.PointerType)):
|
545 |
+
typ = lasttyp
|
546 |
+
else:
|
547 |
+
typ = typ.as_pointer(lastaddrspace)
|
548 |
+
|
549 |
+
super(GEPInstr, self).__init__(parent, typ, "getelementptr",
|
550 |
+
[ptr] + list(indices), name=name)
|
551 |
+
self.pointer = ptr
|
552 |
+
self.indices = indices
|
553 |
+
self.inbounds = inbounds
|
554 |
+
|
555 |
+
def descr(self, buf):
|
556 |
+
indices = ['{0} {1}'.format(i.type, i.get_reference())
|
557 |
+
for i in self.indices]
|
558 |
+
op = "getelementptr inbounds" if self.inbounds else "getelementptr"
|
559 |
+
buf.append("{0} {1}, {2} {3}, {4} {5}\n".format(
|
560 |
+
op,
|
561 |
+
self.pointer.type.pointee,
|
562 |
+
self.pointer.type,
|
563 |
+
self.pointer.get_reference(),
|
564 |
+
', '.join(indices),
|
565 |
+
self._stringify_metadata(leading_comma=True),
|
566 |
+
))
|
567 |
+
|
568 |
+
|
569 |
+
class PhiInstr(Instruction):
|
570 |
+
def __init__(self, parent, typ, name, flags=()):
|
571 |
+
super(PhiInstr, self).__init__(parent, typ, "phi", (), name=name,
|
572 |
+
flags=flags)
|
573 |
+
self.incomings = []
|
574 |
+
|
575 |
+
def descr(self, buf):
|
576 |
+
incs = ', '.join('[{0}, {1}]'.format(v.get_reference(),
|
577 |
+
b.get_reference())
|
578 |
+
for v, b in self.incomings)
|
579 |
+
buf.append("phi {0} {1} {2} {3}\n".format(
|
580 |
+
' '.join(self.flags),
|
581 |
+
self.type,
|
582 |
+
incs,
|
583 |
+
self._stringify_metadata(leading_comma=True),
|
584 |
+
))
|
585 |
+
|
586 |
+
def add_incoming(self, value, block):
|
587 |
+
assert isinstance(block, Block)
|
588 |
+
self.incomings.append((value, block))
|
589 |
+
|
590 |
+
def replace_usage(self, old, new):
|
591 |
+
self.incomings = [((new if val is old else val), blk)
|
592 |
+
for (val, blk) in self.incomings]
|
593 |
+
|
594 |
+
|
595 |
+
class ExtractElement(Instruction):
|
596 |
+
def __init__(self, parent, vector, index, name=''):
|
597 |
+
if not isinstance(vector.type, types.VectorType):
|
598 |
+
raise TypeError("vector needs to be of VectorType.")
|
599 |
+
if not isinstance(index.type, types.IntType):
|
600 |
+
raise TypeError("index needs to be of IntType.")
|
601 |
+
typ = vector.type.element
|
602 |
+
super(ExtractElement, self).__init__(parent, typ, "extractelement",
|
603 |
+
[vector, index], name=name)
|
604 |
+
|
605 |
+
def descr(self, buf):
|
606 |
+
operands = ", ".join("{0} {1}".format(
|
607 |
+
op.type, op.get_reference()) for op in self.operands)
|
608 |
+
buf.append("{opname} {operands}\n".format(
|
609 |
+
opname=self.opname, operands=operands))
|
610 |
+
|
611 |
+
|
612 |
+
class InsertElement(Instruction):
|
613 |
+
def __init__(self, parent, vector, value, index, name=''):
|
614 |
+
if not isinstance(vector.type, types.VectorType):
|
615 |
+
raise TypeError("vector needs to be of VectorType.")
|
616 |
+
if not value.type == vector.type.element:
|
617 |
+
raise TypeError(
|
618 |
+
"value needs to be of type {} not {}.".format(
|
619 |
+
vector.type.element, value.type))
|
620 |
+
if not isinstance(index.type, types.IntType):
|
621 |
+
raise TypeError("index needs to be of IntType.")
|
622 |
+
typ = vector.type
|
623 |
+
super(InsertElement, self).__init__(parent, typ, "insertelement",
|
624 |
+
[vector, value, index], name=name)
|
625 |
+
|
626 |
+
def descr(self, buf):
|
627 |
+
operands = ", ".join("{0} {1}".format(
|
628 |
+
op.type, op.get_reference()) for op in self.operands)
|
629 |
+
buf.append("{opname} {operands}\n".format(
|
630 |
+
opname=self.opname, operands=operands))
|
631 |
+
|
632 |
+
|
633 |
+
class ShuffleVector(Instruction):
|
634 |
+
def __init__(self, parent, vector1, vector2, mask, name=''):
|
635 |
+
if not isinstance(vector1.type, types.VectorType):
|
636 |
+
raise TypeError("vector1 needs to be of VectorType.")
|
637 |
+
if vector2 != Undefined:
|
638 |
+
if vector2.type != vector1.type:
|
639 |
+
raise TypeError("vector2 needs to be " +
|
640 |
+
"Undefined or of the same type as vector1.")
|
641 |
+
if (not isinstance(mask, Constant) or
|
642 |
+
not isinstance(mask.type, types.VectorType) or
|
643 |
+
not (isinstance(mask.type.element, types.IntType) and
|
644 |
+
mask.type.element.width == 32)):
|
645 |
+
raise TypeError("mask needs to be a constant i32 vector.")
|
646 |
+
typ = types.VectorType(vector1.type.element, mask.type.count)
|
647 |
+
index_range = range(vector1.type.count
|
648 |
+
if vector2 == Undefined
|
649 |
+
else 2 * vector1.type.count)
|
650 |
+
if not all(ii.constant in index_range for ii in mask.constant):
|
651 |
+
raise IndexError(
|
652 |
+
"mask values need to be in {0}".format(index_range),
|
653 |
+
)
|
654 |
+
super(ShuffleVector, self).__init__(parent, typ, "shufflevector",
|
655 |
+
[vector1, vector2, mask], name=name)
|
656 |
+
|
657 |
+
def descr(self, buf):
|
658 |
+
buf.append("shufflevector {0} {1}\n".format(
|
659 |
+
", ".join("{0} {1}".format(op.type, op.get_reference())
|
660 |
+
for op in self.operands),
|
661 |
+
self._stringify_metadata(leading_comma=True),
|
662 |
+
))
|
663 |
+
|
664 |
+
|
665 |
+
class ExtractValue(Instruction):
|
666 |
+
def __init__(self, parent, agg, indices, name=''):
|
667 |
+
typ = agg.type
|
668 |
+
try:
|
669 |
+
for i in indices:
|
670 |
+
typ = typ.elements[i]
|
671 |
+
except (AttributeError, IndexError):
|
672 |
+
raise TypeError("Can't index at %r in %s"
|
673 |
+
% (list(indices), agg.type))
|
674 |
+
|
675 |
+
super(ExtractValue, self).__init__(parent, typ, "extractvalue",
|
676 |
+
[agg], name=name)
|
677 |
+
|
678 |
+
self.aggregate = agg
|
679 |
+
self.indices = indices
|
680 |
+
|
681 |
+
def descr(self, buf):
|
682 |
+
indices = [str(i) for i in self.indices]
|
683 |
+
|
684 |
+
buf.append("extractvalue {0} {1}, {2} {3}\n".format(
|
685 |
+
self.aggregate.type,
|
686 |
+
self.aggregate.get_reference(),
|
687 |
+
', '.join(indices),
|
688 |
+
self._stringify_metadata(leading_comma=True),
|
689 |
+
))
|
690 |
+
|
691 |
+
|
692 |
+
class InsertValue(Instruction):
|
693 |
+
def __init__(self, parent, agg, elem, indices, name=''):
|
694 |
+
typ = agg.type
|
695 |
+
try:
|
696 |
+
for i in indices:
|
697 |
+
typ = typ.elements[i]
|
698 |
+
except (AttributeError, IndexError):
|
699 |
+
raise TypeError("Can't index at %r in %s"
|
700 |
+
% (list(indices), agg.type))
|
701 |
+
if elem.type != typ:
|
702 |
+
raise TypeError("Can only insert %s at %r in %s: got %s"
|
703 |
+
% (typ, list(indices), agg.type, elem.type))
|
704 |
+
super(InsertValue, self).__init__(parent, agg.type, "insertvalue",
|
705 |
+
[agg, elem], name=name)
|
706 |
+
|
707 |
+
self.aggregate = agg
|
708 |
+
self.value = elem
|
709 |
+
self.indices = indices
|
710 |
+
|
711 |
+
def descr(self, buf):
|
712 |
+
indices = [str(i) for i in self.indices]
|
713 |
+
|
714 |
+
buf.append("insertvalue {0} {1}, {2} {3}, {4} {5}\n".format(
|
715 |
+
self.aggregate.type, self.aggregate.get_reference(),
|
716 |
+
self.value.type, self.value.get_reference(),
|
717 |
+
', '.join(indices),
|
718 |
+
self._stringify_metadata(leading_comma=True),
|
719 |
+
))
|
720 |
+
|
721 |
+
|
722 |
+
class Unreachable(Instruction):
|
723 |
+
def __init__(self, parent):
|
724 |
+
super(Unreachable, self).__init__(parent, types.VoidType(),
|
725 |
+
"unreachable", (), name='')
|
726 |
+
|
727 |
+
def descr(self, buf):
|
728 |
+
buf += (self.opname, "\n")
|
729 |
+
|
730 |
+
|
731 |
+
class InlineAsm(object):
|
732 |
+
def __init__(self, ftype, asm, constraint, side_effect=False):
|
733 |
+
self.type = ftype.return_type
|
734 |
+
self.function_type = ftype
|
735 |
+
self.asm = asm
|
736 |
+
self.constraint = constraint
|
737 |
+
self.side_effect = side_effect
|
738 |
+
|
739 |
+
def descr(self, buf):
|
740 |
+
sideeffect = 'sideeffect' if self.side_effect else ''
|
741 |
+
fmt = 'asm {sideeffect} "{asm}", "{constraint}"\n'
|
742 |
+
buf.append(fmt.format(sideeffect=sideeffect, asm=self.asm,
|
743 |
+
constraint=self.constraint))
|
744 |
+
|
745 |
+
def get_reference(self):
|
746 |
+
buf = []
|
747 |
+
self.descr(buf)
|
748 |
+
return "".join(buf)
|
749 |
+
|
750 |
+
def __str__(self):
|
751 |
+
return "{0} {1}".format(self.type, self.get_reference())
|
752 |
+
|
753 |
+
|
754 |
+
class AtomicRMW(Instruction):
|
755 |
+
def __init__(self, parent, op, ptr, val, ordering, name):
|
756 |
+
super(AtomicRMW, self).__init__(parent, val.type, "atomicrmw",
|
757 |
+
(ptr, val), name=name)
|
758 |
+
self.operation = op
|
759 |
+
self.ordering = ordering
|
760 |
+
|
761 |
+
def descr(self, buf):
|
762 |
+
ptr, val = self.operands
|
763 |
+
fmt = ("atomicrmw {op} {ptrty} {ptr}, {valty} {val} {ordering} "
|
764 |
+
"{metadata}\n")
|
765 |
+
buf.append(fmt.format(op=self.operation,
|
766 |
+
ptrty=ptr.type,
|
767 |
+
ptr=ptr.get_reference(),
|
768 |
+
valty=val.type,
|
769 |
+
val=val.get_reference(),
|
770 |
+
ordering=self.ordering,
|
771 |
+
metadata=self._stringify_metadata(
|
772 |
+
leading_comma=True),
|
773 |
+
))
|
774 |
+
|
775 |
+
|
776 |
+
class CmpXchg(Instruction):
|
777 |
+
"""This instruction has changed since llvm3.5. It is not compatible with
|
778 |
+
older llvm versions.
|
779 |
+
"""
|
780 |
+
|
781 |
+
def __init__(self, parent, ptr, cmp, val, ordering, failordering, name):
|
782 |
+
outtype = types.LiteralStructType([val.type, types.IntType(1)])
|
783 |
+
super(CmpXchg, self).__init__(parent, outtype, "cmpxchg",
|
784 |
+
(ptr, cmp, val), name=name)
|
785 |
+
self.ordering = ordering
|
786 |
+
self.failordering = failordering
|
787 |
+
|
788 |
+
def descr(self, buf):
|
789 |
+
ptr, cmpval, val = self.operands
|
790 |
+
fmt = "cmpxchg {ptrty} {ptr}, {ty} {cmp}, {ty} {val} {ordering} " \
|
791 |
+
"{failordering} {metadata}\n"
|
792 |
+
buf.append(fmt.format(ptrty=ptr.type,
|
793 |
+
ptr=ptr.get_reference(),
|
794 |
+
ty=cmpval.type,
|
795 |
+
cmp=cmpval.get_reference(),
|
796 |
+
val=val.get_reference(),
|
797 |
+
ordering=self.ordering,
|
798 |
+
failordering=self.failordering,
|
799 |
+
metadata=self._stringify_metadata(
|
800 |
+
leading_comma=True),
|
801 |
+
))
|
802 |
+
|
803 |
+
|
804 |
+
class _LandingPadClause(object):
|
805 |
+
def __init__(self, value):
|
806 |
+
self.value = value
|
807 |
+
|
808 |
+
def __str__(self):
|
809 |
+
return "{kind} {type} {value}".format(
|
810 |
+
kind=self.kind,
|
811 |
+
type=self.value.type,
|
812 |
+
value=self.value.get_reference())
|
813 |
+
|
814 |
+
|
815 |
+
class CatchClause(_LandingPadClause):
|
816 |
+
kind = 'catch'
|
817 |
+
|
818 |
+
|
819 |
+
class FilterClause(_LandingPadClause):
|
820 |
+
kind = 'filter'
|
821 |
+
|
822 |
+
def __init__(self, value):
|
823 |
+
assert isinstance(value, Constant)
|
824 |
+
assert isinstance(value.type, types.ArrayType)
|
825 |
+
super(FilterClause, self).__init__(value)
|
826 |
+
|
827 |
+
|
828 |
+
class LandingPadInstr(Instruction):
|
829 |
+
def __init__(self, parent, typ, name='', cleanup=False):
|
830 |
+
super(LandingPadInstr, self).__init__(parent, typ, "landingpad", [],
|
831 |
+
name=name)
|
832 |
+
self.cleanup = cleanup
|
833 |
+
self.clauses = []
|
834 |
+
|
835 |
+
def add_clause(self, clause):
|
836 |
+
assert isinstance(clause, _LandingPadClause)
|
837 |
+
self.clauses.append(clause)
|
838 |
+
|
839 |
+
def descr(self, buf):
|
840 |
+
fmt = "landingpad {type}{cleanup}{clauses}\n"
|
841 |
+
buf.append(fmt.format(type=self.type,
|
842 |
+
cleanup=' cleanup' if self.cleanup else '',
|
843 |
+
clauses=''.join(["\n {0}".format(clause)
|
844 |
+
for clause in self.clauses]),
|
845 |
+
))
|
846 |
+
|
847 |
+
|
848 |
+
class Fence(Instruction):
|
849 |
+
"""
|
850 |
+
The `fence` instruction.
|
851 |
+
|
852 |
+
As of LLVM 5.0.1:
|
853 |
+
|
854 |
+
fence [syncscope("<target-scope>")] <ordering> ; yields void
|
855 |
+
"""
|
856 |
+
|
857 |
+
VALID_FENCE_ORDERINGS = {"acquire", "release", "acq_rel", "seq_cst"}
|
858 |
+
|
859 |
+
def __init__(self, parent, ordering, targetscope=None, name=''):
|
860 |
+
super(Fence, self).__init__(parent, types.VoidType(), "fence", (),
|
861 |
+
name=name)
|
862 |
+
if ordering not in self.VALID_FENCE_ORDERINGS:
|
863 |
+
msg = "Invalid fence ordering \"{0}\"! Should be one of {1}."
|
864 |
+
raise ValueError(msg .format(ordering,
|
865 |
+
", ".join(self.VALID_FENCE_ORDERINGS)))
|
866 |
+
self.ordering = ordering
|
867 |
+
self.targetscope = targetscope
|
868 |
+
|
869 |
+
def descr(self, buf):
|
870 |
+
if self.targetscope is None:
|
871 |
+
syncscope = ""
|
872 |
+
else:
|
873 |
+
syncscope = 'syncscope("{0}") '.format(self.targetscope)
|
874 |
+
|
875 |
+
fmt = "fence {syncscope}{ordering}\n"
|
876 |
+
buf.append(fmt.format(syncscope=syncscope,
|
877 |
+
ordering=self.ordering,
|
878 |
+
))
|
879 |
+
|
880 |
+
|
881 |
+
class Comment(Instruction):
|
882 |
+
"""
|
883 |
+
A line comment.
|
884 |
+
"""
|
885 |
+
|
886 |
+
def __init__(self, parent, text):
|
887 |
+
super(Comment, self).__init__(parent, types.VoidType(), ";", (),
|
888 |
+
name='')
|
889 |
+
assert "\n" not in text, "Comment cannot contain new line"
|
890 |
+
self.text = text
|
891 |
+
|
892 |
+
def descr(self, buf):
|
893 |
+
buf.append(f"; {self.text}")
|
lib/python3.11/site-packages/llvmlite/ir/module.py
ADDED
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import collections
|
2 |
+
|
3 |
+
from llvmlite.ir import context, values, types, _utils
|
4 |
+
|
5 |
+
|
6 |
+
class Module(object):
|
7 |
+
def __init__(self, name='', context=context.global_context):
|
8 |
+
self.context = context
|
9 |
+
self.name = name # name is for debugging/informational
|
10 |
+
self.data_layout = ""
|
11 |
+
self.scope = _utils.NameScope()
|
12 |
+
self.triple = 'unknown-unknown-unknown'
|
13 |
+
self.globals = collections.OrderedDict()
|
14 |
+
# Innamed metadata nodes.
|
15 |
+
self.metadata = []
|
16 |
+
# Named metadata nodes
|
17 |
+
self.namedmetadata = {}
|
18 |
+
# Cache for metadata node deduplication
|
19 |
+
self._metadatacache = {}
|
20 |
+
|
21 |
+
def _fix_metadata_operands(self, operands):
|
22 |
+
fixed_ops = []
|
23 |
+
for op in operands:
|
24 |
+
if op is None:
|
25 |
+
# A literal None creates a null metadata value
|
26 |
+
op = types.MetaDataType()(None)
|
27 |
+
elif isinstance(op, str):
|
28 |
+
# A literal string creates a metadata string value
|
29 |
+
op = values.MetaDataString(self, op)
|
30 |
+
elif isinstance(op, (list, tuple)):
|
31 |
+
# A sequence creates a metadata node reference
|
32 |
+
op = self.add_metadata(op)
|
33 |
+
fixed_ops.append(op)
|
34 |
+
return fixed_ops
|
35 |
+
|
36 |
+
def _fix_di_operands(self, operands):
|
37 |
+
fixed_ops = []
|
38 |
+
for name, op in operands:
|
39 |
+
if isinstance(op, (list, tuple)):
|
40 |
+
# A sequence creates a metadata node reference
|
41 |
+
op = self.add_metadata(op)
|
42 |
+
fixed_ops.append((name, op))
|
43 |
+
return fixed_ops
|
44 |
+
|
45 |
+
def add_metadata(self, operands):
|
46 |
+
"""
|
47 |
+
Add an unnamed metadata to the module with the given *operands*
|
48 |
+
(a sequence of values) or return a previous equivalent metadata.
|
49 |
+
A MDValue instance is returned, it can then be associated to
|
50 |
+
e.g. an instruction.
|
51 |
+
"""
|
52 |
+
if not isinstance(operands, (list, tuple)):
|
53 |
+
raise TypeError("expected a list or tuple of metadata values, "
|
54 |
+
"got %r" % (operands,))
|
55 |
+
operands = self._fix_metadata_operands(operands)
|
56 |
+
key = tuple(operands)
|
57 |
+
if key not in self._metadatacache:
|
58 |
+
n = len(self.metadata)
|
59 |
+
md = values.MDValue(self, operands, name=str(n))
|
60 |
+
self._metadatacache[key] = md
|
61 |
+
else:
|
62 |
+
md = self._metadatacache[key]
|
63 |
+
return md
|
64 |
+
|
65 |
+
def add_debug_info(self, kind, operands, is_distinct=False):
|
66 |
+
"""
|
67 |
+
Add debug information metadata to the module with the given
|
68 |
+
*operands* (a dict of values with string keys) or return
|
69 |
+
a previous equivalent metadata. *kind* is a string of the
|
70 |
+
debug information kind (e.g. "DICompileUnit").
|
71 |
+
|
72 |
+
A DIValue instance is returned, it can then be associated to e.g.
|
73 |
+
an instruction.
|
74 |
+
"""
|
75 |
+
operands = tuple(sorted(self._fix_di_operands(operands.items())))
|
76 |
+
key = (kind, operands, is_distinct)
|
77 |
+
if key not in self._metadatacache:
|
78 |
+
n = len(self.metadata)
|
79 |
+
di = values.DIValue(self, is_distinct, kind, operands, name=str(n))
|
80 |
+
self._metadatacache[key] = di
|
81 |
+
else:
|
82 |
+
di = self._metadatacache[key]
|
83 |
+
return di
|
84 |
+
|
85 |
+
def add_named_metadata(self, name, element=None):
|
86 |
+
"""
|
87 |
+
Add a named metadata node to the module, if it doesn't exist,
|
88 |
+
or return the existing node.
|
89 |
+
If *element* is given, it will append a new element to
|
90 |
+
the named metadata node. If *element* is a sequence of values
|
91 |
+
(rather than a metadata value), a new unnamed node will first be
|
92 |
+
created.
|
93 |
+
|
94 |
+
Example::
|
95 |
+
module.add_named_metadata("llvm.ident", ["llvmlite/1.0"])
|
96 |
+
"""
|
97 |
+
if name in self.namedmetadata:
|
98 |
+
nmd = self.namedmetadata[name]
|
99 |
+
else:
|
100 |
+
nmd = self.namedmetadata[name] = values.NamedMetaData(self)
|
101 |
+
if element is not None:
|
102 |
+
if not isinstance(element, values.Value):
|
103 |
+
element = self.add_metadata(element)
|
104 |
+
if not isinstance(element.type, types.MetaDataType):
|
105 |
+
raise TypeError("wrong type for metadata element: got %r"
|
106 |
+
% (element,))
|
107 |
+
nmd.add(element)
|
108 |
+
return nmd
|
109 |
+
|
110 |
+
def get_named_metadata(self, name):
|
111 |
+
"""
|
112 |
+
Return the metadata node with the given *name*. KeyError is raised
|
113 |
+
if no such node exists (contrast with add_named_metadata()).
|
114 |
+
"""
|
115 |
+
return self.namedmetadata[name]
|
116 |
+
|
117 |
+
@property
|
118 |
+
def functions(self):
|
119 |
+
"""
|
120 |
+
A list of functions declared or defined in this module.
|
121 |
+
"""
|
122 |
+
return [v for v in self.globals.values()
|
123 |
+
if isinstance(v, values.Function)]
|
124 |
+
|
125 |
+
@property
|
126 |
+
def global_values(self):
|
127 |
+
"""
|
128 |
+
An iterable of global values in this module.
|
129 |
+
"""
|
130 |
+
return self.globals.values()
|
131 |
+
|
132 |
+
def get_global(self, name):
|
133 |
+
"""
|
134 |
+
Get a global value by name.
|
135 |
+
"""
|
136 |
+
return self.globals[name]
|
137 |
+
|
138 |
+
def add_global(self, globalvalue):
|
139 |
+
"""
|
140 |
+
Add a new global value.
|
141 |
+
"""
|
142 |
+
assert globalvalue.name not in self.globals
|
143 |
+
self.globals[globalvalue.name] = globalvalue
|
144 |
+
|
145 |
+
def get_unique_name(self, name=''):
|
146 |
+
"""
|
147 |
+
Get a unique global name with the following *name* hint.
|
148 |
+
"""
|
149 |
+
return self.scope.deduplicate(name)
|
150 |
+
|
151 |
+
def declare_intrinsic(self, intrinsic, tys=(), fnty=None):
|
152 |
+
def _error():
|
153 |
+
raise NotImplementedError("unknown intrinsic %r with %d types"
|
154 |
+
% (intrinsic, len(tys)))
|
155 |
+
|
156 |
+
if intrinsic in {'llvm.cttz', 'llvm.ctlz', 'llvm.fma'}:
|
157 |
+
suffixes = [tys[0].intrinsic_name]
|
158 |
+
else:
|
159 |
+
suffixes = [t.intrinsic_name for t in tys]
|
160 |
+
name = '.'.join([intrinsic] + suffixes)
|
161 |
+
if name in self.globals:
|
162 |
+
return self.globals[name]
|
163 |
+
|
164 |
+
if fnty is not None:
|
165 |
+
# General case: function type is given
|
166 |
+
pass
|
167 |
+
# Compute function type if omitted for common cases
|
168 |
+
elif len(tys) == 0 and intrinsic == 'llvm.assume':
|
169 |
+
fnty = types.FunctionType(types.VoidType(), [types.IntType(1)])
|
170 |
+
elif len(tys) == 1:
|
171 |
+
if intrinsic == 'llvm.powi':
|
172 |
+
fnty = types.FunctionType(tys[0], [tys[0], types.IntType(32)])
|
173 |
+
elif intrinsic == 'llvm.pow':
|
174 |
+
fnty = types.FunctionType(tys[0], tys * 2)
|
175 |
+
elif intrinsic == 'llvm.convert.from.fp16':
|
176 |
+
fnty = types.FunctionType(tys[0], [types.IntType(16)])
|
177 |
+
elif intrinsic == 'llvm.convert.to.fp16':
|
178 |
+
fnty = types.FunctionType(types.IntType(16), tys)
|
179 |
+
else:
|
180 |
+
fnty = types.FunctionType(tys[0], tys)
|
181 |
+
elif len(tys) == 2:
|
182 |
+
if intrinsic == 'llvm.memset':
|
183 |
+
tys = [tys[0], types.IntType(8), tys[1],
|
184 |
+
types.IntType(1)]
|
185 |
+
fnty = types.FunctionType(types.VoidType(), tys)
|
186 |
+
elif intrinsic in {'llvm.cttz', 'llvm.ctlz'}:
|
187 |
+
tys = [tys[0], types.IntType(1)]
|
188 |
+
fnty = types.FunctionType(tys[0], tys)
|
189 |
+
else:
|
190 |
+
_error()
|
191 |
+
elif len(tys) == 3:
|
192 |
+
if intrinsic in ('llvm.memcpy', 'llvm.memmove'):
|
193 |
+
tys = tys + [types.IntType(1)]
|
194 |
+
fnty = types.FunctionType(types.VoidType(), tys)
|
195 |
+
elif intrinsic == 'llvm.fma':
|
196 |
+
tys = [tys[0]] * 3
|
197 |
+
fnty = types.FunctionType(tys[0], tys)
|
198 |
+
else:
|
199 |
+
_error()
|
200 |
+
else:
|
201 |
+
_error()
|
202 |
+
return values.Function(self, fnty, name=name)
|
203 |
+
|
204 |
+
def get_identified_types(self):
|
205 |
+
return self.context.identified_types
|
206 |
+
|
207 |
+
def _get_body_lines(self):
|
208 |
+
# Type declarations
|
209 |
+
lines = [it.get_declaration()
|
210 |
+
for it in self.get_identified_types().values()]
|
211 |
+
# Global values (including function definitions)
|
212 |
+
lines += [str(v) for v in self.globals.values()]
|
213 |
+
return lines
|
214 |
+
|
215 |
+
def _get_metadata_lines(self):
|
216 |
+
mdbuf = []
|
217 |
+
for k, v in self.namedmetadata.items():
|
218 |
+
mdbuf.append("!{name} = !{{ {operands} }}".format(
|
219 |
+
name=k, operands=', '.join(i.get_reference()
|
220 |
+
for i in v.operands)))
|
221 |
+
for md in self.metadata:
|
222 |
+
mdbuf.append(str(md))
|
223 |
+
return mdbuf
|
224 |
+
|
225 |
+
def _stringify_body(self):
|
226 |
+
# For testing
|
227 |
+
return "\n".join(self._get_body_lines())
|
228 |
+
|
229 |
+
def _stringify_metadata(self):
|
230 |
+
# For testing
|
231 |
+
return "\n".join(self._get_metadata_lines())
|
232 |
+
|
233 |
+
def __repr__(self):
|
234 |
+
lines = []
|
235 |
+
# Header
|
236 |
+
lines += [
|
237 |
+
'; ModuleID = "%s"' % (self.name,),
|
238 |
+
'target triple = "%s"' % (self.triple,),
|
239 |
+
'target datalayout = "%s"' % (self.data_layout,),
|
240 |
+
'']
|
241 |
+
# Body
|
242 |
+
lines += self._get_body_lines()
|
243 |
+
# Metadata
|
244 |
+
lines += self._get_metadata_lines()
|
245 |
+
|
246 |
+
return "\n".join(lines)
|
lib/python3.11/site-packages/llvmlite/ir/transforms.py
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llvmlite.ir import CallInstr
|
2 |
+
|
3 |
+
|
4 |
+
class Visitor(object):
|
5 |
+
def visit(self, module):
|
6 |
+
self._module = module
|
7 |
+
for func in module.functions:
|
8 |
+
self.visit_Function(func)
|
9 |
+
|
10 |
+
def visit_Function(self, func):
|
11 |
+
self._function = func
|
12 |
+
for bb in func.blocks:
|
13 |
+
self.visit_BasicBlock(bb)
|
14 |
+
|
15 |
+
def visit_BasicBlock(self, bb):
|
16 |
+
self._basic_block = bb
|
17 |
+
for instr in bb.instructions:
|
18 |
+
self.visit_Instruction(instr)
|
19 |
+
|
20 |
+
def visit_Instruction(self, instr):
|
21 |
+
raise NotImplementedError
|
22 |
+
|
23 |
+
@property
|
24 |
+
def module(self):
|
25 |
+
return self._module
|
26 |
+
|
27 |
+
@property
|
28 |
+
def function(self):
|
29 |
+
return self._function
|
30 |
+
|
31 |
+
@property
|
32 |
+
def basic_block(self):
|
33 |
+
return self._basic_block
|
34 |
+
|
35 |
+
|
36 |
+
class CallVisitor(Visitor):
|
37 |
+
def visit_Instruction(self, instr):
|
38 |
+
if isinstance(instr, CallInstr):
|
39 |
+
self.visit_Call(instr)
|
40 |
+
|
41 |
+
def visit_Call(self, instr):
|
42 |
+
raise NotImplementedError
|
43 |
+
|
44 |
+
|
45 |
+
class ReplaceCalls(CallVisitor):
|
46 |
+
def __init__(self, orig, repl):
|
47 |
+
super(ReplaceCalls, self).__init__()
|
48 |
+
self.orig = orig
|
49 |
+
self.repl = repl
|
50 |
+
self.calls = []
|
51 |
+
|
52 |
+
def visit_Call(self, instr):
|
53 |
+
if instr.callee == self.orig:
|
54 |
+
instr.replace_callee(self.repl)
|
55 |
+
self.calls.append(instr)
|
56 |
+
|
57 |
+
|
58 |
+
def replace_all_calls(mod, orig, repl):
|
59 |
+
"""Replace all calls to `orig` to `repl` in module `mod`.
|
60 |
+
Returns the references to the returned calls
|
61 |
+
"""
|
62 |
+
rc = ReplaceCalls(orig, repl)
|
63 |
+
rc.visit(mod)
|
64 |
+
return rc.calls
|
lib/python3.11/site-packages/llvmlite/ir/types.py
ADDED
@@ -0,0 +1,614 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Classes that are LLVM types
|
3 |
+
"""
|
4 |
+
|
5 |
+
import struct
|
6 |
+
|
7 |
+
from llvmlite.ir._utils import _StrCaching
|
8 |
+
|
9 |
+
|
10 |
+
def _wrapname(x):
|
11 |
+
return '"{0}"'.format(x.replace('\\', '\\5c').replace('"', '\\22'))
|
12 |
+
|
13 |
+
|
14 |
+
class Type(_StrCaching):
|
15 |
+
"""
|
16 |
+
The base class for all LLVM types.
|
17 |
+
"""
|
18 |
+
is_pointer = False
|
19 |
+
null = 'zeroinitializer'
|
20 |
+
|
21 |
+
def __repr__(self):
|
22 |
+
return "<%s %s>" % (type(self), str(self))
|
23 |
+
|
24 |
+
def _to_string(self):
|
25 |
+
raise NotImplementedError
|
26 |
+
|
27 |
+
def as_pointer(self, addrspace=0):
|
28 |
+
return PointerType(self, addrspace)
|
29 |
+
|
30 |
+
def __ne__(self, other):
|
31 |
+
return not (self == other)
|
32 |
+
|
33 |
+
def _get_ll_pointer_type(self, target_data, context=None):
|
34 |
+
"""
|
35 |
+
Convert this type object to an LLVM type.
|
36 |
+
"""
|
37 |
+
from llvmlite.ir import Module, GlobalVariable
|
38 |
+
from llvmlite.binding import parse_assembly
|
39 |
+
|
40 |
+
if context is None:
|
41 |
+
m = Module()
|
42 |
+
else:
|
43 |
+
m = Module(context=context)
|
44 |
+
foo = GlobalVariable(m, self, name="foo")
|
45 |
+
with parse_assembly(str(m)) as llmod:
|
46 |
+
return llmod.get_global_variable(foo.name).type
|
47 |
+
|
48 |
+
def get_abi_size(self, target_data, context=None):
|
49 |
+
"""
|
50 |
+
Get the ABI size of this type according to data layout *target_data*.
|
51 |
+
"""
|
52 |
+
llty = self._get_ll_pointer_type(target_data, context)
|
53 |
+
return target_data.get_pointee_abi_size(llty)
|
54 |
+
|
55 |
+
def get_abi_alignment(self, target_data, context=None):
|
56 |
+
"""
|
57 |
+
Get the minimum ABI alignment of this type according to data layout
|
58 |
+
*target_data*.
|
59 |
+
"""
|
60 |
+
llty = self._get_ll_pointer_type(target_data, context)
|
61 |
+
return target_data.get_pointee_abi_alignment(llty)
|
62 |
+
|
63 |
+
def format_constant(self, value):
|
64 |
+
"""
|
65 |
+
Format constant *value* of this type. This method may be overriden
|
66 |
+
by subclasses.
|
67 |
+
"""
|
68 |
+
return str(value)
|
69 |
+
|
70 |
+
def wrap_constant_value(self, value):
|
71 |
+
"""
|
72 |
+
Wrap constant *value* if necessary. This method may be overriden
|
73 |
+
by subclasses (especially aggregate types).
|
74 |
+
"""
|
75 |
+
return value
|
76 |
+
|
77 |
+
def __call__(self, value):
|
78 |
+
"""
|
79 |
+
Create a LLVM constant of this type with the given Python value.
|
80 |
+
"""
|
81 |
+
from llvmlite.ir import Constant
|
82 |
+
return Constant(self, value)
|
83 |
+
|
84 |
+
|
85 |
+
class MetaDataType(Type):
|
86 |
+
|
87 |
+
def _to_string(self):
|
88 |
+
return "metadata"
|
89 |
+
|
90 |
+
def as_pointer(self):
|
91 |
+
raise TypeError
|
92 |
+
|
93 |
+
def __eq__(self, other):
|
94 |
+
return isinstance(other, MetaDataType)
|
95 |
+
|
96 |
+
def __hash__(self):
|
97 |
+
return hash(MetaDataType)
|
98 |
+
|
99 |
+
|
100 |
+
class LabelType(Type):
|
101 |
+
"""
|
102 |
+
The label type is the type of e.g. basic blocks.
|
103 |
+
"""
|
104 |
+
|
105 |
+
def _to_string(self):
|
106 |
+
return "label"
|
107 |
+
|
108 |
+
|
109 |
+
class PointerType(Type):
|
110 |
+
"""
|
111 |
+
The type of all pointer values.
|
112 |
+
"""
|
113 |
+
is_pointer = True
|
114 |
+
null = 'null'
|
115 |
+
|
116 |
+
def __init__(self, pointee, addrspace=0):
|
117 |
+
assert not isinstance(pointee, VoidType)
|
118 |
+
self.pointee = pointee
|
119 |
+
self.addrspace = addrspace
|
120 |
+
|
121 |
+
def _to_string(self):
|
122 |
+
if self.addrspace != 0:
|
123 |
+
return "{0} addrspace({1})*".format(self.pointee, self.addrspace)
|
124 |
+
else:
|
125 |
+
return "{0}*".format(self.pointee)
|
126 |
+
|
127 |
+
def __eq__(self, other):
|
128 |
+
if isinstance(other, PointerType):
|
129 |
+
return (self.pointee, self.addrspace) == (other.pointee,
|
130 |
+
other.addrspace)
|
131 |
+
else:
|
132 |
+
return False
|
133 |
+
|
134 |
+
def __hash__(self):
|
135 |
+
return hash(PointerType)
|
136 |
+
|
137 |
+
def gep(self, i):
|
138 |
+
"""
|
139 |
+
Resolve the type of the i-th element (for getelementptr lookups).
|
140 |
+
"""
|
141 |
+
if not isinstance(i.type, IntType):
|
142 |
+
raise TypeError(i.type)
|
143 |
+
return self.pointee
|
144 |
+
|
145 |
+
@property
|
146 |
+
def intrinsic_name(self):
|
147 |
+
return 'p%d%s' % (self.addrspace, self.pointee.intrinsic_name)
|
148 |
+
|
149 |
+
|
150 |
+
class VoidType(Type):
|
151 |
+
"""
|
152 |
+
The type for empty values (e.g. a function returning no value).
|
153 |
+
"""
|
154 |
+
|
155 |
+
def _to_string(self):
|
156 |
+
return 'void'
|
157 |
+
|
158 |
+
def __eq__(self, other):
|
159 |
+
return isinstance(other, VoidType)
|
160 |
+
|
161 |
+
def __hash__(self):
|
162 |
+
return hash(VoidType)
|
163 |
+
|
164 |
+
|
165 |
+
class FunctionType(Type):
|
166 |
+
"""
|
167 |
+
The type for functions.
|
168 |
+
"""
|
169 |
+
|
170 |
+
def __init__(self, return_type, args, var_arg=False):
|
171 |
+
self.return_type = return_type
|
172 |
+
self.args = tuple(args)
|
173 |
+
self.var_arg = var_arg
|
174 |
+
|
175 |
+
def _to_string(self):
|
176 |
+
if self.args:
|
177 |
+
strargs = ', '.join([str(a) for a in self.args])
|
178 |
+
if self.var_arg:
|
179 |
+
return '{0} ({1}, ...)'.format(self.return_type, strargs)
|
180 |
+
else:
|
181 |
+
return '{0} ({1})'.format(self.return_type, strargs)
|
182 |
+
elif self.var_arg:
|
183 |
+
return '{0} (...)'.format(self.return_type)
|
184 |
+
else:
|
185 |
+
return '{0} ()'.format(self.return_type)
|
186 |
+
|
187 |
+
def __eq__(self, other):
|
188 |
+
if isinstance(other, FunctionType):
|
189 |
+
return (self.return_type == other.return_type and
|
190 |
+
self.args == other.args and self.var_arg == other.var_arg)
|
191 |
+
else:
|
192 |
+
return False
|
193 |
+
|
194 |
+
def __hash__(self):
|
195 |
+
return hash(FunctionType)
|
196 |
+
|
197 |
+
|
198 |
+
class IntType(Type):
|
199 |
+
"""
|
200 |
+
The type for integers.
|
201 |
+
"""
|
202 |
+
null = '0'
|
203 |
+
_instance_cache = {}
|
204 |
+
width: int
|
205 |
+
|
206 |
+
def __new__(cls, bits):
|
207 |
+
# Cache all common integer types
|
208 |
+
if 0 <= bits <= 128:
|
209 |
+
try:
|
210 |
+
return cls._instance_cache[bits]
|
211 |
+
except KeyError:
|
212 |
+
inst = cls._instance_cache[bits] = cls.__new(bits)
|
213 |
+
return inst
|
214 |
+
return cls.__new(bits)
|
215 |
+
|
216 |
+
@classmethod
|
217 |
+
def __new(cls, bits):
|
218 |
+
assert isinstance(bits, int) and bits >= 0
|
219 |
+
self = super(IntType, cls).__new__(cls)
|
220 |
+
self.width = bits
|
221 |
+
return self
|
222 |
+
|
223 |
+
def __getnewargs__(self):
|
224 |
+
return self.width,
|
225 |
+
|
226 |
+
def __copy__(self):
|
227 |
+
return self
|
228 |
+
|
229 |
+
def _to_string(self):
|
230 |
+
return 'i%u' % (self.width,)
|
231 |
+
|
232 |
+
def __eq__(self, other):
|
233 |
+
if isinstance(other, IntType):
|
234 |
+
return self.width == other.width
|
235 |
+
else:
|
236 |
+
return False
|
237 |
+
|
238 |
+
def __hash__(self):
|
239 |
+
return hash(IntType)
|
240 |
+
|
241 |
+
def format_constant(self, val):
|
242 |
+
if isinstance(val, bool):
|
243 |
+
return str(val).lower()
|
244 |
+
else:
|
245 |
+
return str(val)
|
246 |
+
|
247 |
+
def wrap_constant_value(self, val):
|
248 |
+
if val is None:
|
249 |
+
return 0
|
250 |
+
return val
|
251 |
+
|
252 |
+
@property
|
253 |
+
def intrinsic_name(self):
|
254 |
+
return str(self)
|
255 |
+
|
256 |
+
|
257 |
+
def _as_float(value):
|
258 |
+
"""
|
259 |
+
Truncate to single-precision float.
|
260 |
+
"""
|
261 |
+
return struct.unpack('f', struct.pack('f', value))[0]
|
262 |
+
|
263 |
+
|
264 |
+
def _as_half(value):
|
265 |
+
"""
|
266 |
+
Truncate to half-precision float.
|
267 |
+
"""
|
268 |
+
try:
|
269 |
+
return struct.unpack('e', struct.pack('e', value))[0]
|
270 |
+
except struct.error:
|
271 |
+
# 'e' only added in Python 3.6+
|
272 |
+
return _as_float(value)
|
273 |
+
|
274 |
+
|
275 |
+
def _format_float_as_hex(value, packfmt, unpackfmt, numdigits):
|
276 |
+
raw = struct.pack(packfmt, float(value))
|
277 |
+
intrep = struct.unpack(unpackfmt, raw)[0]
|
278 |
+
out = '{{0:#{0}x}}'.format(numdigits).format(intrep)
|
279 |
+
return out
|
280 |
+
|
281 |
+
|
282 |
+
def _format_double(value):
|
283 |
+
"""
|
284 |
+
Format *value* as a hexadecimal string of its IEEE double precision
|
285 |
+
representation.
|
286 |
+
"""
|
287 |
+
return _format_float_as_hex(value, 'd', 'Q', 16)
|
288 |
+
|
289 |
+
|
290 |
+
class _BaseFloatType(Type):
|
291 |
+
|
292 |
+
def __new__(cls):
|
293 |
+
return cls._instance_cache
|
294 |
+
|
295 |
+
def __eq__(self, other):
|
296 |
+
return isinstance(other, type(self))
|
297 |
+
|
298 |
+
def __hash__(self):
|
299 |
+
return hash(type(self))
|
300 |
+
|
301 |
+
@classmethod
|
302 |
+
def _create_instance(cls):
|
303 |
+
cls._instance_cache = super(_BaseFloatType, cls).__new__(cls)
|
304 |
+
|
305 |
+
|
306 |
+
class HalfType(_BaseFloatType):
|
307 |
+
"""
|
308 |
+
The type for single-precision floats.
|
309 |
+
"""
|
310 |
+
null = '0.0'
|
311 |
+
intrinsic_name = 'f16'
|
312 |
+
|
313 |
+
def __str__(self):
|
314 |
+
return 'half'
|
315 |
+
|
316 |
+
def format_constant(self, value):
|
317 |
+
return _format_double(_as_half(value))
|
318 |
+
|
319 |
+
|
320 |
+
class FloatType(_BaseFloatType):
|
321 |
+
"""
|
322 |
+
The type for single-precision floats.
|
323 |
+
"""
|
324 |
+
null = '0.0'
|
325 |
+
intrinsic_name = 'f32'
|
326 |
+
|
327 |
+
def __str__(self):
|
328 |
+
return 'float'
|
329 |
+
|
330 |
+
def format_constant(self, value):
|
331 |
+
return _format_double(_as_float(value))
|
332 |
+
|
333 |
+
|
334 |
+
class DoubleType(_BaseFloatType):
|
335 |
+
"""
|
336 |
+
The type for double-precision floats.
|
337 |
+
"""
|
338 |
+
null = '0.0'
|
339 |
+
intrinsic_name = 'f64'
|
340 |
+
|
341 |
+
def __str__(self):
|
342 |
+
return 'double'
|
343 |
+
|
344 |
+
def format_constant(self, value):
|
345 |
+
return _format_double(value)
|
346 |
+
|
347 |
+
|
348 |
+
for _cls in (HalfType, FloatType, DoubleType):
|
349 |
+
_cls._create_instance()
|
350 |
+
|
351 |
+
|
352 |
+
class _Repeat(object):
|
353 |
+
def __init__(self, value, size):
|
354 |
+
self.value = value
|
355 |
+
self.size = size
|
356 |
+
|
357 |
+
def __len__(self):
|
358 |
+
return self.size
|
359 |
+
|
360 |
+
def __getitem__(self, item):
|
361 |
+
if 0 <= item < self.size:
|
362 |
+
return self.value
|
363 |
+
else:
|
364 |
+
raise IndexError(item)
|
365 |
+
|
366 |
+
|
367 |
+
class VectorType(Type):
|
368 |
+
"""
|
369 |
+
The type for vectors of primitive data items (e.g. "<f32 x 4>").
|
370 |
+
"""
|
371 |
+
|
372 |
+
def __init__(self, element, count):
|
373 |
+
self.element = element
|
374 |
+
self.count = count
|
375 |
+
|
376 |
+
@property
|
377 |
+
def elements(self):
|
378 |
+
return _Repeat(self.element, self.count)
|
379 |
+
|
380 |
+
def __len__(self):
|
381 |
+
return self.count
|
382 |
+
|
383 |
+
def _to_string(self):
|
384 |
+
return "<%d x %s>" % (self.count, self.element)
|
385 |
+
|
386 |
+
def __eq__(self, other):
|
387 |
+
if isinstance(other, VectorType):
|
388 |
+
return self.element == other.element and self.count == other.count
|
389 |
+
|
390 |
+
def __hash__(self):
|
391 |
+
# TODO: why does this not take self.element/self.count into account?
|
392 |
+
return hash(VectorType)
|
393 |
+
|
394 |
+
def __copy__(self):
|
395 |
+
return self
|
396 |
+
|
397 |
+
def format_constant(self, value):
|
398 |
+
itemstring = ", " .join(["{0} {1}".format(x.type, x.get_reference())
|
399 |
+
for x in value])
|
400 |
+
return "<{0}>".format(itemstring)
|
401 |
+
|
402 |
+
def wrap_constant_value(self, values):
|
403 |
+
from . import Value, Constant
|
404 |
+
if not isinstance(values, (list, tuple)):
|
405 |
+
if isinstance(values, Constant):
|
406 |
+
if values.type != self.element:
|
407 |
+
raise TypeError("expected {} for {}".format(
|
408 |
+
self.element, values.type))
|
409 |
+
return (values, ) * self.count
|
410 |
+
return (Constant(self.element, values), ) * self.count
|
411 |
+
if len(values) != len(self):
|
412 |
+
raise ValueError("wrong constant size for %s: got %d elements"
|
413 |
+
% (self, len(values)))
|
414 |
+
return [Constant(ty, val) if not isinstance(val, Value) else val
|
415 |
+
for ty, val in zip(self.elements, values)]
|
416 |
+
|
417 |
+
|
418 |
+
class Aggregate(Type):
|
419 |
+
"""
|
420 |
+
Base class for aggregate types.
|
421 |
+
See http://llvm.org/docs/LangRef.html#t-aggregate
|
422 |
+
"""
|
423 |
+
|
424 |
+
def wrap_constant_value(self, values):
|
425 |
+
from . import Value, Constant
|
426 |
+
|
427 |
+
if not isinstance(values, (list, tuple)):
|
428 |
+
return values
|
429 |
+
if len(values) != len(self):
|
430 |
+
raise ValueError("wrong constant size for %s: got %d elements"
|
431 |
+
% (self, len(values)))
|
432 |
+
return [Constant(ty, val) if not isinstance(val, Value) else val
|
433 |
+
for ty, val in zip(self.elements, values)]
|
434 |
+
|
435 |
+
|
436 |
+
class ArrayType(Aggregate):
|
437 |
+
"""
|
438 |
+
The type for fixed-size homogenous arrays (e.g. "[f32 x 3]").
|
439 |
+
"""
|
440 |
+
|
441 |
+
def __init__(self, element, count):
|
442 |
+
self.element = element
|
443 |
+
self.count = count
|
444 |
+
|
445 |
+
@property
|
446 |
+
def elements(self):
|
447 |
+
return _Repeat(self.element, self.count)
|
448 |
+
|
449 |
+
def __len__(self):
|
450 |
+
return self.count
|
451 |
+
|
452 |
+
def _to_string(self):
|
453 |
+
return "[%d x %s]" % (self.count, self.element)
|
454 |
+
|
455 |
+
def __eq__(self, other):
|
456 |
+
if isinstance(other, ArrayType):
|
457 |
+
return self.element == other.element and self.count == other.count
|
458 |
+
|
459 |
+
def __hash__(self):
|
460 |
+
return hash(ArrayType)
|
461 |
+
|
462 |
+
def gep(self, i):
|
463 |
+
"""
|
464 |
+
Resolve the type of the i-th element (for getelementptr lookups).
|
465 |
+
"""
|
466 |
+
if not isinstance(i.type, IntType):
|
467 |
+
raise TypeError(i.type)
|
468 |
+
return self.element
|
469 |
+
|
470 |
+
def format_constant(self, value):
|
471 |
+
itemstring = ", " .join(["{0} {1}".format(x.type, x.get_reference())
|
472 |
+
for x in value])
|
473 |
+
return "[{0}]".format(itemstring)
|
474 |
+
|
475 |
+
|
476 |
+
class BaseStructType(Aggregate):
|
477 |
+
"""
|
478 |
+
The base type for heterogenous struct types.
|
479 |
+
"""
|
480 |
+
_packed = False
|
481 |
+
|
482 |
+
@property
|
483 |
+
def packed(self):
|
484 |
+
"""
|
485 |
+
A boolean attribute that indicates whether the structure uses
|
486 |
+
packed layout.
|
487 |
+
"""
|
488 |
+
return self._packed
|
489 |
+
|
490 |
+
@packed.setter
|
491 |
+
def packed(self, val):
|
492 |
+
self._packed = bool(val)
|
493 |
+
|
494 |
+
def __len__(self):
|
495 |
+
assert self.elements is not None
|
496 |
+
return len(self.elements)
|
497 |
+
|
498 |
+
def __iter__(self):
|
499 |
+
assert self.elements is not None
|
500 |
+
return iter(self.elements)
|
501 |
+
|
502 |
+
@property
|
503 |
+
def is_opaque(self):
|
504 |
+
return self.elements is None
|
505 |
+
|
506 |
+
def structure_repr(self):
|
507 |
+
"""
|
508 |
+
Return the LLVM IR for the structure representation
|
509 |
+
"""
|
510 |
+
ret = '{%s}' % ', '.join([str(x) for x in self.elements])
|
511 |
+
return self._wrap_packed(ret)
|
512 |
+
|
513 |
+
def format_constant(self, value):
|
514 |
+
itemstring = ", " .join(["{0} {1}".format(x.type, x.get_reference())
|
515 |
+
for x in value])
|
516 |
+
ret = "{{{0}}}".format(itemstring)
|
517 |
+
return self._wrap_packed(ret)
|
518 |
+
|
519 |
+
def gep(self, i):
|
520 |
+
"""
|
521 |
+
Resolve the type of the i-th element (for getelementptr lookups).
|
522 |
+
|
523 |
+
*i* needs to be a LLVM constant, so that the type can be determined
|
524 |
+
at compile-time.
|
525 |
+
"""
|
526 |
+
if not isinstance(i.type, IntType):
|
527 |
+
raise TypeError(i.type)
|
528 |
+
return self.elements[i.constant]
|
529 |
+
|
530 |
+
def _wrap_packed(self, textrepr):
|
531 |
+
"""
|
532 |
+
Internal helper to wrap textual repr of struct type into packed struct
|
533 |
+
"""
|
534 |
+
if self.packed:
|
535 |
+
return '<{}>'.format(textrepr)
|
536 |
+
else:
|
537 |
+
return textrepr
|
538 |
+
|
539 |
+
|
540 |
+
class LiteralStructType(BaseStructType):
|
541 |
+
"""
|
542 |
+
The type of "literal" structs, i.e. structs with a literally-defined
|
543 |
+
type (by contrast with IdentifiedStructType).
|
544 |
+
"""
|
545 |
+
|
546 |
+
null = 'zeroinitializer'
|
547 |
+
|
548 |
+
def __init__(self, elems, packed=False):
|
549 |
+
"""
|
550 |
+
*elems* is a sequence of types to be used as members.
|
551 |
+
*packed* controls the use of packed layout.
|
552 |
+
"""
|
553 |
+
self.elements = tuple(elems)
|
554 |
+
self.packed = packed
|
555 |
+
|
556 |
+
def _to_string(self):
|
557 |
+
return self.structure_repr()
|
558 |
+
|
559 |
+
def __eq__(self, other):
|
560 |
+
if isinstance(other, LiteralStructType):
|
561 |
+
return self.elements == other.elements
|
562 |
+
|
563 |
+
def __hash__(self):
|
564 |
+
return hash(LiteralStructType)
|
565 |
+
|
566 |
+
|
567 |
+
class IdentifiedStructType(BaseStructType):
|
568 |
+
"""
|
569 |
+
A type which is a named alias for another struct type, akin to a typedef.
|
570 |
+
While literal struct types can be structurally equal (see
|
571 |
+
LiteralStructType), identified struct types are compared by name.
|
572 |
+
|
573 |
+
Do not use this directly.
|
574 |
+
"""
|
575 |
+
null = 'zeroinitializer'
|
576 |
+
|
577 |
+
def __init__(self, context, name, packed=False):
|
578 |
+
"""
|
579 |
+
*context* is a llvmlite.ir.Context.
|
580 |
+
*name* is the identifier for the new struct type.
|
581 |
+
*packed* controls the use of packed layout.
|
582 |
+
"""
|
583 |
+
assert name
|
584 |
+
self.context = context
|
585 |
+
self.name = name
|
586 |
+
self.elements = None
|
587 |
+
self.packed = packed
|
588 |
+
|
589 |
+
def _to_string(self):
|
590 |
+
return "%{name}".format(name=_wrapname(self.name))
|
591 |
+
|
592 |
+
def get_declaration(self):
|
593 |
+
"""
|
594 |
+
Returns the string for the declaration of the type
|
595 |
+
"""
|
596 |
+
if self.is_opaque:
|
597 |
+
out = "{strrep} = type opaque".format(strrep=str(self))
|
598 |
+
else:
|
599 |
+
out = "{strrep} = type {struct}".format(
|
600 |
+
strrep=str(self), struct=self.structure_repr())
|
601 |
+
return out
|
602 |
+
|
603 |
+
def __eq__(self, other):
|
604 |
+
if isinstance(other, IdentifiedStructType):
|
605 |
+
return self.name == other.name
|
606 |
+
|
607 |
+
def __hash__(self):
|
608 |
+
return hash(IdentifiedStructType)
|
609 |
+
|
610 |
+
def set_body(self, *elems):
|
611 |
+
if not self.is_opaque:
|
612 |
+
raise RuntimeError("{name} is already defined".format(
|
613 |
+
name=self.name))
|
614 |
+
self.elements = tuple(elems)
|
lib/python3.11/site-packages/llvmlite/ir/values.py
ADDED
@@ -0,0 +1,1217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Classes that are LLVM values: Value, Constant...
|
3 |
+
Instructions are in the instructions module.
|
4 |
+
"""
|
5 |
+
|
6 |
+
import functools
|
7 |
+
import string
|
8 |
+
import re
|
9 |
+
from types import MappingProxyType
|
10 |
+
|
11 |
+
from llvmlite.ir import values, types, _utils
|
12 |
+
from llvmlite.ir._utils import (_StrCaching, _StringReferenceCaching,
|
13 |
+
_HasMetadata)
|
14 |
+
|
15 |
+
_VALID_CHARS = (frozenset(map(ord, string.ascii_letters)) |
|
16 |
+
frozenset(map(ord, string.digits)) |
|
17 |
+
frozenset(map(ord, ' !#$%&\'()*+,-./:;<=>?@[]^_`{|}~')))
|
18 |
+
|
19 |
+
_SIMPLE_IDENTIFIER_RE = re.compile(r"[-a-zA-Z$._][-a-zA-Z$._0-9]*$")
|
20 |
+
|
21 |
+
_CMP_MAP = {
|
22 |
+
'>': 'gt',
|
23 |
+
'<': 'lt',
|
24 |
+
'==': 'eq',
|
25 |
+
'!=': 'ne',
|
26 |
+
'>=': 'ge',
|
27 |
+
'<=': 'le',
|
28 |
+
}
|
29 |
+
|
30 |
+
|
31 |
+
def _escape_string(text, _map={}):
|
32 |
+
"""
|
33 |
+
Escape the given bytestring for safe use as a LLVM array constant.
|
34 |
+
Any unicode string input is first encoded with utf8 into bytes.
|
35 |
+
"""
|
36 |
+
if isinstance(text, str):
|
37 |
+
text = text.encode()
|
38 |
+
assert isinstance(text, (bytes, bytearray))
|
39 |
+
|
40 |
+
if not _map:
|
41 |
+
for ch in range(256):
|
42 |
+
if ch in _VALID_CHARS:
|
43 |
+
_map[ch] = chr(ch)
|
44 |
+
else:
|
45 |
+
_map[ch] = '\\%02x' % ch
|
46 |
+
|
47 |
+
buf = [_map[ch] for ch in text]
|
48 |
+
return ''.join(buf)
|
49 |
+
|
50 |
+
|
51 |
+
def _binop(opname):
|
52 |
+
def wrap(fn):
|
53 |
+
@functools.wraps(fn)
|
54 |
+
def wrapped(lhs, rhs):
|
55 |
+
if lhs.type != rhs.type:
|
56 |
+
raise ValueError("Operands must be the same type, got (%s, %s)"
|
57 |
+
% (lhs.type, rhs.type))
|
58 |
+
|
59 |
+
fmt = "{0} ({1} {2}, {3} {4})".format(opname,
|
60 |
+
lhs.type, lhs.get_reference(),
|
61 |
+
rhs.type, rhs.get_reference())
|
62 |
+
return FormattedConstant(lhs.type, fmt)
|
63 |
+
|
64 |
+
return wrapped
|
65 |
+
return wrap
|
66 |
+
|
67 |
+
|
68 |
+
def _castop(opname):
|
69 |
+
def wrap(fn):
|
70 |
+
@functools.wraps(fn)
|
71 |
+
def wrapped(self, typ):
|
72 |
+
fn(self, typ)
|
73 |
+
if typ == self.type:
|
74 |
+
return self
|
75 |
+
|
76 |
+
op = "{0} ({1} {2} to {3})".format(opname, self.type,
|
77 |
+
self.get_reference(), typ)
|
78 |
+
return FormattedConstant(typ, op)
|
79 |
+
|
80 |
+
return wrapped
|
81 |
+
return wrap
|
82 |
+
|
83 |
+
|
84 |
+
class _ConstOpMixin(object):
|
85 |
+
"""
|
86 |
+
A mixin defining constant operations, for use in constant-like classes.
|
87 |
+
"""
|
88 |
+
|
89 |
+
#
|
90 |
+
# Arithmetic APIs
|
91 |
+
#
|
92 |
+
|
93 |
+
@_binop('shl')
|
94 |
+
def shl(self, other):
|
95 |
+
"""
|
96 |
+
Left integer shift:
|
97 |
+
lhs << rhs
|
98 |
+
"""
|
99 |
+
|
100 |
+
@_binop('lshr')
|
101 |
+
def lshr(self, other):
|
102 |
+
"""
|
103 |
+
Logical (unsigned) right integer shift:
|
104 |
+
lhs >> rhs
|
105 |
+
"""
|
106 |
+
|
107 |
+
@_binop('ashr')
|
108 |
+
def ashr(self, other):
|
109 |
+
"""
|
110 |
+
Arithmetic (signed) right integer shift:
|
111 |
+
lhs >> rhs
|
112 |
+
"""
|
113 |
+
|
114 |
+
@_binop('add')
|
115 |
+
def add(self, other):
|
116 |
+
"""
|
117 |
+
Integer addition:
|
118 |
+
lhs + rhs
|
119 |
+
"""
|
120 |
+
|
121 |
+
@_binop('fadd')
|
122 |
+
def fadd(self, other):
|
123 |
+
"""
|
124 |
+
Floating-point addition:
|
125 |
+
lhs + rhs
|
126 |
+
"""
|
127 |
+
|
128 |
+
@_binop('sub')
|
129 |
+
def sub(self, other):
|
130 |
+
"""
|
131 |
+
Integer subtraction:
|
132 |
+
lhs - rhs
|
133 |
+
"""
|
134 |
+
|
135 |
+
@_binop('fsub')
|
136 |
+
def fsub(self, other):
|
137 |
+
"""
|
138 |
+
Floating-point subtraction:
|
139 |
+
lhs - rhs
|
140 |
+
"""
|
141 |
+
|
142 |
+
@_binop('mul')
|
143 |
+
def mul(self, other):
|
144 |
+
"""
|
145 |
+
Integer multiplication:
|
146 |
+
lhs * rhs
|
147 |
+
"""
|
148 |
+
|
149 |
+
@_binop('fmul')
|
150 |
+
def fmul(self, other):
|
151 |
+
"""
|
152 |
+
Floating-point multiplication:
|
153 |
+
lhs * rhs
|
154 |
+
"""
|
155 |
+
|
156 |
+
@_binop('udiv')
|
157 |
+
def udiv(self, other):
|
158 |
+
"""
|
159 |
+
Unsigned integer division:
|
160 |
+
lhs / rhs
|
161 |
+
"""
|
162 |
+
|
163 |
+
@_binop('sdiv')
|
164 |
+
def sdiv(self, other):
|
165 |
+
"""
|
166 |
+
Signed integer division:
|
167 |
+
lhs / rhs
|
168 |
+
"""
|
169 |
+
|
170 |
+
@_binop('fdiv')
|
171 |
+
def fdiv(self, other):
|
172 |
+
"""
|
173 |
+
Floating-point division:
|
174 |
+
lhs / rhs
|
175 |
+
"""
|
176 |
+
|
177 |
+
@_binop('urem')
|
178 |
+
def urem(self, other):
|
179 |
+
"""
|
180 |
+
Unsigned integer remainder:
|
181 |
+
lhs % rhs
|
182 |
+
"""
|
183 |
+
|
184 |
+
@_binop('srem')
|
185 |
+
def srem(self, other):
|
186 |
+
"""
|
187 |
+
Signed integer remainder:
|
188 |
+
lhs % rhs
|
189 |
+
"""
|
190 |
+
|
191 |
+
@_binop('frem')
|
192 |
+
def frem(self, other):
|
193 |
+
"""
|
194 |
+
Floating-point remainder:
|
195 |
+
lhs % rhs
|
196 |
+
"""
|
197 |
+
|
198 |
+
@_binop('or')
|
199 |
+
def or_(self, other):
|
200 |
+
"""
|
201 |
+
Bitwise integer OR:
|
202 |
+
lhs | rhs
|
203 |
+
"""
|
204 |
+
|
205 |
+
@_binop('and')
|
206 |
+
def and_(self, other):
|
207 |
+
"""
|
208 |
+
Bitwise integer AND:
|
209 |
+
lhs & rhs
|
210 |
+
"""
|
211 |
+
|
212 |
+
@_binop('xor')
|
213 |
+
def xor(self, other):
|
214 |
+
"""
|
215 |
+
Bitwise integer XOR:
|
216 |
+
lhs ^ rhs
|
217 |
+
"""
|
218 |
+
|
219 |
+
def _cmp(self, prefix, sign, cmpop, other):
|
220 |
+
ins = prefix + 'cmp'
|
221 |
+
try:
|
222 |
+
op = _CMP_MAP[cmpop]
|
223 |
+
except KeyError:
|
224 |
+
raise ValueError("invalid comparison %r for %s" % (cmpop, ins))
|
225 |
+
|
226 |
+
if not (prefix == 'i' and cmpop in ('==', '!=')):
|
227 |
+
op = sign + op
|
228 |
+
|
229 |
+
if self.type != other.type:
|
230 |
+
raise ValueError("Operands must be the same type, got (%s, %s)"
|
231 |
+
% (self.type, other.type))
|
232 |
+
|
233 |
+
fmt = "{0} {1} ({2} {3}, {4} {5})".format(
|
234 |
+
ins, op,
|
235 |
+
self.type, self.get_reference(),
|
236 |
+
other.type, other.get_reference())
|
237 |
+
|
238 |
+
return FormattedConstant(types.IntType(1), fmt)
|
239 |
+
|
240 |
+
def icmp_signed(self, cmpop, other):
|
241 |
+
"""
|
242 |
+
Signed integer comparison:
|
243 |
+
lhs <cmpop> rhs
|
244 |
+
|
245 |
+
where cmpop can be '==', '!=', '<', '<=', '>', '>='
|
246 |
+
"""
|
247 |
+
return self._cmp('i', 's', cmpop, other)
|
248 |
+
|
249 |
+
def icmp_unsigned(self, cmpop, other):
|
250 |
+
"""
|
251 |
+
Unsigned integer (or pointer) comparison:
|
252 |
+
lhs <cmpop> rhs
|
253 |
+
|
254 |
+
where cmpop can be '==', '!=', '<', '<=', '>', '>='
|
255 |
+
"""
|
256 |
+
return self._cmp('i', 'u', cmpop, other)
|
257 |
+
|
258 |
+
def fcmp_ordered(self, cmpop, other):
|
259 |
+
"""
|
260 |
+
Floating-point ordered comparison:
|
261 |
+
lhs <cmpop> rhs
|
262 |
+
|
263 |
+
where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno'
|
264 |
+
"""
|
265 |
+
return self._cmp('f', 'o', cmpop, other)
|
266 |
+
|
267 |
+
def fcmp_unordered(self, cmpop, other):
|
268 |
+
"""
|
269 |
+
Floating-point unordered comparison:
|
270 |
+
lhs <cmpop> rhs
|
271 |
+
|
272 |
+
where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno'
|
273 |
+
"""
|
274 |
+
return self._cmp('f', 'u', cmpop, other)
|
275 |
+
|
276 |
+
#
|
277 |
+
# Unary APIs
|
278 |
+
#
|
279 |
+
|
280 |
+
def not_(self):
|
281 |
+
"""
|
282 |
+
Bitwise integer complement:
|
283 |
+
~value
|
284 |
+
"""
|
285 |
+
if isinstance(self.type, types.VectorType):
|
286 |
+
rhs = values.Constant(self.type, (-1,) * self.type.count)
|
287 |
+
else:
|
288 |
+
rhs = values.Constant(self.type, -1)
|
289 |
+
|
290 |
+
return self.xor(rhs)
|
291 |
+
|
292 |
+
def neg(self):
|
293 |
+
"""
|
294 |
+
Integer negative:
|
295 |
+
-value
|
296 |
+
"""
|
297 |
+
zero = values.Constant(self.type, 0)
|
298 |
+
return zero.sub(self)
|
299 |
+
|
300 |
+
def fneg(self):
|
301 |
+
"""
|
302 |
+
Floating-point negative:
|
303 |
+
-value
|
304 |
+
"""
|
305 |
+
fmt = "fneg ({0} {1})".format(self.type, self.get_reference())
|
306 |
+
return FormattedConstant(self.type, fmt)
|
307 |
+
|
308 |
+
#
|
309 |
+
# Cast APIs
|
310 |
+
#
|
311 |
+
|
312 |
+
@_castop('trunc')
|
313 |
+
def trunc(self, typ):
|
314 |
+
"""
|
315 |
+
Truncating integer downcast to a smaller type.
|
316 |
+
"""
|
317 |
+
|
318 |
+
@_castop('zext')
|
319 |
+
def zext(self, typ):
|
320 |
+
"""
|
321 |
+
Zero-extending integer upcast to a larger type
|
322 |
+
"""
|
323 |
+
|
324 |
+
@_castop('sext')
|
325 |
+
def sext(self, typ):
|
326 |
+
"""
|
327 |
+
Sign-extending integer upcast to a larger type.
|
328 |
+
"""
|
329 |
+
|
330 |
+
@_castop('fptrunc')
|
331 |
+
def fptrunc(self, typ):
|
332 |
+
"""
|
333 |
+
Floating-point downcast to a less precise type.
|
334 |
+
"""
|
335 |
+
|
336 |
+
@_castop('fpext')
|
337 |
+
def fpext(self, typ):
|
338 |
+
"""
|
339 |
+
Floating-point upcast to a more precise type.
|
340 |
+
"""
|
341 |
+
|
342 |
+
@_castop('bitcast')
|
343 |
+
def bitcast(self, typ):
|
344 |
+
"""
|
345 |
+
Pointer cast to a different pointer type.
|
346 |
+
"""
|
347 |
+
|
348 |
+
@_castop('fptoui')
|
349 |
+
def fptoui(self, typ):
|
350 |
+
"""
|
351 |
+
Convert floating-point to unsigned integer.
|
352 |
+
"""
|
353 |
+
|
354 |
+
@_castop('uitofp')
|
355 |
+
def uitofp(self, typ):
|
356 |
+
"""
|
357 |
+
Convert unsigned integer to floating-point.
|
358 |
+
"""
|
359 |
+
|
360 |
+
@_castop('fptosi')
|
361 |
+
def fptosi(self, typ):
|
362 |
+
"""
|
363 |
+
Convert floating-point to signed integer.
|
364 |
+
"""
|
365 |
+
|
366 |
+
@_castop('sitofp')
|
367 |
+
def sitofp(self, typ):
|
368 |
+
"""
|
369 |
+
Convert signed integer to floating-point.
|
370 |
+
"""
|
371 |
+
|
372 |
+
@_castop('ptrtoint')
|
373 |
+
def ptrtoint(self, typ):
|
374 |
+
"""
|
375 |
+
Cast pointer to integer.
|
376 |
+
"""
|
377 |
+
if not isinstance(self.type, types.PointerType):
|
378 |
+
msg = "can only call ptrtoint() on pointer type, not '%s'"
|
379 |
+
raise TypeError(msg % (self.type,))
|
380 |
+
if not isinstance(typ, types.IntType):
|
381 |
+
raise TypeError("can only ptrtoint() to integer type, not '%s'"
|
382 |
+
% (typ,))
|
383 |
+
|
384 |
+
@_castop('inttoptr')
|
385 |
+
def inttoptr(self, typ):
|
386 |
+
"""
|
387 |
+
Cast integer to pointer.
|
388 |
+
"""
|
389 |
+
if not isinstance(self.type, types.IntType):
|
390 |
+
msg = "can only call inttoptr() on integer constants, not '%s'"
|
391 |
+
raise TypeError(msg % (self.type,))
|
392 |
+
if not isinstance(typ, types.PointerType):
|
393 |
+
raise TypeError("can only inttoptr() to pointer type, not '%s'"
|
394 |
+
% (typ,))
|
395 |
+
|
396 |
+
def gep(self, indices):
|
397 |
+
"""
|
398 |
+
Call getelementptr on this pointer constant.
|
399 |
+
"""
|
400 |
+
if not isinstance(self.type, types.PointerType):
|
401 |
+
raise TypeError("can only call gep() on pointer constants, not '%s'"
|
402 |
+
% (self.type,))
|
403 |
+
|
404 |
+
outtype = self.type
|
405 |
+
for i in indices:
|
406 |
+
outtype = outtype.gep(i)
|
407 |
+
|
408 |
+
strindices = ["{0} {1}".format(idx.type, idx.get_reference())
|
409 |
+
for idx in indices]
|
410 |
+
|
411 |
+
op = "getelementptr ({0}, {1} {2}, {3})".format(
|
412 |
+
self.type.pointee, self.type,
|
413 |
+
self.get_reference(), ', '.join(strindices))
|
414 |
+
return FormattedConstant(outtype.as_pointer(self.addrspace), op)
|
415 |
+
|
416 |
+
|
417 |
+
class Value(object):
|
418 |
+
"""
|
419 |
+
The base class for all values.
|
420 |
+
"""
|
421 |
+
|
422 |
+
def __repr__(self):
|
423 |
+
return "<ir.%s type='%s' ...>" % (self.__class__.__name__, self.type,)
|
424 |
+
|
425 |
+
|
426 |
+
class _Undefined(object):
|
427 |
+
"""
|
428 |
+
'undef': a value for undefined values.
|
429 |
+
"""
|
430 |
+
def __new__(cls):
|
431 |
+
try:
|
432 |
+
return Undefined
|
433 |
+
except NameError:
|
434 |
+
return object.__new__(_Undefined)
|
435 |
+
|
436 |
+
|
437 |
+
Undefined = _Undefined()
|
438 |
+
|
439 |
+
|
440 |
+
class Constant(_StrCaching, _StringReferenceCaching, _ConstOpMixin, Value):
|
441 |
+
"""
|
442 |
+
A constant LLVM value.
|
443 |
+
"""
|
444 |
+
|
445 |
+
def __init__(self, typ, constant):
|
446 |
+
assert isinstance(typ, types.Type)
|
447 |
+
assert not isinstance(typ, types.VoidType)
|
448 |
+
self.type = typ
|
449 |
+
constant = typ.wrap_constant_value(constant)
|
450 |
+
self.constant = constant
|
451 |
+
|
452 |
+
def _to_string(self):
|
453 |
+
return '{0} {1}'.format(self.type, self.get_reference())
|
454 |
+
|
455 |
+
def _get_reference(self):
|
456 |
+
if self.constant is None:
|
457 |
+
val = self.type.null
|
458 |
+
|
459 |
+
elif self.constant is Undefined:
|
460 |
+
val = "undef"
|
461 |
+
|
462 |
+
elif isinstance(self.constant, bytearray):
|
463 |
+
val = 'c"{0}"'.format(_escape_string(self.constant))
|
464 |
+
|
465 |
+
else:
|
466 |
+
val = self.type.format_constant(self.constant)
|
467 |
+
|
468 |
+
return val
|
469 |
+
|
470 |
+
@classmethod
|
471 |
+
def literal_array(cls, elems):
|
472 |
+
"""
|
473 |
+
Construct a literal array constant made of the given members.
|
474 |
+
"""
|
475 |
+
tys = [el.type for el in elems]
|
476 |
+
if len(tys) == 0:
|
477 |
+
raise ValueError("need at least one element")
|
478 |
+
ty = tys[0]
|
479 |
+
for other in tys:
|
480 |
+
if ty != other:
|
481 |
+
raise TypeError("all elements must have the same type")
|
482 |
+
return cls(types.ArrayType(ty, len(elems)), elems)
|
483 |
+
|
484 |
+
@classmethod
|
485 |
+
def literal_struct(cls, elems):
|
486 |
+
"""
|
487 |
+
Construct a literal structure constant made of the given members.
|
488 |
+
"""
|
489 |
+
tys = [el.type for el in elems]
|
490 |
+
return cls(types.LiteralStructType(tys), elems)
|
491 |
+
|
492 |
+
@property
|
493 |
+
def addrspace(self):
|
494 |
+
if not isinstance(self.type, types.PointerType):
|
495 |
+
raise TypeError("Only pointer constant have address spaces")
|
496 |
+
return self.type.addrspace
|
497 |
+
|
498 |
+
def __eq__(self, other):
|
499 |
+
if isinstance(other, Constant):
|
500 |
+
return str(self) == str(other)
|
501 |
+
else:
|
502 |
+
return False
|
503 |
+
|
504 |
+
def __ne__(self, other):
|
505 |
+
return not self.__eq__(other)
|
506 |
+
|
507 |
+
def __hash__(self):
|
508 |
+
return hash(str(self))
|
509 |
+
|
510 |
+
def __repr__(self):
|
511 |
+
return "<ir.Constant type='%s' value=%r>" % (self.type, self.constant)
|
512 |
+
|
513 |
+
|
514 |
+
class FormattedConstant(Constant):
|
515 |
+
"""
|
516 |
+
A constant with an already formatted IR representation.
|
517 |
+
"""
|
518 |
+
|
519 |
+
def __init__(self, typ, constant):
|
520 |
+
assert isinstance(constant, str)
|
521 |
+
Constant.__init__(self, typ, constant)
|
522 |
+
|
523 |
+
def _to_string(self):
|
524 |
+
return self.constant
|
525 |
+
|
526 |
+
def _get_reference(self):
|
527 |
+
return self.constant
|
528 |
+
|
529 |
+
|
530 |
+
class NamedValue(_StrCaching, _StringReferenceCaching, Value):
|
531 |
+
"""
|
532 |
+
The base class for named values.
|
533 |
+
"""
|
534 |
+
name_prefix = '%'
|
535 |
+
deduplicate_name = True
|
536 |
+
|
537 |
+
def __init__(self, parent, type, name):
|
538 |
+
assert parent is not None
|
539 |
+
assert isinstance(type, types.Type)
|
540 |
+
self.parent = parent
|
541 |
+
self.type = type
|
542 |
+
self._set_name(name)
|
543 |
+
|
544 |
+
def _to_string(self):
|
545 |
+
buf = []
|
546 |
+
if not isinstance(self.type, types.VoidType):
|
547 |
+
buf.append("{0} = ".format(self.get_reference()))
|
548 |
+
self.descr(buf)
|
549 |
+
return "".join(buf).rstrip()
|
550 |
+
|
551 |
+
def descr(self, buf):
|
552 |
+
raise NotImplementedError
|
553 |
+
|
554 |
+
def _get_name(self):
|
555 |
+
return self._name
|
556 |
+
|
557 |
+
def _set_name(self, name):
|
558 |
+
name = self.parent.scope.register(name,
|
559 |
+
deduplicate=self.deduplicate_name)
|
560 |
+
self._name = name
|
561 |
+
|
562 |
+
name = property(_get_name, _set_name)
|
563 |
+
|
564 |
+
def _get_reference(self):
|
565 |
+
name = self.name
|
566 |
+
# Quote and escape value name
|
567 |
+
if '\\' in name or '"' in name:
|
568 |
+
name = name.replace('\\', '\\5c').replace('"', '\\22')
|
569 |
+
return '{0}"{1}"'.format(self.name_prefix, name)
|
570 |
+
|
571 |
+
def __repr__(self):
|
572 |
+
return "<ir.%s %r of type '%s'>" % (
|
573 |
+
self.__class__.__name__, self.name, self.type)
|
574 |
+
|
575 |
+
@property
|
576 |
+
def function_type(self):
|
577 |
+
ty = self.type
|
578 |
+
if isinstance(ty, types.PointerType):
|
579 |
+
ty = self.type.pointee
|
580 |
+
if isinstance(ty, types.FunctionType):
|
581 |
+
return ty
|
582 |
+
else:
|
583 |
+
raise TypeError("Not a function: {0}".format(self.type))
|
584 |
+
|
585 |
+
|
586 |
+
class MetaDataString(NamedValue):
|
587 |
+
"""
|
588 |
+
A metadata string, i.e. a constant string used as a value in a metadata
|
589 |
+
node.
|
590 |
+
"""
|
591 |
+
|
592 |
+
def __init__(self, parent, string):
|
593 |
+
super(MetaDataString, self).__init__(parent,
|
594 |
+
types.MetaDataType(),
|
595 |
+
name="")
|
596 |
+
self.string = string
|
597 |
+
|
598 |
+
def descr(self, buf):
|
599 |
+
buf += (self.get_reference(), "\n")
|
600 |
+
|
601 |
+
def _get_reference(self):
|
602 |
+
return '!"{0}"'.format(_escape_string(self.string))
|
603 |
+
|
604 |
+
_to_string = _get_reference
|
605 |
+
|
606 |
+
def __eq__(self, other):
|
607 |
+
if isinstance(other, MetaDataString):
|
608 |
+
return self.string == other.string
|
609 |
+
else:
|
610 |
+
return False
|
611 |
+
|
612 |
+
def __ne__(self, other):
|
613 |
+
return not self.__eq__(other)
|
614 |
+
|
615 |
+
def __hash__(self):
|
616 |
+
return hash(self.string)
|
617 |
+
|
618 |
+
|
619 |
+
class MetaDataArgument(_StrCaching, _StringReferenceCaching, Value):
|
620 |
+
"""
|
621 |
+
An argument value to a function taking metadata arguments.
|
622 |
+
This can wrap any other kind of LLVM value.
|
623 |
+
|
624 |
+
Do not instantiate directly, Builder.call() will create these
|
625 |
+
automatically.
|
626 |
+
"""
|
627 |
+
|
628 |
+
def __init__(self, value):
|
629 |
+
assert isinstance(value, Value)
|
630 |
+
assert not isinstance(value.type, types.MetaDataType)
|
631 |
+
self.type = types.MetaDataType()
|
632 |
+
self.wrapped_value = value
|
633 |
+
|
634 |
+
def _get_reference(self):
|
635 |
+
# e.g. "i32* %2"
|
636 |
+
return "{0} {1}".format(self.wrapped_value.type,
|
637 |
+
self.wrapped_value.get_reference())
|
638 |
+
|
639 |
+
_to_string = _get_reference
|
640 |
+
|
641 |
+
|
642 |
+
class NamedMetaData(object):
|
643 |
+
"""
|
644 |
+
A named metadata node.
|
645 |
+
|
646 |
+
Do not instantiate directly, use Module.add_named_metadata() instead.
|
647 |
+
"""
|
648 |
+
|
649 |
+
def __init__(self, parent):
|
650 |
+
self.parent = parent
|
651 |
+
self.operands = []
|
652 |
+
|
653 |
+
def add(self, md):
|
654 |
+
self.operands.append(md)
|
655 |
+
|
656 |
+
|
657 |
+
class MDValue(NamedValue):
|
658 |
+
"""
|
659 |
+
A metadata node's value, consisting of a sequence of elements ("operands").
|
660 |
+
|
661 |
+
Do not instantiate directly, use Module.add_metadata() instead.
|
662 |
+
"""
|
663 |
+
name_prefix = '!'
|
664 |
+
|
665 |
+
def __init__(self, parent, values, name):
|
666 |
+
super(MDValue, self).__init__(parent,
|
667 |
+
types.MetaDataType(),
|
668 |
+
name=name)
|
669 |
+
self.operands = tuple(values)
|
670 |
+
parent.metadata.append(self)
|
671 |
+
|
672 |
+
def descr(self, buf):
|
673 |
+
operands = []
|
674 |
+
for op in self.operands:
|
675 |
+
if isinstance(op.type, types.MetaDataType):
|
676 |
+
if isinstance(op, Constant) and op.constant is None:
|
677 |
+
operands.append("null")
|
678 |
+
else:
|
679 |
+
operands.append(op.get_reference())
|
680 |
+
else:
|
681 |
+
operands.append("{0} {1}".format(op.type, op.get_reference()))
|
682 |
+
operands = ', '.join(operands)
|
683 |
+
buf += ("!{{ {0} }}".format(operands), "\n")
|
684 |
+
|
685 |
+
def _get_reference(self):
|
686 |
+
return self.name_prefix + str(self.name)
|
687 |
+
|
688 |
+
def __eq__(self, other):
|
689 |
+
if isinstance(other, MDValue):
|
690 |
+
return self.operands == other.operands
|
691 |
+
else:
|
692 |
+
return False
|
693 |
+
|
694 |
+
def __ne__(self, other):
|
695 |
+
return not self.__eq__(other)
|
696 |
+
|
697 |
+
def __hash__(self):
|
698 |
+
return hash(self.operands)
|
699 |
+
|
700 |
+
|
701 |
+
class DIToken:
|
702 |
+
"""
|
703 |
+
A debug information enumeration value that should appear bare in
|
704 |
+
the emitted metadata.
|
705 |
+
|
706 |
+
Use this to wrap known constants, e.g. the DW_* enumerations.
|
707 |
+
"""
|
708 |
+
|
709 |
+
def __init__(self, value):
|
710 |
+
self.value = value
|
711 |
+
|
712 |
+
|
713 |
+
class DIValue(NamedValue):
|
714 |
+
"""
|
715 |
+
A debug information descriptor, containing key-value pairs.
|
716 |
+
|
717 |
+
Do not instantiate directly, use Module.add_debug_info() instead.
|
718 |
+
"""
|
719 |
+
name_prefix = '!'
|
720 |
+
|
721 |
+
def __init__(self, parent, is_distinct, kind, operands, name):
|
722 |
+
super(DIValue, self).__init__(parent,
|
723 |
+
types.MetaDataType(),
|
724 |
+
name=name)
|
725 |
+
self.is_distinct = is_distinct
|
726 |
+
self.kind = kind
|
727 |
+
self.operands = tuple(operands)
|
728 |
+
parent.metadata.append(self)
|
729 |
+
|
730 |
+
def descr(self, buf):
|
731 |
+
if self.is_distinct:
|
732 |
+
buf += ("distinct ",)
|
733 |
+
operands = []
|
734 |
+
for key, value in self.operands:
|
735 |
+
if value is None:
|
736 |
+
strvalue = "null"
|
737 |
+
elif value is True:
|
738 |
+
strvalue = "true"
|
739 |
+
elif value is False:
|
740 |
+
strvalue = "false"
|
741 |
+
elif isinstance(value, DIToken):
|
742 |
+
strvalue = value.value
|
743 |
+
elif isinstance(value, str):
|
744 |
+
strvalue = '"{}"'.format(_escape_string(value))
|
745 |
+
elif isinstance(value, int):
|
746 |
+
strvalue = str(value)
|
747 |
+
elif isinstance(value, NamedValue):
|
748 |
+
strvalue = value.get_reference()
|
749 |
+
else:
|
750 |
+
raise TypeError("invalid operand type for debug info: %r"
|
751 |
+
% (value,))
|
752 |
+
operands.append("{0}: {1}".format(key, strvalue))
|
753 |
+
operands = ', '.join(operands)
|
754 |
+
buf += ("!", self.kind, "(", operands, ")\n")
|
755 |
+
|
756 |
+
def _get_reference(self):
|
757 |
+
return self.name_prefix + str(self.name)
|
758 |
+
|
759 |
+
def __eq__(self, other):
|
760 |
+
if isinstance(other, DIValue):
|
761 |
+
return self.is_distinct == other.is_distinct and \
|
762 |
+
self.kind == other.kind and \
|
763 |
+
self.operands == other.operands
|
764 |
+
else:
|
765 |
+
return False
|
766 |
+
|
767 |
+
def __ne__(self, other):
|
768 |
+
return not self.__eq__(other)
|
769 |
+
|
770 |
+
def __hash__(self):
|
771 |
+
return hash((self.is_distinct, self.kind, self.operands))
|
772 |
+
|
773 |
+
|
774 |
+
class GlobalValue(NamedValue, _ConstOpMixin, _HasMetadata):
|
775 |
+
"""
|
776 |
+
A global value.
|
777 |
+
"""
|
778 |
+
name_prefix = '@'
|
779 |
+
deduplicate_name = False
|
780 |
+
|
781 |
+
def __init__(self, *args, **kwargs):
|
782 |
+
super(GlobalValue, self).__init__(*args, **kwargs)
|
783 |
+
self.linkage = ''
|
784 |
+
self.storage_class = ''
|
785 |
+
self.section = ''
|
786 |
+
self.metadata = {}
|
787 |
+
|
788 |
+
|
789 |
+
class GlobalVariable(GlobalValue):
|
790 |
+
"""
|
791 |
+
A global variable.
|
792 |
+
"""
|
793 |
+
|
794 |
+
def __init__(self, module, typ, name, addrspace=0):
|
795 |
+
assert isinstance(typ, types.Type)
|
796 |
+
super(GlobalVariable, self).__init__(module, typ.as_pointer(addrspace),
|
797 |
+
name=name)
|
798 |
+
self.value_type = typ
|
799 |
+
self.initializer = None
|
800 |
+
self.unnamed_addr = False
|
801 |
+
self.global_constant = False
|
802 |
+
self.addrspace = addrspace
|
803 |
+
self.align = None
|
804 |
+
self.parent.add_global(self)
|
805 |
+
|
806 |
+
def descr(self, buf):
|
807 |
+
if self.global_constant:
|
808 |
+
kind = 'constant'
|
809 |
+
else:
|
810 |
+
kind = 'global'
|
811 |
+
|
812 |
+
if not self.linkage:
|
813 |
+
# Default to external linkage
|
814 |
+
linkage = 'external' if self.initializer is None else ''
|
815 |
+
else:
|
816 |
+
linkage = self.linkage
|
817 |
+
|
818 |
+
if linkage:
|
819 |
+
buf.append(linkage + " ")
|
820 |
+
if self.storage_class:
|
821 |
+
buf.append(self.storage_class + " ")
|
822 |
+
if self.unnamed_addr:
|
823 |
+
buf.append("unnamed_addr ")
|
824 |
+
if self.addrspace != 0:
|
825 |
+
buf.append('addrspace({0:d}) '.format(self.addrspace))
|
826 |
+
|
827 |
+
buf.append("{kind} {type}" .format(kind=kind, type=self.value_type))
|
828 |
+
|
829 |
+
if self.initializer is not None:
|
830 |
+
if self.initializer.type != self.value_type:
|
831 |
+
raise TypeError("got initializer of type %s "
|
832 |
+
"for global value type %s"
|
833 |
+
% (self.initializer.type, self.value_type))
|
834 |
+
buf.append(" " + self.initializer.get_reference())
|
835 |
+
elif linkage not in ('external', 'extern_weak'):
|
836 |
+
# emit 'undef' for non-external linkage GV
|
837 |
+
buf.append(" " + self.value_type(Undefined).get_reference())
|
838 |
+
|
839 |
+
if self.section:
|
840 |
+
buf.append(", section \"%s\"" % (self.section,))
|
841 |
+
|
842 |
+
if self.align is not None:
|
843 |
+
buf.append(", align %d" % (self.align,))
|
844 |
+
|
845 |
+
if self.metadata:
|
846 |
+
buf.append(self._stringify_metadata(leading_comma=True))
|
847 |
+
|
848 |
+
buf.append("\n")
|
849 |
+
|
850 |
+
|
851 |
+
class AttributeSet(set):
|
852 |
+
"""A set of string attribute.
|
853 |
+
Only accept items listed in *_known*.
|
854 |
+
|
855 |
+
Properties:
|
856 |
+
* Iterate in sorted order
|
857 |
+
"""
|
858 |
+
_known = ()
|
859 |
+
|
860 |
+
def __init__(self, args=()):
|
861 |
+
super().__init__()
|
862 |
+
if isinstance(args, str):
|
863 |
+
args = [args]
|
864 |
+
for name in args:
|
865 |
+
self.add(name)
|
866 |
+
|
867 |
+
def _expand(self, name, typ):
|
868 |
+
return name
|
869 |
+
|
870 |
+
def add(self, name):
|
871 |
+
if name not in self._known:
|
872 |
+
raise ValueError('unknown attr {!r} for {}'.format(name, self))
|
873 |
+
return super(AttributeSet, self).add(name)
|
874 |
+
|
875 |
+
def _to_list(self, typ):
|
876 |
+
return [self._expand(i, typ) for i in sorted(self)]
|
877 |
+
|
878 |
+
|
879 |
+
class FunctionAttributes(AttributeSet):
|
880 |
+
_known = frozenset([
|
881 |
+
'argmemonly', 'alwaysinline', 'builtin', 'cold',
|
882 |
+
'inaccessiblememonly', 'inaccessiblemem_or_argmemonly', 'inlinehint',
|
883 |
+
'jumptable', 'minsize', 'naked', 'nobuiltin', 'noduplicate',
|
884 |
+
'noimplicitfloat', 'noinline', 'nonlazybind', 'norecurse',
|
885 |
+
'noredzone', 'noreturn', 'nounwind', 'optnone', 'optsize',
|
886 |
+
'readnone', 'readonly', 'returns_twice', 'sanitize_address',
|
887 |
+
'sanitize_memory', 'sanitize_thread', 'ssp',
|
888 |
+
'sspreg', 'sspstrong', 'uwtable'])
|
889 |
+
|
890 |
+
def __init__(self, args=()):
|
891 |
+
self._alignstack = 0
|
892 |
+
self._personality = None
|
893 |
+
super(FunctionAttributes, self).__init__(args)
|
894 |
+
|
895 |
+
def add(self, name):
|
896 |
+
if ((name == 'alwaysinline' and 'noinline' in self) or
|
897 |
+
(name == 'noinline' and 'alwaysinline' in self)):
|
898 |
+
raise ValueError("Can't have alwaysinline and noinline")
|
899 |
+
|
900 |
+
super().add(name)
|
901 |
+
|
902 |
+
@property
|
903 |
+
def alignstack(self):
|
904 |
+
return self._alignstack
|
905 |
+
|
906 |
+
@alignstack.setter
|
907 |
+
def alignstack(self, val):
|
908 |
+
assert val >= 0
|
909 |
+
self._alignstack = val
|
910 |
+
|
911 |
+
@property
|
912 |
+
def personality(self):
|
913 |
+
return self._personality
|
914 |
+
|
915 |
+
@personality.setter
|
916 |
+
def personality(self, val):
|
917 |
+
assert val is None or isinstance(val, GlobalValue)
|
918 |
+
self._personality = val
|
919 |
+
|
920 |
+
def _to_list(self, ret_type):
|
921 |
+
attrs = super()._to_list(ret_type)
|
922 |
+
if self.alignstack:
|
923 |
+
attrs.append('alignstack({0:d})'.format(self.alignstack))
|
924 |
+
if self.personality:
|
925 |
+
attrs.append('personality {persty} {persfn}'.format(
|
926 |
+
persty=self.personality.type,
|
927 |
+
persfn=self.personality.get_reference()))
|
928 |
+
return attrs
|
929 |
+
|
930 |
+
|
931 |
+
class Function(GlobalValue):
|
932 |
+
"""Represent a LLVM Function but does uses a Module as parent.
|
933 |
+
Global Values are stored as a set of dependencies (attribute `depends`).
|
934 |
+
"""
|
935 |
+
|
936 |
+
def __init__(self, module, ftype, name):
|
937 |
+
assert isinstance(ftype, types.Type)
|
938 |
+
super(Function, self).__init__(module, ftype.as_pointer(), name=name)
|
939 |
+
self.ftype = ftype
|
940 |
+
self.scope = _utils.NameScope()
|
941 |
+
self.blocks = []
|
942 |
+
self.attributes = FunctionAttributes()
|
943 |
+
self.args = tuple([Argument(self, t)
|
944 |
+
for t in ftype.args])
|
945 |
+
self.return_value = ReturnValue(self, ftype.return_type)
|
946 |
+
self.parent.add_global(self)
|
947 |
+
self.calling_convention = ''
|
948 |
+
|
949 |
+
@property
|
950 |
+
def module(self):
|
951 |
+
return self.parent
|
952 |
+
|
953 |
+
@property
|
954 |
+
def entry_basic_block(self):
|
955 |
+
return self.blocks[0]
|
956 |
+
|
957 |
+
@property
|
958 |
+
def basic_blocks(self):
|
959 |
+
return self.blocks
|
960 |
+
|
961 |
+
def append_basic_block(self, name=''):
|
962 |
+
blk = Block(parent=self, name=name)
|
963 |
+
self.blocks.append(blk)
|
964 |
+
return blk
|
965 |
+
|
966 |
+
def insert_basic_block(self, before, name=''):
|
967 |
+
"""Insert block before
|
968 |
+
"""
|
969 |
+
blk = Block(parent=self, name=name)
|
970 |
+
self.blocks.insert(before, blk)
|
971 |
+
return blk
|
972 |
+
|
973 |
+
def descr_prototype(self, buf):
|
974 |
+
"""
|
975 |
+
Describe the prototype ("head") of the function.
|
976 |
+
"""
|
977 |
+
state = "define" if self.blocks else "declare"
|
978 |
+
ret = self.return_value
|
979 |
+
args = ", ".join(str(a) for a in self.args)
|
980 |
+
name = self.get_reference()
|
981 |
+
attrs = ' ' + ' '.join(self.attributes._to_list(
|
982 |
+
self.ftype.return_type)) if self.attributes else ''
|
983 |
+
if any(self.args):
|
984 |
+
vararg = ', ...' if self.ftype.var_arg else ''
|
985 |
+
else:
|
986 |
+
vararg = '...' if self.ftype.var_arg else ''
|
987 |
+
linkage = self.linkage
|
988 |
+
cconv = self.calling_convention
|
989 |
+
prefix = " ".join(str(x) for x in [state, linkage, cconv, ret] if x)
|
990 |
+
metadata = self._stringify_metadata()
|
991 |
+
metadata = ' {}'.format(metadata) if metadata else ''
|
992 |
+
section = ' section "{}"'.format(self.section) if self.section else ''
|
993 |
+
pt_str = "{prefix} {name}({args}{vararg}){attrs}{section}{metadata}\n"
|
994 |
+
prototype = pt_str.format(prefix=prefix, name=name, args=args,
|
995 |
+
vararg=vararg, attrs=attrs, section=section,
|
996 |
+
metadata=metadata)
|
997 |
+
buf.append(prototype)
|
998 |
+
|
999 |
+
def descr_body(self, buf):
|
1000 |
+
"""
|
1001 |
+
Describe of the body of the function.
|
1002 |
+
"""
|
1003 |
+
for blk in self.blocks:
|
1004 |
+
blk.descr(buf)
|
1005 |
+
|
1006 |
+
def descr(self, buf):
|
1007 |
+
self.descr_prototype(buf)
|
1008 |
+
if self.blocks:
|
1009 |
+
buf.append("{\n")
|
1010 |
+
self.descr_body(buf)
|
1011 |
+
buf.append("}\n")
|
1012 |
+
|
1013 |
+
def __str__(self):
|
1014 |
+
buf = []
|
1015 |
+
self.descr(buf)
|
1016 |
+
return "".join(buf)
|
1017 |
+
|
1018 |
+
@property
|
1019 |
+
def is_declaration(self):
|
1020 |
+
return len(self.blocks) == 0
|
1021 |
+
|
1022 |
+
|
1023 |
+
class ArgumentAttributes(AttributeSet):
|
1024 |
+
# List from
|
1025 |
+
# https://releases.llvm.org/14.0.0/docs/LangRef.html#parameter-attributes
|
1026 |
+
_known = MappingProxyType({
|
1027 |
+
# True (emit type),
|
1028 |
+
# False (emit name only)
|
1029 |
+
'byref': True,
|
1030 |
+
'byval': True,
|
1031 |
+
'elementtype': True,
|
1032 |
+
'immarg': False,
|
1033 |
+
'inalloca': True,
|
1034 |
+
'inreg': False,
|
1035 |
+
'nest': False,
|
1036 |
+
'noalias': False,
|
1037 |
+
'nocapture': False,
|
1038 |
+
'nofree': False,
|
1039 |
+
'nonnull': False,
|
1040 |
+
'noundef': False,
|
1041 |
+
'preallocated': True,
|
1042 |
+
'returned': False,
|
1043 |
+
'signext': False,
|
1044 |
+
'sret': True,
|
1045 |
+
'swiftasync': False,
|
1046 |
+
'swifterror': False,
|
1047 |
+
'swiftself': False,
|
1048 |
+
'zeroext': False,
|
1049 |
+
})
|
1050 |
+
|
1051 |
+
def __init__(self, args=()):
|
1052 |
+
self._align = 0
|
1053 |
+
self._dereferenceable = 0
|
1054 |
+
self._dereferenceable_or_null = 0
|
1055 |
+
super(ArgumentAttributes, self).__init__(args)
|
1056 |
+
|
1057 |
+
def _expand(self, name, typ):
|
1058 |
+
requires_type = self._known.get(name)
|
1059 |
+
if requires_type:
|
1060 |
+
return f"{name}({typ.pointee})"
|
1061 |
+
else:
|
1062 |
+
return name
|
1063 |
+
|
1064 |
+
@property
|
1065 |
+
def align(self):
|
1066 |
+
return self._align
|
1067 |
+
|
1068 |
+
@align.setter
|
1069 |
+
def align(self, val):
|
1070 |
+
assert isinstance(val, int) and val >= 0
|
1071 |
+
self._align = val
|
1072 |
+
|
1073 |
+
@property
|
1074 |
+
def dereferenceable(self):
|
1075 |
+
return self._dereferenceable
|
1076 |
+
|
1077 |
+
@dereferenceable.setter
|
1078 |
+
def dereferenceable(self, val):
|
1079 |
+
assert isinstance(val, int) and val >= 0
|
1080 |
+
self._dereferenceable = val
|
1081 |
+
|
1082 |
+
@property
|
1083 |
+
def dereferenceable_or_null(self):
|
1084 |
+
return self._dereferenceable_or_null
|
1085 |
+
|
1086 |
+
@dereferenceable_or_null.setter
|
1087 |
+
def dereferenceable_or_null(self, val):
|
1088 |
+
assert isinstance(val, int) and val >= 0
|
1089 |
+
self._dereferenceable_or_null = val
|
1090 |
+
|
1091 |
+
def _to_list(self, typ):
|
1092 |
+
attrs = super()._to_list(typ)
|
1093 |
+
if self.align:
|
1094 |
+
attrs.append('align {0:d}'.format(self.align))
|
1095 |
+
if self.dereferenceable:
|
1096 |
+
attrs.append('dereferenceable({0:d})'.format(self.dereferenceable))
|
1097 |
+
if self.dereferenceable_or_null:
|
1098 |
+
dref = 'dereferenceable_or_null({0:d})'
|
1099 |
+
attrs.append(dref.format(self.dereferenceable_or_null))
|
1100 |
+
return attrs
|
1101 |
+
|
1102 |
+
|
1103 |
+
class _BaseArgument(NamedValue):
|
1104 |
+
def __init__(self, parent, typ, name=''):
|
1105 |
+
assert isinstance(typ, types.Type)
|
1106 |
+
super(_BaseArgument, self).__init__(parent, typ, name=name)
|
1107 |
+
self.parent = parent
|
1108 |
+
self.attributes = ArgumentAttributes()
|
1109 |
+
|
1110 |
+
def __repr__(self):
|
1111 |
+
return "<ir.%s %r of type %s>" % (self.__class__.__name__, self.name,
|
1112 |
+
self.type)
|
1113 |
+
|
1114 |
+
def add_attribute(self, attr):
|
1115 |
+
self.attributes.add(attr)
|
1116 |
+
|
1117 |
+
|
1118 |
+
class Argument(_BaseArgument):
|
1119 |
+
"""
|
1120 |
+
The specification of a function argument.
|
1121 |
+
"""
|
1122 |
+
|
1123 |
+
def __str__(self):
|
1124 |
+
attrs = self.attributes._to_list(self.type)
|
1125 |
+
if attrs:
|
1126 |
+
return "{0} {1} {2}".format(self.type, ' '.join(attrs),
|
1127 |
+
self.get_reference())
|
1128 |
+
else:
|
1129 |
+
return "{0} {1}".format(self.type, self.get_reference())
|
1130 |
+
|
1131 |
+
|
1132 |
+
class ReturnValue(_BaseArgument):
|
1133 |
+
"""
|
1134 |
+
The specification of a function's return value.
|
1135 |
+
"""
|
1136 |
+
|
1137 |
+
def __str__(self):
|
1138 |
+
attrs = self.attributes._to_list(self.type)
|
1139 |
+
if attrs:
|
1140 |
+
return "{0} {1}".format(' '.join(attrs), self.type)
|
1141 |
+
else:
|
1142 |
+
return str(self.type)
|
1143 |
+
|
1144 |
+
|
1145 |
+
class Block(NamedValue):
|
1146 |
+
"""
|
1147 |
+
A LLVM IR basic block. A basic block is a sequence of
|
1148 |
+
instructions whose execution always goes from start to end. That
|
1149 |
+
is, a control flow instruction (branch) can only appear as the
|
1150 |
+
last instruction, and incoming branches can only jump to the first
|
1151 |
+
instruction.
|
1152 |
+
"""
|
1153 |
+
|
1154 |
+
def __init__(self, parent, name=''):
|
1155 |
+
super(Block, self).__init__(parent, types.LabelType(), name=name)
|
1156 |
+
self.scope = parent.scope
|
1157 |
+
self.instructions = []
|
1158 |
+
self.terminator = None
|
1159 |
+
|
1160 |
+
@property
|
1161 |
+
def is_terminated(self):
|
1162 |
+
return self.terminator is not None
|
1163 |
+
|
1164 |
+
@property
|
1165 |
+
def function(self):
|
1166 |
+
return self.parent
|
1167 |
+
|
1168 |
+
@property
|
1169 |
+
def module(self):
|
1170 |
+
return self.parent.module
|
1171 |
+
|
1172 |
+
def descr(self, buf):
|
1173 |
+
buf.append("{0}:\n".format(self._format_name()))
|
1174 |
+
buf += [" {0}\n".format(instr) for instr in self.instructions]
|
1175 |
+
|
1176 |
+
def replace(self, old, new):
|
1177 |
+
"""Replace an instruction"""
|
1178 |
+
if old.type != new.type:
|
1179 |
+
raise TypeError("new instruction has a different type")
|
1180 |
+
pos = self.instructions.index(old)
|
1181 |
+
self.instructions.remove(old)
|
1182 |
+
self.instructions.insert(pos, new)
|
1183 |
+
|
1184 |
+
for bb in self.parent.basic_blocks:
|
1185 |
+
for instr in bb.instructions:
|
1186 |
+
instr.replace_usage(old, new)
|
1187 |
+
|
1188 |
+
def _format_name(self):
|
1189 |
+
# Per the LLVM Language Ref on identifiers, names matching the following
|
1190 |
+
# regex do not need to be quoted: [%@][-a-zA-Z$._][-a-zA-Z$._0-9]*
|
1191 |
+
# Otherwise, the identifier must be quoted and escaped.
|
1192 |
+
name = self.name
|
1193 |
+
if not _SIMPLE_IDENTIFIER_RE.match(name):
|
1194 |
+
name = name.replace('\\', '\\5c').replace('"', '\\22')
|
1195 |
+
name = '"{0}"'.format(name)
|
1196 |
+
return name
|
1197 |
+
|
1198 |
+
|
1199 |
+
class BlockAddress(Value):
|
1200 |
+
"""
|
1201 |
+
The address of a basic block.
|
1202 |
+
"""
|
1203 |
+
|
1204 |
+
def __init__(self, function, basic_block):
|
1205 |
+
assert isinstance(function, Function)
|
1206 |
+
assert isinstance(basic_block, Block)
|
1207 |
+
self.type = types.IntType(8).as_pointer()
|
1208 |
+
self.function = function
|
1209 |
+
self.basic_block = basic_block
|
1210 |
+
|
1211 |
+
def __str__(self):
|
1212 |
+
return '{0} {1}'.format(self.type, self.get_reference())
|
1213 |
+
|
1214 |
+
def get_reference(self):
|
1215 |
+
return "blockaddress({0}, {1})".format(
|
1216 |
+
self.function.get_reference(),
|
1217 |
+
self.basic_block.get_reference())
|
lib/python3.11/site-packages/llvmlite/tests/__init__.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
|
3 |
+
import unittest
|
4 |
+
from unittest import TestCase
|
5 |
+
|
6 |
+
import faulthandler
|
7 |
+
|
8 |
+
|
9 |
+
try:
|
10 |
+
# May fail in IPython Notebook with UnsupportedOperation
|
11 |
+
faulthandler.enable()
|
12 |
+
except BaseException as e:
|
13 |
+
msg = "Failed to enable faulthandler due to:\n{err}"
|
14 |
+
warnings.warn(msg.format(err=e))
|
15 |
+
|
16 |
+
|
17 |
+
# Try to inject Numba's unittest customizations.
|
18 |
+
from llvmlite.tests import customize
|
19 |
+
|
20 |
+
|
21 |
+
def discover_tests(startdir):
|
22 |
+
"""Discover test under a directory
|
23 |
+
"""
|
24 |
+
# Avoid importing unittest
|
25 |
+
loader = unittest.TestLoader()
|
26 |
+
suite = loader.discover(startdir)
|
27 |
+
return suite
|
28 |
+
|
29 |
+
|
30 |
+
def run_tests(suite=None, xmloutput=None, verbosity=1):
|
31 |
+
"""
|
32 |
+
args
|
33 |
+
----
|
34 |
+
- suite [TestSuite]
|
35 |
+
A suite of all tests to run
|
36 |
+
- xmloutput [str or None]
|
37 |
+
Path of XML output directory (optional)
|
38 |
+
- verbosity [int]
|
39 |
+
Verbosity level of tests output
|
40 |
+
|
41 |
+
Returns the TestResult object after running the test *suite*.
|
42 |
+
"""
|
43 |
+
if suite is None:
|
44 |
+
suite = discover_tests("llvmlite.tests")
|
45 |
+
if xmloutput is not None:
|
46 |
+
import xmlrunner
|
47 |
+
runner = xmlrunner.XMLTestRunner(output=xmloutput)
|
48 |
+
else:
|
49 |
+
runner = None
|
50 |
+
prog = unittest.main(suite=suite, testRunner=runner, exit=False,
|
51 |
+
verbosity=verbosity)
|
52 |
+
return prog.result
|
53 |
+
|
54 |
+
|
55 |
+
def main():
|
56 |
+
res = run_tests()
|
57 |
+
sys.exit(0 if res.wasSuccessful() else 1)
|
lib/python3.11/site-packages/llvmlite/tests/__main__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from llvmlite.tests import main
|
2 |
+
|
3 |
+
main()
|
lib/python3.11/site-packages/llvmlite/tests/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (2.3 kB). View file
|
|