mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 11:42:57 +01:00
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
81b635da44
commit
eb6bad32e9
@ -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);
|
||||
|
||||
// Save the argument list
|
||||
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);
|
||||
|
||||
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,17 +734,13 @@ 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
|
||||
F->replaceAllUsesWith(FuncWrapper);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user