mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 19:31:58 +00:00
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:
parent
f6f7ec1ee2
commit
de4803d0af
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user