LLVM API Documentation

StructRetPromotion.cpp

Go to the documentation of this file.
00001 //===-- StructRetPromotion.cpp - Promote sret arguments ------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This pass finds functions that return a struct (using a pointer to the struct
00011 // as the first argument of the function, marked with the 'sret' attribute) and
00012 // replaces them with a new function that simply returns each of the elements of
00013 // that struct (using multiple return values).
00014 //
00015 // This pass works under a number of conditions:
00016 //  1. The returned struct must not contain other structs
00017 //  2. The returned struct must only be used to load values from
00018 //  3. The placeholder struct passed in is the result of an alloca
00019 //
00020 //===----------------------------------------------------------------------===//
00021 
00022 #define DEBUG_TYPE "sretpromotion"
00023 #include "llvm/Transforms/IPO.h"
00024 #include "llvm/Constants.h"
00025 #include "llvm/DerivedTypes.h"
00026 #include "llvm/Module.h"
00027 #include "llvm/CallGraphSCCPass.h"
00028 #include "llvm/Instructions.h"
00029 #include "llvm/Analysis/CallGraph.h"
00030 #include "llvm/Support/CallSite.h"
00031 #include "llvm/Support/CFG.h"
00032 #include "llvm/Support/Debug.h"
00033 #include "llvm/ADT/Statistic.h"
00034 #include "llvm/ADT/SmallVector.h"
00035 #include "llvm/ADT/Statistic.h"
00036 #include "llvm/Support/Compiler.h"
00037 using namespace llvm;
00038 
00039 STATISTIC(NumRejectedSRETUses , "Number of sret rejected due to unexpected uses");
00040 STATISTIC(NumSRET , "Number of sret promoted");
00041 namespace {
00042   /// SRETPromotion - This pass removes sret parameter and updates
00043   /// function to use multiple return value.
00044   ///
00045   struct VISIBILITY_HIDDEN SRETPromotion : public CallGraphSCCPass {
00046     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
00047       CallGraphSCCPass::getAnalysisUsage(AU);
00048     }
00049 
00050     virtual bool runOnSCC(const std::vector<CallGraphNode *> &SCC);
00051     static char ID; // Pass identification, replacement for typeid
00052     SRETPromotion() : CallGraphSCCPass(&ID) {}
00053 
00054   private:
00055     bool PromoteReturn(CallGraphNode *CGN);
00056     bool isSafeToUpdateAllCallers(Function *F);
00057     Function *cloneFunctionBody(Function *F, const StructType *STy);
00058     void updateCallSites(Function *F, Function *NF);
00059     bool nestedStructType(const StructType *STy);
00060   };
00061 }
00062 
00063 char SRETPromotion::ID = 0;
00064 static RegisterPass<SRETPromotion>
00065 X("sretpromotion", "Promote sret arguments to multiple ret values");
00066 
00067 Pass *llvm::createStructRetPromotionPass() {
00068   return new SRETPromotion();
00069 }
00070 
00071 bool SRETPromotion::runOnSCC(const std::vector<CallGraphNode *> &SCC) {
00072   bool Changed = false;
00073 
00074   for (unsigned i = 0, e = SCC.size(); i != e; ++i)
00075     Changed |= PromoteReturn(SCC[i]);
00076 
00077   return Changed;
00078 }
00079 
00080 /// PromoteReturn - This method promotes function that uses StructRet paramater 
00081 /// into a function that uses mulitple return value.
00082 bool SRETPromotion::PromoteReturn(CallGraphNode *CGN) {
00083   Function *F = CGN->getFunction();
00084 
00085   if (!F || F->isDeclaration() || !F->hasLocalLinkage())
00086     return false;
00087 
00088   // Make sure that function returns struct.
00089   if (F->arg_size() == 0 || !F->hasStructRetAttr() || F->doesNotReturn())
00090     return false;
00091 
00092   DOUT << "SretPromotion: Looking at sret function " << F->getNameStart() << "\n";
00093 
00094   assert (F->getReturnType() == Type::VoidTy && "Invalid function return type");
00095   Function::arg_iterator AI = F->arg_begin();
00096   const llvm::PointerType *FArgType = dyn_cast<PointerType>(AI->getType());
00097   assert (FArgType && "Invalid sret parameter type");
00098   const llvm::StructType *STy = 
00099     dyn_cast<StructType>(FArgType->getElementType());
00100   assert (STy && "Invalid sret parameter element type");
00101 
00102   // Check if it is ok to perform this promotion.
00103   if (isSafeToUpdateAllCallers(F) == false) {
00104     DOUT << "SretPromotion: Not all callers can be updated\n";
00105     NumRejectedSRETUses++;
00106     return false;
00107   }
00108 
00109   DOUT << "SretPromotion: sret argument will be promoted\n";
00110   NumSRET++;
00111   // [1] Replace use of sret parameter 
00112   AllocaInst *TheAlloca = new AllocaInst (STy, NULL, "mrv", 
00113                                           F->getEntryBlock().begin());
00114   Value *NFirstArg = F->arg_begin();
00115   NFirstArg->replaceAllUsesWith(TheAlloca);
00116 
00117   // [2] Find and replace ret instructions
00118   for (Function::iterator FI = F->begin(), FE = F->end();  FI != FE; ++FI) 
00119     for(BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
00120       Instruction *I = BI;
00121       ++BI;
00122       if (isa<ReturnInst>(I)) {
00123         Value *NV = new LoadInst(TheAlloca, "mrv.ld", I);
00124         ReturnInst *NR = ReturnInst::Create(NV, I);
00125         I->replaceAllUsesWith(NR);
00126         I->eraseFromParent();
00127       }
00128     }
00129 
00130   // [3] Create the new function body and insert it into the module.
00131   Function *NF = cloneFunctionBody(F, STy);
00132 
00133   // [4] Update all call sites to use new function
00134   updateCallSites(F, NF);
00135 
00136   F->eraseFromParent();
00137   getAnalysis<CallGraph>().changeFunction(F, NF);
00138   return true;
00139 }
00140 
00141 // Check if it is ok to perform this promotion.
00142 bool SRETPromotion::isSafeToUpdateAllCallers(Function *F) {
00143 
00144   if (F->use_empty())
00145     // No users. OK to modify signature.
00146     return true;
00147 
00148   for (Value::use_iterator FnUseI = F->use_begin(), FnUseE = F->use_end();
00149        FnUseI != FnUseE; ++FnUseI) {
00150     // The function is passed in as an argument to (possibly) another function,
00151     // we can't change it!
00152     CallSite CS = CallSite::get(*FnUseI);
00153     Instruction *Call = CS.getInstruction();
00154     // The function is used by something else than a call or invoke instruction,
00155     // we can't change it!
00156     if (!Call || !CS.isCallee(FnUseI))
00157       return false;
00158     CallSite::arg_iterator AI = CS.arg_begin();
00159     Value *FirstArg = *AI;
00160 
00161     if (!isa<AllocaInst>(FirstArg))
00162       return false;
00163 
00164     // Check FirstArg's users.
00165     for (Value::use_iterator ArgI = FirstArg->use_begin(), 
00166            ArgE = FirstArg->use_end(); ArgI != ArgE; ++ArgI) {
00167 
00168       // If FirstArg user is a CallInst that does not correspond to current
00169       // call site then this function F is not suitable for sret promotion.
00170       if (CallInst *CI = dyn_cast<CallInst>(ArgI)) {
00171         if (CI != Call)
00172           return false;
00173       }
00174       // If FirstArg user is a GEP whose all users are not LoadInst then
00175       // this function F is not suitable for sret promotion.
00176       else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(ArgI)) {
00177         // TODO : Use dom info and insert PHINodes to collect get results
00178         // from multiple call sites for this GEP.
00179         if (GEP->getParent() != Call->getParent())
00180           return false;
00181         for (Value::use_iterator GEPI = GEP->use_begin(), GEPE = GEP->use_end();
00182              GEPI != GEPE; ++GEPI) 
00183           if (!isa<LoadInst>(GEPI))
00184             return false;
00185       } 
00186       // Any other FirstArg users make this function unsuitable for sret 
00187       // promotion.
00188       else
00189         return false;
00190     }
00191   }
00192 
00193   return true;
00194 }
00195 
00196 /// cloneFunctionBody - Create a new function based on F and
00197 /// insert it into module. Remove first argument. Use STy as
00198 /// the return type for new function.
00199 Function *SRETPromotion::cloneFunctionBody(Function *F, 
00200                                            const StructType *STy) {
00201 
00202   const FunctionType *FTy = F->getFunctionType();
00203   std::vector<const Type*> Params;
00204 
00205   // Attributes - Keep track of the parameter attributes for the arguments.
00206   SmallVector<AttributeWithIndex, 8> AttributesVec;
00207   const AttrListPtr &PAL = F->getAttributes();
00208 
00209   // Add any return attributes.
00210   if (Attributes attrs = PAL.getRetAttributes())
00211     AttributesVec.push_back(AttributeWithIndex::get(0, attrs));
00212 
00213   // Skip first argument.
00214   Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
00215   ++I;
00216   // 0th parameter attribute is reserved for return type.
00217   // 1th parameter attribute is for first 1st sret argument.
00218   unsigned ParamIndex = 2; 
00219   while (I != E) {
00220     Params.push_back(I->getType());
00221     if (Attributes Attrs = PAL.getParamAttributes(ParamIndex))
00222       AttributesVec.push_back(AttributeWithIndex::get(ParamIndex - 1, Attrs));
00223     ++I;
00224     ++ParamIndex;
00225   }
00226 
00227   // Add any fn attributes.
00228   if (Attributes attrs = PAL.getFnAttributes())
00229     AttributesVec.push_back(AttributeWithIndex::get(~0, attrs));
00230 
00231 
00232   FunctionType *NFTy = FunctionType::get(STy, Params, FTy->isVarArg());
00233   Function *NF = Function::Create(NFTy, F->getLinkage());
00234   NF->takeName(F);
00235   NF->copyAttributesFrom(F);
00236   NF->setAttributes(AttrListPtr::get(AttributesVec.begin(), AttributesVec.end()));
00237   F->getParent()->getFunctionList().insert(F, NF);
00238   NF->getBasicBlockList().splice(NF->begin(), F->getBasicBlockList());
00239 
00240   // Replace arguments
00241   I = F->arg_begin();
00242   E = F->arg_end();
00243   Function::arg_iterator NI = NF->arg_begin();
00244   ++I;
00245   while (I != E) {
00246       I->replaceAllUsesWith(NI);
00247       NI->takeName(I);
00248       ++I;
00249       ++NI;
00250   }
00251 
00252   return NF;
00253 }
00254 
00255 /// updateCallSites - Update all sites that call F to use NF.
00256 void SRETPromotion::updateCallSites(Function *F, Function *NF) {
00257   CallGraph &CG = getAnalysis<CallGraph>();
00258   SmallVector<Value*, 16> Args;
00259 
00260   // Attributes - Keep track of the parameter attributes for the arguments.
00261   SmallVector<AttributeWithIndex, 8> ArgAttrsVec;
00262 
00263   while (!F->use_empty()) {
00264     CallSite CS = CallSite::get(*F->use_begin());
00265     Instruction *Call = CS.getInstruction();
00266 
00267     const AttrListPtr &PAL = F->getAttributes();
00268     // Add any return attributes.
00269     if (Attributes attrs = PAL.getRetAttributes())
00270       ArgAttrsVec.push_back(AttributeWithIndex::get(0, attrs));
00271 
00272     // Copy arguments, however skip first one.
00273     CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
00274     Value *FirstCArg = *AI;
00275     ++AI;
00276     // 0th parameter attribute is reserved for return type.
00277     // 1th parameter attribute is for first 1st sret argument.
00278     unsigned ParamIndex = 2; 
00279     while (AI != AE) {
00280       Args.push_back(*AI); 
00281       if (Attributes Attrs = PAL.getParamAttributes(ParamIndex))
00282         ArgAttrsVec.push_back(AttributeWithIndex::get(ParamIndex - 1, Attrs));
00283       ++ParamIndex;
00284       ++AI;
00285     }
00286 
00287     // Add any function attributes.
00288     if (Attributes attrs = PAL.getFnAttributes())
00289       ArgAttrsVec.push_back(AttributeWithIndex::get(~0, attrs));
00290     
00291     AttrListPtr NewPAL = AttrListPtr::get(ArgAttrsVec.begin(), ArgAttrsVec.end());
00292     
00293     // Build new call instruction.
00294     Instruction *New;
00295     if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
00296       New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(),
00297                                Args.begin(), Args.end(), "", Call);
00298       cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv());
00299       cast<InvokeInst>(New)->setAttributes(NewPAL);
00300     } else {
00301       New = CallInst::Create(NF, Args.begin(), Args.end(), "", Call);
00302       cast<CallInst>(New)->setCallingConv(CS.getCallingConv());
00303       cast<CallInst>(New)->setAttributes(NewPAL);
00304       if (cast<CallInst>(Call)->isTailCall())
00305         cast<CallInst>(New)->setTailCall();
00306     }
00307     Args.clear();
00308     ArgAttrsVec.clear();
00309     New->takeName(Call);
00310 
00311     // Update the callgraph to know that the callsite has been transformed.
00312     CG[Call->getParent()->getParent()]->replaceCallSite(Call, New);
00313 
00314     // Update all users of sret parameter to extract value using extractvalue.
00315     for (Value::use_iterator UI = FirstCArg->use_begin(), 
00316            UE = FirstCArg->use_end(); UI != UE; ) {
00317       User *U2 = *UI++;
00318       CallInst *C2 = dyn_cast<CallInst>(U2);
00319       if (C2 && (C2 == Call))
00320         continue;
00321       else if (GetElementPtrInst *UGEP = dyn_cast<GetElementPtrInst>(U2)) {
00322         ConstantInt *Idx = dyn_cast<ConstantInt>(UGEP->getOperand(2));
00323         assert (Idx && "Unexpected getelementptr index!");
00324         Value *GR = ExtractValueInst::Create(New, Idx->getZExtValue(),
00325                                              "evi", UGEP);
00326         while(!UGEP->use_empty()) {
00327           // isSafeToUpdateAllCallers has checked that all GEP uses are
00328           // LoadInsts
00329           LoadInst *L = cast<LoadInst>(*UGEP->use_begin());
00330           L->replaceAllUsesWith(GR);
00331           L->eraseFromParent();
00332         }
00333         UGEP->eraseFromParent();
00334       }
00335       else assert( 0 && "Unexpected sret parameter use");
00336     }
00337     Call->eraseFromParent();
00338   }
00339 }
00340 
00341 /// nestedStructType - Return true if STy includes any
00342 /// other aggregate types
00343 bool SRETPromotion::nestedStructType(const StructType *STy) {
00344   unsigned Num = STy->getNumElements();
00345   for (unsigned i = 0; i < Num; i++) {
00346     const Type *Ty = STy->getElementType(i);
00347     if (!Ty->isSingleValueType() && Ty != Type::VoidTy)
00348       return true;
00349   }
00350   return false;
00351 }