//
// The LLVM Compiler Infrastructure
//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
#include "X86JITInfo.h"
#include "X86Relocations.h"
#include "X86Subtarget.h"
+#include "llvm/Function.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/Config/alloca.h"
#include <cstdlib>
+#include <cstring>
using namespace llvm;
-#ifdef _MSC_VER
- extern "C" void *_AddressOfReturnAddress(void);
- #pragma intrinsic(_AddressOfReturnAddress)
+// Determine the platform we're running on
+#if defined (__x86_64__) || defined (_M_AMD64)
+# define X86_64_JIT
+#elif defined(__i386__) || defined(i386) || defined(_M_IX86)
+# define X86_32_JIT
#endif
void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
// FIXME: Disable this until we really want to use it. Also, we will
// need to add some workarounds for compilers, which support
// only subset of these directives.
-# define CFI(x) x
+# define CFI(x)
#endif
// Provide a wrapper for X86CompilationCallback2 that saves non-traditional
// callee saved registers, for the fastcc calling convention.
extern "C" {
-#if defined(__x86_64__)
+#if defined(X86_64_JIT)
+# ifndef _MSC_VER
// No need to save EAX/EDX for X86-64.
void X86CompilationCallback(void);
asm(
"ret\n"
CFI(".cfi_endproc\n")
);
-#elif defined(__i386__) || defined(i386) || defined(_M_IX86)
-#ifndef _MSC_VER
+# else
+ // No inline assembler support on this platform. The routine is in external
+ // file.
+ void X86CompilationCallback();
+
+# endif
+#elif defined (X86_32_JIT)
+# ifndef _MSC_VER
void X86CompilationCallback(void);
asm(
".text\n"
CFI(".cfi_rel_offset %edx, 4\n")
"pushl %ecx\n"
CFI(".cfi_rel_offset %ecx, 8\n")
-#if defined(__APPLE__)
+# if defined(__APPLE__)
"andl $-16, %esp\n" // Align ESP on 16-byte boundary
-#endif
+# endif
"subl $16, %esp\n"
"movl 4(%ebp), %eax\n" // Pass prev frame and return address
"movl %eax, 4(%esp)\n"
"ret\n"
CFI(".cfi_endproc\n")
);
-#else
- void X86CompilationCallback2(void);
+# else
+ void X86CompilationCallback2(intptr_t *StackPtr, intptr_t RetAddr);
_declspec(naked) void X86CompilationCallback(void) {
__asm {
+ push ebp
+ mov ebp, esp
push eax
push edx
push ecx
+ and esp, -16
+ mov eax, dword ptr [ebp+4]
+ mov dword ptr [esp+4], eax
+ mov dword ptr [esp], ebp
call X86CompilationCallback2
+ mov esp, ebp
+ sub esp, 12
pop ecx
pop edx
pop eax
+ pop ebp
ret
}
}
-#endif // _MSC_VER
+
+# endif // _MSC_VER
#else // Not an i386 host
void X86CompilationCallback() {
/// 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.
-#ifdef _MSC_VER
-extern "C" void X86CompilationCallback2() {
- assert(sizeof(size_t) == 4); // FIXME: handle Win64
- intptr_t *RetAddrLoc = (intptr_t *)_AddressOfReturnAddress();
- RetAddrLoc += 4; // skip over ret addr, edx, eax, ecx
- intptr_t RetAddr = *RetAddrLoc;
-#else
extern "C" void X86CompilationCallback2(intptr_t *StackPtr, intptr_t RetAddr) {
intptr_t *RetAddrLoc = &StackPtr[1];
-#endif
assert(*RetAddrLoc == RetAddr &&
"Could not find return address on the stack!");
bool isStub = ((unsigned char*)RetAddr)[0] == 0xCD;
// The call instruction should have pushed the return value onto the stack...
-#ifdef __x86_64__
+#if defined (X86_64_JIT)
RetAddr--; // Backtrack to the reference itself...
#else
RetAddr -= 4; // Backtrack to the reference itself...
#endif
// Sanity check to make sure this really is a call instruction.
-#ifdef __x86_64__
+#if defined (X86_64_JIT)
assert(((unsigned char*)RetAddr)[-2] == 0x41 &&"Not a call instr!");
assert(((unsigned char*)RetAddr)[-1] == 0xFF &&"Not a call instr!");
#else
// Rewrite the call target... so that we don't end up here every time we
// execute the call.
-#ifdef __x86_64__
+#if defined (X86_64_JIT)
*(intptr_t *)(RetAddr - 0xa) = NewVal;
#else
*(intptr_t *)RetAddr = (intptr_t)(NewVal-RetAddr-4);
// instruction so that two return addresses are not pushed onto the stack
// when the requested function finally gets called. This also makes the
// 0xCD byte (interrupt) dead, so the marker doesn't effect anything.
-#ifdef __x86_64__
+#if defined (X86_64_JIT)
((unsigned char*)RetAddr)[0] = (2 | (4 << 3) | (3 << 6));
#else
((unsigned char*)RetAddr)[-1] = 0xE9;
}
// Change the return address to reexecute the call instruction...
-#ifdef __x86_64__
+#if defined (X86_64_JIT)
*RetAddrLoc -= 0xd;
#else
*RetAddrLoc -= 5;
X86JITInfo::getLazyResolverFunction(JITCompilerFn F) {
JITCompilerFunction = F;
-#if (defined(__i386__) || defined(i386) || defined(_M_IX86)) && \
- !defined(_MSC_VER) && !defined(__x86_64__)
+#if defined (X86_32_JIT) && !defined (_MSC_VER)
unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
union {
unsigned u[3];
return X86CompilationCallback;
}
-void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
+void *X86JITInfo::emitGlobalValueLazyPtr(const GlobalValue* GV, void *ptr,
+ MachineCodeEmitter &MCE) {
+#if defined (X86_64_JIT)
+ MCE.startFunctionStub(GV, 8, 8);
+ MCE.emitWordLE((unsigned)(intptr_t)ptr);
+ MCE.emitWordLE((unsigned)(((intptr_t)ptr) >> 32));
+#else
+ MCE.startFunctionStub(GV, 4, 4);
+ MCE.emitWordLE((intptr_t)ptr);
+#endif
+ return MCE.finishFunctionStub(GV);
+}
+
+void *X86JITInfo::emitFunctionStub(const Function* F, void *Fn,
+ MachineCodeEmitter &MCE) {
// 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(__i386__) || defined(i386) || defined(_M_IX86)) && \
- !defined(_MSC_VER) && !defined(__x86_64__)
+#if defined (X86_32_JIT) && !defined (_MSC_VER)
bool NotCC = (Fn != (void*)(intptr_t)X86CompilationCallback &&
Fn != (void*)(intptr_t)X86CompilationCallback_SSE);
#else
bool NotCC = Fn != (void*)(intptr_t)X86CompilationCallback;
#endif
if (NotCC) {
-#ifdef __x86_64__
- MCE.startFunctionStub(13, 4);
+#if defined (X86_64_JIT)
+ MCE.startFunctionStub(F, 13, 4);
MCE.emitByte(0x49); // REX prefix
MCE.emitByte(0xB8+2); // movabsq r10
- MCE.emitWordLE(((unsigned *)&Fn)[0]);
- MCE.emitWordLE(((unsigned *)&Fn)[1]);
+ MCE.emitWordLE((unsigned)(intptr_t)Fn);
+ MCE.emitWordLE((unsigned)(((intptr_t)Fn) >> 32));
MCE.emitByte(0x41); // REX prefix
MCE.emitByte(0xFF); // jmpq *r10
MCE.emitByte(2 | (4 << 3) | (3 << 6));
#else
- MCE.startFunctionStub(5, 4);
+ MCE.startFunctionStub(F, 5, 4);
MCE.emitByte(0xE9);
MCE.emitWordLE((intptr_t)Fn-MCE.getCurrentPCValue()-4);
#endif
- return MCE.finishFunctionStub(0);
+ return MCE.finishFunctionStub(F);
}
-#ifdef __x86_64__
- MCE.startFunctionStub(14, 4);
+#if defined (X86_64_JIT)
+ MCE.startFunctionStub(F, 14, 4);
MCE.emitByte(0x49); // REX prefix
MCE.emitByte(0xB8+2); // movabsq r10
- MCE.emitWordLE(((unsigned *)&Fn)[0]);
- MCE.emitWordLE(((unsigned *)&Fn)[1]);
+ MCE.emitWordLE((unsigned)(intptr_t)Fn);
+ MCE.emitWordLE((unsigned)(((intptr_t)Fn) >> 32));
MCE.emitByte(0x41); // REX prefix
MCE.emitByte(0xFF); // callq *r10
MCE.emitByte(2 | (2 << 3) | (3 << 6));
#else
- MCE.startFunctionStub(6, 4);
+ MCE.startFunctionStub(F, 6, 4);
MCE.emitByte(0xE8); // Call with 32 bit pc-rel destination...
MCE.emitWordLE((intptr_t)Fn-MCE.getCurrentPCValue()-4);
#endif
MCE.emitByte(0xCD); // Interrupt - Just a marker identifying the stub!
- return MCE.finishFunctionStub(0);
+ return MCE.finishFunctionStub(F);
+}
+
+/// getPICJumpTableEntry - Returns the value of the jumptable entry for the
+/// specific basic block.
+intptr_t X86JITInfo::getPICJumpTableEntry(intptr_t BB, intptr_t Entry) {
+ return BB - PICBase;
}
/// relocate - Before the JIT can run a block of code that has been emitted,