MipsJITInfo.cpp revision 263509
155320Stanimura//===-- MipsJITInfo.cpp - Implement the Mips JIT Interface ----------------===// 253553Stanimura// 353553Stanimura// The LLVM Compiler Infrastructure 453553Stanimura// 554377Stanimura// This file is distributed under the University of Illinois Open Source 654377Stanimura// License. See LICENSE.TXT for details. 754377Stanimura// 854377Stanimura//===----------------------------------------------------------------------===// 953553Stanimura// 1053553Stanimura// This file implements the JIT interfaces for the Mips target. 1153553Stanimura// 1253553Stanimura//===----------------------------------------------------------------------===// 1353553Stanimura 1453553Stanimura#define DEBUG_TYPE "jit" 1553553Stanimura#include "MipsJITInfo.h" 1653553Stanimura#include "MipsInstrInfo.h" 1753553Stanimura#include "MipsRelocations.h" 1853553Stanimura#include "MipsSubtarget.h" 1953553Stanimura#include "llvm/CodeGen/JITCodeEmitter.h" 2053553Stanimura#include "llvm/IR/Function.h" 2153553Stanimura#include "llvm/Support/Debug.h" 2253553Stanimura#include "llvm/Support/ErrorHandling.h" 2353553Stanimura#include "llvm/Support/Memory.h" 2453553Stanimura#include "llvm/Support/raw_ostream.h" 2553553Stanimura#include <cstdlib> 2653553Stanimurausing namespace llvm; 2753553Stanimura 2853553Stanimura 2953553Stanimuravoid MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { 3053553Stanimura unsigned NewAddr = (intptr_t)New; 3153553Stanimura unsigned OldAddr = (intptr_t)Old; 3253553Stanimura const unsigned NopInstr = 0x0; 3353553Stanimura 3453553Stanimura // If the functions are in the same memory segment, insert PC-region branch. 3553553Stanimura if ((NewAddr & 0xF0000000) == ((OldAddr + 4) & 0xF0000000)) { 3653553Stanimura unsigned *OldInstruction = (unsigned *)Old; 3753553Stanimura *OldInstruction = 0x08000000; 38119287Simp unsigned JTargetAddr = NewAddr & 0x0FFFFFFC; 39119287Simp 4053553Stanimura JTargetAddr >>= 2; 4182180Scg *OldInstruction |= JTargetAddr; 4282180Scg 4377504Scg // Insert a NOP. 4477504Scg OldInstruction++; 4577504Scg *OldInstruction = NopInstr; 4677504Scg 4777504Scg sys::Memory::InvalidateInstructionCache(Old, 2 * 4); 4853553Stanimura } else { 4953553Stanimura // We need to clear hint bits from the instruction, in case it is 'jr ra'. 5053553Stanimura const unsigned HintMask = 0xFFFFF83F, ReturnSequence = 0x03e00008; 5153553Stanimura unsigned* CurrentInstr = (unsigned*)Old; 5253553Stanimura unsigned CurrInstrHintClear = (*CurrentInstr) & HintMask; 5374763Scg unsigned* NextInstr = CurrentInstr + 1; 5474763Scg unsigned NextInstrHintClear = (*NextInstr) & HintMask; 5553553Stanimura 5677504Scg // Do absolute jump if there are 2 or more instructions before return from 5755321Stanimura // the old function. 5853553Stanimura if ((CurrInstrHintClear != ReturnSequence) && 5953553Stanimura (NextInstrHintClear != ReturnSequence)) { 6053553Stanimura const unsigned LuiT0Instr = 0x3c080000, AddiuT0Instr = 0x25080000; 6153553Stanimura const unsigned JrT0Instr = 0x01000008; 6253553Stanimura // lui t0, high 16 bit of the NewAddr 6353553Stanimura (*(CurrentInstr++)) = LuiT0Instr | ((NewAddr & 0xffff0000) >> 16); 6455320Stanimura // addiu t0, t0, low 16 bit of the NewAddr 6577504Scg (*(CurrentInstr++)) = AddiuT0Instr | (NewAddr & 0x0000ffff); 6653553Stanimura // jr t0 6777504Scg (*(CurrentInstr++)) = JrT0Instr; 6853553Stanimura (*CurrentInstr) = NopInstr; 6953553Stanimura 7053553Stanimura sys::Memory::InvalidateInstructionCache(Old, 4 * 4); 7153553Stanimura } else { 7253553Stanimura // Unsupported case 7353553Stanimura report_fatal_error("MipsJITInfo::replaceMachineCodeForFunction"); 7453553Stanimura } 7553553Stanimura } 7653553Stanimura} 7753553Stanimura 7853553Stanimura/// JITCompilerFunction - This contains the address of the JIT function used to 7953553Stanimura/// compile a function lazily. 8053553Stanimurastatic TargetJITInfo::JITCompilerFn JITCompilerFunction; 8153553Stanimura 8253553Stanimura// Get the ASMPREFIX for the current host. This is often '_'. 8353553Stanimura#ifndef __USER_LABEL_PREFIX__ 8453553Stanimura#define __USER_LABEL_PREFIX__ 8553553Stanimura#endif 8653553Stanimura#define GETASMPREFIX2(X) #X 8753553Stanimura#define GETASMPREFIX(X) GETASMPREFIX2(X) 8853553Stanimura#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__) 8953553Stanimura 9064881Scg// CompilationCallback stub - We can't use a C function with inline assembly in 9164881Scg// it, because the prolog/epilog inserted by GCC won't work for us. Instead, 9264881Scg// write our own wrapper, which does things our way, so we have complete control 9364881Scg// over register saving and restoring. This code saves registers, calls 9464881Scg// MipsCompilationCallbackC and restores registers. 9564881Scgextern "C" { 9664881Scg#if defined (__mips__) 9764881Scgvoid MipsCompilationCallback(); 9864881Scg 9964881Scg asm( 10053553Stanimura ".text\n" 10174763Scg ".align 2\n" 10253553Stanimura ".globl " ASMPREFIX "MipsCompilationCallback\n" 10364881Scg ASMPREFIX "MipsCompilationCallback:\n" 10464881Scg ".ent " ASMPREFIX "MipsCompilationCallback\n" 10553553Stanimura ".frame $sp, 32, $ra\n" 10664881Scg ".set noreorder\n" 10753553Stanimura ".cpload $t9\n" 10874763Scg 10953553Stanimura "addiu $sp, $sp, -64\n" 11053553Stanimura ".cprestore 16\n" 11177504Scg 11277504Scg // Save argument registers a0, a1, a2, a3, f12, f14 since they may contain 11377504Scg // stuff for the real target function right now. We have to act as if this 11477504Scg // whole compilation callback doesn't exist as far as the caller is 11577504Scg // concerned. We also need to save the ra register since it contains the 11677504Scg // original return address, and t8 register since it contains the address 11777504Scg // of the end of function stub. 11877504Scg "sw $a0, 20($sp)\n" 11977504Scg "sw $a1, 24($sp)\n" 12077504Scg "sw $a2, 28($sp)\n" 12177504Scg "sw $a3, 32($sp)\n" 12277504Scg "sw $ra, 36($sp)\n" 12377504Scg "sw $t8, 40($sp)\n" 12477504Scg "sdc1 $f12, 48($sp)\n" 12577504Scg "sdc1 $f14, 56($sp)\n" 12677504Scg 12777504Scg // t8 points at the end of function stub. Pass the beginning of the stub 12877504Scg // to the MipsCompilationCallbackC. 12970134Scg "addiu $a0, $t8, -16\n" 13053553Stanimura "jal " ASMPREFIX "MipsCompilationCallbackC\n" 13153553Stanimura "nop\n" 13270134Scg 13353553Stanimura // Restore registers. 13470134Scg "lw $a0, 20($sp)\n" 13570134Scg "lw $a1, 24($sp)\n" 13653553Stanimura "lw $a2, 28($sp)\n" 13777504Scg "lw $a3, 32($sp)\n" 13870134Scg "lw $ra, 36($sp)\n" 13970134Scg "lw $t8, 40($sp)\n" 14077504Scg "ldc1 $f12, 48($sp)\n" 14153553Stanimura "ldc1 $f14, 56($sp)\n" 14270134Scg "addiu $sp, $sp, 64\n" 14353553Stanimura 14453553Stanimura // Jump to the (newly modified) stub to invoke the real function. 14553553Stanimura "addiu $t8, $t8, -16\n" 14670134Scg "jr $t8\n" 14753553Stanimura "nop\n" 14870134Scg 14953553Stanimura ".set reorder\n" 15077504Scg ".end " ASMPREFIX "MipsCompilationCallback\n" 15170134Scg ); 15277504Scg#else // host != Mips 15353553Stanimura void MipsCompilationCallback() { 15453553Stanimura llvm_unreachable( 15553553Stanimura "Cannot call MipsCompilationCallback() on a non-Mips arch!"); 15653553Stanimura } 15770134Scg#endif 15870134Scg} 15970134Scg 16070134Scg/// MipsCompilationCallbackC - This is the target-specific function invoked 16170134Scg/// by the function stub when we did not know the real target of a call. 16270134Scg/// This function must locate the start of the stub or call site and pass 16353553Stanimura/// it into the JIT compiler function. 16453553Stanimuraextern "C" void MipsCompilationCallbackC(intptr_t StubAddr) { 16553553Stanimura // Get the address of the compiled code for this function. 16653553Stanimura intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); 16753553Stanimura 16853553Stanimura // Rewrite the function stub so that we don't end up here every time we 16953553Stanimura // execute the call. We're replacing the first four instructions of the 17053553Stanimura // stub with code that jumps to the compiled function: 17153553Stanimura // lui $t9, %hi(NewVal) 17253553Stanimura // addiu $t9, $t9, %lo(NewVal) 17353553Stanimura // jr $t9 17453553Stanimura // nop 17553553Stanimura 17653553Stanimura int Hi = ((unsigned)NewVal & 0xffff0000) >> 16; 17753553Stanimura if ((NewVal & 0x8000) != 0) 17853553Stanimura Hi++; 17953553Stanimura int Lo = (int)(NewVal & 0xffff); 18053553Stanimura 18153553Stanimura *(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi; 18253553Stanimura *(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo; 18353553Stanimura *(intptr_t *)(StubAddr + 8) = 25 << 21 | 8; 18453553Stanimura *(intptr_t *)(StubAddr + 12) = 0; 18553553Stanimura 18653553Stanimura sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16); 18753553Stanimura} 18853553Stanimura 18953553StanimuraTargetJITInfo::LazyResolverFn MipsJITInfo::getLazyResolverFunction( 19053553Stanimura JITCompilerFn F) { 19153553Stanimura JITCompilerFunction = F; 19253553Stanimura return MipsCompilationCallback; 19353553Stanimura} 19453553Stanimura 19553553StanimuraTargetJITInfo::StubLayout MipsJITInfo::getStubLayout() { 19653553Stanimura // The stub contains 4 4-byte instructions, aligned at 4 bytes. See 19753553Stanimura // emitFunctionStub for details. 19853553Stanimura StubLayout Result = { 4*4, 4 }; 19953553Stanimura return Result; 20053553Stanimura} 20153553Stanimura 20253553Stanimuravoid *MipsJITInfo::emitFunctionStub(const Function *F, void *Fn, 20353553Stanimura JITCodeEmitter &JCE) { 20453553Stanimura JCE.emitAlignment(4); 20553553Stanimura void *Addr = (void*) (JCE.getCurrentPCValue()); 20653553Stanimura if (!sys::Memory::setRangeWritable(Addr, 16)) 20753553Stanimura llvm_unreachable("ERROR: Unable to mark stub writable."); 20853553Stanimura 20953553Stanimura intptr_t EmittedAddr; 21053553Stanimura if (Fn != (void*)(intptr_t)MipsCompilationCallback) 21153553Stanimura EmittedAddr = (intptr_t)Fn; 21253553Stanimura else 21353553Stanimura EmittedAddr = (intptr_t)MipsCompilationCallback; 21453553Stanimura 21553553Stanimura 21653553Stanimura int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16; 21753553Stanimura if ((EmittedAddr & 0x8000) != 0) 21853553Stanimura Hi++; 21953553Stanimura int Lo = (int)(EmittedAddr & 0xffff); 22053553Stanimura 22153553Stanimura // lui $t9, %hi(EmittedAddr) 22253553Stanimura // addiu $t9, $t9, %lo(EmittedAddr) 22353553Stanimura // jalr $t8, $t9 22453553Stanimura // nop 22553553Stanimura if (IsLittleEndian) { 22653553Stanimura JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi); 22753553Stanimura JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo); 22853553Stanimura JCE.emitWordLE(25 << 21 | 24 << 11 | 9); 22953553Stanimura JCE.emitWordLE(0); 23053553Stanimura } else { 23153553Stanimura JCE.emitWordBE(0xf << 26 | 25 << 16 | Hi); 23253553Stanimura JCE.emitWordBE(9 << 26 | 25 << 21 | 25 << 16 | Lo); 23353553Stanimura JCE.emitWordBE(25 << 21 | 24 << 11 | 9); 23453553Stanimura JCE.emitWordBE(0); 23553553Stanimura } 23653553Stanimura 23753553Stanimura sys::Memory::InvalidateInstructionCache(Addr, 16); 23853553Stanimura if (!sys::Memory::setRangeExecutable(Addr, 16)) 23953553Stanimura llvm_unreachable("ERROR: Unable to mark stub executable."); 24053553Stanimura 24153553Stanimura return Addr; 24253553Stanimura} 24353553Stanimura 24453553Stanimura/// relocate - Before the JIT can run a block of code that has been emitted, 24553553Stanimura/// it must rewrite the code to contain the actual addresses of any 24653553Stanimura/// referenced global symbols. 24753553Stanimuravoid MipsJITInfo::relocate(void *Function, MachineRelocation *MR, 24853553Stanimura unsigned NumRelocs, unsigned char *GOTBase) { 24953553Stanimura for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { 25053553Stanimura 25153553Stanimura void *RelocPos = (char*) Function + MR->getMachineCodeOffset(); 25253553Stanimura intptr_t ResultPtr = (intptr_t) MR->getResultPointer(); 25353553Stanimura 25453553Stanimura switch ((Mips::RelocationType) MR->getRelocationType()) { 25553553Stanimura case Mips::reloc_mips_pc16: 25653553Stanimura ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff; 25753553Stanimura *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 25853553Stanimura break; 25953553Stanimura 26053553Stanimura case Mips::reloc_mips_26: 26153553Stanimura ResultPtr = (ResultPtr & 0x0fffffff) >> 2; 26253553Stanimura *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 26353553Stanimura break; 26453553Stanimura 26553553Stanimura case Mips::reloc_mips_hi: 26653553Stanimura ResultPtr = ResultPtr >> 16; 26753553Stanimura if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) { 26853553Stanimura ResultPtr += 1; 26953553Stanimura } 27053553Stanimura *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 27153553Stanimura break; 27253553Stanimura 27353553Stanimura case Mips::reloc_mips_lo: { 27453553Stanimura // Addend is needed for unaligned load/store instructions, where offset 27553553Stanimura // for the second load/store in the expanded instruction sequence must 27653553Stanimura // be modified by +1 or +3. Otherwise, Addend is 0. 27753553Stanimura int Addend = *((unsigned*) RelocPos) & 0xffff; 27853553Stanimura ResultPtr = (ResultPtr + Addend) & 0xffff; 27956249Scg *((unsigned*) RelocPos) &= 0xffff0000; 28053553Stanimura *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 28153553Stanimura break; 28256249Scg } 28353553Stanimura } 28453553Stanimura } 28553553Stanimura} 28653553Stanimura