From dc7fef83dcab053f86119d00478e6b008166fcf5 Mon Sep 17 00:00:00 2001 From: Misha Brukman Date: Mon, 19 Apr 2004 01:12:01 +0000 Subject: [PATCH] Finally implement rewriting global initializers which use external functions 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 | 93 +++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 10 deletions(-) diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index 7c82b582eff..fa60aa57f4a 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -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 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 Users(F->use_begin(), F->use_end()); + for (std::vector::iterator U = Users.begin(), UE = Users.end(); + U != UE; ++U) + { + User *Use = *U; + if (Instruction *Inst = dyn_cast(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 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(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(Init)) + CA->replaceUsesOfWithOnConstant(F, FuncWrapper); + else if (ConstantStruct *CS = dyn_cast(Init)) + CS->replaceUsesOfWithOnConstant(F, FuncWrapper); + else { + std::cerr << "UNHANDLED global initializer: " << *Init << "\n"; + exit(1); + } + } else if (Constant *C = dyn_cast(Use)) { + // no need to do anything for constants + } else if (Function *FuncUser = dyn_cast(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(F->use_back())) { + std::vector Uses(F->use_begin(), F->use_end()); + for (std::vector::iterator U = Uses.begin(), UE = Uses.end(); + U != UE; ++U) { + User *Use = *U; + if (Instruction *Inst = dyn_cast(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(Use)) { + // no need to do anything for constants + } else if (Function *FuncUser = dyn_cast(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); } + } } } }