forked from OSchip/llvm-project
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!). llvm-svn: 22387
This commit is contained in:
parent
de69bf9972
commit
986675cb75
|
@ -686,28 +686,47 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
|
||||||
|
|
||||||
// Rewrite uses of F in global initializers, etc. to uses of a wrapper
|
// 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
|
// 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
|
// Construct a new stub function that will re-route calls to F
|
||||||
const FunctionType *FuncTy = F->getFunctionType();
|
const FunctionType *FuncTy = F->getFunctionType();
|
||||||
Function *FuncWrapper = new Function(FuncTy,
|
Function *FuncWrapper = new Function(FuncTy,
|
||||||
GlobalValue::InternalLinkage,
|
GlobalValue::InternalLinkage,
|
||||||
F->getName() + "_wrapper",
|
F->getName() + "_wrapper",
|
||||||
F->getParent());
|
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:
|
// Resolve the call to function F via the JIT API:
|
||||||
//
|
//
|
||||||
// call resolver(GetElementPtr...)
|
// call resolver(GetElementPtr...)
|
||||||
CallInst *resolve = new CallInst(resolverFunc, ResolverArgs,
|
CallInst *Resolver = new CallInst(resolverFunc, ResolverArgs,
|
||||||
"resolver");
|
"resolver", LookupBB);
|
||||||
Header->getInstList().push_back(resolve);
|
|
||||||
// cast the result from the resolver to correctly-typed function
|
// cast the result from the resolver to correctly-typed function
|
||||||
CastInst *castResolver =
|
CastInst *CastedResolver =
|
||||||
new CastInst(resolve, PointerType::get(F->getFunctionType()),
|
new CastInst(Resolver, PointerType::get(F->getFunctionType()),
|
||||||
"resolverCast");
|
"resolverCast", LookupBB);
|
||||||
Header->getInstList().push_back(castResolver);
|
// Save the value in our cache.
|
||||||
|
new StoreInst(CastedResolver, Cache, LookupBB);
|
||||||
// Save the argument list
|
new BranchInst(DoCallBB, LookupBB);
|
||||||
|
|
||||||
|
PHINode *FuncPtr = new PHINode(NullPtr->getType(), "fp", DoCallBB);
|
||||||
|
FuncPtr->addIncoming(CastedResolver, LookupBB);
|
||||||
|
FuncPtr->addIncoming(CachedVal, EntryBB);
|
||||||
|
|
||||||
|
// Save the argument list.
|
||||||
std::vector<Value*> Args;
|
std::vector<Value*> Args;
|
||||||
for (Function::arg_iterator i = FuncWrapper->arg_begin(),
|
for (Function::arg_iterator i = FuncWrapper->arg_begin(),
|
||||||
e = FuncWrapper->arg_end(); i != e; ++i)
|
e = FuncWrapper->arg_end(); i != e; ++i)
|
||||||
|
@ -715,17 +734,13 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
|
||||||
|
|
||||||
// Pass on the arguments to the real function, return its result
|
// Pass on the arguments to the real function, return its result
|
||||||
if (F->getReturnType() == Type::VoidTy) {
|
if (F->getReturnType() == Type::VoidTy) {
|
||||||
CallInst *Call = new CallInst(castResolver, Args);
|
CallInst *Call = new CallInst(FuncPtr, Args, "", DoCallBB);
|
||||||
Header->getInstList().push_back(Call);
|
new ReturnInst(DoCallBB);
|
||||||
ReturnInst *Ret = new ReturnInst();
|
|
||||||
Header->getInstList().push_back(Ret);
|
|
||||||
} else {
|
} else {
|
||||||
CallInst *Call = new CallInst(castResolver, Args, "redir");
|
CallInst *Call = new CallInst(FuncPtr, Args, "retval", DoCallBB);
|
||||||
Header->getInstList().push_back(Call);
|
new ReturnInst(Call, DoCallBB);
|
||||||
ReturnInst *Ret = new ReturnInst(Call);
|
|
||||||
Header->getInstList().push_back(Ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the wrapper function instead of the old function
|
// Use the wrapper function instead of the old function
|
||||||
F->replaceAllUsesWith(FuncWrapper);
|
F->replaceAllUsesWith(FuncWrapper);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue