llvmlite 0.46.0b1__cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of llvmlite might be problematic. Click here for more details.
- llvmlite/__init__.py +11 -0
- llvmlite/_version.py +11 -0
- llvmlite/binding/__init__.py +18 -0
- llvmlite/binding/analysis.py +69 -0
- llvmlite/binding/common.py +34 -0
- llvmlite/binding/config.py +143 -0
- llvmlite/binding/context.py +31 -0
- llvmlite/binding/dylib.py +45 -0
- llvmlite/binding/executionengine.py +330 -0
- llvmlite/binding/ffi.py +395 -0
- llvmlite/binding/initfini.py +85 -0
- llvmlite/binding/libllvmlite.so +0 -0
- llvmlite/binding/linker.py +20 -0
- llvmlite/binding/module.py +349 -0
- llvmlite/binding/newpassmanagers.py +1049 -0
- llvmlite/binding/object_file.py +82 -0
- llvmlite/binding/options.py +17 -0
- llvmlite/binding/orcjit.py +342 -0
- llvmlite/binding/targets.py +462 -0
- llvmlite/binding/typeref.py +267 -0
- llvmlite/binding/value.py +632 -0
- llvmlite/ir/__init__.py +11 -0
- llvmlite/ir/_utils.py +80 -0
- llvmlite/ir/builder.py +1120 -0
- llvmlite/ir/context.py +20 -0
- llvmlite/ir/instructions.py +920 -0
- llvmlite/ir/module.py +256 -0
- llvmlite/ir/transforms.py +64 -0
- llvmlite/ir/types.py +730 -0
- llvmlite/ir/values.py +1217 -0
- llvmlite/tests/__init__.py +57 -0
- llvmlite/tests/__main__.py +3 -0
- llvmlite/tests/customize.py +407 -0
- llvmlite/tests/refprune_proto.py +330 -0
- llvmlite/tests/test_binding.py +3155 -0
- llvmlite/tests/test_ir.py +3095 -0
- llvmlite/tests/test_refprune.py +574 -0
- llvmlite/tests/test_valuerepr.py +60 -0
- llvmlite/utils.py +29 -0
- llvmlite-0.46.0b1.dist-info/METADATA +145 -0
- llvmlite-0.46.0b1.dist-info/RECORD +45 -0
- llvmlite-0.46.0b1.dist-info/WHEEL +6 -0
- llvmlite-0.46.0b1.dist-info/licenses/LICENSE +24 -0
- llvmlite-0.46.0b1.dist-info/licenses/LICENSE.thirdparty +225 -0
- llvmlite-0.46.0b1.dist-info/top_level.txt +1 -0
llvmlite/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from ._version import get_versions
|
|
2
|
+
__version__ = get_versions()['version']
|
|
3
|
+
del get_versions
|
|
4
|
+
|
|
5
|
+
# We default to IR layer typed pointers being enabled, since they're needed in
|
|
6
|
+
# the most common usage scenarios with later LLVMs.
|
|
7
|
+
def _ir_layer_typed_pointers_enabled():
|
|
8
|
+
import os
|
|
9
|
+
return os.environ.get('LLVMLITE_ENABLE_IR_LAYER_TYPED_POINTERS', '1') == '1'
|
|
10
|
+
ir_layer_typed_pointers_enabled = _ir_layer_typed_pointers_enabled()
|
|
11
|
+
del _ir_layer_typed_pointers_enabled
|
llvmlite/_version.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
# This file was generated by 'versioneer.py' (0.14) from
|
|
3
|
+
# revision-control system data, or from the parent directory name of an
|
|
4
|
+
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
|
5
|
+
# of this file.
|
|
6
|
+
|
|
7
|
+
version_version = '0.46.0b1'
|
|
8
|
+
version_full = '5f77715902a7a311953fad682f41f25c81c21790'
|
|
9
|
+
def get_versions(default={}, verbose=False):
|
|
10
|
+
return {'version': version_version, 'full': version_full}
|
|
11
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Things that rely on the LLVM library
|
|
3
|
+
"""
|
|
4
|
+
from .dylib import *
|
|
5
|
+
from .executionengine import *
|
|
6
|
+
from .initfini import *
|
|
7
|
+
from .linker import *
|
|
8
|
+
from .module import *
|
|
9
|
+
from .options import *
|
|
10
|
+
from .newpassmanagers import *
|
|
11
|
+
from .targets import *
|
|
12
|
+
from .value import *
|
|
13
|
+
from .typeref import *
|
|
14
|
+
from .analysis import *
|
|
15
|
+
from .object_file import *
|
|
16
|
+
from .context import *
|
|
17
|
+
from .orcjit import *
|
|
18
|
+
from .config import *
|
|
@@ -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]
|
|
@@ -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]
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import warnings
|
|
3
|
+
from functools import cache
|
|
4
|
+
from ctypes import c_int, c_char_p
|
|
5
|
+
from llvmlite.binding import ffi
|
|
6
|
+
|
|
7
|
+
# these are here as they cannot be lazy bound as the module globals make calls
|
|
8
|
+
# to the LLVMPY API functions
|
|
9
|
+
ffi.lib.LLVMPY_HasSVMLSupport.argtypes = ()
|
|
10
|
+
ffi.lib.LLVMPY_HasSVMLSupport.restype = c_int
|
|
11
|
+
|
|
12
|
+
ffi.lib.LLVMPY_IsStaticLibstdcxxLinkageBuild.argtypes = ()
|
|
13
|
+
ffi.lib.LLVMPY_IsStaticLibstdcxxLinkageBuild.restype = c_int
|
|
14
|
+
|
|
15
|
+
ffi.lib.LLVMPY_IsDynamicLLVMLinkageBuild.argtypes = ()
|
|
16
|
+
ffi.lib.LLVMPY_IsDynamicLLVMLinkageBuild.restype = c_int
|
|
17
|
+
|
|
18
|
+
ffi.lib.LLVMPY_PackageFormat.argtypes = ()
|
|
19
|
+
ffi.lib.LLVMPY_PackageFormat.restype = c_char_p
|
|
20
|
+
|
|
21
|
+
ffi.lib.LLVMPY_LlvmAssertionsState.argtypes = ()
|
|
22
|
+
ffi.lib.LLVMPY_LlvmAssertionsState.restype = c_char_p
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _has_svml():
|
|
26
|
+
"""
|
|
27
|
+
Returns True if SVML was enabled at FFI support compile time.
|
|
28
|
+
"""
|
|
29
|
+
if ffi.lib.LLVMPY_HasSVMLSupport() == 0:
|
|
30
|
+
return False
|
|
31
|
+
else:
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
has_svml = _has_svml()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _build_llvm_linkage_type():
|
|
39
|
+
"""
|
|
40
|
+
Returns "static" if the FFI support is statically linked against LLVM,
|
|
41
|
+
returns "dynamic" otherwise.
|
|
42
|
+
"""
|
|
43
|
+
if ffi.lib.LLVMPY_IsDynamicLLVMLinkageBuild() == 0:
|
|
44
|
+
return "static"
|
|
45
|
+
else:
|
|
46
|
+
return "dynamic"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
build_llvm_linkage_type = _build_llvm_linkage_type()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _build_libstdcxx_linkage_type():
|
|
53
|
+
"""
|
|
54
|
+
Returns "static" if the FFI support is statically linked against libstdc++,
|
|
55
|
+
returns "dynamic" otherwise.
|
|
56
|
+
"""
|
|
57
|
+
if ffi.lib.LLVMPY_IsStaticLibstdcxxLinkageBuild() == 1:
|
|
58
|
+
return "static"
|
|
59
|
+
else:
|
|
60
|
+
return "dynamic"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
build_libstdcxx_linkage_type = _build_libstdcxx_linkage_type()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _package_format():
|
|
67
|
+
"""
|
|
68
|
+
Returns "wheel", "conda" or "unspecified"
|
|
69
|
+
"""
|
|
70
|
+
return ffi.lib.LLVMPY_PackageFormat().decode()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
package_format = _package_format()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _llvm_assertions_state():
|
|
77
|
+
"""
|
|
78
|
+
Returns one of "on", "off" or "unknown". Depending on whether it is
|
|
79
|
+
determined that LLVM was build with assertions on, off, or is not known.
|
|
80
|
+
"Is not known" is typically from a dynamic linkage against LLVM in which
|
|
81
|
+
case it's not easily identified whether LLVM was built with assertions.
|
|
82
|
+
"""
|
|
83
|
+
return ffi.lib.LLVMPY_LlvmAssertionsState().decode()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
llvm_assertions_state = _llvm_assertions_state()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@cache
|
|
90
|
+
def get_sysinfo():
|
|
91
|
+
d = dict()
|
|
92
|
+
d["ffi_lib_location"] = ffi.lib._name
|
|
93
|
+
d["package_format"] = package_format
|
|
94
|
+
d["llvm_linkage_type"] = build_llvm_linkage_type
|
|
95
|
+
d["libstdcxx_linkage_type"] = build_libstdcxx_linkage_type
|
|
96
|
+
d["llvm_assertions_state"] = llvm_assertions_state
|
|
97
|
+
|
|
98
|
+
# import lief
|
|
99
|
+
HAVE_LIEF = False
|
|
100
|
+
try:
|
|
101
|
+
import lief
|
|
102
|
+
HAVE_LIEF = True
|
|
103
|
+
except ImportError:
|
|
104
|
+
msg = "py-lief package not found, sysinfo is limited as a result"
|
|
105
|
+
warnings.warn(msg)
|
|
106
|
+
|
|
107
|
+
d["lief_probe_status"] = HAVE_LIEF
|
|
108
|
+
d["linked_libraries"] = None
|
|
109
|
+
d["canonicalised_linked_libraries"] = None
|
|
110
|
+
|
|
111
|
+
def canonicalise_library_type(dso):
|
|
112
|
+
"""Canonicalises the representation of the binary::libraries as a
|
|
113
|
+
sequence of strings"""
|
|
114
|
+
# Note lief v16:
|
|
115
|
+
# Mach-O .libraries are DylibCommand instances.
|
|
116
|
+
# Windows PE and Linux ELF .libraries are strings.
|
|
117
|
+
return [getattr(x, "name", x) for x in dso.libraries]
|
|
118
|
+
|
|
119
|
+
def canonicalise_library_spelling(libs):
|
|
120
|
+
# This adjusts the library "spelling" so that it just contains the
|
|
121
|
+
# name given to the linker. e.g. `@rpath/somewhere/libfoo.so.1.3`
|
|
122
|
+
# would be canonicalised to "foo".
|
|
123
|
+
fixes = []
|
|
124
|
+
for lib in libs:
|
|
125
|
+
# some libraries, e.g. Mach-O have an @rpath or system path
|
|
126
|
+
# prefix in their name, remove it.
|
|
127
|
+
path_stripped = os.path.split(lib)[-1]
|
|
128
|
+
# Assume all library names contain at least one dot, even if they
|
|
129
|
+
# don't it's fine, the first part is the piece of interest.
|
|
130
|
+
prefix_libname = path_stripped.split(".")[0]
|
|
131
|
+
linker_name = prefix_libname.replace("lib", "").replace("LIB", "")
|
|
132
|
+
# further canonicalize by referring to all libraries in lower case.
|
|
133
|
+
fixes.append(linker_name.lower())
|
|
134
|
+
return fixes
|
|
135
|
+
|
|
136
|
+
if HAVE_LIEF:
|
|
137
|
+
dso = lief.parse(d["ffi_lib_location"])
|
|
138
|
+
link_libs = tuple(canonicalise_library_type(dso))
|
|
139
|
+
d["linked_libraries"] = link_libs
|
|
140
|
+
canonicalised_libs = canonicalise_library_spelling(link_libs)
|
|
141
|
+
d["canonicalised_linked_libraries"] = canonicalised_libs
|
|
142
|
+
|
|
143
|
+
return d
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from llvmlite.binding import ffi
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def create_context():
|
|
5
|
+
return ContextRef(
|
|
6
|
+
ffi.lib.LLVMPY_ContextCreate())
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_global_context():
|
|
10
|
+
return GlobalContextRef(
|
|
11
|
+
ffi.lib.LLVMPY_GetGlobalContext())
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ContextRef(ffi.ObjectRef):
|
|
15
|
+
def __init__(self, context_ptr):
|
|
16
|
+
super(ContextRef, self).__init__(context_ptr)
|
|
17
|
+
|
|
18
|
+
def _dispose(self):
|
|
19
|
+
ffi.lib.LLVMPY_ContextDispose(self)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class GlobalContextRef(ContextRef):
|
|
23
|
+
def _dispose(self):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
ffi.lib.LLVMPY_GetGlobalContext.restype = ffi.LLVMContextRef
|
|
28
|
+
|
|
29
|
+
ffi.lib.LLVMPY_ContextCreate.restype = ffi.LLVMContextRef
|
|
30
|
+
|
|
31
|
+
ffi.lib.LLVMPY_ContextDispose.argtypes = [ffi.LLVMContextRef]
|
|
@@ -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
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
from ctypes import (POINTER, c_char_p, c_bool, c_void_p,
|
|
3
|
+
c_int, c_uint64, c_size_t, CFUNCTYPE, string_at, cast,
|
|
4
|
+
py_object, Structure)
|
|
5
|
+
|
|
6
|
+
from llvmlite.binding import ffi, targets, object_file
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Just check these weren't optimized out of the DLL.
|
|
10
|
+
ffi.lib.LLVMPY_LinkInMCJIT
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def create_mcjit_compiler(module, target_machine, use_lmm=None):
|
|
14
|
+
"""
|
|
15
|
+
Create a MCJIT ExecutionEngine from the given *module* and
|
|
16
|
+
*target_machine*.
|
|
17
|
+
|
|
18
|
+
*lmm* controls whether the llvmlite memory manager is used. If not supplied,
|
|
19
|
+
the default choice for the platform will be used (``True`` on 64-bit ARM
|
|
20
|
+
systems, ``False`` otherwise).
|
|
21
|
+
"""
|
|
22
|
+
if use_lmm is None:
|
|
23
|
+
use_lmm = platform.machine() in ('arm64', 'aarch64')
|
|
24
|
+
|
|
25
|
+
with ffi.OutputString() as outerr:
|
|
26
|
+
engine = ffi.lib.LLVMPY_CreateMCJITCompiler(
|
|
27
|
+
module, target_machine, use_lmm, outerr)
|
|
28
|
+
if not engine:
|
|
29
|
+
raise RuntimeError(str(outerr))
|
|
30
|
+
|
|
31
|
+
target_machine._owned = True
|
|
32
|
+
return ExecutionEngine(engine, module=module)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def check_jit_execution():
|
|
36
|
+
"""
|
|
37
|
+
Check the system allows execution of in-memory JITted functions.
|
|
38
|
+
An exception is raised otherwise.
|
|
39
|
+
"""
|
|
40
|
+
errno = ffi.lib.LLVMPY_TryAllocateExecutableMemory()
|
|
41
|
+
if errno != 0:
|
|
42
|
+
raise OSError(errno,
|
|
43
|
+
"cannot allocate executable memory. "
|
|
44
|
+
"This may be due to security restrictions on your "
|
|
45
|
+
"system, such as SELinux or similar mechanisms."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ExecutionEngine(ffi.ObjectRef):
|
|
50
|
+
"""An ExecutionEngine owns all Modules associated with it.
|
|
51
|
+
Deleting the engine will remove all associated modules.
|
|
52
|
+
It is an error to delete the associated modules.
|
|
53
|
+
"""
|
|
54
|
+
_object_cache = None
|
|
55
|
+
|
|
56
|
+
def __init__(self, ptr, module):
|
|
57
|
+
"""
|
|
58
|
+
Module ownership is transferred to the EE
|
|
59
|
+
"""
|
|
60
|
+
self._modules = set([module])
|
|
61
|
+
self._td = None
|
|
62
|
+
module._owned = True
|
|
63
|
+
ffi.ObjectRef.__init__(self, ptr)
|
|
64
|
+
|
|
65
|
+
def get_function_address(self, name):
|
|
66
|
+
"""
|
|
67
|
+
Return the address of the function 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_GetFunctionAddress(self, name.encode("ascii"))
|
|
72
|
+
|
|
73
|
+
def get_global_value_address(self, name):
|
|
74
|
+
"""
|
|
75
|
+
Return the address of the global value named *name* as an integer.
|
|
76
|
+
|
|
77
|
+
It's a fatal error in LLVM if the symbol of *name* doesn't exist.
|
|
78
|
+
"""
|
|
79
|
+
return ffi.lib.LLVMPY_GetGlobalValueAddress(self, name.encode("ascii"))
|
|
80
|
+
|
|
81
|
+
def add_global_mapping(self, gv, addr):
|
|
82
|
+
ffi.lib.LLVMPY_AddGlobalMapping(self, gv, addr)
|
|
83
|
+
|
|
84
|
+
def add_module(self, module):
|
|
85
|
+
"""
|
|
86
|
+
Ownership of module is transferred to the execution engine
|
|
87
|
+
"""
|
|
88
|
+
if module in self._modules:
|
|
89
|
+
raise KeyError("module already added to this engine")
|
|
90
|
+
ffi.lib.LLVMPY_AddModule(self, module)
|
|
91
|
+
module._owned = True
|
|
92
|
+
self._modules.add(module)
|
|
93
|
+
|
|
94
|
+
def finalize_object(self):
|
|
95
|
+
"""
|
|
96
|
+
Make sure all modules owned by the execution engine are fully processed
|
|
97
|
+
and "usable" for execution.
|
|
98
|
+
"""
|
|
99
|
+
ffi.lib.LLVMPY_FinalizeObject(self)
|
|
100
|
+
|
|
101
|
+
def run_static_constructors(self):
|
|
102
|
+
"""
|
|
103
|
+
Run static constructors which initialize module-level static objects.
|
|
104
|
+
"""
|
|
105
|
+
ffi.lib.LLVMPY_RunStaticConstructors(self)
|
|
106
|
+
|
|
107
|
+
def run_static_destructors(self):
|
|
108
|
+
"""
|
|
109
|
+
Run static destructors which perform module-level cleanup of static
|
|
110
|
+
resources.
|
|
111
|
+
"""
|
|
112
|
+
ffi.lib.LLVMPY_RunStaticDestructors(self)
|
|
113
|
+
|
|
114
|
+
def remove_module(self, module):
|
|
115
|
+
"""
|
|
116
|
+
Ownership of module is returned
|
|
117
|
+
"""
|
|
118
|
+
with ffi.OutputString() as outerr:
|
|
119
|
+
if ffi.lib.LLVMPY_RemoveModule(self, module, outerr):
|
|
120
|
+
raise RuntimeError(str(outerr))
|
|
121
|
+
self._modules.remove(module)
|
|
122
|
+
module._owned = False
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def target_data(self):
|
|
126
|
+
"""
|
|
127
|
+
The TargetData for this execution engine.
|
|
128
|
+
"""
|
|
129
|
+
if self._td is not None:
|
|
130
|
+
return self._td
|
|
131
|
+
ptr = ffi.lib.LLVMPY_GetExecutionEngineTargetData(self)
|
|
132
|
+
self._td = targets.TargetData(ptr)
|
|
133
|
+
self._td._owned = True
|
|
134
|
+
return self._td
|
|
135
|
+
|
|
136
|
+
def enable_jit_events(self):
|
|
137
|
+
"""
|
|
138
|
+
Enable JIT events for profiling of generated code.
|
|
139
|
+
Return value indicates whether connection to profiling tool
|
|
140
|
+
was successful.
|
|
141
|
+
"""
|
|
142
|
+
ret = ffi.lib.LLVMPY_EnableJITEvents(self)
|
|
143
|
+
return ret
|
|
144
|
+
|
|
145
|
+
def _find_module_ptr(self, module_ptr):
|
|
146
|
+
"""
|
|
147
|
+
Find the ModuleRef corresponding to the given pointer.
|
|
148
|
+
"""
|
|
149
|
+
ptr = cast(module_ptr, c_void_p).value
|
|
150
|
+
for module in self._modules:
|
|
151
|
+
if cast(module._ptr, c_void_p).value == ptr:
|
|
152
|
+
return module
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
def add_object_file(self, obj_file):
|
|
156
|
+
"""
|
|
157
|
+
Add object file to the jit. object_file can be instance of
|
|
158
|
+
:class:ObjectFile or a string representing file system path
|
|
159
|
+
"""
|
|
160
|
+
if isinstance(obj_file, str):
|
|
161
|
+
obj_file = object_file.ObjectFileRef.from_path(obj_file)
|
|
162
|
+
|
|
163
|
+
ffi.lib.LLVMPY_MCJITAddObjectFile(self, obj_file)
|
|
164
|
+
|
|
165
|
+
def set_object_cache(self, notify_func=None, getbuffer_func=None):
|
|
166
|
+
"""
|
|
167
|
+
Set the object cache "notifyObjectCompiled" and "getBuffer"
|
|
168
|
+
callbacks to the given Python functions.
|
|
169
|
+
"""
|
|
170
|
+
self._object_cache_notify = notify_func
|
|
171
|
+
self._object_cache_getbuffer = getbuffer_func
|
|
172
|
+
# Lifetime of the object cache is managed by us.
|
|
173
|
+
self._object_cache = _ObjectCacheRef(self)
|
|
174
|
+
# Note this doesn't keep a reference to self, to avoid reference
|
|
175
|
+
# cycles.
|
|
176
|
+
ffi.lib.LLVMPY_SetObjectCache(self, self._object_cache)
|
|
177
|
+
|
|
178
|
+
def _raw_object_cache_notify(self, data):
|
|
179
|
+
"""
|
|
180
|
+
Low-level notify hook.
|
|
181
|
+
"""
|
|
182
|
+
if self._object_cache_notify is None:
|
|
183
|
+
return
|
|
184
|
+
module_ptr = data.contents.module_ptr
|
|
185
|
+
buf_ptr = data.contents.buf_ptr
|
|
186
|
+
buf_len = data.contents.buf_len
|
|
187
|
+
buf = string_at(buf_ptr, buf_len)
|
|
188
|
+
module = self._find_module_ptr(module_ptr)
|
|
189
|
+
if module is None:
|
|
190
|
+
# The LLVM EE should only give notifications for modules
|
|
191
|
+
# known by us.
|
|
192
|
+
raise RuntimeError("object compilation notification "
|
|
193
|
+
"for unknown module %s" % (module_ptr,))
|
|
194
|
+
self._object_cache_notify(module, buf)
|
|
195
|
+
|
|
196
|
+
def _raw_object_cache_getbuffer(self, data):
|
|
197
|
+
"""
|
|
198
|
+
Low-level getbuffer hook.
|
|
199
|
+
"""
|
|
200
|
+
if self._object_cache_getbuffer is None:
|
|
201
|
+
return
|
|
202
|
+
module_ptr = data.contents.module_ptr
|
|
203
|
+
module = self._find_module_ptr(module_ptr)
|
|
204
|
+
if module is None:
|
|
205
|
+
# The LLVM EE should only give notifications for modules
|
|
206
|
+
# known by us.
|
|
207
|
+
raise RuntimeError("object compilation notification "
|
|
208
|
+
"for unknown module %s" % (module_ptr,))
|
|
209
|
+
|
|
210
|
+
buf = self._object_cache_getbuffer(module)
|
|
211
|
+
if buf is not None:
|
|
212
|
+
# Create a copy, which will be freed by the caller
|
|
213
|
+
data[0].buf_ptr = ffi.lib.LLVMPY_CreateByteString(buf, len(buf))
|
|
214
|
+
data[0].buf_len = len(buf)
|
|
215
|
+
|
|
216
|
+
def _dispose(self):
|
|
217
|
+
# The modules will be cleaned up by the EE
|
|
218
|
+
for mod in self._modules:
|
|
219
|
+
mod.detach()
|
|
220
|
+
if self._td is not None:
|
|
221
|
+
self._td.detach()
|
|
222
|
+
self._modules.clear()
|
|
223
|
+
self._object_cache = None
|
|
224
|
+
self._capi.LLVMPY_DisposeExecutionEngine(self)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class _ObjectCacheRef(ffi.ObjectRef):
|
|
228
|
+
"""
|
|
229
|
+
Internal: an ObjectCache instance for use within an ExecutionEngine.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
def __init__(self, obj):
|
|
233
|
+
ptr = ffi.lib.LLVMPY_CreateObjectCache(_notify_c_hook,
|
|
234
|
+
_getbuffer_c_hook,
|
|
235
|
+
obj)
|
|
236
|
+
ffi.ObjectRef.__init__(self, ptr)
|
|
237
|
+
|
|
238
|
+
def _dispose(self):
|
|
239
|
+
self._capi.LLVMPY_DisposeObjectCache(self)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# ============================================================================
|
|
243
|
+
# FFI
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
ffi.lib.LLVMPY_CreateMCJITCompiler.argtypes = [
|
|
247
|
+
ffi.LLVMModuleRef,
|
|
248
|
+
ffi.LLVMTargetMachineRef,
|
|
249
|
+
c_bool,
|
|
250
|
+
POINTER(c_char_p),
|
|
251
|
+
]
|
|
252
|
+
ffi.lib.LLVMPY_CreateMCJITCompiler.restype = ffi.LLVMExecutionEngineRef
|
|
253
|
+
|
|
254
|
+
ffi.lib.LLVMPY_RemoveModule.argtypes = [
|
|
255
|
+
ffi.LLVMExecutionEngineRef,
|
|
256
|
+
ffi.LLVMModuleRef,
|
|
257
|
+
POINTER(c_char_p),
|
|
258
|
+
]
|
|
259
|
+
ffi.lib.LLVMPY_RemoveModule.restype = c_bool
|
|
260
|
+
|
|
261
|
+
ffi.lib.LLVMPY_AddModule.argtypes = [
|
|
262
|
+
ffi.LLVMExecutionEngineRef,
|
|
263
|
+
ffi.LLVMModuleRef
|
|
264
|
+
]
|
|
265
|
+
|
|
266
|
+
ffi.lib.LLVMPY_AddGlobalMapping.argtypes = [ffi.LLVMExecutionEngineRef,
|
|
267
|
+
ffi.LLVMValueRef,
|
|
268
|
+
c_void_p]
|
|
269
|
+
|
|
270
|
+
ffi.lib.LLVMPY_FinalizeObject.argtypes = [ffi.LLVMExecutionEngineRef]
|
|
271
|
+
|
|
272
|
+
ffi.lib.LLVMPY_GetExecutionEngineTargetData.argtypes = [
|
|
273
|
+
ffi.LLVMExecutionEngineRef
|
|
274
|
+
]
|
|
275
|
+
ffi.lib.LLVMPY_GetExecutionEngineTargetData.restype = ffi.LLVMTargetDataRef
|
|
276
|
+
|
|
277
|
+
ffi.lib.LLVMPY_TryAllocateExecutableMemory.argtypes = []
|
|
278
|
+
ffi.lib.LLVMPY_TryAllocateExecutableMemory.restype = c_int
|
|
279
|
+
|
|
280
|
+
ffi.lib.LLVMPY_GetFunctionAddress.argtypes = [
|
|
281
|
+
ffi.LLVMExecutionEngineRef,
|
|
282
|
+
c_char_p
|
|
283
|
+
]
|
|
284
|
+
ffi.lib.LLVMPY_GetFunctionAddress.restype = c_uint64
|
|
285
|
+
|
|
286
|
+
ffi.lib.LLVMPY_GetGlobalValueAddress.argtypes = [
|
|
287
|
+
ffi.LLVMExecutionEngineRef,
|
|
288
|
+
c_char_p
|
|
289
|
+
]
|
|
290
|
+
ffi.lib.LLVMPY_GetGlobalValueAddress.restype = c_uint64
|
|
291
|
+
|
|
292
|
+
ffi.lib.LLVMPY_MCJITAddObjectFile.argtypes = [
|
|
293
|
+
ffi.LLVMExecutionEngineRef,
|
|
294
|
+
ffi.LLVMObjectFileRef
|
|
295
|
+
]
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class _ObjectCacheData(Structure):
|
|
299
|
+
_fields_ = [
|
|
300
|
+
('module_ptr', ffi.LLVMModuleRef),
|
|
301
|
+
('buf_ptr', c_void_p),
|
|
302
|
+
('buf_len', c_size_t),
|
|
303
|
+
]
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
_ObjectCacheNotifyFunc = CFUNCTYPE(None, py_object,
|
|
307
|
+
POINTER(_ObjectCacheData))
|
|
308
|
+
_ObjectCacheGetBufferFunc = CFUNCTYPE(None, py_object,
|
|
309
|
+
POINTER(_ObjectCacheData))
|
|
310
|
+
|
|
311
|
+
# XXX The ctypes function wrappers are created at the top-level, otherwise
|
|
312
|
+
# there are issues when creating CFUNCTYPEs in child processes on CentOS 5
|
|
313
|
+
# 32 bits.
|
|
314
|
+
_notify_c_hook = _ObjectCacheNotifyFunc(
|
|
315
|
+
ExecutionEngine._raw_object_cache_notify)
|
|
316
|
+
_getbuffer_c_hook = _ObjectCacheGetBufferFunc(
|
|
317
|
+
ExecutionEngine._raw_object_cache_getbuffer)
|
|
318
|
+
|
|
319
|
+
ffi.lib.LLVMPY_CreateObjectCache.argtypes = [_ObjectCacheNotifyFunc,
|
|
320
|
+
_ObjectCacheGetBufferFunc,
|
|
321
|
+
py_object]
|
|
322
|
+
ffi.lib.LLVMPY_CreateObjectCache.restype = ffi.LLVMObjectCacheRef
|
|
323
|
+
|
|
324
|
+
ffi.lib.LLVMPY_DisposeObjectCache.argtypes = [ffi.LLVMObjectCacheRef]
|
|
325
|
+
|
|
326
|
+
ffi.lib.LLVMPY_SetObjectCache.argtypes = [ffi.LLVMExecutionEngineRef,
|
|
327
|
+
ffi.LLVMObjectCacheRef]
|
|
328
|
+
|
|
329
|
+
ffi.lib.LLVMPY_CreateByteString.restype = c_void_p
|
|
330
|
+
ffi.lib.LLVMPY_CreateByteString.argtypes = [c_void_p, c_size_t]
|