Fix PR576.

Instead of emitting a JIT stub that looks like this:

internal void %l1_main_entry_2E_ce_wrapper(int) {
header:
        %resolver = call sbyte* %getPointerToNamedFunction( sbyte* getelementptr ([20 x sbyte]* %l1_main_entry_2E_ce_name, int 0, int 0) )           ; <sbyte*> [#uses=1]
        %resolverCast = cast sbyte* %resolver to void (int)*            ; <void (int)*> [#uses=1]
        call void %resolverCast( int %0 )
        ret void
}

Emit one that looks like this:

internal void %l1_main_entry_2E_ce_wrapper(int) {
Entry:
	%fpcache = load void (int)** %l1_main_entry_2E_ce.fpcache               ; <void (int)*> [#uses=2]
        %isNull = seteq void (int)* %fpcache, null              ; <bool> [#uses=1]
        br bool %isNull, label %lookupfp, label %usecache

usecache:               ; preds = %lookupfp, %Entry
        %fp = phi void (int)* [ %resolverCast, %lookupfp ], [ %fpcache, %Entry ]            ; <void (int)*> [#uses=1]
        call void %fp( int %0 )
        ret void

lookupfp:               ; preds = %Entry
        %resolver = call sbyte* %getPointerToNamedFunction( sbyte* getelementptr ([20 x sbyte]* %l1_main_entry_2E_ce_name, int 0, int 0) )           ; <sbyte*> [#uses=1]
        %resolverCast = cast sbyte* %resolver to void (int)*            ; <void (int)*> [#uses=2]
        store void (int)* %resolverCast, void (int)** %l1_main_entry_2E_ce.fpcache
        br label %usecache
}


This makes the JIT debugger *MUCH* faster on large programs, as
getPointerToNamedFunction takes time linear with the size of the program, and
before we would call it every time a function in the text module was called from
the safe module (ouch!).


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22387 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2005-07-12 01:00:32 +00:00
parent 9b988be187
commit a3efca16f2

View File

@ -686,28 +686,47 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
// Rewrite uses of F in global initializers, etc. to uses of a wrapper
// function that dynamically resolves the calls to F via our JIT API
if (F->use_begin() != F->use_end()) {
if (!F->use_empty()) {
// Create a new global to hold the cached function pointer.
Constant *NullPtr = ConstantPointerNull::get(F->getType());
GlobalVariable *Cache =
new GlobalVariable(F->getType(), false,GlobalValue::InternalLinkage,
NullPtr,F->getName()+".fpcache", F->getParent());
// Construct a new stub function that will re-route calls to F
const FunctionType *FuncTy = F->getFunctionType();
Function *FuncWrapper = new Function(FuncTy,
GlobalValue::InternalLinkage,
F->getName() + "_wrapper",
F->getParent());
BasicBlock *Header = new BasicBlock("header", FuncWrapper);
BasicBlock *EntryBB = new BasicBlock("entry", FuncWrapper);
BasicBlock *DoCallBB = new BasicBlock("usecache", FuncWrapper);
BasicBlock *LookupBB = new BasicBlock("lookupfp", FuncWrapper);
// Check to see if we already looked up the value.
Value *CachedVal = new LoadInst(Cache, "fpcache", EntryBB);
Value *IsNull = new SetCondInst(Instruction::SetEQ, CachedVal,
NullPtr, "isNull", EntryBB);
new BranchInst(LookupBB, DoCallBB, IsNull, EntryBB);
// Resolve the call to function F via the JIT API:
//
// call resolver(GetElementPtr...)
CallInst *resolve = new CallInst(resolverFunc, ResolverArgs,
"resolver");
Header->getInstList().push_back(resolve);
CallInst *Resolver = new CallInst(resolverFunc, ResolverArgs,
"resolver", LookupBB);
// cast the result from the resolver to correctly-typed function
CastInst *castResolver =
new CastInst(resolve, PointerType::get(F->getFunctionType()),
"resolverCast");
Header->getInstList().push_back(castResolver);
CastInst *CastedResolver =
new CastInst(Resolver, PointerType::get(F->getFunctionType()),
"resolverCast", LookupBB);
// Save the value in our cache.
new StoreInst(CastedResolver, Cache, LookupBB);
new BranchInst(DoCallBB, LookupBB);
// Save the argument list
PHINode *FuncPtr = new PHINode(NullPtr->getType(), "fp", DoCallBB);
FuncPtr->addIncoming(CastedResolver, LookupBB);
FuncPtr->addIncoming(CachedVal, EntryBB);
// Save the argument list.
std::vector<Value*> Args;
for (Function::arg_iterator i = FuncWrapper->arg_begin(),
e = FuncWrapper->arg_end(); i != e; ++i)
@ -715,15 +734,11 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
// Pass on the arguments to the real function, return its result
if (F->getReturnType() == Type::VoidTy) {
CallInst *Call = new CallInst(castResolver, Args);
Header->getInstList().push_back(Call);
ReturnInst *Ret = new ReturnInst();
Header->getInstList().push_back(Ret);
CallInst *Call = new CallInst(FuncPtr, Args, "", DoCallBB);
new ReturnInst(DoCallBB);
} else {
CallInst *Call = new CallInst(castResolver, Args, "redir");
Header->getInstList().push_back(Call);
ReturnInst *Ret = new ReturnInst(Call);
Header->getInstList().push_back(Ret);
CallInst *Call = new CallInst(FuncPtr, Args, "retval", DoCallBB);
new ReturnInst(Call, DoCallBB);
}
// Use the wrapper function instead of the old function