#===- 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()