|
from ctypes import (c_char_p, byref, POINTER, c_bool, create_string_buffer, |
|
c_size_t, string_at) |
|
|
|
from llvmlite.binding import ffi |
|
from llvmlite.binding.linker import link_modules |
|
from llvmlite.binding.common import _decode_string, _encode_string |
|
from llvmlite.binding.value import ValueRef, TypeRef |
|
from llvmlite.binding.context import get_global_context |
|
|
|
|
|
def parse_assembly(llvmir, context=None): |
|
""" |
|
Create Module from a LLVM IR string |
|
""" |
|
if context is None: |
|
context = get_global_context() |
|
llvmir = _encode_string(llvmir) |
|
strbuf = c_char_p(llvmir) |
|
with ffi.OutputString() as errmsg: |
|
mod = ModuleRef( |
|
ffi.lib.LLVMPY_ParseAssembly(context, strbuf, errmsg), |
|
context) |
|
if errmsg: |
|
mod.close() |
|
raise RuntimeError("LLVM IR parsing error\n{0}".format(errmsg)) |
|
return mod |
|
|
|
|
|
def parse_bitcode(bitcode, context=None): |
|
""" |
|
Create Module from a LLVM *bitcode* (a bytes object). |
|
""" |
|
if context is None: |
|
context = get_global_context() |
|
buf = c_char_p(bitcode) |
|
bufsize = len(bitcode) |
|
with ffi.OutputString() as errmsg: |
|
mod = ModuleRef(ffi.lib.LLVMPY_ParseBitcode( |
|
context, buf, bufsize, errmsg), context) |
|
if errmsg: |
|
mod.close() |
|
raise RuntimeError( |
|
"LLVM bitcode parsing error\n{0}".format(errmsg)) |
|
return mod |
|
|
|
|
|
class ModuleRef(ffi.ObjectRef): |
|
""" |
|
A reference to a LLVM module. |
|
""" |
|
|
|
def __init__(self, module_ptr, context): |
|
super(ModuleRef, self).__init__(module_ptr) |
|
self._context = context |
|
|
|
def __str__(self): |
|
with ffi.OutputString() as outstr: |
|
ffi.lib.LLVMPY_PrintModuleToString(self, outstr) |
|
return str(outstr) |
|
|
|
def as_bitcode(self): |
|
""" |
|
Return the module's LLVM bitcode, as a bytes object. |
|
""" |
|
ptr = c_char_p(None) |
|
size = c_size_t(-1) |
|
ffi.lib.LLVMPY_WriteBitcodeToString(self, byref(ptr), byref(size)) |
|
if not ptr: |
|
raise MemoryError |
|
try: |
|
assert size.value >= 0 |
|
return string_at(ptr, size.value) |
|
finally: |
|
ffi.lib.LLVMPY_DisposeString(ptr) |
|
|
|
def _dispose(self): |
|
self._capi.LLVMPY_DisposeModule(self) |
|
|
|
def get_function(self, name): |
|
""" |
|
Get a ValueRef pointing to the function named *name*. |
|
NameError is raised if the symbol isn't found. |
|
""" |
|
p = ffi.lib.LLVMPY_GetNamedFunction(self, _encode_string(name)) |
|
if not p: |
|
raise NameError(name) |
|
return ValueRef(p, 'function', dict(module=self)) |
|
|
|
def get_global_variable(self, name): |
|
""" |
|
Get a ValueRef pointing to the global variable named *name*. |
|
NameError is raised if the symbol isn't found. |
|
""" |
|
p = ffi.lib.LLVMPY_GetNamedGlobalVariable(self, _encode_string(name)) |
|
if not p: |
|
raise NameError(name) |
|
return ValueRef(p, 'global', dict(module=self)) |
|
|
|
def get_struct_type(self, name): |
|
""" |
|
Get a TypeRef pointing to a structure type named *name*. |
|
NameError is raised if the struct type isn't found. |
|
""" |
|
p = ffi.lib.LLVMPY_GetNamedStructType(self, _encode_string(name)) |
|
if not p: |
|
raise NameError(name) |
|
return TypeRef(p) |
|
|
|
def verify(self): |
|
""" |
|
Verify the module IR's correctness. RuntimeError is raised on error. |
|
""" |
|
with ffi.OutputString() as outmsg: |
|
if ffi.lib.LLVMPY_VerifyModule(self, outmsg): |
|
raise RuntimeError(str(outmsg)) |
|
|
|
@property |
|
def name(self): |
|
""" |
|
The module's identifier. |
|
""" |
|
return _decode_string(ffi.lib.LLVMPY_GetModuleName(self)) |
|
|
|
@name.setter |
|
def name(self, value): |
|
ffi.lib.LLVMPY_SetModuleName(self, _encode_string(value)) |
|
|
|
@property |
|
def source_file(self): |
|
""" |
|
The module's original source file name |
|
""" |
|
return _decode_string(ffi.lib.LLVMPY_GetModuleSourceFileName(self)) |
|
|
|
@property |
|
def data_layout(self): |
|
""" |
|
This module's data layout specification, as a string. |
|
""" |
|
|
|
with ffi.OutputString(owned=False) as outmsg: |
|
ffi.lib.LLVMPY_GetDataLayout(self, outmsg) |
|
return str(outmsg) |
|
|
|
@data_layout.setter |
|
def data_layout(self, strrep): |
|
ffi.lib.LLVMPY_SetDataLayout(self, |
|
create_string_buffer( |
|
strrep.encode('utf8'))) |
|
|
|
@property |
|
def triple(self): |
|
""" |
|
This module's target "triple" specification, as a string. |
|
""" |
|
|
|
with ffi.OutputString(owned=False) as outmsg: |
|
ffi.lib.LLVMPY_GetTarget(self, outmsg) |
|
return str(outmsg) |
|
|
|
@triple.setter |
|
def triple(self, strrep): |
|
ffi.lib.LLVMPY_SetTarget(self, |
|
create_string_buffer( |
|
strrep.encode('utf8'))) |
|
|
|
def link_in(self, other, preserve=False): |
|
""" |
|
Link the *other* module into this one. The *other* module will |
|
be destroyed unless *preserve* is true. |
|
""" |
|
if preserve: |
|
other = other.clone() |
|
link_modules(self, other) |
|
|
|
@property |
|
def global_variables(self): |
|
""" |
|
Return an iterator over this module's global variables. |
|
The iterator will yield a ValueRef for each global variable. |
|
|
|
Note that global variables don't include functions |
|
(a function is a "global value" but not a "global variable" in |
|
LLVM parlance) |
|
""" |
|
it = ffi.lib.LLVMPY_ModuleGlobalsIter(self) |
|
return _GlobalsIterator(it, dict(module=self)) |
|
|
|
@property |
|
def functions(self): |
|
""" |
|
Return an iterator over this module's functions. |
|
The iterator will yield a ValueRef for each function. |
|
""" |
|
it = ffi.lib.LLVMPY_ModuleFunctionsIter(self) |
|
return _FunctionsIterator(it, dict(module=self)) |
|
|
|
@property |
|
def struct_types(self): |
|
""" |
|
Return an iterator over the struct types defined in |
|
the module. The iterator will yield a TypeRef. |
|
""" |
|
it = ffi.lib.LLVMPY_ModuleTypesIter(self) |
|
return _TypesIterator(it, dict(module=self)) |
|
|
|
def clone(self): |
|
return ModuleRef(ffi.lib.LLVMPY_CloneModule(self), self._context) |
|
|
|
|
|
class _Iterator(ffi.ObjectRef): |
|
|
|
kind = None |
|
|
|
def __init__(self, ptr, parents): |
|
ffi.ObjectRef.__init__(self, ptr) |
|
self._parents = parents |
|
assert self.kind is not None |
|
|
|
def __next__(self): |
|
vp = self._next() |
|
if vp: |
|
return ValueRef(vp, self.kind, self._parents) |
|
else: |
|
raise StopIteration |
|
|
|
next = __next__ |
|
|
|
def __iter__(self): |
|
return self |
|
|
|
|
|
class _GlobalsIterator(_Iterator): |
|
|
|
kind = 'global' |
|
|
|
def _dispose(self): |
|
self._capi.LLVMPY_DisposeGlobalsIter(self) |
|
|
|
def _next(self): |
|
return ffi.lib.LLVMPY_GlobalsIterNext(self) |
|
|
|
|
|
class _FunctionsIterator(_Iterator): |
|
|
|
kind = 'function' |
|
|
|
def _dispose(self): |
|
self._capi.LLVMPY_DisposeFunctionsIter(self) |
|
|
|
def _next(self): |
|
return ffi.lib.LLVMPY_FunctionsIterNext(self) |
|
|
|
|
|
class _TypesIterator(_Iterator): |
|
|
|
kind = 'type' |
|
|
|
def _dispose(self): |
|
self._capi.LLVMPY_DisposeTypesIter(self) |
|
|
|
def __next__(self): |
|
vp = self._next() |
|
if vp: |
|
return TypeRef(vp) |
|
else: |
|
raise StopIteration |
|
|
|
def _next(self): |
|
return ffi.lib.LLVMPY_TypesIterNext(self) |
|
|
|
next = __next__ |
|
|
|
|
|
|
|
|
|
|
|
ffi.lib.LLVMPY_ParseAssembly.argtypes = [ffi.LLVMContextRef, |
|
c_char_p, |
|
POINTER(c_char_p)] |
|
ffi.lib.LLVMPY_ParseAssembly.restype = ffi.LLVMModuleRef |
|
|
|
ffi.lib.LLVMPY_ParseBitcode.argtypes = [ffi.LLVMContextRef, |
|
c_char_p, c_size_t, |
|
POINTER(c_char_p)] |
|
ffi.lib.LLVMPY_ParseBitcode.restype = ffi.LLVMModuleRef |
|
|
|
ffi.lib.LLVMPY_DisposeModule.argtypes = [ffi.LLVMModuleRef] |
|
|
|
ffi.lib.LLVMPY_PrintModuleToString.argtypes = [ffi.LLVMModuleRef, |
|
POINTER(c_char_p)] |
|
ffi.lib.LLVMPY_WriteBitcodeToString.argtypes = [ffi.LLVMModuleRef, |
|
POINTER(c_char_p), |
|
POINTER(c_size_t)] |
|
|
|
ffi.lib.LLVMPY_GetNamedFunction.argtypes = [ffi.LLVMModuleRef, |
|
c_char_p] |
|
ffi.lib.LLVMPY_GetNamedFunction.restype = ffi.LLVMValueRef |
|
|
|
ffi.lib.LLVMPY_VerifyModule.argtypes = [ffi.LLVMModuleRef, |
|
POINTER(c_char_p)] |
|
ffi.lib.LLVMPY_VerifyModule.restype = c_bool |
|
|
|
ffi.lib.LLVMPY_GetDataLayout.argtypes = [ffi.LLVMModuleRef, POINTER(c_char_p)] |
|
ffi.lib.LLVMPY_SetDataLayout.argtypes = [ffi.LLVMModuleRef, c_char_p] |
|
|
|
ffi.lib.LLVMPY_GetTarget.argtypes = [ffi.LLVMModuleRef, POINTER(c_char_p)] |
|
ffi.lib.LLVMPY_SetTarget.argtypes = [ffi.LLVMModuleRef, c_char_p] |
|
|
|
ffi.lib.LLVMPY_GetNamedGlobalVariable.argtypes = [ffi.LLVMModuleRef, c_char_p] |
|
ffi.lib.LLVMPY_GetNamedGlobalVariable.restype = ffi.LLVMValueRef |
|
|
|
ffi.lib.LLVMPY_GetNamedStructType.argtypes = [ffi.LLVMModuleRef, c_char_p] |
|
ffi.lib.LLVMPY_GetNamedStructType.restype = ffi.LLVMTypeRef |
|
|
|
ffi.lib.LLVMPY_ModuleGlobalsIter.argtypes = [ffi.LLVMModuleRef] |
|
ffi.lib.LLVMPY_ModuleGlobalsIter.restype = ffi.LLVMGlobalsIterator |
|
|
|
ffi.lib.LLVMPY_DisposeGlobalsIter.argtypes = [ffi.LLVMGlobalsIterator] |
|
|
|
ffi.lib.LLVMPY_GlobalsIterNext.argtypes = [ffi.LLVMGlobalsIterator] |
|
ffi.lib.LLVMPY_GlobalsIterNext.restype = ffi.LLVMValueRef |
|
|
|
ffi.lib.LLVMPY_ModuleFunctionsIter.argtypes = [ffi.LLVMModuleRef] |
|
ffi.lib.LLVMPY_ModuleFunctionsIter.restype = ffi.LLVMFunctionsIterator |
|
|
|
ffi.lib.LLVMPY_ModuleTypesIter.argtypes = [ffi.LLVMModuleRef] |
|
ffi.lib.LLVMPY_ModuleTypesIter.restype = ffi.LLVMTypesIterator |
|
|
|
ffi.lib.LLVMPY_DisposeFunctionsIter.argtypes = [ffi.LLVMFunctionsIterator] |
|
|
|
ffi.lib.LLVMPY_DisposeTypesIter.argtypes = [ffi.LLVMTypesIterator] |
|
|
|
ffi.lib.LLVMPY_FunctionsIterNext.argtypes = [ffi.LLVMFunctionsIterator] |
|
ffi.lib.LLVMPY_FunctionsIterNext.restype = ffi.LLVMValueRef |
|
|
|
ffi.lib.LLVMPY_TypesIterNext.argtypes = [ffi.LLVMTypesIterator] |
|
ffi.lib.LLVMPY_TypesIterNext.restype = ffi.LLVMTypeRef |
|
|
|
ffi.lib.LLVMPY_CloneModule.argtypes = [ffi.LLVMModuleRef] |
|
ffi.lib.LLVMPY_CloneModule.restype = ffi.LLVMModuleRef |
|
|
|
ffi.lib.LLVMPY_GetModuleName.argtypes = [ffi.LLVMModuleRef] |
|
ffi.lib.LLVMPY_GetModuleName.restype = c_char_p |
|
|
|
ffi.lib.LLVMPY_SetModuleName.argtypes = [ffi.LLVMModuleRef, c_char_p] |
|
|
|
ffi.lib.LLVMPY_GetModuleSourceFileName.argtypes = [ffi.LLVMModuleRef] |
|
ffi.lib.LLVMPY_GetModuleSourceFileName.restype = c_char_p |
|
|