Factor the trampoline transformation into a subroutine.

llvm-svn: 42021
This commit is contained in:
Duncan Sands 2007-09-17 10:26:40 +00:00
parent 699c2410a8
commit 6d5da71288
1 changed files with 148 additions and 137 deletions

View File

@ -235,6 +235,7 @@ namespace {
private:
Instruction *visitCallSite(CallSite CS);
bool transformConstExprCastCall(CallSite CS);
Instruction *transformCallThroughTrampoline(CallSite CS);
public:
// InsertNewInstBefore - insert an instruction New before instruction Old
@ -7834,6 +7835,11 @@ Instruction *InstCombiner::visitCallSite(CallSite CS) {
return EraseInstFromFunction(*CS.getInstruction());
}
if (BitCastInst *BC = dyn_cast<BitCastInst>(Callee))
if (IntrinsicInst *In = dyn_cast<IntrinsicInst>(BC->getOperand(0)))
if (In->getIntrinsicID() == Intrinsic::init_trampoline)
return transformCallThroughTrampoline(CS);
const PointerType *PTy = cast<PointerType>(Callee->getType());
const FunctionType *FTy = cast<FunctionType>(PTy->getElementType());
if (FTy->isVarArg()) {
@ -7852,143 +7858,6 @@ Instruction *InstCombiner::visitCallSite(CallSite CS) {
}
}
if (BitCastInst *BC = dyn_cast<BitCastInst>(Callee)) {
IntrinsicInst *In = dyn_cast<IntrinsicInst>(BC->getOperand(0));
if (In && In->getIntrinsicID() == Intrinsic::init_trampoline) {
Function *NestF =
cast<Function>(IntrinsicInst::StripPointerCasts(In->getOperand(2)));
const PointerType *NestFPTy = cast<PointerType>(NestF->getType());
const FunctionType *NestFTy =
cast<FunctionType>(NestFPTy->getElementType());
if (const ParamAttrsList *NestAttrs = NestFTy->getParamAttrs()) {
unsigned NestIdx = 1;
const Type *NestTy = 0;
uint16_t NestAttr = 0;
Instruction *Caller = CS.getInstruction();
// Look for a parameter marked with the 'nest' attribute.
for (FunctionType::param_iterator I = NestFTy->param_begin(),
E = NestFTy->param_end(); I != E; ++NestIdx, ++I)
if (NestAttrs->paramHasAttr(NestIdx, ParamAttr::Nest)) {
// Record the parameter type and any other attributes.
NestTy = *I;
NestAttr = NestAttrs->getParamAttrs(NestIdx);
break;
}
if (NestTy) {
std::vector<Value*> NewArgs;
NewArgs.reserve(unsigned(CS.arg_end()-CS.arg_begin())+1);
// Insert the nest argument into the call argument list, which may
// mean appending it.
{
unsigned Idx = 1;
CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
do {
if (Idx == NestIdx) {
// Add the chain argument.
Value *NestVal = In->getOperand(3);
if (NestVal->getType() != NestTy)
NestVal = new BitCastInst(NestVal, NestTy, "nest", Caller);
NewArgs.push_back(NestVal);
}
if (I == E)
break;
// Add the original argument.
NewArgs.push_back(*I);
++Idx, ++I;
} while (1);
}
// The trampoline may have been bitcast to a bogus type (FTy).
// Handle this by synthesizing a new function type, equal to FTy
// with the chain parameter inserted. Likewise for attributes.
const ParamAttrsList *Attrs = FTy->getParamAttrs();
std::vector<const Type*> NewTypes;
ParamAttrsVector NewAttrs;
NewTypes.reserve(FTy->getNumParams()+1);
// Add any function result attributes.
uint16_t Attr = Attrs ? Attrs->getParamAttrs(0) : 0;
if (Attr)
NewAttrs.push_back (ParamAttrsWithIndex::get(0, Attr));
// Insert the chain's type into the list of parameter types, which may
// mean appending it. Likewise for the chain's attributes.
{
unsigned Idx = 1;
FunctionType::param_iterator I = FTy->param_begin(),
E = FTy->param_end();
do {
if (Idx == NestIdx) {
// Add the chain's type and attributes.
NewTypes.push_back(NestTy);
NewAttrs.push_back(ParamAttrsWithIndex::get(NestIdx, NestAttr));
}
if (I == E)
break;
// Add the original type and attributes.
NewTypes.push_back(*I);
Attr = Attrs ? Attrs->getParamAttrs(Idx) : 0;
if (Attr)
NewAttrs.push_back
(ParamAttrsWithIndex::get(Idx + (Idx >= NestIdx), Attr));
++Idx, ++I;
} while (1);
}
// Replace the trampoline call with a direct call. Let the generic
// code sort out any function type mismatches.
FunctionType *NewFTy =
FunctionType::get(FTy->getReturnType(), NewTypes, FTy->isVarArg(),
ParamAttrsList::get(NewAttrs));
Constant *NewCallee = NestF->getType() == PointerType::get(NewFTy) ?
NestF : ConstantExpr::getBitCast(NestF, PointerType::get(NewFTy));
Instruction *NewCaller;
if (InvokeInst *II = dyn_cast<InvokeInst>(Caller)) {
NewCaller = new InvokeInst(NewCallee, II->getNormalDest(),
II->getUnwindDest(), NewArgs.begin(),
NewArgs.end(), Caller->getName(),
Caller);
cast<InvokeInst>(NewCaller)->setCallingConv(II->getCallingConv());
} else {
NewCaller = new CallInst(NewCallee, NewArgs.begin(), NewArgs.end(),
Caller->getName(), Caller);
if (cast<CallInst>(Caller)->isTailCall())
cast<CallInst>(NewCaller)->setTailCall();
cast<CallInst>(NewCaller)->
setCallingConv(cast<CallInst>(Caller)->getCallingConv());
}
if (Caller->getType() != Type::VoidTy && !Caller->use_empty())
Caller->replaceAllUsesWith(NewCaller);
Caller->eraseFromParent();
RemoveFromWorkList(Caller);
return 0;
}
}
// Replace the trampoline call with a direct call. Since there is no
// 'nest' parameter, there is no need to adjust the argument list. Let
// the generic code sort out any function type mismatches.
Constant *NewCallee = NestF->getType() == PTy ?
NestF : ConstantExpr::getBitCast(NestF, PTy);
CS.setCalledFunction(NewCallee);
Changed = true;
}
}
return Changed ? CS.getInstruction() : 0;
}
@ -8191,6 +8060,148 @@ bool InstCombiner::transformConstExprCastCall(CallSite CS) {
return true;
}
// transformCallThroughTrampoline - Turn a call to a function created by the
// init_trampoline intrinsic into a direct call to the underlying function.
//
Instruction *InstCombiner::transformCallThroughTrampoline(CallSite CS) {
Value *Callee = CS.getCalledValue();
const PointerType *PTy = cast<PointerType>(Callee->getType());
const FunctionType *FTy = cast<FunctionType>(PTy->getElementType());
IntrinsicInst *Tramp =
cast<IntrinsicInst>(cast<BitCastInst>(Callee)->getOperand(0));
Function *NestF =
cast<Function>(IntrinsicInst::StripPointerCasts(Tramp->getOperand(2)));
const PointerType *NestFPTy = cast<PointerType>(NestF->getType());
const FunctionType *NestFTy = cast<FunctionType>(NestFPTy->getElementType());
if (const ParamAttrsList *NestAttrs = NestFTy->getParamAttrs()) {
unsigned NestIdx = 1;
const Type *NestTy = 0;
uint16_t NestAttr = 0;
// Look for a parameter marked with the 'nest' attribute.
for (FunctionType::param_iterator I = NestFTy->param_begin(),
E = NestFTy->param_end(); I != E; ++NestIdx, ++I)
if (NestAttrs->paramHasAttr(NestIdx, ParamAttr::Nest)) {
// Record the parameter type and any other attributes.
NestTy = *I;
NestAttr = NestAttrs->getParamAttrs(NestIdx);
break;
}
if (NestTy) {
Instruction *Caller = CS.getInstruction();
std::vector<Value*> NewArgs;
NewArgs.reserve(unsigned(CS.arg_end()-CS.arg_begin())+1);
// Insert the nest argument into the call argument list, which may
// mean appending it.
{
unsigned Idx = 1;
CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
do {
if (Idx == NestIdx) {
// Add the chain argument.
Value *NestVal = Tramp->getOperand(3);
if (NestVal->getType() != NestTy)
NestVal = new BitCastInst(NestVal, NestTy, "nest", Caller);
NewArgs.push_back(NestVal);
}
if (I == E)
break;
// Add the original argument.
NewArgs.push_back(*I);
++Idx, ++I;
} while (1);
}
// The trampoline may have been bitcast to a bogus type (FTy).
// Handle this by synthesizing a new function type, equal to FTy
// with the chain parameter inserted. Likewise for attributes.
const ParamAttrsList *Attrs = FTy->getParamAttrs();
std::vector<const Type*> NewTypes;
ParamAttrsVector NewAttrs;
NewTypes.reserve(FTy->getNumParams()+1);
// Add any function result attributes.
uint16_t Attr = Attrs ? Attrs->getParamAttrs(0) : 0;
if (Attr)
NewAttrs.push_back (ParamAttrsWithIndex::get(0, Attr));
// Insert the chain's type into the list of parameter types, which may
// mean appending it. Likewise for the chain's attributes.
{
unsigned Idx = 1;
FunctionType::param_iterator I = FTy->param_begin(),
E = FTy->param_end();
do {
if (Idx == NestIdx) {
// Add the chain's type and attributes.
NewTypes.push_back(NestTy);
NewAttrs.push_back(ParamAttrsWithIndex::get(NestIdx, NestAttr));
}
if (I == E)
break;
// Add the original type and attributes.
NewTypes.push_back(*I);
Attr = Attrs ? Attrs->getParamAttrs(Idx) : 0;
if (Attr)
NewAttrs.push_back
(ParamAttrsWithIndex::get(Idx + (Idx >= NestIdx), Attr));
++Idx, ++I;
} while (1);
}
// Replace the trampoline call with a direct call. Let the generic
// code sort out any function type mismatches.
FunctionType *NewFTy =
FunctionType::get(FTy->getReturnType(), NewTypes, FTy->isVarArg(),
ParamAttrsList::get(NewAttrs));
Constant *NewCallee = NestF->getType() == PointerType::get(NewFTy) ?
NestF : ConstantExpr::getBitCast(NestF, PointerType::get(NewFTy));
Instruction *NewCaller;
if (InvokeInst *II = dyn_cast<InvokeInst>(Caller)) {
NewCaller = new InvokeInst(NewCallee,
II->getNormalDest(), II->getUnwindDest(),
NewArgs.begin(), NewArgs.end(),
Caller->getName(), Caller);
cast<InvokeInst>(NewCaller)->setCallingConv(II->getCallingConv());
} else {
NewCaller = new CallInst(NewCallee, NewArgs.begin(), NewArgs.end(),
Caller->getName(), Caller);
if (cast<CallInst>(Caller)->isTailCall())
cast<CallInst>(NewCaller)->setTailCall();
cast<CallInst>(NewCaller)->
setCallingConv(cast<CallInst>(Caller)->getCallingConv());
}
if (Caller->getType() != Type::VoidTy && !Caller->use_empty())
Caller->replaceAllUsesWith(NewCaller);
Caller->eraseFromParent();
RemoveFromWorkList(Caller);
return 0;
}
}
// Replace the trampoline call with a direct call. Since there is no 'nest'
// parameter, there is no need to adjust the argument list. Let the generic
// code sort out any function type mismatches.
Constant *NewCallee =
NestF->getType() == PTy ? NestF : ConstantExpr::getBitCast(NestF, PTy);
CS.setCalledFunction(NewCallee);
return CS.getInstruction();
}
/// FoldPHIArgBinOpIntoPHI - If we have something like phi [add (a,b), add(c,d)]
/// and if a/b/c/d and the add's all have a single use, turn this into two phi's
/// and a single binop.