As per Chris, greatly simplify handling of external functions by using the

wrapper idea uniformly: we can use Value::replaceAllUsesWith() instead of
special-casing by class of user.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@13063 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Misha Brukman 2004-04-19 03:36:47 +00:00
parent f6f7ec1ee2
commit de4803d0af

View File

@ -491,31 +491,29 @@ 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.
// 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()) {
// Construct a new stub function that will re-route calls to F
const FunctionType *FuncTy = F->getFunctionType();
Function *FuncWrapper = new Function(FuncTy, F->getLinkage(),
Function *FuncWrapper = new Function(FuncTy,
GlobalValue::InternalLinkage,
F->getName() + "_wrapper",
F->getParent());
BasicBlock *Header = new BasicBlock("header", FuncWrapper);
// 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);
// 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
std::vector<Value*> Args;
for (Function::aiterator i = FuncWrapper->abegin(),
@ -524,70 +522,19 @@ 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(F, Args);
CallInst *Call = new CallInst(castResolver, Args);
Header->getInstList().push_back(Call);
ReturnInst *Ret = new ReturnInst();
Header->getInstList().push_back(Ret);
} else {
CallInst *Call = new CallInst(F, Args, "redir");
CallInst *Call = new CallInst(castResolver, 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
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);
// cast the result from the resolver to correctly-typed function
CastInst *castResolver =
new CastInst(resolve, PointerType::get(F->getFunctionType()),
"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 {
std::cerr << "UNHANDLED: use of function not rewritten to become "
<< "an instruction: " << *Use << "\n";
exit(1);
}
// Use the wrapper function instead of the old function
F->replaceAllUsesWith(FuncWrapper);
}
}
}