summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorJeffrey Yasskin <jyasskin@google.com>2009-11-23 23:35:19 +0000
committerJeffrey Yasskin <jyasskin@google.com>2009-11-23 23:35:19 +0000
commitf2ad57144363decdd185dbcc6da16c9a6440dfb0 (patch)
tree4aae7b9a6f4abc76e47790acfad50fe9a553bc22 /llvm/lib/Target
parentbf2956a88b016026c549fcfe29f2799c129533e7 (diff)
downloadbcm5719-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.cpp45
-rw-r--r--llvm/lib/Target/ARM/ARMJITInfo.h4
-rw-r--r--llvm/lib/Target/Alpha/AlphaJITInfo.cpp13
-rw-r--r--llvm/lib/Target/Alpha/AlphaJITInfo.h1
-rw-r--r--llvm/lib/Target/PowerPC/PPCJITInfo.cpp25
-rw-r--r--llvm/lib/Target/PowerPC/PPCJITInfo.h1
-rw-r--r--llvm/lib/Target/X86/X86JITInfo.cpp59
-rw-r--r--llvm/lib/Target/X86/X86JITInfo.h12
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);
OpenPOWER on IntegriCloud