MipsJITInfo.cpp revision 234353
1254721Semaste//===-- MipsJITInfo.cpp - Implement the Mips JIT Interface ----------------===// 2254721Semaste// 3254721Semaste// The LLVM Compiler Infrastructure 4254721Semaste// 5254721Semaste// This file is distributed under the University of Illinois Open Source 6254721Semaste// License. See LICENSE.TXT for details. 7254721Semaste// 8254721Semaste//===----------------------------------------------------------------------===// 9254721Semaste// 10254721Semaste// This file implements the JIT interfaces for the Mips target. 11254721Semaste// 12254721Semaste//===----------------------------------------------------------------------===// 13263363Semaste 14254721Semaste#define DEBUG_TYPE "jit" 15254721Semaste#include "MipsJITInfo.h" 16254721Semaste#include "MipsInstrInfo.h" 17254721Semaste#include "MipsRelocations.h" 18254721Semaste#include "MipsSubtarget.h" 19254721Semaste#include "llvm/Function.h" 20254721Semaste#include "llvm/CodeGen/JITCodeEmitter.h" 21254721Semaste#include "llvm/Support/Debug.h" 22254721Semaste#include "llvm/Support/ErrorHandling.h" 23254721Semaste#include "llvm/Support/raw_ostream.h" 24254721Semaste#include "llvm/Support/Memory.h" 25254721Semaste#include <cstdlib> 26254721Semasteusing namespace llvm; 27254721Semaste 28254721Semaste 29254721Semastevoid MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { 30254721Semaste report_fatal_error("MipsJITInfo::replaceMachineCodeForFunction"); 31254721Semaste} 32254721Semaste 33254721Semaste/// JITCompilerFunction - This contains the address of the JIT function used to 34254721Semaste/// compile a function lazily. 35254721Semastestatic TargetJITInfo::JITCompilerFn JITCompilerFunction; 36254721Semaste 37254721Semaste// Get the ASMPREFIX for the current host. This is often '_'. 38254721Semaste#ifndef __USER_LABEL_PREFIX__ 39254721Semaste#define __USER_LABEL_PREFIX__ 40254721Semaste#endif 41254721Semaste#define GETASMPREFIX2(X) #X 42254721Semaste#define GETASMPREFIX(X) GETASMPREFIX2(X) 43254721Semaste#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__) 44254721Semaste 45254721Semaste// CompilationCallback stub - We can't use a C function with inline assembly in 46254721Semaste// it, because the prolog/epilog inserted by GCC won't work for us. Instead, 47254721Semaste// write our own wrapper, which does things our way, so we have complete control 48254721Semaste// over register saving and restoring. This code saves registers, calls 49254721Semaste// MipsCompilationCallbackC and restores registers. 50254721Semasteextern "C" { 51254721Semaste#if defined (__mips__) 52254721Semastevoid MipsCompilationCallback(); 53254721Semaste 54254721Semaste asm( 55254721Semaste ".text\n" 56254721Semaste ".align 2\n" 57254721Semaste ".globl " ASMPREFIX "MipsCompilationCallback\n" 58254721Semaste ASMPREFIX "MipsCompilationCallback:\n" 59254721Semaste ".ent " ASMPREFIX "MipsCompilationCallback\n" 60254721Semaste ".frame $sp, 32, $ra\n" 61254721Semaste ".set noreorder\n" 62254721Semaste ".cpload $t9\n" 63254721Semaste 64254721Semaste "addiu $sp, $sp, -64\n" 65254721Semaste ".cprestore 16\n" 66254721Semaste 67254721Semaste // Save argument registers a0, a1, a2, a3, f12, f14 since they may contain 68254721Semaste // stuff for the real target function right now. We have to act as if this 69254721Semaste // whole compilation callback doesn't exist as far as the caller is 70254721Semaste // concerned. We also need to save the ra register since it contains the 71254721Semaste // original return address, and t8 register since it contains the address 72254721Semaste // of the end of function stub. 73254721Semaste "sw $a0, 20($sp)\n" 74254721Semaste "sw $a1, 24($sp)\n" 75254721Semaste "sw $a2, 28($sp)\n" 76254721Semaste "sw $a3, 32($sp)\n" 77254721Semaste "sw $ra, 36($sp)\n" 78254721Semaste "sw $t8, 40($sp)\n" 79254721Semaste "sdc1 $f12, 48($sp)\n" 80254721Semaste "sdc1 $f14, 56($sp)\n" 81254721Semaste 82254721Semaste // t8 points at the end of function stub. Pass the beginning of the stub 83254721Semaste // to the MipsCompilationCallbackC. 84254721Semaste "addiu $a0, $t8, -16\n" 85254721Semaste "jal " ASMPREFIX "MipsCompilationCallbackC\n" 86254721Semaste "nop\n" 87254721Semaste 88254721Semaste // Restore registers. 89254721Semaste "lw $a0, 20($sp)\n" 90254721Semaste "lw $a1, 24($sp)\n" 91254721Semaste "lw $a2, 28($sp)\n" 92254721Semaste "lw $a3, 32($sp)\n" 93254721Semaste "lw $ra, 36($sp)\n" 94254721Semaste "lw $t8, 40($sp)\n" 95254721Semaste "ldc1 $f12, 48($sp)\n" 96254721Semaste "ldc1 $f14, 56($sp)\n" 97254721Semaste "addiu $sp, $sp, 64\n" 98254721Semaste 99254721Semaste // Jump to the (newly modified) stub to invoke the real function. 100254721Semaste "addiu $t8, $t8, -16\n" 101254721Semaste "jr $t8\n" 102254721Semaste "nop\n" 103254721Semaste 104254721Semaste ".set reorder\n" 105254721Semaste ".end " ASMPREFIX "MipsCompilationCallback\n" 106254721Semaste ); 107254721Semaste#else // host != Mips 108254721Semaste void MipsCompilationCallback() { 109254721Semaste llvm_unreachable( 110254721Semaste "Cannot call MipsCompilationCallback() on a non-Mips arch!"); 111254721Semaste } 112254721Semaste#endif 113254721Semaste} 114254721Semaste 115254721Semaste/// MipsCompilationCallbackC - This is the target-specific function invoked 116254721Semaste/// by the function stub when we did not know the real target of a call. 117254721Semaste/// This function must locate the start of the stub or call site and pass 118254721Semaste/// it into the JIT compiler function. 119254721Semasteextern "C" void MipsCompilationCallbackC(intptr_t StubAddr) { 120254721Semaste // Get the address of the compiled code for this function. 121254721Semaste intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); 122254721Semaste 123254721Semaste // Rewrite the function stub so that we don't end up here every time we 124254721Semaste // execute the call. We're replacing the first four instructions of the 125254721Semaste // stub with code that jumps to the compiled function: 126254721Semaste // lui $t9, %hi(NewVal) 127254721Semaste // addiu $t9, $t9, %lo(NewVal) 128254721Semaste // jr $t9 129254721Semaste // nop 130254721Semaste 131254721Semaste int Hi = ((unsigned)NewVal & 0xffff0000) >> 16; 132254721Semaste if ((NewVal & 0x8000) != 0) 133254721Semaste Hi++; 134254721Semaste int Lo = (int)(NewVal & 0xffff); 135254721Semaste 136254721Semaste *(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi; 137254721Semaste *(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo; 138254721Semaste *(intptr_t *)(StubAddr + 8) = 25 << 21 | 8; 139254721Semaste *(intptr_t *)(StubAddr + 12) = 0; 140254721Semaste 141254721Semaste sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16); 142254721Semaste} 143254721Semaste 144254721SemasteTargetJITInfo::LazyResolverFn MipsJITInfo::getLazyResolverFunction( 145254721Semaste JITCompilerFn F) { 146254721Semaste JITCompilerFunction = F; 147254721Semaste return MipsCompilationCallback; 148254721Semaste} 149254721Semaste 150254721SemasteTargetJITInfo::StubLayout MipsJITInfo::getStubLayout() { 151254721Semaste // The stub contains 4 4-byte instructions, aligned at 4 bytes. See 152254721Semaste // emitFunctionStub for details. 153254721Semaste StubLayout Result = { 4*4, 4 }; 154254721Semaste return Result; 155254721Semaste} 156254721Semaste 157254721Semastevoid *MipsJITInfo::emitFunctionStub(const Function* F, void *Fn, 158254721Semaste JITCodeEmitter &JCE) { 159254721Semaste JCE.emitAlignment(4); 160254721Semaste void *Addr = (void*) (JCE.getCurrentPCValue()); 161254721Semaste if (!sys::Memory::setRangeWritable(Addr, 16)) 162254721Semaste llvm_unreachable("ERROR: Unable to mark stub writable."); 163254721Semaste 164254721Semaste intptr_t EmittedAddr; 165254721Semaste if (Fn != (void*)(intptr_t)MipsCompilationCallback) 166254721Semaste EmittedAddr = (intptr_t)Fn; 167254721Semaste else 168254721Semaste EmittedAddr = (intptr_t)MipsCompilationCallback; 169254721Semaste 170254721Semaste 171254721Semaste int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16; 172254721Semaste if ((EmittedAddr & 0x8000) != 0) 173254721Semaste Hi++; 174254721Semaste int Lo = (int)(EmittedAddr & 0xffff); 175254721Semaste 176254721Semaste // lui t9, %hi(EmittedAddr) 177254721Semaste // addiu t9, t9, %lo(EmittedAddr) 178254721Semaste // jalr t8, t9 179254721Semaste // nop 180263363Semaste JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi); 181263363Semaste JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo); 182263363Semaste JCE.emitWordLE(25 << 21 | 24 << 11 | 9); 183263363Semaste JCE.emitWordLE(0); 184263363Semaste 185263363Semaste sys::Memory::InvalidateInstructionCache(Addr, 16); 186263363Semaste if (!sys::Memory::setRangeExecutable(Addr, 16)) 187263363Semaste llvm_unreachable("ERROR: Unable to mark stub executable."); 188263363Semaste 189263363Semaste return Addr; 190263363Semaste} 191263363Semaste 192263363Semaste/// relocate - Before the JIT can run a block of code that has been emitted, 193263363Semaste/// it must rewrite the code to contain the actual addresses of any 194263363Semaste/// referenced global symbols. 195263363Semastevoid MipsJITInfo::relocate(void *Function, MachineRelocation *MR, 196263363Semaste unsigned NumRelocs, unsigned char* GOTBase) { 197263363Semaste for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { 198263363Semaste 199263363Semaste void *RelocPos = (char*) Function + MR->getMachineCodeOffset(); 200263363Semaste intptr_t ResultPtr = (intptr_t) MR->getResultPointer(); 201263363Semaste 202263363Semaste switch ((Mips::RelocationType) MR->getRelocationType()) { 203263363Semaste case Mips::reloc_mips_pc16: 204263363Semaste ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff; 205263363Semaste *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 206263363Semaste break; 207263363Semaste 208263363Semaste case Mips::reloc_mips_26: 209263363Semaste ResultPtr = (ResultPtr & 0x0fffffff) >> 2; 210263363Semaste *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 211263363Semaste break; 212263363Semaste 213263363Semaste case Mips::reloc_mips_hi: 214263363Semaste ResultPtr = ResultPtr >> 16; 215263363Semaste if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) { 216263363Semaste ResultPtr += 1; 217263363Semaste } 218263363Semaste *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 219263363Semaste break; 220263363Semaste 221263363Semaste case Mips::reloc_mips_lo: { 222263363Semaste // Addend is needed for unaligned load/store instructions, where offset 223263363Semaste // for the second load/store in the expanded instruction sequence must 224263363Semaste // be modified by +1 or +3. Otherwise, Addend is 0. 225263363Semaste int Addend = *((unsigned*) RelocPos) & 0xffff; 226263363Semaste ResultPtr = (ResultPtr + Addend) & 0xffff; 227263363Semaste *((unsigned*) RelocPos) &= 0xffff0000; 228263363Semaste *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 229263363Semaste break; 230263363Semaste } 231263363Semaste } 232263363Semaste } 233263363Semaste} 234263363Semaste