#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
using namespace llvm;
+STATISTIC(NumRejectedSRETUses , "Number of sret rejected due to unexpected uses");
+STATISTIC(NumSRET , "Number of sret promoted");
namespace {
/// SRETPromotion - This pass removes sret parameter and updates
/// function to use multiple return value.
bool isSafeToUpdateAllCallers(Function *F);
Function *cloneFunctionBody(Function *F, const StructType *STy);
void updateCallSites(Function *F, Function *NF);
+ bool nestedStructType(const StructType *STy);
};
char SRETPromotion::ID = 0;
bool SRETPromotion::PromoteReturn(CallGraphNode *CGN) {
Function *F = CGN->getFunction();
- // Make sure that it is local to this module.
- if (!F || !F->hasInternalLinkage())
+ if (!F || F->isDeclaration())
return false;
// Make sure that function returns struct.
- if (F->arg_size() == 0 || !F->isStructReturn() || F->doesNotReturn())
+ if (F->arg_size() == 0 || !F->hasStructRetAttr() || F->doesNotReturn())
return false;
assert (F->getReturnType() == Type::VoidTy && "Invalid function return type");
dyn_cast<StructType>(FArgType->getElementType());
assert (STy && "Invalid sret parameter element type");
+ if (nestedStructType(STy))
+ return false;
+
// Check if it is ok to perform this promotion.
- if (isSafeToUpdateAllCallers(F) == false)
+ if (isSafeToUpdateAllCallers(F) == false) {
+ NumRejectedSRETUses++;
return false;
+ }
+ NumSRET++;
// [1] Replace use of sret parameter
- AllocaInst *TheAlloca = new AllocaInst (STy, NULL, "mrv", F->getEntryBlock().begin());
+ AllocaInst *TheAlloca = new AllocaInst (STy, NULL, "mrv",
+ F->getEntryBlock().begin());
Value *NFirstArg = F->arg_begin();
NFirstArg->replaceAllUsesWith(TheAlloca);
- // Find and replace ret instructions
+ // [2] Find and replace ret instructions
SmallVector<Value *,4> RetVals;
for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI)
for(BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
}
}
- // Create the new function body and insert it into the module.
+ // [3] Create the new function body and insert it into the module.
Function *NF = cloneFunctionBody(F, STy);
- // Update all call sites to use new function
+ // [4] Update all call sites to use new function
updateCallSites(F, NF);
F->eraseFromParent();
// If FirstArg user is a GEP whose all users are not LoadInst then
// this function F is not suitable for sret promotion.
else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(ArgI)) {
+ // TODO : Use dom info and insert PHINodes to collect get results
+ // from multiple call sites for this GEP.
+ if (GEP->getParent() != Call->getParent())
+ return false;
for (Value::use_iterator GEPI = GEP->use_begin(), GEPE = GEP->use_end();
GEPI != GEPE; ++GEPI)
if (!isa<LoadInst>(GEPI))
unsigned ParamIndex = 1; // 0th parameter attribute is reserved for return type.
while (I != E) {
Params.push_back(I->getType());
- if (ParameterAttributes attrs = PAL ? PAL->getParamAttrs(ParamIndex) :
- ParamAttr::None)
- ParamAttrsVec.push_back(ParamAttrsWithIndex::get(Params.size(), attrs));
+ ParameterAttributes Attrs = ParamAttr::None;
+ if (PAL) {
+ Attrs = PAL->getParamAttrs(ParamIndex);
+ if (ParamIndex == 1) // Skip sret attribute
+ Attrs = Attrs ^ ParamAttr::StructRet;
+ }
+ if (Attrs != ParamAttr::None)
+ ParamAttrsVec.push_back(ParamAttrsWithIndex::get(ParamIndex, Attrs));
++I;
++ParamIndex;
}
SmallVector<Value*, 16> Args;
// ParamAttrs - Keep track of the parameter attributes for the arguments.
- ParamAttrsVector ParamAttrsVec;
+ ParamAttrsVector ArgAttrsVec;
for (Value::use_iterator FUI = F->use_begin(), FUE = F->use_end(); FUI != FUE;) {
CallSite CS = CallSite::get(*FUI);
const ParamAttrsList *PAL = F->getParamAttrs();
// Add any return attributes.
if (ParameterAttributes attrs = PAL ? PAL->getParamAttrs(0) : ParamAttr::None)
- ParamAttrsVec.push_back(ParamAttrsWithIndex::get(0, attrs));
+ ArgAttrsVec.push_back(ParamAttrsWithIndex::get(0, attrs));
// Copy arguments, however skip first one.
CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
unsigned ParamIndex = 1; // 0th parameter attribute is reserved for return type.
while (AI != AE) {
Args.push_back(*AI);
- if (ParameterAttributes Attrs = PAL ? PAL->getParamAttrs(ParamIndex) :
- ParamAttr::None)
- ParamAttrsVec.push_back(ParamAttrsWithIndex::get(Args.size(), Attrs));
+ ParameterAttributes Attrs = ParamAttr::None;
+ if (PAL) {
+ Attrs = PAL->getParamAttrs(ParamIndex);
+ if (ParamIndex == 1) // Skip sret attribute
+ Attrs = Attrs ^ ParamAttr::StructRet;
+ }
+ if (Attrs != ParamAttr::None)
+ ArgAttrsVec.push_back(ParamAttrsWithIndex::get(Args.size(), Attrs));
++ParamIndex;
++AI;
}
New = new InvokeInst(NF, II->getNormalDest(), II->getUnwindDest(),
Args.begin(), Args.end(), "", Call);
cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv());
- cast<InvokeInst>(New)->setParamAttrs(ParamAttrsList::get(ParamAttrsVec));
+ cast<InvokeInst>(New)->setParamAttrs(ParamAttrsList::get(ArgAttrsVec));
} else {
New = new CallInst(NF, Args.begin(), Args.end(), "", Call);
cast<CallInst>(New)->setCallingConv(CS.getCallingConv());
- cast<CallInst>(New)->setParamAttrs(ParamAttrsList::get(ParamAttrsVec));
+ cast<CallInst>(New)->setParamAttrs(ParamAttrsList::get(ArgAttrsVec));
if (cast<CallInst>(Call)->isTailCall())
cast<CallInst>(New)->setTailCall();
}
Args.clear();
- ParamAttrsVec.clear();
+ ArgAttrsVec.clear();
New->takeName(Call);
// Update all users of sret parameter to extract value using getresult.
if (C2 && (C2 == Call))
continue;
else if (GetElementPtrInst *UGEP = dyn_cast<GetElementPtrInst>(U2)) {
- Value *GR = new GetResultInst(New, 5, "xxx", UGEP);
+ ConstantInt *Idx = dyn_cast<ConstantInt>(UGEP->getOperand(2));
+ assert (Idx && "Unexpected getelementptr index!");
+ Value *GR = new GetResultInst(New, Idx->getZExtValue(), "gr", UGEP);
for (Value::use_iterator GI = UGEP->use_begin(),
GE = UGEP->use_end(); GI != GE; ++GI) {
if (LoadInst *L = dyn_cast<LoadInst>(*GI)) {
Call->eraseFromParent();
}
}
+
+/// nestedStructType - Return true if STy includes any
+/// other aggregate types
+bool SRETPromotion::nestedStructType(const StructType *STy) {
+ unsigned Num = STy->getNumElements();
+ for (unsigned i = 0; i < Num; i++) {
+ const Type *Ty = STy->getElementType(i);
+ if (!Ty->isFirstClassType() && Ty != Type::VoidTy)
+ return true;
+ }
+ return false;
+}