Finally implement rewriting global initializers which use external functions
authorMisha Brukman <brukman+llvm@gmail.com>
Mon, 19 Apr 2004 01:12:01 +0000 (01:12 +0000)
committerMisha Brukman <brukman+llvm@gmail.com>
Mon, 19 Apr 2004 01:12:01 +0000 (01:12 +0000)
by creating an internal wrapper function with same signature as the external
function, and use it instead of the "real" function.

The wrapper then calls the external function using the same JIT function
resolution API that has been used before for rewriting instructions, since the
wrapper has an explicit call instruction which we can rewrite.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@13054 91177308-0d34-0410-b5e6-96231b3b80d8

tools/bugpoint/Miscompilation.cpp

index 7c82b582eff5df067fab206697c6439e76f057eb..fa60aa57f4a9d91d065a2a41b7788fe8bea3e99c 100644 (file)
@@ -466,10 +466,10 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
                               PointerType::get(Type::SByteTy), 0);
     
   // Use the function we just added to get addresses of functions we need.
-  for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F){
+  for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) {
     if (F->isExternal() && !F->use_empty() && &*F != resolverFunc &&
         F->getIntrinsicID() == 0 /* ignore intrinsics */) {
-      Function *TestFn =Test->getFunction(F->getName(), F->getFunctionType());
+      Function *TestFn = Test->getFunction(F->getName(), F->getFunctionType());
 
       // Don't forward functions which are external in the test module too.
       if (TestFn && !TestFn->isExternal()) {
@@ -491,14 +491,85 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
         std::vector<Value*> ResolverArgs;
         ResolverArgs.push_back(GEP);
 
+        // Convert uses of F in global initializers, etc. to uses in
+        // instructions, which are then fixed-up below
+        std::vector<User*> Users(F->use_begin(), F->use_end());
+        for (std::vector<User*>::iterator U = Users.begin(), UE = Users.end();
+             U != UE; ++U)
+        {
+          User *Use = *U;
+          if (Instruction *Inst = dyn_cast<Instruction>(Use))
+            continue; // Will be taken care of below
+
+          // Take care of cases where a function is used by something other
+          // than an instruction; e.g., global variable initializers and
+          // constant expressions.
+          //
+          // Create a new wrapper function with the same signature as the old
+          // function which will just pass the call to the other function. The
+          // use of the other function will then be re-written (below) to look
+          // up the function by name.
+
+          const FunctionType *FuncTy = F->getFunctionType();
+          Function *FuncWrapper = new Function(FuncTy, F->getLinkage(),
+                                               F->getName() + "_wrapper",
+                                               F->getParent());
+          BasicBlock *Header = new BasicBlock("header", FuncWrapper);
+
+          // Save the argument list
+          std::vector<Value*> Args;
+          for (Function::aiterator i = FuncWrapper->abegin(),
+                 e = FuncWrapper->aend(); i != e; ++i)
+            Args.push_back(i);
+
+          // Pass on the arguments to the real function, return its result
+          if (F->getReturnType() == Type::VoidTy) {
+            CallInst *Call = new CallInst(F, Args);
+            Header->getInstList().push_back(Call);
+            ReturnInst *Ret = new ReturnInst();
+            Header->getInstList().push_back(Ret);
+          } else {
+            CallInst *Call = new CallInst(F, Args, "redir");
+            Header->getInstList().push_back(Call);
+            ReturnInst *Ret = new ReturnInst(Call);
+            Header->getInstList().push_back(Ret);
+          }
+
+          // Replace uses of old function with our wrapper
+          if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Use)) {
+            Constant *Init = GV->getInitializer();
+            // Functions should only be used as pointers in arrays and structs;
+            // if any other uses come up, they must be handled here
+            if (ConstantArray *CA = dyn_cast<ConstantArray>(Init))
+              CA->replaceUsesOfWithOnConstant(F, FuncWrapper);
+            else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Init))
+              CS->replaceUsesOfWithOnConstant(F, FuncWrapper);
+            else {
+              std::cerr << "UNHANDLED global initializer: " << *Init << "\n";
+              exit(1);
+            }
+          } else if (Constant *C = dyn_cast<Constant>(Use)) {
+            // no need to do anything for constants
+          } else if (Function *FuncUser = dyn_cast<Function>(Use)) {
+            // no need to do anything for function declarations
+          } else {
+            std::cerr << "UNHANDLED non-instruction use, not a global: "
+                      << *Use << "\ntype: " << *Use->getType() << "\n";
+            exit(1);
+          } 
+        }
+
         // 3. Replace all uses of `func' with calls to resolver by:
         // (a) Iterating through the list of uses of this function
         // (b) Insert a cast instruction in front of each use
         // (c) Replace use of old call with new call
 
         // Insert code at the beginning of the function
-        while (!F->use_empty())
-          if (Instruction *Inst = dyn_cast<Instruction>(F->use_back())) {
+        std::vector<User*> Uses(F->use_begin(), F->use_end());
+        for (std::vector<User*>::iterator U = Uses.begin(), UE = Uses.end();
+             U != UE; ++U) {
+          User *Use = *U;
+          if (Instruction *Inst = dyn_cast<Instruction>(Use)) {
             // call resolver(GetElementPtr...)
             CallInst *resolve = new CallInst(resolverFunc, ResolverArgs, 
                                              "resolver", Inst);
@@ -508,14 +579,16 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
                            "resolverCast", Inst);
             // actually use the resolved function
             Inst->replaceUsesOfWith(F, castResolver);
+          } else if (Constant *C = dyn_cast<Constant>(Use)) {
+            // no need to do anything for constants
+          } else if (Function *FuncUser = dyn_cast<Function>(Use)) {
+            // no need to do anything for function declarations
           } else {
-            // FIXME: need to take care of cases where a function is used by
-            // something other than an instruction; e.g., global variable
-            // initializers and constant expressions.
-            std::cerr << "UNSUPPORTED: Non-instruction is using an external "
-                      << "function, " << F->getName() << "().\n";
-            abort();
+            std::cerr << "UNHANDLED: use of function not rewritten to become "
+                      << "an instruction: " << *Use << "\n";
+            exit(1);
           }
+        }
       }
     }
   }