Partially revert r91626. Materializing extra functions to determine whether

they're available_externally broke VMKit, which was relying on the fact that
functions would only be materialized when they were first called.  We'll have
to wait for http://llvm.org/PR5737 to really fix this.

I also added a test for one of the F->isDeclaration() calls which wasn't
covered by anything else in the test suite.

llvm-svn: 91943
This commit is contained in:
Jeffrey Yasskin 2009-12-22 23:47:23 +00:00
parent 68e8f657a2
commit 0c46d96fd0
3 changed files with 106 additions and 23 deletions

View File

@ -59,6 +59,12 @@ STATISTIC(NumRetries, "Number of retries with more memory");
static JIT *TheJIT = 0;
// A declaration may stop being a declaration once it's fully read from bitcode.
// This function returns true if F is fully read and is still a declaration.
static bool isNonGhostDeclaration(const Function *F) {
return F->isDeclaration() && !F->hasNotBeenReadFromBitcode();
}
//===----------------------------------------------------------------------===//
// JIT lazy compilation code.
//
@ -517,15 +523,9 @@ void *JITResolver::getLazyFunctionStub(Function *F) {
void *Actual = TheJIT->isCompilingLazily()
? (void *)(intptr_t)LazyResolverFn : (void *)0;
// TODO: Delete this when PR5737 is fixed.
std::string ErrorMsg;
if (TheJIT->materializeFunction(F, &ErrorMsg)) {
llvm_report_error("Error reading function '" + F->getName()+
"' from bitcode file: " + ErrorMsg);
}
// If this is an external declaration, attempt to resolve the address now
// to place in the stub.
if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
if (isNonGhostDeclaration(F) || F->hasAvailableExternallyLinkage()) {
Actual = TheJIT->getPointerToFunction(F);
// If we resolved the symbol to a null address (eg. a weak external)
@ -558,7 +558,7 @@ void *JITResolver::getLazyFunctionStub(Function *F) {
// exist yet, add it to the JIT's work list so that we can fill in the stub
// address later.
if (!Actual && !TheJIT->isCompilingLazily())
if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage())
if (!isNonGhostDeclaration(F) && !F->hasAvailableExternallyLinkage())
TheJIT->addPendingFunction(F);
return Stub;
@ -761,16 +761,9 @@ void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference,
void *ResultPtr = TheJIT->getPointerToGlobalIfAvailable(F);
if (ResultPtr) return ResultPtr;
// TODO: Delete this when PR5737 is fixed.
std::string ErrorMsg;
if (TheJIT->materializeFunction(F, &ErrorMsg)) {
llvm_report_error("Error reading function '" + F->getName()+
"' from bitcode file: " + ErrorMsg);
}
// If this is an external function pointer, we can force the JIT to
// 'compile' it, which really just adds it to the map.
if (F->isDeclaration() || F->hasAvailableExternallyLinkage())
if (isNonGhostDeclaration(F) || F->hasAvailableExternallyLinkage())
return TheJIT->getPointerToFunction(F);
}

View File

@ -12,6 +12,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/BasicBlock.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Constant.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
@ -24,6 +25,7 @@
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TypeBuilder.h"
#include "llvm/Target/TargetSelect.h"
@ -177,6 +179,17 @@ public:
}
};
bool LoadAssemblyInto(Module *M, const char *assembly) {
SMDiagnostic Error;
bool success =
NULL != ParseAssemblyString(assembly, M, Error, M->getContext());
std::string errMsg;
raw_string_ostream os(errMsg);
Error.Print("", os);
EXPECT_TRUE(success) << os.str();
return success;
}
class JITTest : public testing::Test {
protected:
virtual void SetUp() {
@ -192,12 +205,7 @@ class JITTest : public testing::Test {
}
void LoadAssembly(const char *assembly) {
SMDiagnostic Error;
bool success = NULL != ParseAssemblyString(assembly, M, Error, Context);
std::string errMsg;
raw_string_ostream os(errMsg);
Error.Print("", os);
ASSERT_TRUE(success) << os.str();
LoadAssemblyInto(M, assembly);
}
LLVMContext Context;
@ -619,6 +627,88 @@ TEST_F(JITTest, AvailableExternallyFunctionIsntCompiled) {
<< " not 7 from the IR version.";
}
// Converts the LLVM assembly to bitcode and returns it in a std::string. An
// empty string indicates an error.
std::string AssembleToBitcode(LLVMContext &Context, const char *Assembly) {
Module TempModule("TempModule", Context);
if (!LoadAssemblyInto(&TempModule, Assembly)) {
return "";
}
std::string Result;
raw_string_ostream OS(Result);
WriteBitcodeToFile(&TempModule, OS);
OS.flush();
return Result;
}
// Returns a newly-created ExecutionEngine that reads the bitcode in 'Bitcode'
// lazily. The associated ModuleProvider (owned by the ExecutionEngine) is
// returned in MP. Both will be NULL on an error. Bitcode must live at least
// as long as the ExecutionEngine.
ExecutionEngine *getJITFromBitcode(
LLVMContext &Context, const std::string &Bitcode, ModuleProvider *&MP) {
// c_str() is null-terminated like MemoryBuffer::getMemBuffer requires.
MemoryBuffer *BitcodeBuffer =
MemoryBuffer::getMemBuffer(Bitcode.c_str(),
Bitcode.c_str() + Bitcode.size(),
"Bitcode for test");
std::string errMsg;
MP = getBitcodeModuleProvider(BitcodeBuffer, Context, &errMsg);
if (MP == NULL) {
ADD_FAILURE() << errMsg;
delete BitcodeBuffer;
return NULL;
}
ExecutionEngine *TheJIT = EngineBuilder(MP)
.setEngineKind(EngineKind::JIT)
.setErrorStr(&errMsg)
.create();
if (TheJIT == NULL) {
ADD_FAILURE() << errMsg;
delete MP;
MP = NULL;
return NULL;
}
return TheJIT;
}
TEST(LazyLoadedJITTest, EagerCompiledRecursionThroughGhost) {
LLVMContext Context;
const std::string Bitcode =
AssembleToBitcode(Context,
"define i32 @recur1(i32 %a) { "
" %zero = icmp eq i32 %a, 0 "
" br i1 %zero, label %done, label %notdone "
"done: "
" ret i32 3 "
"notdone: "
" %am1 = sub i32 %a, 1 "
" %result = call i32 @recur2(i32 %am1) "
" ret i32 %result "
"} "
" "
"define i32 @recur2(i32 %b) { "
" %result = call i32 @recur1(i32 %b) "
" ret i32 %result "
"} ");
ASSERT_FALSE(Bitcode.empty()) << "Assembling failed";
ModuleProvider *MP;
OwningPtr<ExecutionEngine> TheJIT(getJITFromBitcode(Context, Bitcode, MP));
ASSERT_TRUE(TheJIT.get()) << "Failed to create JIT.";
TheJIT->DisableLazyCompilation(true);
Module *M = MP->getModule();
Function *recur1IR = M->getFunction("recur1");
Function *recur2IR = M->getFunction("recur2");
EXPECT_TRUE(recur1IR->hasNotBeenReadFromBitcode());
EXPECT_TRUE(recur2IR->hasNotBeenReadFromBitcode());
int32_t (*recur1)(int32_t) = reinterpret_cast<int32_t(*)(int32_t)>(
(intptr_t)TheJIT->getPointerToFunction(recur1IR));
EXPECT_EQ(3, recur1(4));
}
// This code is copied from JITEventListenerTest, but it only runs once for all
// the tests in this directory. Everything seems fine, but that's strange
// behavior.

View File

@ -9,7 +9,7 @@
LEVEL = ../../..
TESTNAME = JIT
LINK_COMPONENTS := asmparser core support jit native
LINK_COMPONENTS := asmparser bitreader bitwriter core jit native support
include $(LEVEL)/Makefile.config
include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest