diff options
author | Jeffrey Yasskin <jyasskin@google.com> | 2009-11-23 23:35:19 +0000 |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@google.com> | 2009-11-23 23:35:19 +0000 |
commit | f2ad57144363decdd185dbcc6da16c9a6440dfb0 (patch) | |
tree | 4aae7b9a6f4abc76e47790acfad50fe9a553bc22 /llvm/lib/Target | |
parent | bf2956a88b016026c549fcfe29f2799c129533e7 (diff) | |
download | bcm5719-llvm-f2ad57144363decdd185dbcc6da16c9a6440dfb0.tar.gz bcm5719-llvm-f2ad57144363decdd185dbcc6da16c9a6440dfb0.zip |
* Move stub allocation inside the JITEmitter, instead of exposing a
way for each TargetJITInfo subclass to allocate its own stubs. This
means stubs aren't as exactly-sized anymore, but it lets us get rid of
TargetJITInfo::emitFunctionStubAtAddr(), which lets ARM and PPC
support the eager JIT, fixing http://llvm.org/PR4816.
* Rename the JITEmitter's stub creation functions to describe the kind
of stub they create. So far, all of them create lazy-compilation
stubs, but they sometimes get used when far-call stubs are needed.
Fixing http://llvm.org/PR5201 will involve fixing this.
llvm-svn: 89715
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r-- | llvm/lib/Target/ARM/ARMJITInfo.cpp | 45 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMJITInfo.h | 4 | ||||
-rw-r--r-- | llvm/lib/Target/Alpha/AlphaJITInfo.cpp | 13 | ||||
-rw-r--r-- | llvm/lib/Target/Alpha/AlphaJITInfo.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/PowerPC/PPCJITInfo.cpp | 25 | ||||
-rw-r--r-- | llvm/lib/Target/PowerPC/PPCJITInfo.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86JITInfo.cpp | 59 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86JITInfo.h | 12 |
8 files changed, 89 insertions, 71 deletions
diff --git a/llvm/lib/Target/ARM/ARMJITInfo.cpp b/llvm/lib/Target/ARM/ARMJITInfo.cpp index 7031640471f..aa50cfd3074 100644 --- a/llvm/lib/Target/ARM/ARMJITInfo.cpp +++ b/llvm/lib/Target/ARM/ARMJITInfo.cpp @@ -154,15 +154,22 @@ void *ARMJITInfo::emitGlobalValueIndirectSym(const GlobalValue *GV, void *Ptr, 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) { - MachineCodeEmitter::BufferState BS; + 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. @@ -174,30 +181,30 @@ void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn, errs() << "JIT: Stub emitted at [" << LazyPtr << "] for external function at '" << Fn << "'\n"); } - JCE.startGVStub(BS, F, 16, 4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); - if (!sys::Memory::setRangeWritable((void*)Addr, 16)) { + 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); - if (!sys::Memory::setRangeExecutable((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(BS, F, 8, 4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); - if (!sys::Memory::setRangeWritable((void*)Addr, 8)) { + 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); - if (!sys::Memory::setRangeExecutable((void*)Addr, 8)) { + sys::Memory::InvalidateInstructionCache(Addr, 8); + if (!sys::Memory::setRangeExecutable(Addr, 8)) { llvm_unreachable("ERROR: Unable to mark stub executable"); } } @@ -209,9 +216,9 @@ 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(BS, F, 16, 4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); - if (!sys::Memory::setRangeWritable((void*)Addr, 16)) { + 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. @@ -224,13 +231,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); - if (!sys::Memory::setRangeExecutable((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(BS); + return Addr; } intptr_t ARMJITInfo::resolveRelocDestAddr(MachineRelocation *MR) const { diff --git a/llvm/lib/Target/ARM/ARMJITInfo.h b/llvm/lib/Target/ARM/ARMJITInfo.h index 7dfeed8b7bf..ff332b7ee15 100644 --- a/llvm/lib/Target/ARM/ARMJITInfo.h +++ b/llvm/lib/Target/ARM/ARMJITInfo.h @@ -61,6 +61,10 @@ namespace llvm { virtual void *emitGlobalValueIndirectSym(const GlobalValue* GV, void *ptr, JITCodeEmitter &JCE); + // getStubLayout - Returns the size and alignment of the largest call stub + // on ARM. + virtual StubLayout getStubLayout(); + /// emitFunctionStub - Use the specified JITCodeEmitter object to emit a /// small native function that simply calls the function at the specified /// address. diff --git a/llvm/lib/Target/Alpha/AlphaJITInfo.cpp b/llvm/lib/Target/Alpha/AlphaJITInfo.cpp index 4e59833953b..b3b711eea98 100644 --- a/llvm/lib/Target/Alpha/AlphaJITInfo.cpp +++ b/llvm/lib/Target/Alpha/AlphaJITInfo.cpp @@ -190,18 +190,27 @@ extern "C" { #endif } +TargetJITInfo::StubLayout AlphaJITInfo::getStubLayout() { + // The stub contains 19 4-byte instructions, aligned at 4 bytes: + // R0 = R27 + // 8 x "R27 <<= 8; R27 |= 8-bits-of-Target" == 16 instructions + // JMP R27 + // Magic number so the compilation callback can recognize the stub. + StubLayout Result = {19 * 4, 4}; + return Result; +} + void *AlphaJITInfo::emitFunctionStub(const Function* F, void *Fn, JITCodeEmitter &JCE) { MachineCodeEmitter::BufferState BS; //assert(Fn == AlphaCompilationCallback && "Where are you going?\n"); //Do things in a stupid slow way! - JCE.startGVStub(BS, F, 19*4); void* Addr = (void*)(intptr_t)JCE.getCurrentPCValue(); for (int x = 0; x < 19; ++ x) JCE.emitWordLE(0); EmitBranchToAt(Addr, Fn); DEBUG(errs() << "Emitting Stub to " << Fn << " at [" << Addr << "]\n"); - return JCE.finishGVStub(BS); + return Addr; } TargetJITInfo::LazyResolverFn diff --git a/llvm/lib/Target/Alpha/AlphaJITInfo.h b/llvm/lib/Target/Alpha/AlphaJITInfo.h index ecb467fbc5e..bd358a41312 100644 --- a/llvm/lib/Target/Alpha/AlphaJITInfo.h +++ b/llvm/lib/Target/Alpha/AlphaJITInfo.h @@ -31,6 +31,7 @@ namespace llvm { explicit AlphaJITInfo(TargetMachine &tm) : TM(tm) { useGOT = true; } + virtual StubLayout getStubLayout(); virtual void *emitFunctionStub(const Function* F, void *Fn, JITCodeEmitter &JCE); virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn); diff --git a/llvm/lib/Target/PowerPC/PPCJITInfo.cpp b/llvm/lib/Target/PowerPC/PPCJITInfo.cpp index ddbb3265700..c679bcdf58b 100644 --- a/llvm/lib/Target/PowerPC/PPCJITInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCJITInfo.cpp @@ -323,6 +323,15 @@ PPCJITInfo::getLazyResolverFunction(JITCompilerFn Fn) { return is64Bit ? PPC64CompilationCallback : PPC32CompilationCallback; } +TargetJITInfo::StubLayout PPCJITInfo::getStubLayout() { + // The stub contains up to 10 4-byte instructions, aligned at 4 bytes: 3 + // instructions to save the caller's address if this is a lazy-compilation + // stub, plus a 1-, 4-, or 7-instruction sequence to load an arbitrary address + // into a register and jump through it. + StubLayout Result = {10*4, 4}; + return Result; +} + #if (defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)) && \ defined(__APPLE__) extern "C" void sys_icache_invalidate(const void *Addr, size_t len); @@ -335,8 +344,7 @@ void *PPCJITInfo::emitFunctionStub(const Function* F, void *Fn, // call. The code is the same except for one bit of the last instruction. if (Fn != (void*)(intptr_t)PPC32CompilationCallback && Fn != (void*)(intptr_t)PPC64CompilationCallback) { - JCE.startGVStub(BS, F, 7*4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); + void *Addr = (void*)JCE.getCurrentPCValue(); JCE.emitWordBE(0); JCE.emitWordBE(0); JCE.emitWordBE(0); @@ -344,13 +352,12 @@ void *PPCJITInfo::emitFunctionStub(const Function* F, void *Fn, JCE.emitWordBE(0); JCE.emitWordBE(0); JCE.emitWordBE(0); - EmitBranchToAt(Addr, (intptr_t)Fn, false, is64Bit); - sys::Memory::InvalidateInstructionCache((void*)Addr, 7*4); - return JCE.finishGVStub(BS); + EmitBranchToAt((intptr_t)Addr, (intptr_t)Fn, false, is64Bit); + sys::Memory::InvalidateInstructionCache(Addr, 7*4); + return Addr; } - JCE.startGVStub(BS, F, 10*4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); + void *Addr = (void*)JCE.getCurrentPCValue(); if (is64Bit) { JCE.emitWordBE(0xf821ffb1); // stdu r1,-80(r1) JCE.emitWordBE(0x7d6802a6); // mflr r11 @@ -373,8 +380,8 @@ void *PPCJITInfo::emitFunctionStub(const Function* F, void *Fn, JCE.emitWordBE(0); JCE.emitWordBE(0); EmitBranchToAt(BranchAddr, (intptr_t)Fn, true, is64Bit); - sys::Memory::InvalidateInstructionCache((void*)Addr, 10*4); - return JCE.finishGVStub(BS); + sys::Memory::InvalidateInstructionCache(Addr, 10*4); + return Addr; } diff --git a/llvm/lib/Target/PowerPC/PPCJITInfo.h b/llvm/lib/Target/PowerPC/PPCJITInfo.h index 2e25b295f43..47ead59b587 100644 --- a/llvm/lib/Target/PowerPC/PPCJITInfo.h +++ b/llvm/lib/Target/PowerPC/PPCJITInfo.h @@ -30,6 +30,7 @@ namespace llvm { is64Bit = tmIs64Bit; } + virtual StubLayout getStubLayout(); virtual void *emitFunctionStub(const Function* F, void *Fn, JITCodeEmitter &JCE); virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn); diff --git a/llvm/lib/Target/X86/X86JITInfo.cpp b/llvm/lib/Target/X86/X86JITInfo.cpp index a14c155f174..ce06f0fdebe 100644 --- a/llvm/lib/Target/X86/X86JITInfo.cpp +++ b/llvm/lib/Target/X86/X86JITInfo.cpp @@ -438,74 +438,65 @@ void *X86JITInfo::emitGlobalValueIndirectSym(const GlobalValue* GV, void *ptr, return JCE.finishGVStub(BS); } -void *X86JITInfo::emitFunctionStub(const Function* F, void *Fn, +TargetJITInfo::StubLayout X86JITInfo::getStubLayout() { + // The 64-bit stub contains: + // movabs r10 <- 8-byte-target-address # 10 bytes + // call|jmp *r10 # 3 bytes + // The 32-bit stub contains a 5-byte call|jmp. + // If the stub is a call to the compilation callback, an extra byte is added + // to mark it as a stub. + StubLayout Result = {14, 4}; + return Result; +} + +void *X86JITInfo::emitFunctionStub(const Function* F, void *Target, JITCodeEmitter &JCE) { MachineCodeEmitter::BufferState BS; // Note, we cast to intptr_t here to silence a -pedantic warning that // complains about casting a function pointer to a normal pointer. #if defined (X86_32_JIT) && !defined (_MSC_VER) - bool NotCC = (Fn != (void*)(intptr_t)X86CompilationCallback && - Fn != (void*)(intptr_t)X86CompilationCallback_SSE); + bool NotCC = (Target != (void*)(intptr_t)X86CompilationCallback && + Target != (void*)(intptr_t)X86CompilationCallback_SSE); #else - bool NotCC = Fn != (void*)(intptr_t)X86CompilationCallback; + bool NotCC = Target != (void*)(intptr_t)X86CompilationCallback; #endif + JCE.emitAlignment(4); + void *Result = (void*)JCE.getCurrentPCValue(); if (NotCC) { #if defined (X86_64_JIT) - JCE.startGVStub(BS, F, 13, 4); JCE.emitByte(0x49); // REX prefix JCE.emitByte(0xB8+2); // movabsq r10 - JCE.emitWordLE((unsigned)(intptr_t)Fn); - JCE.emitWordLE((unsigned)(((intptr_t)Fn) >> 32)); + JCE.emitWordLE((unsigned)(intptr_t)Target); + JCE.emitWordLE((unsigned)(((intptr_t)Target) >> 32)); JCE.emitByte(0x41); // REX prefix JCE.emitByte(0xFF); // jmpq *r10 JCE.emitByte(2 | (4 << 3) | (3 << 6)); #else - JCE.startGVStub(BS, F, 5, 4); JCE.emitByte(0xE9); - JCE.emitWordLE((intptr_t)Fn-JCE.getCurrentPCValue()-4); + JCE.emitWordLE((intptr_t)Target-JCE.getCurrentPCValue()-4); #endif - return JCE.finishGVStub(BS); + return Result; } #if defined (X86_64_JIT) - JCE.startGVStub(BS, F, 14, 4); JCE.emitByte(0x49); // REX prefix JCE.emitByte(0xB8+2); // movabsq r10 - JCE.emitWordLE((unsigned)(intptr_t)Fn); - JCE.emitWordLE((unsigned)(((intptr_t)Fn) >> 32)); + JCE.emitWordLE((unsigned)(intptr_t)Target); + JCE.emitWordLE((unsigned)(((intptr_t)Target) >> 32)); JCE.emitByte(0x41); // REX prefix JCE.emitByte(0xFF); // callq *r10 JCE.emitByte(2 | (2 << 3) | (3 << 6)); #else - JCE.startGVStub(BS, F, 6, 4); JCE.emitByte(0xE8); // Call with 32 bit pc-rel destination... - JCE.emitWordLE((intptr_t)Fn-JCE.getCurrentPCValue()-4); + JCE.emitWordLE((intptr_t)Target-JCE.getCurrentPCValue()-4); #endif // This used to use 0xCD, but that value is used by JITMemoryManager to // initialize the buffer with garbage, which means it may follow a // noreturn function call, confusing X86CompilationCallback2. PR 4929. JCE.emitByte(0xCE); // Interrupt - Just a marker identifying the stub! - return JCE.finishGVStub(BS); -} - -void X86JITInfo::emitFunctionStubAtAddr(const Function* F, void *Fn, void *Stub, - JITCodeEmitter &JCE) { - MachineCodeEmitter::BufferState BS; - // Note, we cast to intptr_t here to silence a -pedantic warning that - // complains about casting a function pointer to a normal pointer. - JCE.startGVStub(BS, Stub, 5); - JCE.emitByte(0xE9); -#if defined (X86_64_JIT) && !defined (NDEBUG) - // Yes, we need both of these casts, or some broken versions of GCC (4.2.4) - // get the signed-ness of the expression wrong. Go figure. - intptr_t Displacement = (intptr_t)Fn - (intptr_t)JCE.getCurrentPCValue() - 5; - assert(((Displacement << 32) >> 32) == Displacement - && "PIC displacement does not fit in displacement field!"); -#endif - JCE.emitWordLE((intptr_t)Fn-JCE.getCurrentPCValue()-4); - JCE.finishGVStub(BS); + return Result; } /// getPICJumpTableEntry - Returns the value of the jumptable entry for the diff --git a/llvm/lib/Target/X86/X86JITInfo.h b/llvm/lib/Target/X86/X86JITInfo.h index c381433bf35..238420c236b 100644 --- a/llvm/lib/Target/X86/X86JITInfo.h +++ b/llvm/lib/Target/X86/X86JITInfo.h @@ -43,18 +43,16 @@ namespace llvm { virtual void *emitGlobalValueIndirectSym(const GlobalValue* GV, void *ptr, JITCodeEmitter &JCE); + // getStubLayout - Returns the size and alignment of the largest call stub + // on X86. + virtual StubLayout getStubLayout(); + /// emitFunctionStub - Use the specified JITCodeEmitter object to emit a /// small native function that simply calls the function at the specified /// address. - virtual void *emitFunctionStub(const Function* F, void *Fn, + virtual void *emitFunctionStub(const Function* F, void *Target, JITCodeEmitter &JCE); - /// emitFunctionStubAtAddr - Use the specified JITCodeEmitter object to - /// emit a small native function that simply calls Fn. Emit the stub into - /// the supplied buffer. - virtual void emitFunctionStubAtAddr(const Function* F, void *Fn, - void *Buffer, JITCodeEmitter &JCE); - /// getPICJumpTableEntry - Returns the value of the jumptable entry for the /// specific basic block. virtual uintptr_t getPICJumpTableEntry(uintptr_t BB, uintptr_t JTBase); |