X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FARMJITInfo.cpp;h=45b7e48d0cfb7513eef55f31ca69ff24bf3a8e4f;hb=3a96122c4ae4e7727ba976a9f658626c18997689;hp=50a798f14c175d0ad3188f3c0e04da093d752bb1;hpb=ce63ffb52f249b62cdf2d250c128007b13f27e71;p=oota-llvm.git diff --git a/lib/Target/ARM/ARMJITInfo.cpp b/lib/Target/ARM/ARMJITInfo.cpp index 50a798f14c1..45b7e48d0cf 100644 --- a/lib/Target/ARM/ARMJITInfo.cpp +++ b/lib/Target/ARM/ARMJITInfo.cpp @@ -19,17 +19,15 @@ #include "ARMSubtarget.h" #include "llvm/Function.h" #include "llvm/CodeGen/JITCodeEmitter.h" -#include "llvm/Config/alloca.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Memory.h" +#include "llvm/Support/Memory.h" #include using namespace llvm; 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,13 +43,13 @@ 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 +// write our own wrapper, which does things our way, so we have complete // control over register saving and restoring. extern "C" { #if defined(__arm__) - void ARMCompilationCallback(void); + void ARMCompilationCallback(); asm( ".text\n" ".align 2\n" @@ -62,7 +60,7 @@ 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__ +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) "fstmfdd sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n" #endif // The LR contains the address of the stub function on entry. @@ -79,13 +77,13 @@ extern "C" { // order for the registers. // +--------+ // 0 | LR | Original return address - // +--------+ + // +--------+ // 1 | LR | Stub address (start of stub) // 2-5 | R3..R0 | Saved registers (we need to preserve all regs) // 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" #endif @@ -99,9 +97,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() { @@ -110,9 +109,9 @@ extern "C" { #endif } -/// ARMCompilationCallbackC - This is the target-specific function invoked -/// by the function stub when we did not know the real target of a call. -/// This function must locate the start of the stub or call site and pass +/// ARMCompilationCallbackC - This is the target-specific function invoked +/// by the function stub when we did not know the real target of a call. +/// This function must locate the start of the stub or call site and pass /// it into the JIT compiler function. extern "C" void ARMCompilationCallbackC(intptr_t StubAddr) { // Get the address of the compiled code for this function. @@ -141,57 +140,82 @@ 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); DEBUG(if (F) - errs() << "JIT: Indirect symbol emitted at [" << LazyPtr + errs() << "JIT: Indirect symbol emitted at [" << LazyPtr << "] for GV '" << F->getName() << "'\n"; else 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 - // stub with indirect branch instructions targeting the compiled code. + // stub with indirect branch instructions targeting the compiled code. // This stub sets the return address to restart the stub, so that // the new branch will be invoked when we come back. // // 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 +226,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 { @@ -264,7 +291,7 @@ void ARMJITInfo::relocate(void *Function, MachineRelocation *MR, *((intptr_t*)RelocPos) |= ResultPtr; // Set register Rn to PC. *((intptr_t*)RelocPos) |= - ARMRegisterInfo::getRegisterNumbering(ARM::PC) << ARMII::RegRnShift; + getARMRegisterNumbering(ARM::PC) << ARMII::RegRnShift; break; } case ARM::reloc_arm_pic_jt: @@ -292,6 +319,18 @@ 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; + } } } }