X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;ds=sidebyside;f=lib%2FTarget%2FARM%2FARMJITInfo.cpp;h=6d1114d51aabfc54ab8f80e9387190d0de51215a;hb=4437658aff84fa25563740c806a091de1395e5f4;hp=a3866c8bd6a571d474970aad8e707257ba8d1814;hpb=a9ad04191cb56c42944b17980b8b2bb2afe11ab2;p=oota-llvm.git diff --git a/lib/Target/ARM/ARMJITInfo.cpp b/lib/Target/ARM/ARMJITInfo.cpp index a3866c8bd6a..6d1114d51aa 100644 --- a/lib/Target/ARM/ARMJITInfo.cpp +++ b/lib/Target/ARM/ARMJITInfo.cpp @@ -11,25 +11,24 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "jit" #include "ARMJITInfo.h" -#include "ARMInstrInfo.h" #include "ARMConstantPoolValue.h" +#include "ARMMachineFunctionInfo.h" #include "ARMRelocations.h" -#include "ARMSubtarget.h" -#include "llvm/Function.h" +#include "MCTargetDesc/ARMBaseInfo.h" #include "llvm/CodeGen/JITCodeEmitter.h" -#include "llvm/Config/alloca.h" +#include "llvm/IR/Function.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Streams.h" +#include "llvm/Support/Memory.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Memory.h" #include using namespace llvm; +#define DEBUG_TYPE "jit" + void ARMJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { - llvm_report_error("ARMJITInfo::replaceMachineCodeForFunction"); + report_fatal_error("ARMJITInfo::replaceMachineCodeForFunction"); } /// JITCompilerFunction - This contains the address of the JIT function used to @@ -45,7 +44,7 @@ static TargetJITInfo::JITCompilerFn JITCompilerFunction; #define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__) // CompilationCallback stub - We can't use a C function with inline assembly in -// it, because we the prolog/epilog inserted by GCC won't work for us (we need +// it, because the prolog/epilog inserted by GCC won't work for us. (We need // to preserve more context and manipulate the stack directly). Instead, // write our own wrapper, which does things our way, so we have complete // control over register saving and restoring. @@ -62,8 +61,8 @@ extern "C" { // whole compilation callback doesn't exist as far as the caller is // concerned, so we can't just preserve the callee saved regs. "stmdb sp!, {r0, r1, r2, r3, lr}\n" -#ifndef __SOFTFP__ - "fstmfdd sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n" +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + "vstmdb sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n" #endif // The LR contains the address of the stub function on entry. // pass it as the argument to the C part of the callback @@ -85,9 +84,9 @@ extern "C" { // 6-20 | D0..D7 | Saved VFP registers // +--------+ // -#ifndef __SOFTFP__ +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) // Restore VFP caller-saved registers. - "fldmfdd sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n" + "vldmia sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n" #endif // // We need to exchange the values in slots 0 and 1 so we can @@ -99,9 +98,10 @@ extern "C" { "str r0, [sp,#16]\n" // Return to the (newly modified) stub to invoke the real function. // The above twiddling of the saved return addresses allows us to - // deallocate everything, including the LR the stub saved, all in one - // pop instruction. - "ldmia sp!, {r0, r1, r2, r3, lr, pc}\n" + // deallocate everything, including the LR the stub saved, with two + // updating load instructions. + "ldmia sp!, {r0, r1, r2, r3, lr}\n" + "ldr pc, [sp], #4\n" ); #else // Not an ARM host void ARMCompilationCallback() { @@ -141,25 +141,35 @@ ARMJITInfo::getLazyResolverFunction(JITCompilerFn F) { void *ARMJITInfo::emitGlobalValueIndirectSym(const GlobalValue *GV, void *Ptr, JITCodeEmitter &JCE) { - JCE.startGVStub(GV, 4, 4); - JCE.emitWordLE((intptr_t)Ptr); - void *PtrAddr = JCE.finishGVStub(GV); + uint8_t Buffer[4]; + uint8_t *Cur = Buffer; + MachineCodeEmitter::emitWordLEInto(Cur, (intptr_t)Ptr); + void *PtrAddr = JCE.allocIndirectGV( + GV, Buffer, sizeof(Buffer), /*Alignment=*/4); addIndirectSymAddr(Ptr, (intptr_t)PtrAddr); return PtrAddr; } +TargetJITInfo::StubLayout ARMJITInfo::getStubLayout() { + // The stub contains up to 3 4-byte instructions, aligned at 4 bytes, and a + // 4-byte address. See emitFunctionStub for details. + StubLayout Result = {16, 4}; + return Result; +} + void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn, JITCodeEmitter &JCE) { + void *Addr; // If this is just a call to an external function, emit a branch instead of a // call. The code is the same except for one bit of the last instruction. if (Fn != (void*)(intptr_t)ARMCompilationCallback) { // Branch to the corresponding function addr. if (IsPIC) { - // The stub is 8-byte size and 4-aligned. + // The stub is 16-byte size and 4-aligned. intptr_t LazyPtr = getIndirectSymAddr(Fn); if (!LazyPtr) { // In PIC mode, the function stub is loading a lazy-ptr. - LazyPtr= (intptr_t)emitGlobalValueIndirectSym((GlobalValue*)F, Fn, JCE); + LazyPtr= (intptr_t)emitGlobalValueIndirectSym((const GlobalValue*)F, Fn, JCE); DEBUG(if (F) errs() << "JIT: Indirect symbol emitted at [" << LazyPtr << "] for GV '" << F->getName() << "'\n"; @@ -167,20 +177,32 @@ void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn, errs() << "JIT: Stub emitted at [" << LazyPtr << "] for external function at '" << Fn << "'\n"); } - JCE.startGVStub(F, 16, 4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); - JCE.emitWordLE(0xe59fc004); // ldr pc, [pc, #+4] + JCE.emitAlignment(4); + Addr = (void*)JCE.getCurrentPCValue(); + if (!sys::Memory::setRangeWritable(Addr, 16)) { + llvm_unreachable("ERROR: Unable to mark stub writable"); + } + JCE.emitWordLE(0xe59fc004); // ldr ip, [pc, #+4] JCE.emitWordLE(0xe08fc00c); // L_func$scv: add ip, pc, ip JCE.emitWordLE(0xe59cf000); // ldr pc, [ip] - JCE.emitWordLE(LazyPtr - (Addr+4+8)); // func - (L_func$scv+8) - sys::Memory::InvalidateInstructionCache((void*)Addr, 16); + JCE.emitWordLE(LazyPtr - (intptr_t(Addr)+4+8)); // func - (L_func$scv+8) + sys::Memory::InvalidateInstructionCache(Addr, 16); + if (!sys::Memory::setRangeExecutable(Addr, 16)) { + llvm_unreachable("ERROR: Unable to mark stub executable"); + } } else { // The stub is 8-byte size and 4-aligned. - JCE.startGVStub(F, 8, 4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); + JCE.emitAlignment(4); + Addr = (void*)JCE.getCurrentPCValue(); + if (!sys::Memory::setRangeWritable(Addr, 8)) { + llvm_unreachable("ERROR: Unable to mark stub writable"); + } JCE.emitWordLE(0xe51ff004); // ldr pc, [pc, #-4] JCE.emitWordLE((intptr_t)Fn); // addr of function - sys::Memory::InvalidateInstructionCache((void*)Addr, 8); + sys::Memory::InvalidateInstructionCache(Addr, 8); + if (!sys::Memory::setRangeExecutable(Addr, 8)) { + llvm_unreachable("ERROR: Unable to mark stub executable"); + } } } else { // The compilation callback will overwrite the first two words of this @@ -190,8 +212,11 @@ void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn, // // Branch and link to the compilation callback. // The stub is 16-byte size and 4-byte aligned. - JCE.startGVStub(F, 16, 4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); + JCE.emitAlignment(4); + Addr = (void*)JCE.getCurrentPCValue(); + if (!sys::Memory::setRangeWritable(Addr, 16)) { + llvm_unreachable("ERROR: Unable to mark stub writable"); + } // Save LR so the callback can determine which stub called it. // The compilation callback is responsible for popping this prior // to returning. @@ -202,10 +227,13 @@ void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn, JCE.emitWordLE(0xe51ff004); // ldr pc, [pc, #-4] // The address of the compilation callback. JCE.emitWordLE((intptr_t)ARMCompilationCallback); - sys::Memory::InvalidateInstructionCache((void*)Addr, 16); + sys::Memory::InvalidateInstructionCache(Addr, 16); + if (!sys::Memory::setRangeExecutable(Addr, 16)) { + llvm_unreachable("ERROR: Unable to mark stub executable"); + } } - return JCE.finishGVStub(F); + return Addr; } intptr_t ARMJITInfo::resolveRelocDestAddr(MachineRelocation *MR) const { @@ -262,9 +290,9 @@ void ARMJITInfo::relocate(void *Function, MachineRelocation *MR, if (MR->getRelocationType() == ARM::reloc_arm_vfp_cp_entry) ResultPtr = ResultPtr >> 2; *((intptr_t*)RelocPos) |= ResultPtr; - // Set register Rn to PC. - *((intptr_t*)RelocPos) |= - ARMRegisterInfo::getRegisterNumbering(ARM::PC) << ARMII::RegRnShift; + // Set register Rn to PC (which is register 15 on all architectures). + // FIXME: This avoids the need for register info in the JIT class. + *((intptr_t*)RelocPos) |= 15 << ARMII::RegRnShift; break; } case ARM::reloc_arm_pic_jt: @@ -292,6 +320,25 @@ void ARMJITInfo::relocate(void *Function, MachineRelocation *MR, *((intptr_t*)RelocPos) |= ResultPtr; break; } + case ARM::reloc_arm_movw: { + ResultPtr = ResultPtr & 0xFFFF; + *((intptr_t*)RelocPos) |= ResultPtr & 0xFFF; + *((intptr_t*)RelocPos) |= ((ResultPtr >> 12) & 0xF) << 16; + break; + } + case ARM::reloc_arm_movt: { + ResultPtr = (ResultPtr >> 16) & 0xFFFF; + *((intptr_t*)RelocPos) |= ResultPtr & 0xFFF; + *((intptr_t*)RelocPos) |= ((ResultPtr >> 12) & 0xF) << 16; + break; + } } } } + +void ARMJITInfo::Initialize(const MachineFunction &MF, bool isPIC) { + const ARMFunctionInfo *AFI = MF.getInfo(); + ConstPoolId2AddrMap.resize(AFI->getNumPICLabels()); + JumpTableId2AddrMap.resize(AFI->getNumJumpTables()); + IsPIC = isPIC; +}