1//===- MipsJITInfo.cpp - Implement the JIT interfaces for the Mips target -===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the JIT interfaces for the Mips target. 11// 12//===----------------------------------------------------------------------===// 13 14#define DEBUG_TYPE "jit" 15#include "MipsJITInfo.h" 16#include "MipsInstrInfo.h" 17#include "MipsRelocations.h" 18#include "MipsSubtarget.h" 19#include "llvm/Function.h" 20#include "llvm/CodeGen/JITCodeEmitter.h" 21#include "llvm/Support/Debug.h" 22#include "llvm/Support/ErrorHandling.h" 23#include "llvm/Support/raw_ostream.h" 24#include "llvm/Support/Memory.h" 25#include <cstdlib> 26using namespace llvm; 27 28 29void MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { 30 report_fatal_error("MipsJITInfo::replaceMachineCodeForFunction"); 31} 32 33/// JITCompilerFunction - This contains the address of the JIT function used to 34/// compile a function lazily. 35static TargetJITInfo::JITCompilerFn JITCompilerFunction; 36 37// Get the ASMPREFIX for the current host. This is often '_'. 38#ifndef __USER_LABEL_PREFIX__ 39#define __USER_LABEL_PREFIX__ 40#endif 41#define GETASMPREFIX2(X) #X 42#define GETASMPREFIX(X) GETASMPREFIX2(X) 43#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__) 44 45// CompilationCallback stub - We can't use a C function with inline assembly in 46// it, because the prolog/epilog inserted by GCC won't work for us. Instead, 47// write our own wrapper, which does things our way, so we have complete control 48// over register saving and restoring. This code saves registers, calls 49// MipsCompilationCallbackC and restores registers. 50extern "C" { 51#if defined (__mips__) 52void MipsCompilationCallback(); 53 54 asm( 55 ".text\n" 56 ".align 2\n" 57 ".globl " ASMPREFIX "MipsCompilationCallback\n" 58 ASMPREFIX "MipsCompilationCallback:\n" 59 ".ent " ASMPREFIX "MipsCompilationCallback\n" 60 ".frame $sp, 32, $ra\n" 61 ".set noreorder\n" 62 ".cpload $t9\n" 63 64 "addiu $sp, $sp, -64\n" 65 ".cprestore 16\n" 66 67 // Save argument registers a0, a1, a2, a3, f12, f14 since they may contain 68 // stuff for the real target function right now. We have to act as if this 69 // whole compilation callback doesn't exist as far as the caller is 70 // concerned. We also need to save the ra register since it contains the 71 // original return address, and t8 register since it contains the address 72 // of the end of function stub. 73 "sw $a0, 20($sp)\n" 74 "sw $a1, 24($sp)\n" 75 "sw $a2, 28($sp)\n" 76 "sw $a3, 32($sp)\n" 77 "sw $ra, 36($sp)\n" 78 "sw $t8, 40($sp)\n" 79 "sdc1 $f12, 48($sp)\n" 80 "sdc1 $f14, 56($sp)\n" 81 82 // t8 points at the end of function stub. Pass the beginning of the stub 83 // to the MipsCompilationCallbackC. 84 "addiu $a0, $t8, -16\n" 85 "jal " ASMPREFIX "MipsCompilationCallbackC\n" 86 "nop\n" 87 88 // Restore registers. 89 "lw $a0, 20($sp)\n" 90 "lw $a1, 24($sp)\n" 91 "lw $a2, 28($sp)\n" 92 "lw $a3, 32($sp)\n" 93 "lw $ra, 36($sp)\n" 94 "lw $t8, 40($sp)\n" 95 "ldc1 $f12, 48($sp)\n" 96 "ldc1 $f14, 56($sp)\n" 97 "addiu $sp, $sp, 64\n" 98 99 // Jump to the (newly modified) stub to invoke the real function. 100 "addiu $t8, $t8, -16\n" 101 "jr $t8\n" 102 "nop\n" 103 104 ".set reorder\n" 105 ".end " ASMPREFIX "MipsCompilationCallback\n" 106 ); 107#else // host != Mips 108 void MipsCompilationCallback() { 109 llvm_unreachable( 110 "Cannot call MipsCompilationCallback() on a non-Mips arch!"); 111 } 112#endif 113} 114 115/// MipsCompilationCallbackC - This is the target-specific function invoked 116/// by the function stub when we did not know the real target of a call. 117/// This function must locate the start of the stub or call site and pass 118/// it into the JIT compiler function. 119extern "C" void MipsCompilationCallbackC(intptr_t StubAddr) { 120 // Get the address of the compiled code for this function. 121 intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); 122 123 // Rewrite the function stub so that we don't end up here every time we 124 // execute the call. We're replacing the first four instructions of the 125 // stub with code that jumps to the compiled function: 126 // lui $t9, %hi(NewVal) 127 // addiu $t9, $t9, %lo(NewVal) 128 // jr $t9 129 // nop 130 131 int Hi = ((unsigned)NewVal & 0xffff0000) >> 16; 132 if ((NewVal & 0x8000) != 0) 133 Hi++; 134 int Lo = (int)(NewVal & 0xffff); 135 136 *(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi; 137 *(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo; 138 *(intptr_t *)(StubAddr + 8) = 25 << 21 | 8; 139 *(intptr_t *)(StubAddr + 12) = 0; 140 141 sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16); 142} 143 144TargetJITInfo::LazyResolverFn MipsJITInfo::getLazyResolverFunction( 145 JITCompilerFn F) { 146 JITCompilerFunction = F; 147 return MipsCompilationCallback; 148} 149 150TargetJITInfo::StubLayout MipsJITInfo::getStubLayout() { 151 // The stub contains 4 4-byte instructions, aligned at 4 bytes. See 152 // emitFunctionStub for details. 153 StubLayout Result = { 4*4, 4 }; 154 return Result; 155} 156 157void *MipsJITInfo::emitFunctionStub(const Function* F, void *Fn, 158 JITCodeEmitter &JCE) { 159 JCE.emitAlignment(4); 160 void *Addr = (void*) (JCE.getCurrentPCValue()); 161 if (!sys::Memory::setRangeWritable(Addr, 16)) 162 llvm_unreachable("ERROR: Unable to mark stub writable."); 163 164 intptr_t EmittedAddr; 165 if (Fn != (void*)(intptr_t)MipsCompilationCallback) 166 EmittedAddr = (intptr_t)Fn; 167 else 168 EmittedAddr = (intptr_t)MipsCompilationCallback; 169 170 171 int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16; 172 if ((EmittedAddr & 0x8000) != 0) 173 Hi++; 174 int Lo = (int)(EmittedAddr & 0xffff); 175 176 // lui t9, %hi(EmittedAddr) 177 // addiu t9, t9, %lo(EmittedAddr) 178 // jalr t8, t9 179 // nop 180 JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi); 181 JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo); 182 JCE.emitWordLE(25 << 21 | 24 << 11 | 9); 183 JCE.emitWordLE(0); 184 185 sys::Memory::InvalidateInstructionCache(Addr, 16); 186 if (!sys::Memory::setRangeExecutable(Addr, 16)) 187 llvm_unreachable("ERROR: Unable to mark stub executable."); 188 189 return Addr; 190} 191 192/// relocate - Before the JIT can run a block of code that has been emitted, 193/// it must rewrite the code to contain the actual addresses of any 194/// referenced global symbols. 195void MipsJITInfo::relocate(void *Function, MachineRelocation *MR, 196 unsigned NumRelocs, unsigned char* GOTBase) { 197 for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { 198 199 void *RelocPos = (char*) Function + MR->getMachineCodeOffset(); 200 intptr_t ResultPtr = (intptr_t) MR->getResultPointer(); 201 202 switch ((Mips::RelocationType) MR->getRelocationType()) { 203 case Mips::reloc_mips_branch: 204 ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff; 205 *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 206 break; 207 208 case Mips::reloc_mips_26: 209 ResultPtr = (ResultPtr & 0x0fffffff) >> 2; 210 *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 211 break; 212 213 case Mips::reloc_mips_hi: 214 ResultPtr = ResultPtr >> 16; 215 if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) { 216 ResultPtr += 1; 217 } 218 *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 219 break; 220 221 case Mips::reloc_mips_lo: 222 ResultPtr = ResultPtr & 0xffff; 223 *((unsigned*) RelocPos) |= (unsigned) ResultPtr; 224 break; 225 226 default: 227 llvm_unreachable("ERROR: Unknown Mips relocation."); 228 } 229 } 230} 231