641 lines
18 KiB
Python
641 lines
18 KiB
Python
#===- core.py - Python LLVM Bindings -------------------------*- python -*--===#
|
|
#
|
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
# See https://llvm.org/LICENSE.txt for license information.
|
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
#
|
|
#===------------------------------------------------------------------------===#
|
|
from __future__ import print_function
|
|
|
|
from .common import LLVMObject
|
|
from .common import c_object_p
|
|
from .common import get_library
|
|
|
|
from . import enumerations
|
|
|
|
from ctypes import POINTER
|
|
from ctypes import byref
|
|
from ctypes import c_char_p
|
|
from ctypes import c_uint
|
|
|
|
import sys
|
|
|
|
__all__ = [
|
|
"lib",
|
|
"Enums",
|
|
"OpCode",
|
|
"MemoryBuffer",
|
|
"Module",
|
|
"Value",
|
|
"Function",
|
|
"BasicBlock",
|
|
"Instruction",
|
|
"Context",
|
|
"PassRegistry"
|
|
]
|
|
|
|
lib = get_library()
|
|
Enums = []
|
|
|
|
class LLVMEnumeration(object):
|
|
"""Represents an individual LLVM enumeration."""
|
|
|
|
def __init__(self, name, value):
|
|
self.name = name
|
|
self.value = value
|
|
|
|
def __repr__(self):
|
|
return '%s.%s' % (self.__class__.__name__,
|
|
self.name)
|
|
|
|
@classmethod
|
|
def from_value(cls, value):
|
|
"""Obtain an enumeration instance from a numeric value."""
|
|
result = cls._value_map.get(value, None)
|
|
|
|
if result is None:
|
|
raise ValueError('Unknown %s: %d' % (cls.__name__,
|
|
value))
|
|
|
|
return result
|
|
|
|
@classmethod
|
|
def register(cls, name, value):
|
|
"""Registers a new enumeration.
|
|
|
|
This is called by this module for each enumeration defined in
|
|
enumerations. You should not need to call this outside this module.
|
|
"""
|
|
if value in cls._value_map:
|
|
raise ValueError('%s value already registered: %d' % (cls.__name__,
|
|
value))
|
|
enum = cls(name, value)
|
|
cls._value_map[value] = enum
|
|
setattr(cls, name, enum)
|
|
|
|
class Attribute(LLVMEnumeration):
|
|
"""Represents an individual Attribute enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(Attribute, self).__init__(name, value)
|
|
|
|
class OpCode(LLVMEnumeration):
|
|
"""Represents an individual OpCode enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(OpCode, self).__init__(name, value)
|
|
|
|
class TypeKind(LLVMEnumeration):
|
|
"""Represents an individual TypeKind enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(TypeKind, self).__init__(name, value)
|
|
|
|
class Linkage(LLVMEnumeration):
|
|
"""Represents an individual Linkage enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(Linkage, self).__init__(name, value)
|
|
|
|
class Visibility(LLVMEnumeration):
|
|
"""Represents an individual visibility enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(Visibility, self).__init__(name, value)
|
|
|
|
class CallConv(LLVMEnumeration):
|
|
"""Represents an individual calling convention enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(CallConv, self).__init__(name, value)
|
|
|
|
class IntPredicate(LLVMEnumeration):
|
|
"""Represents an individual IntPredicate enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(IntPredicate, self).__init__(name, value)
|
|
|
|
class RealPredicate(LLVMEnumeration):
|
|
"""Represents an individual RealPredicate enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(RealPredicate, self).__init__(name, value)
|
|
|
|
class LandingPadClauseTy(LLVMEnumeration):
|
|
"""Represents an individual LandingPadClauseTy enumeration."""
|
|
|
|
_value_map = {}
|
|
|
|
def __init__(self, name, value):
|
|
super(LandingPadClauseTy, self).__init__(name, value)
|
|
|
|
class MemoryBuffer(LLVMObject):
|
|
"""Represents an opaque memory buffer."""
|
|
|
|
def __init__(self, filename=None):
|
|
"""Create a new memory buffer.
|
|
|
|
Currently, we support creating from the contents of a file at the
|
|
specified filename.
|
|
"""
|
|
if filename is None:
|
|
raise Exception("filename argument must be defined")
|
|
|
|
memory = c_object_p()
|
|
out = c_char_p(None)
|
|
|
|
result = lib.LLVMCreateMemoryBufferWithContentsOfFile(filename,
|
|
byref(memory), byref(out))
|
|
|
|
if result:
|
|
raise Exception("Could not create memory buffer: %s" % out.value)
|
|
|
|
LLVMObject.__init__(self, memory, disposer=lib.LLVMDisposeMemoryBuffer)
|
|
|
|
def __len__(self):
|
|
return lib.LLVMGetBufferSize(self)
|
|
|
|
class Value(LLVMObject):
|
|
|
|
def __init__(self, value):
|
|
LLVMObject.__init__(self, value)
|
|
|
|
@property
|
|
def name(self):
|
|
return lib.LLVMGetValueName(self)
|
|
|
|
def dump(self):
|
|
lib.LLVMDumpValue(self)
|
|
|
|
def get_operand(self, i):
|
|
return Value(lib.LLVMGetOperand(self, i))
|
|
|
|
def set_operand(self, i, v):
|
|
return lib.LLVMSetOperand(self, i, v)
|
|
|
|
def __len__(self):
|
|
return lib.LLVMGetNumOperands(self)
|
|
|
|
class Module(LLVMObject):
|
|
"""Represents the top-level structure of an llvm program in an opaque object."""
|
|
|
|
def __init__(self, module, name=None, context=None):
|
|
LLVMObject.__init__(self, module, disposer=lib.LLVMDisposeModule)
|
|
|
|
@classmethod
|
|
def CreateWithName(cls, module_id):
|
|
m = Module(lib.LLVMModuleCreateWithName(module_id))
|
|
Context.GetGlobalContext().take_ownership(m)
|
|
return m
|
|
|
|
@property
|
|
def datalayout(self):
|
|
return lib.LLVMGetDataLayout(self)
|
|
|
|
@datalayout.setter
|
|
def datalayout(self, new_data_layout):
|
|
"""new_data_layout is a string."""
|
|
lib.LLVMSetDataLayout(self, new_data_layout)
|
|
|
|
@property
|
|
def target(self):
|
|
return lib.LLVMGetTarget(self)
|
|
|
|
@target.setter
|
|
def target(self, new_target):
|
|
"""new_target is a string."""
|
|
lib.LLVMSetTarget(self, new_target)
|
|
|
|
def dump(self):
|
|
lib.LLVMDumpModule(self)
|
|
|
|
class __function_iterator(object):
|
|
def __init__(self, module, reverse=False):
|
|
self.module = module
|
|
self.reverse = reverse
|
|
if self.reverse:
|
|
self.function = self.module.last
|
|
else:
|
|
self.function = self.module.first
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
if not isinstance(self.function, Function):
|
|
raise StopIteration("")
|
|
result = self.function
|
|
if self.reverse:
|
|
self.function = self.function.prev
|
|
else:
|
|
self.function = self.function.next
|
|
return result
|
|
|
|
if sys.version_info.major == 2:
|
|
next = __next__
|
|
|
|
def __iter__(self):
|
|
return Module.__function_iterator(self)
|
|
|
|
def __reversed__(self):
|
|
return Module.__function_iterator(self, reverse=True)
|
|
|
|
@property
|
|
def first(self):
|
|
return Function(lib.LLVMGetFirstFunction(self))
|
|
|
|
@property
|
|
def last(self):
|
|
return Function(lib.LLVMGetLastFunction(self))
|
|
|
|
def print_module_to_file(self, filename):
|
|
out = c_char_p(None)
|
|
# Result is inverted so 0 means everything was ok.
|
|
result = lib.LLVMPrintModuleToFile(self, filename, byref(out))
|
|
if result:
|
|
raise RuntimeError("LLVM Error: %s" % out.value)
|
|
|
|
class Function(Value):
|
|
|
|
def __init__(self, value):
|
|
Value.__init__(self, value)
|
|
|
|
@property
|
|
def next(self):
|
|
f = lib.LLVMGetNextFunction(self)
|
|
return f and Function(f)
|
|
|
|
@property
|
|
def prev(self):
|
|
f = lib.LLVMGetPreviousFunction(self)
|
|
return f and Function(f)
|
|
|
|
@property
|
|
def first(self):
|
|
b = lib.LLVMGetFirstBasicBlock(self)
|
|
return b and BasicBlock(b)
|
|
|
|
@property
|
|
def last(self):
|
|
b = lib.LLVMGetLastBasicBlock(self)
|
|
return b and BasicBlock(b)
|
|
|
|
class __bb_iterator(object):
|
|
def __init__(self, function, reverse=False):
|
|
self.function = function
|
|
self.reverse = reverse
|
|
if self.reverse:
|
|
self.bb = function.last
|
|
else:
|
|
self.bb = function.first
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
if not isinstance(self.bb, BasicBlock):
|
|
raise StopIteration("")
|
|
result = self.bb
|
|
if self.reverse:
|
|
self.bb = self.bb.prev
|
|
else:
|
|
self.bb = self.bb.next
|
|
return result
|
|
|
|
if sys.version_info.major == 2:
|
|
next = __next__
|
|
|
|
def __iter__(self):
|
|
return Function.__bb_iterator(self)
|
|
|
|
def __reversed__(self):
|
|
return Function.__bb_iterator(self, reverse=True)
|
|
|
|
def __len__(self):
|
|
return lib.LLVMCountBasicBlocks(self)
|
|
|
|
class BasicBlock(LLVMObject):
|
|
|
|
def __init__(self, value):
|
|
LLVMObject.__init__(self, value)
|
|
|
|
@property
|
|
def next(self):
|
|
b = lib.LLVMGetNextBasicBlock(self)
|
|
return b and BasicBlock(b)
|
|
|
|
@property
|
|
def prev(self):
|
|
b = lib.LLVMGetPreviousBasicBlock(self)
|
|
return b and BasicBlock(b)
|
|
|
|
@property
|
|
def first(self):
|
|
i = lib.LLVMGetFirstInstruction(self)
|
|
return i and Instruction(i)
|
|
|
|
@property
|
|
def last(self):
|
|
i = lib.LLVMGetLastInstruction(self)
|
|
return i and Instruction(i)
|
|
|
|
def __as_value(self):
|
|
return Value(lib.LLVMBasicBlockAsValue(self))
|
|
|
|
@property
|
|
def name(self):
|
|
return lib.LLVMGetValueName(self.__as_value())
|
|
|
|
def dump(self):
|
|
lib.LLVMDumpValue(self.__as_value())
|
|
|
|
def get_operand(self, i):
|
|
return Value(lib.LLVMGetOperand(self.__as_value(),
|
|
i))
|
|
|
|
def set_operand(self, i, v):
|
|
return lib.LLVMSetOperand(self.__as_value(),
|
|
i, v)
|
|
|
|
def __len__(self):
|
|
return lib.LLVMGetNumOperands(self.__as_value())
|
|
|
|
class __inst_iterator(object):
|
|
def __init__(self, bb, reverse=False):
|
|
self.bb = bb
|
|
self.reverse = reverse
|
|
if self.reverse:
|
|
self.inst = self.bb.last
|
|
else:
|
|
self.inst = self.bb.first
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
if not isinstance(self.inst, Instruction):
|
|
raise StopIteration("")
|
|
result = self.inst
|
|
if self.reverse:
|
|
self.inst = self.inst.prev
|
|
else:
|
|
self.inst = self.inst.next
|
|
return result
|
|
|
|
if sys.version_info.major == 2:
|
|
next = __next__
|
|
|
|
def __iter__(self):
|
|
return BasicBlock.__inst_iterator(self)
|
|
|
|
def __reversed__(self):
|
|
return BasicBlock.__inst_iterator(self, reverse=True)
|
|
|
|
|
|
class Instruction(Value):
|
|
|
|
def __init__(self, value):
|
|
Value.__init__(self, value)
|
|
|
|
@property
|
|
def next(self):
|
|
i = lib.LLVMGetNextInstruction(self)
|
|
return i and Instruction(i)
|
|
|
|
@property
|
|
def prev(self):
|
|
i = lib.LLVMGetPreviousInstruction(self)
|
|
return i and Instruction(i)
|
|
|
|
@property
|
|
def opcode(self):
|
|
return OpCode.from_value(lib.LLVMGetInstructionOpcode(self))
|
|
|
|
class Context(LLVMObject):
|
|
|
|
def __init__(self, context=None):
|
|
if context is None:
|
|
context = lib.LLVMContextCreate()
|
|
LLVMObject.__init__(self, context, disposer=lib.LLVMContextDispose)
|
|
else:
|
|
LLVMObject.__init__(self, context)
|
|
|
|
@classmethod
|
|
def GetGlobalContext(cls):
|
|
return Context(lib.LLVMGetGlobalContext())
|
|
|
|
class PassRegistry(LLVMObject):
|
|
"""Represents an opaque pass registry object."""
|
|
|
|
def __init__(self):
|
|
LLVMObject.__init__(self,
|
|
lib.LLVMGetGlobalPassRegistry())
|
|
|
|
def register_library(library):
|
|
# Initialization/Shutdown declarations.
|
|
library.LLVMInitializeCore.argtypes = [PassRegistry]
|
|
library.LLVMInitializeCore.restype = None
|
|
|
|
library.LLVMInitializeTransformUtils.argtypes = [PassRegistry]
|
|
library.LLVMInitializeTransformUtils.restype = None
|
|
|
|
library.LLVMInitializeScalarOpts.argtypes = [PassRegistry]
|
|
library.LLVMInitializeScalarOpts.restype = None
|
|
|
|
library.LLVMInitializeObjCARCOpts.argtypes = [PassRegistry]
|
|
library.LLVMInitializeObjCARCOpts.restype = None
|
|
|
|
library.LLVMInitializeVectorization.argtypes = [PassRegistry]
|
|
library.LLVMInitializeVectorization.restype = None
|
|
|
|
library.LLVMInitializeInstCombine.argtypes = [PassRegistry]
|
|
library.LLVMInitializeInstCombine.restype = None
|
|
|
|
library.LLVMInitializeAggressiveInstCombiner.argtypes = [PassRegistry]
|
|
library.LLVMInitializeAggressiveInstCombiner.restype = None
|
|
|
|
library.LLVMInitializeIPO.argtypes = [PassRegistry]
|
|
library.LLVMInitializeIPO.restype = None
|
|
|
|
library.LLVMInitializeInstrumentation.argtypes = [PassRegistry]
|
|
library.LLVMInitializeInstrumentation.restype = None
|
|
|
|
library.LLVMInitializeAnalysis.argtypes = [PassRegistry]
|
|
library.LLVMInitializeAnalysis.restype = None
|
|
|
|
library.LLVMInitializeCodeGen.argtypes = [PassRegistry]
|
|
library.LLVMInitializeCodeGen.restype = None
|
|
|
|
library.LLVMInitializeTarget.argtypes = [PassRegistry]
|
|
library.LLVMInitializeTarget.restype = None
|
|
|
|
library.LLVMShutdown.argtypes = []
|
|
library.LLVMShutdown.restype = None
|
|
|
|
# Pass Registry declarations.
|
|
library.LLVMGetGlobalPassRegistry.argtypes = []
|
|
library.LLVMGetGlobalPassRegistry.restype = c_object_p
|
|
|
|
# Context declarations.
|
|
library.LLVMContextCreate.argtypes = []
|
|
library.LLVMContextCreate.restype = c_object_p
|
|
|
|
library.LLVMContextDispose.argtypes = [Context]
|
|
library.LLVMContextDispose.restype = None
|
|
|
|
library.LLVMGetGlobalContext.argtypes = []
|
|
library.LLVMGetGlobalContext.restype = c_object_p
|
|
|
|
# Memory buffer declarations
|
|
library.LLVMCreateMemoryBufferWithContentsOfFile.argtypes = [c_char_p,
|
|
POINTER(c_object_p), POINTER(c_char_p)]
|
|
library.LLVMCreateMemoryBufferWithContentsOfFile.restype = bool
|
|
|
|
library.LLVMGetBufferSize.argtypes = [MemoryBuffer]
|
|
|
|
library.LLVMDisposeMemoryBuffer.argtypes = [MemoryBuffer]
|
|
|
|
# Module declarations
|
|
library.LLVMModuleCreateWithName.argtypes = [c_char_p]
|
|
library.LLVMModuleCreateWithName.restype = c_object_p
|
|
|
|
library.LLVMDisposeModule.argtypes = [Module]
|
|
library.LLVMDisposeModule.restype = None
|
|
|
|
library.LLVMGetDataLayout.argtypes = [Module]
|
|
library.LLVMGetDataLayout.restype = c_char_p
|
|
|
|
library.LLVMSetDataLayout.argtypes = [Module, c_char_p]
|
|
library.LLVMSetDataLayout.restype = None
|
|
|
|
library.LLVMGetTarget.argtypes = [Module]
|
|
library.LLVMGetTarget.restype = c_char_p
|
|
|
|
library.LLVMSetTarget.argtypes = [Module, c_char_p]
|
|
library.LLVMSetTarget.restype = None
|
|
|
|
library.LLVMDumpModule.argtypes = [Module]
|
|
library.LLVMDumpModule.restype = None
|
|
|
|
library.LLVMPrintModuleToFile.argtypes = [Module, c_char_p,
|
|
POINTER(c_char_p)]
|
|
library.LLVMPrintModuleToFile.restype = bool
|
|
|
|
library.LLVMGetFirstFunction.argtypes = [Module]
|
|
library.LLVMGetFirstFunction.restype = c_object_p
|
|
|
|
library.LLVMGetLastFunction.argtypes = [Module]
|
|
library.LLVMGetLastFunction.restype = c_object_p
|
|
|
|
library.LLVMGetNextFunction.argtypes = [Function]
|
|
library.LLVMGetNextFunction.restype = c_object_p
|
|
|
|
library.LLVMGetPreviousFunction.argtypes = [Function]
|
|
library.LLVMGetPreviousFunction.restype = c_object_p
|
|
|
|
# Value declarations.
|
|
library.LLVMGetValueName.argtypes = [Value]
|
|
library.LLVMGetValueName.restype = c_char_p
|
|
|
|
library.LLVMDumpValue.argtypes = [Value]
|
|
library.LLVMDumpValue.restype = None
|
|
|
|
library.LLVMGetOperand.argtypes = [Value, c_uint]
|
|
library.LLVMGetOperand.restype = c_object_p
|
|
|
|
library.LLVMSetOperand.argtypes = [Value, Value, c_uint]
|
|
library.LLVMSetOperand.restype = None
|
|
|
|
library.LLVMGetNumOperands.argtypes = [Value]
|
|
library.LLVMGetNumOperands.restype = c_uint
|
|
|
|
# Basic Block Declarations.
|
|
library.LLVMGetFirstBasicBlock.argtypes = [Function]
|
|
library.LLVMGetFirstBasicBlock.restype = c_object_p
|
|
|
|
library.LLVMGetLastBasicBlock.argtypes = [Function]
|
|
library.LLVMGetLastBasicBlock.restype = c_object_p
|
|
|
|
library.LLVMGetNextBasicBlock.argtypes = [BasicBlock]
|
|
library.LLVMGetNextBasicBlock.restype = c_object_p
|
|
|
|
library.LLVMGetPreviousBasicBlock.argtypes = [BasicBlock]
|
|
library.LLVMGetPreviousBasicBlock.restype = c_object_p
|
|
|
|
library.LLVMGetFirstInstruction.argtypes = [BasicBlock]
|
|
library.LLVMGetFirstInstruction.restype = c_object_p
|
|
|
|
library.LLVMGetLastInstruction.argtypes = [BasicBlock]
|
|
library.LLVMGetLastInstruction.restype = c_object_p
|
|
|
|
library.LLVMBasicBlockAsValue.argtypes = [BasicBlock]
|
|
library.LLVMBasicBlockAsValue.restype = c_object_p
|
|
|
|
library.LLVMCountBasicBlocks.argtypes = [Function]
|
|
library.LLVMCountBasicBlocks.restype = c_uint
|
|
|
|
# Instruction Declarations.
|
|
library.LLVMGetNextInstruction.argtypes = [Instruction]
|
|
library.LLVMGetNextInstruction.restype = c_object_p
|
|
|
|
library.LLVMGetPreviousInstruction.argtypes = [Instruction]
|
|
library.LLVMGetPreviousInstruction.restype = c_object_p
|
|
|
|
library.LLVMGetInstructionOpcode.argtypes = [Instruction]
|
|
library.LLVMGetInstructionOpcode.restype = c_uint
|
|
|
|
def register_enumerations():
|
|
if Enums:
|
|
return None
|
|
enums = [
|
|
(Attribute, enumerations.Attributes),
|
|
(OpCode, enumerations.OpCodes),
|
|
(TypeKind, enumerations.TypeKinds),
|
|
(Linkage, enumerations.Linkages),
|
|
(Visibility, enumerations.Visibility),
|
|
(CallConv, enumerations.CallConv),
|
|
(IntPredicate, enumerations.IntPredicate),
|
|
(RealPredicate, enumerations.RealPredicate),
|
|
(LandingPadClauseTy, enumerations.LandingPadClauseTy),
|
|
]
|
|
for enum_class, enum_spec in enums:
|
|
for name, value in enum_spec:
|
|
print(name, value)
|
|
enum_class.register(name, value)
|
|
return enums
|
|
|
|
def initialize_llvm():
|
|
Context.GetGlobalContext()
|
|
p = PassRegistry()
|
|
lib.LLVMInitializeCore(p)
|
|
lib.LLVMInitializeTransformUtils(p)
|
|
lib.LLVMInitializeScalarOpts(p)
|
|
lib.LLVMInitializeObjCARCOpts(p)
|
|
lib.LLVMInitializeVectorization(p)
|
|
lib.LLVMInitializeInstCombine(p)
|
|
lib.LLVMInitializeIPO(p)
|
|
lib.LLVMInitializeInstrumentation(p)
|
|
lib.LLVMInitializeAnalysis(p)
|
|
lib.LLVMInitializeCodeGen(p)
|
|
lib.LLVMInitializeTarget(p)
|
|
|
|
register_library(lib)
|
|
Enums = register_enumerations()
|
|
initialize_llvm()
|