import os import llvm.core as lc import llvm.passes as lp import llvm.ee as le def replace_divmod64(lfunc): '''Replaces all 64-bit integer division (sdiv, udiv) and modulo (srem, urem) ''' int64 = lc.Type.int(64) int64ptr = lc.Type.pointer(lc.Type.int(64)) functy = lc.Type.function(int64, [int64, int64]) udiv64 = lfunc.module.get_or_insert_function(functy, '__llrt_udiv64') sdiv64 = lfunc.module.get_or_insert_function(functy, '__llrt_sdiv64') umod64 = lfunc.module.get_or_insert_function(functy, '__llrt_umod64') smod64 = lfunc.module.get_or_insert_function(functy, '__llrt_smod64') builder = lc.Builder.new(lfunc.entry_basic_block) for bb in lfunc.basic_blocks: for inst in bb.instructions: if inst.opcode_name == 'sdiv' and inst.type == int64: _replace_with(builder, inst, sdiv64) elif inst.opcode_name == 'udiv' and inst.type == int64: _replace_with(builder, inst, udiv64) elif inst.opcode_name == 'srem' and inst.type == int64: _replace_with(builder, inst, smod64) elif inst.opcode_name == 'urem' and inst.type == int64: _replace_with(builder, inst, umod64) def _replace_with(builder, inst, func): '''Replace instruction with a call to the function with the same operands as arguments. ''' builder.position_before(inst) replacement = builder.call(func, inst.operands) inst.replace_all_uses_with(replacement._ptr) inst.erase_from_parent() def load(arch): '''Load the LLRT module corresponding to the given architecture Creates a new module and optimizes it using the information from the host machine. ''' if arch != 'x86_64': arch = 'x86' path = os.path.join(os.path.dirname(__file__), 'llrt', 'llrt_%s.ll' % arch) with open(path) as fin: lib = lc.Module.from_assembly(fin) # run passes to optimize tm = le.TargetMachine.new() pms = lp.build_pass_managers(tm, opt=3, fpm=False) pms.pm.run(lib) return lib class LLRT(object): def __init__(self): arch = le.get_default_triple().split('-', 1)[0] self.module = load(arch) self.engine = le.EngineBuilder.new(self.module).opt(3).create() self.installed_symbols = set() def install_symbols(self): '''Bind all the external symbols to the global symbol map. Any future reference to these symbols will be automatically resolved by LLVM. ''' for lfunc in self.module.functions: if lfunc.linkage == lc.LINKAGE_EXTERNAL: mangled = '__llrt_' + lfunc.name self.installed_symbols.add(mangled) ptr = self.engine.get_pointer_to_function(lfunc) le.dylib_add_symbol(mangled, ptr) def uninstall_symbols(self): for sym in self.installed_symbols: le.dylib_add_symbol(sym, 0)