Fix PR576.
authorChris Lattner <sabre@nondot.org>
Tue, 12 Jul 2005 01:00:32 +0000 (01:00 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 12 Jul 2005 01:00:32 +0000 (01:00 +0000)
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

tools/bugpoint/Miscompilation.cpp

index 2e0bdb33483ed2b8ff93b8b9a0988df2274e73f5..9be7cd5d576229b193a53ad1bbcc51cf32acc81e 100644 (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);
-
-          // 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);
         }