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
This commit is contained in:
Misha Brukman 2004-04-19 01:12:01 +00:00
parent 4e77cc46ac
commit dc7fef83dc

View 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);
}
}
}
}
}