mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-16 14:31:59 +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;
|
std::vector<Value*> ResolverArgs;
|
||||||
ResolverArgs.push_back(GEP);
|
ResolverArgs.push_back(GEP);
|
||||||
|
|
||||||
// Convert uses of F in global initializers, etc. to uses in
|
// Rewrite uses of F in global initializers, etc. to uses of a wrapper
|
||||||
// instructions, which are then fixed-up below
|
// function that dynamically resolves the calls to F via our JIT API
|
||||||
std::vector<User*> Users(F->use_begin(), F->use_end());
|
if (F->use_begin() != F->use_end()) {
|
||||||
for (std::vector<User*>::iterator U = Users.begin(), UE = Users.end();
|
// Construct a new stub function that will re-route calls to F
|
||||||
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();
|
const FunctionType *FuncTy = F->getFunctionType();
|
||||||
Function *FuncWrapper = new Function(FuncTy, F->getLinkage(),
|
Function *FuncWrapper = new Function(FuncTy,
|
||||||
|
GlobalValue::InternalLinkage,
|
||||||
F->getName() + "_wrapper",
|
F->getName() + "_wrapper",
|
||||||
F->getParent());
|
F->getParent());
|
||||||
BasicBlock *Header = new BasicBlock("header", FuncWrapper);
|
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
|
// Save the argument list
|
||||||
std::vector<Value*> Args;
|
std::vector<Value*> Args;
|
||||||
for (Function::aiterator i = FuncWrapper->abegin(),
|
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
|
// Pass on the arguments to the real function, return its result
|
||||||
if (F->getReturnType() == Type::VoidTy) {
|
if (F->getReturnType() == Type::VoidTy) {
|
||||||
CallInst *Call = new CallInst(F, Args);
|
CallInst *Call = new CallInst(castResolver, Args);
|
||||||
Header->getInstList().push_back(Call);
|
Header->getInstList().push_back(Call);
|
||||||
ReturnInst *Ret = new ReturnInst();
|
ReturnInst *Ret = new ReturnInst();
|
||||||
Header->getInstList().push_back(Ret);
|
Header->getInstList().push_back(Ret);
|
||||||
} else {
|
} else {
|
||||||
CallInst *Call = new CallInst(F, Args, "redir");
|
CallInst *Call = new CallInst(castResolver, Args, "redir");
|
||||||
Header->getInstList().push_back(Call);
|
Header->getInstList().push_back(Call);
|
||||||
ReturnInst *Ret = new ReturnInst(Call);
|
ReturnInst *Ret = new ReturnInst(Call);
|
||||||
Header->getInstList().push_back(Ret);
|
Header->getInstList().push_back(Ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace uses of old function with our wrapper
|
// Use the wrapper function instead of the old function
|
||||||
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Use)) {
|
F->replaceAllUsesWith(FuncWrapper);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user