Index: include/llvm/Target/TargetJITInfo.h
===================================================================
--- include/llvm/Target/TargetJITInfo.h (revision 80590)
+++ include/llvm/Target/TargetJITInfo.h (working copy)
@@ -127,6 +127,16 @@
/// separately allocated heap memory rather than in the same
/// code memory allocated by JITCodeEmitter.
virtual bool allocateSeparateGVMemory() const { return false; }
+
+ /// This is used by the JITEmitter to decide whether or not to
+ /// generate a stub for an external function. By default,
+ /// we indicate false so all platforms where the CodeGen
+ /// has advise that stub might be needed have stubs. This
+ /// is the conservative approach.
+ virtual bool fitsInCallInstruction(void *Reference, void *ResultPtr,
+ MachineRelocation &MR) {
+ return false;
+ }
protected:
bool useGOT;
};
Index: unittests/ExecutionEngine/JIT/JITTest.cpp
===================================================================
--- unittests/ExecutionEngine/JIT/JITTest.cpp (revision 80590)
+++ unittests/ExecutionEngine/JIT/JITTest.cpp (working copy)
@@ -24,9 +24,14 @@
#include "llvm/Support/IRBuilder.h"
#include "llvm/Target/TargetSelect.h"
#include "llvm/Type.h"
+#include "llvm/CodeGen/MachineCodeInfo.h"
using namespace llvm;
+extern "C" int test_function() {
+ return 47;
+}
+
namespace {
Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) {
@@ -44,6 +49,79 @@
return F;
}
+void stop() {
+ std::cout << "stop now\n";
+}
+
+#ifdef __LP64__
+
+TEST(JIT, NoStubOnConcreteExternal) {
+ LLVMContext context;
+ Module *M = new Module("<main>", context);
+ ExistingModuleProvider *MP = new ExistingModuleProvider(M);
+
+ JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager();
+ // Tell the memory manager to poison freed memory so that accessing freed
+ // memory is more easily tested.
+ MemMgr->setPoisonMemory(true);
+ std::string Error;
+ OwningPtr<ExecutionEngine> JIT(EngineBuilder(MP)
+ .setEngineKind(EngineKind::JIT)
+ .setErrorStr(&Error)
+ .setJITMemoryManager(MemMgr)
+ .create());
+ ASSERT_EQ(Error, "");
+
+ intptr_t addr = (intptr_t)test_function;
+
+ std::vector<const Type*> params;
+ const FunctionType *ft = FunctionType::get(Type::getInt32Ty(context), params, false);
+ Function *func = cast<Function>(M->getOrInsertFunction("test_function", ft));
+
+ void *ptr = JIT->getPointerToFunction(func);
+
+ // Make sure that we can read it properly.
+ ASSERT_EQ(ptr, (void*)addr);
+
+ // Ok, make a function that calls test_function
+
+ Function *callee = cast<Function>(M->getOrInsertFunction("test_function_callee", ft));
+
+ BasicBlock *Entry = BasicBlock::Create(M->getContext(), "entry", callee);
+ IRBuilder<> builder(Entry);
+ builder.CreateRet(builder.CreateCall(func));
+
+ llvm::MachineCodeInfo mci;
+ JIT->runJITOnFunction(callee, &mci);
+
+ // Ok, this is crazy. But unless i've got a disassembler, there is no
+ // other way to do it.
+
+ uint8_t* buffer = (uint8_t*)mci.address();
+ uint8_t* end = buffer + (mci.size() - sizeof(intptr_t));
+
+ // std::cout << ptr << "\n";
+
+ bool found_in_buffer = false;
+ while(buffer <= end) {
+ if(buffer[0] == 232) { // this might be the call
+ int32_t pc_rel = addr - (((intptr_t)buffer) + 5);
+ int32_t* cur = (int32_t*)(buffer + 1);
+ // std::cout << (void*)buffer << ": " << (*cur) << " vs " << pc_rel << "\n";
+ if(*cur == pc_rel) {
+ found_in_buffer = true;
+ break;
+ }
+ }
+
+ buffer++;
+ }
+
+ ASSERT_EQ(found_in_buffer, true);
+}
+
+#endif
+
// Regression test for a bug. The JIT used to allocate globals inside the same
// memory block used for the function, and when the function code was freed,
// the global was left in the same place. This test allocates a function
Index: lib/Target/X86/X86JITInfo.h
===================================================================
--- lib/Target/X86/X86JITInfo.h (revision 80590)
+++ lib/Target/X86/X86JITInfo.h (working copy)
@@ -78,6 +78,9 @@
/// PIC jumptable entry.
void setPICBase(uintptr_t Base) { PICBase = Base; }
uintptr_t getPICBase() const { return PICBase; }
+
+ virtual bool fitsInCallInstruction(void *Reference, void *ResultPtr,
+ MachineRelocation &MR);
};
}
Index: lib/Target/X86/X86JITInfo.cpp
===================================================================
--- lib/Target/X86/X86JITInfo.cpp (revision 80590)
+++ lib/Target/X86/X86JITInfo.cpp (working copy)
@@ -560,3 +560,19 @@
return 0;
#endif
}
+
+/// Indicates if, for a pc-relative relocation, code located at Reference
+/// call ResultPtr directly. In other words, does the offset between
+/// these two address fit into a word.
+/// This code is conservative and only supports pc-relative relocations.
+/// All other relocations return false.
+bool X86JITInfo::fitsInCallInstruction(void *Reference, void *ResultPtr,
+ MachineRelocation &MR) {
+ if (MR.getRelocationType() != X86::reloc_pcrel_word) return false;
+ intptr_t difference = (intptr_t)Reference - (intptr_t)ResultPtr;
+
+ // Give the difference some tolerance. The tolerance could be eliminated
+ // so that fewer stubs would have to be used, but that requires more
+ // boundary calculations. If you're reading this, you're welcome to fix it!
+ return difference > -0x1fffffff && difference < 0x1fffffff;
+}
Index: lib/ExecutionEngine/JIT/JITEmitter.cpp
===================================================================
--- lib/ExecutionEngine/JIT/JITEmitter.cpp (revision 80590)
+++ lib/ExecutionEngine/JIT/JITEmitter.cpp (working copy)
@@ -614,9 +614,10 @@
JITMemoryManager *getMemMgr() const { return MemMgr; }
private:
- void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub);
+ void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub,
+ MachineRelocation &MR);
void *getPointerToGVIndirectSym(GlobalValue *V, void *Reference,
- bool NoNeedStub);
+ bool NoNeedStub, MachineRelocation &MR);
unsigned addSizeOfGlobal(const GlobalVariable *GV, unsigned Size);
unsigned addSizeOfGlobalsInConstantVal(const Constant *C, unsigned Size);
unsigned addSizeOfGlobalsInInitializer(const Constant *Init, unsigned Size);
@@ -625,7 +626,7 @@
}
void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference,
- bool DoesntNeedStub) {
+ bool DoesntNeedStub, MachineRelocation &MR) {
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
return TheJIT->getOrEmitGlobalVariable(GV);
@@ -646,12 +647,32 @@
if (ResultPtr) return ResultPtr;
// If this is an external function pointer, we can force the JIT to
- // 'compile' it, which really just adds it to the map. In dlsym mode,
+ // 'compile' it, which really just adds it to the map. In dlsym mode,
// external functions are forced through a stub, regardless of reloc type.
if (F->isDeclaration() && !F->hasNotBeenReadFromBitcode() &&
- DoesntNeedStub && !TheJIT->areDlsymStubsEnabled())
- return TheJIT->getPointerToFunction(F);
+ !TheJIT->areDlsymStubsEnabled()) {
+ ResultPtr = TheJIT->getPointerToFunction(F);
+ if (DoesntNeedStub) {
+ // The CodeGen has indicates that the code model is small enough that
+ // all possible pointer values fit in the call, so we can return
+ // the true address of the callee.
+ return ResultPtr;
+ }
+ // Otherwise, the CodeGen is indicating that not all pointers fit. It's
+ // being conservative and indicating that a stub is needed. We verify
+ // this by checking if ResultPtr would in fact fit. If it does, return
+ // it directly. Otherwise, keep going and create a stub and return
+ // the address of the stub (which is assumed to fit).
+ //
+ // FIXME the address of the stub is not asserted to fit though!
+ if (TheJIT->getJITInfo().fitsInCallInstruction(Reference, ResultPtr, MR)) {
+ return ResultPtr;
+ }
+
+ // Otherwise, go ahead and emit a stub.
+ }
+
// Okay, the function has not been compiled yet, if the target callback
// mechanism is capable of rewriting the instruction directly, prefer to do
// that instead of emitting a stub. This uses the lazy resolver, so is not
@@ -673,10 +694,10 @@
}
void *JITEmitter::getPointerToGVIndirectSym(GlobalValue *V, void *Reference,
- bool NoNeedStub) {
+ bool NoNeedStub, MachineRelocation &MR) {
// Make sure GV is emitted first, and create a stub containing the fully
// resolved address.
- void *GVAddress = getPointerToGlobal(V, Reference, true);
+ void *GVAddress = getPointerToGlobal(V, Reference, true, MR);
void *StubAddr = Resolver.getGlobalValueIndirectSym(V, GVAddress);
// Add the stub to the current function's list of referenced stubs, so we can
@@ -1014,11 +1035,11 @@
} else if (MR.isGlobalValue()) {
ResultPtr = getPointerToGlobal(MR.getGlobalValue(),
BufferBegin+MR.getMachineCodeOffset(),
- MR.doesntNeedStub());
+ MR.doesntNeedStub(), MR);
} else if (MR.isIndirectSymbol()) {
ResultPtr = getPointerToGVIndirectSym(MR.getGlobalValue(),
BufferBegin+MR.getMachineCodeOffset(),
- MR.doesntNeedStub());
+ MR.doesntNeedStub(), MR);
} else if (MR.isBasicBlock()) {
ResultPtr = (void*)getMachineBasicBlockAddress(MR.getBasicBlock());
} else if (MR.isConstantPoolIndex()) {
Index: autoconf/config.guess
===================================================================
--- autoconf/config.guess (revision 80590)
+++ autoconf/config.guess (working copy)
@@ -1181,6 +1181,15 @@
*86) UNAME_PROCESSOR=i686 ;;
unknown) UNAME_PROCESSOR=powerpc ;;
esac
+ case $UNAME_RELEASE in
+ 10.*)
+ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -dM -) | grep __LP64__ >/dev/null
+ then
+ echo x86_64-apple-darwin${UNAME_RELEASE}
+ exit 0
+ fi
+ esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
exit 0 ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)