diff options
Diffstat (limited to 'lib/Transforms/IPO')
-rw-r--r-- | lib/Transforms/IPO/ArgumentPromotion.cpp | 15 | ||||
-rw-r--r-- | lib/Transforms/IPO/DeadArgumentElimination.cpp | 7 | ||||
-rw-r--r-- | lib/Transforms/IPO/GlobalOpt.cpp | 51 | ||||
-rw-r--r-- | lib/Transforms/IPO/IPConstantPropagation.cpp | 7 | ||||
-rw-r--r-- | lib/Transforms/IPO/Inliner.cpp | 2 | ||||
-rw-r--r-- | lib/Transforms/IPO/LowerSetJmp.cpp | 18 | ||||
-rw-r--r-- | lib/Transforms/IPO/MergeFunctions.cpp | 3 | ||||
-rw-r--r-- | lib/Transforms/IPO/PartialInlining.cpp | 10 | ||||
-rw-r--r-- | lib/Transforms/IPO/PartialSpecialization.cpp | 48 | ||||
-rw-r--r-- | lib/Transforms/IPO/StripSymbols.cpp | 133 | ||||
-rw-r--r-- | lib/Transforms/IPO/StructRetPromotion.cpp | 10 |
11 files changed, 225 insertions, 79 deletions
diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp index 89f213e2ac36..28ea079abd36 100644 --- a/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -360,19 +360,20 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg, bool isByVal) const { IndicesVector Operands; for (Value::use_iterator UI = Arg->use_begin(), E = Arg->use_end(); UI != E; ++UI) { + User *U = *UI; Operands.clear(); - if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) { + if (LoadInst *LI = dyn_cast<LoadInst>(U)) { if (LI->isVolatile()) return false; // Don't hack volatile loads Loads.push_back(LI); // Direct loads are equivalent to a GEP with a zero index and then a load. Operands.push_back(0); - } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(*UI)) { + } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) { if (GEP->use_empty()) { // Dead GEP's cause trouble later. Just remove them if we run into // them. getAnalysis<AliasAnalysis>().deleteValue(GEP); GEP->eraseFromParent(); - // TODO: This runs the above loop over and over again for dead GEPS + // TODO: This runs the above loop over and over again for dead GEPs // Couldn't we just do increment the UI iterator earlier and erase the // use? return isSafeToPromoteArgument(Arg, isByVal); @@ -452,12 +453,14 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg, bool isByVal) const { // Now check every path from the entry block to the load for transparency. // To do this, we perform a depth first search on the inverse CFG from the // loading block. - for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { + BasicBlock *P = *PI; for (idf_ext_iterator<BasicBlock*, SmallPtrSet<BasicBlock*, 16> > - I = idf_ext_begin(*PI, TranspBlocks), - E = idf_ext_end(*PI, TranspBlocks); I != E; ++I) + I = idf_ext_begin(P, TranspBlocks), + E = idf_ext_end(P, TranspBlocks); I != E; ++I) if (AA.canBasicBlockModify(**I, Arg, LoadSize)) return false; + } } // If the path from the entry of the function to each load is free of diff --git a/lib/Transforms/IPO/DeadArgumentElimination.cpp b/lib/Transforms/IPO/DeadArgumentElimination.cpp index 692e47da71c3..475eee8b19e4 100644 --- a/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -120,9 +120,14 @@ namespace { typedef SmallVector<RetOrArg, 5> UseVector; + protected: + // DAH uses this to specify a different ID. + explicit DAE(void *ID) : ModulePass(ID) {} + public: static char ID; // Pass identification, replacement for typeid DAE() : ModulePass(&ID) {} + bool runOnModule(Module &M); virtual bool ShouldHackArguments() const { return false; } @@ -155,6 +160,8 @@ namespace { /// by bugpoint. struct DAH : public DAE { static char ID; + DAH() : DAE(&ID) {} + virtual bool ShouldHackArguments() const { return true; } }; } diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index b429213a7db3..735a1c47c39b 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -160,13 +160,12 @@ static bool SafeToDestroyConstant(const Constant *C) { static bool AnalyzeGlobal(const Value *V, GlobalStatus &GS, SmallPtrSet<const PHINode*, 16> &PHIUsers) { for (Value::const_use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; - ++UI) - if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(*UI)) { + ++UI) { + const User *U = *UI; + if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) { GS.HasNonInstructionUser = true; - if (AnalyzeGlobal(CE, GS, PHIUsers)) return true; - - } else if (const Instruction *I = dyn_cast<Instruction>(*UI)) { + } else if (const Instruction *I = dyn_cast<Instruction>(U)) { if (!GS.HasMultipleAccessingFunctions) { const Function *F = I->getParent()->getParent(); if (GS.AccessingFunction == 0) @@ -221,18 +220,21 @@ static bool AnalyzeGlobal(const Value *V, GlobalStatus &GS, if (AnalyzeGlobal(I, GS, PHIUsers)) return true; GS.HasPHIUser = true; } else if (isa<CmpInst>(I)) { + // Nothing to analyse. } else if (isa<MemTransferInst>(I)) { - if (I->getOperand(1) == V) + const MemTransferInst *MTI = cast<MemTransferInst>(I); + if (MTI->getArgOperand(0) == V) GS.StoredType = GlobalStatus::isStored; - if (I->getOperand(2) == V) + if (MTI->getArgOperand(1) == V) GS.isLoaded = true; } else if (isa<MemSetInst>(I)) { - assert(I->getOperand(1) == V && "Memset only takes one pointer!"); + assert(cast<MemSetInst>(I)->getArgOperand(0) == V && + "Memset only takes one pointer!"); GS.StoredType = GlobalStatus::isStored; } else { return true; // Any other non-load instruction might take address! } - } else if (const Constant *C = dyn_cast<Constant>(*UI)) { + } else if (const Constant *C = dyn_cast<Constant>(U)) { GS.HasNonInstructionUser = true; // We might have a dead and dangling constant hanging off of here. if (!SafeToDestroyConstant(C)) @@ -242,6 +244,7 @@ static bool AnalyzeGlobal(const Value *V, GlobalStatus &GS, // Otherwise must be some other user. return true; } + } return false; } @@ -1304,7 +1307,7 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, CallInst *CI, const Type *IntPtrTy = TD->getIntPtrType(CI->getContext()); Value *NMI = CallInst::CreateMalloc(CI, IntPtrTy, FieldTy, ConstantInt::get(IntPtrTy, TypeSize), - NElems, + NElems, 0, CI->getName() + ".f" + Twine(FieldNo)); FieldMallocs.push_back(NMI); new StoreInst(NMI, NGV, CI); @@ -1323,8 +1326,8 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, CallInst *CI, // if (F2) { free(F2); F2 = 0; } // } // The malloc can also fail if its argument is too large. - Constant *ConstantZero = ConstantInt::get(CI->getOperand(1)->getType(), 0); - Value *RunningOr = new ICmpInst(CI, ICmpInst::ICMP_SLT, CI->getOperand(1), + Constant *ConstantZero = ConstantInt::get(CI->getArgOperand(0)->getType(), 0); + Value *RunningOr = new ICmpInst(CI, ICmpInst::ICMP_SLT, CI->getArgOperand(0), ConstantZero, "isneg"); for (unsigned i = 0, e = FieldMallocs.size(); i != e; ++i) { Value *Cond = new ICmpInst(CI, ICmpInst::ICMP_EQ, FieldMallocs[i], @@ -1511,10 +1514,10 @@ static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV, // If this is an allocation of a fixed size array of structs, analyze as a // variable size array. malloc [100 x struct],1 -> malloc struct, 100 - if (NElems == ConstantInt::get(CI->getOperand(1)->getType(), 1)) + if (NElems == ConstantInt::get(CI->getArgOperand(0)->getType(), 1)) if (const ArrayType *AT = dyn_cast<ArrayType>(AllocTy)) AllocTy = AT->getElementType(); - + const StructType *AllocSTy = dyn_cast<StructType>(AllocTy); if (!AllocSTy) return false; @@ -1533,7 +1536,7 @@ static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV, Value *NumElements = ConstantInt::get(IntPtrTy, AT->getNumElements()); Instruction *Malloc = CallInst::CreateMalloc(CI, IntPtrTy, AllocSTy, AllocSize, NumElements, - CI->getName()); + 0, CI->getName()); Instruction *Cast = new BitCastInst(Malloc, CI->getType(), "tmp", CI); CI->replaceAllUsesWith(Cast); CI->eraseFromParent(); @@ -1597,13 +1600,15 @@ static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) { GVElType->isFloatingPointTy() || GVElType->isPointerTy() || GVElType->isVectorTy()) return false; - + // Walk the use list of the global seeing if all the uses are load or store. // If there is anything else, bail out. - for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E; ++I) - if (!isa<LoadInst>(I) && !isa<StoreInst>(I)) + for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E; ++I){ + User *U = *I; + if (!isa<LoadInst>(U) && !isa<StoreInst>(U)) return false; - + } + DEBUG(dbgs() << " *** SHRINKING TO BOOL: " << *GV); // Create the new global, initializing it to false. @@ -1641,7 +1646,7 @@ static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) { // bool. Instruction *StoredVal = cast<Instruction>(SI->getOperand(0)); - // If we're already replaced the input, StoredVal will be a cast or + // If we've already replaced the input, StoredVal will be a cast or // select instruction. If not, it will be a load of the original // global. if (LoadInst *LI = dyn_cast<LoadInst>(StoredVal)) { @@ -2260,8 +2265,7 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal, getVal(Values, CI->getOperand(0)), CI->getType()); } else if (SelectInst *SI = dyn_cast<SelectInst>(CurInst)) { - InstResult = - ConstantExpr::getSelect(getVal(Values, SI->getOperand(0)), + InstResult = ConstantExpr::getSelect(getVal(Values, SI->getOperand(0)), getVal(Values, SI->getOperand(1)), getVal(Values, SI->getOperand(2))); } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(CurInst)) { @@ -2302,7 +2306,8 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal, if (!Callee) return false; // Cannot resolve. SmallVector<Constant*, 8> Formals; - for (User::op_iterator i = CI->op_begin() + 1, e = CI->op_end(); + CallSite CS(CI); + for (User::op_iterator i = CS.arg_begin(), e = CS.arg_end(); i != e; ++i) Formals.push_back(getVal(Values, *i)); diff --git a/lib/Transforms/IPO/IPConstantPropagation.cpp b/lib/Transforms/IPO/IPConstantPropagation.cpp index df2456f9f2b7..e4db235b1d10 100644 --- a/lib/Transforms/IPO/IPConstantPropagation.cpp +++ b/lib/Transforms/IPO/IPConstantPropagation.cpp @@ -85,15 +85,16 @@ bool IPCP::PropagateConstantsIntoArguments(Function &F) { unsigned NumNonconstant = 0; for (Value::use_iterator UI = F.use_begin(), E = F.use_end(); UI != E; ++UI) { + User *U = *UI; // Ignore blockaddress uses. - if (isa<BlockAddress>(*UI)) continue; + if (isa<BlockAddress>(U)) continue; // Used by a non-instruction, or not the callee of a function, do not // transform. - if (!isa<CallInst>(*UI) && !isa<InvokeInst>(*UI)) + if (!isa<CallInst>(U) && !isa<InvokeInst>(U)) return false; - CallSite CS = CallSite::get(cast<Instruction>(*UI)); + CallSite CS = CallSite::get(cast<Instruction>(U)); if (!CS.isCallee(UI)) return false; diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index b785bb0a9390..027a220bc7f9 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -468,7 +468,7 @@ bool Inliner::runOnSCC(CallGraphSCC &SCC) { // move a call site to a function in this SCC before the // 'FirstCallInSCC' barrier. if (SCC.isSingular()) { - std::swap(CallSites[CSi], CallSites.back()); + CallSites[CSi] = CallSites.back(); CallSites.pop_back(); } else { CallSites.erase(CallSites.begin()+CSi); diff --git a/lib/Transforms/IPO/LowerSetJmp.cpp b/lib/Transforms/IPO/LowerSetJmp.cpp index 4d61e8345e00..76cfef8335c9 100644 --- a/lib/Transforms/IPO/LowerSetJmp.cpp +++ b/lib/Transforms/IPO/LowerSetJmp.cpp @@ -42,6 +42,7 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Pass.h" +#include "llvm/Support/CallSite.h" #include "llvm/Support/CFG.h" #include "llvm/Support/InstVisitor.h" #include "llvm/Transforms/Utils/Local.h" @@ -262,8 +263,8 @@ void LowerSetJmp::TransformLongJmpCall(CallInst* Inst) // char*. It returns "void", so it doesn't need to replace any of // Inst's uses and doesn't get a name. CastInst* CI = - new BitCastInst(Inst->getOperand(1), SBPTy, "LJBuf", Inst); - Value *Args[] = { CI, Inst->getOperand(2) }; + new BitCastInst(Inst->getArgOperand(0), SBPTy, "LJBuf", Inst); + Value *Args[] = { CI, Inst->getArgOperand(1) }; CallInst::Create(ThrowLongJmp, Args, Args + 2, "", Inst); SwitchValuePair& SVP = SwitchValMap[Inst->getParent()->getParent()]; @@ -378,7 +379,7 @@ void LowerSetJmp::TransformSetJmpCall(CallInst* Inst) const Type* SBPTy = Type::getInt8PtrTy(Inst->getContext()); CastInst* BufPtr = - new BitCastInst(Inst->getOperand(1), SBPTy, "SBJmpBuf", Inst); + new BitCastInst(Inst->getArgOperand(0), SBPTy, "SBJmpBuf", Inst); Value *Args[] = { GetSetJmpMap(Func), BufPtr, ConstantInt::get(Type::getInt32Ty(Inst->getContext()), SetJmpIDMap[Func]++) @@ -405,12 +406,14 @@ void LowerSetJmp::TransformSetJmpCall(CallInst* Inst) // Loop over all of the uses of instruction. If any of them are after the // call, "spill" the value to the stack. for (Value::use_iterator UI = II->use_begin(), E = II->use_end(); - UI != E; ++UI) - if (cast<Instruction>(*UI)->getParent() != ABlock || - InstrsAfterCall.count(cast<Instruction>(*UI))) { + UI != E; ++UI) { + User *U = *UI; + if (cast<Instruction>(U)->getParent() != ABlock || + InstrsAfterCall.count(cast<Instruction>(U))) { DemoteRegToStack(*II); break; } + } InstrsAfterCall.clear(); // Change the setjmp call into a branch statement. We'll remove the @@ -473,7 +476,8 @@ void LowerSetJmp::visitCallInst(CallInst& CI) // Construct the new "invoke" instruction. TerminatorInst* Term = OldBB->getTerminator(); - std::vector<Value*> Params(CI.op_begin() + 1, CI.op_end()); + CallSite CS(&CI); + std::vector<Value*> Params(CS.arg_begin(), CS.arg_end()); InvokeInst* II = InvokeInst::Create(CI.getCalledValue(), NewBB, PrelimBBMap[Func], Params.begin(), Params.end(), CI.getName(), Term); diff --git a/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp index 622a9b529cf3..55d5e2ac4ab8 100644 --- a/lib/Transforms/IPO/MergeFunctions.cpp +++ b/lib/Transforms/IPO/MergeFunctions.cpp @@ -146,7 +146,7 @@ static bool isEquivalentType(const Type *Ty1, const Type *Ty2) { switch(Ty1->getTypeID()) { default: llvm_unreachable("Unknown type!"); - // Fall through in Release-Asserts mode. + // Fall through in Release mode. case Type::IntegerTyID: case Type::OpaqueTyID: // Ty1 == Ty2 would have returned true earlier. @@ -535,6 +535,7 @@ static LinkageCategory categorize(const Function *F) { case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: case GlobalValue::ExternalWeakLinkage: + case GlobalValue::LinkerPrivateWeakLinkage: return ExternalWeak; case GlobalValue::ExternalLinkage: diff --git a/lib/Transforms/IPO/PartialInlining.cpp b/lib/Transforms/IPO/PartialInlining.cpp index 07525eaada5e..6b9814ceb876 100644 --- a/lib/Transforms/IPO/PartialInlining.cpp +++ b/lib/Transforms/IPO/PartialInlining.cpp @@ -66,13 +66,13 @@ Function* PartialInliner::unswitchFunction(Function* F) { return 0; // Clone the function, so that we can hack away on it. - DenseMap<const Value*, Value*> ValueMap; - Function* duplicateFunction = CloneFunction(F, ValueMap); + ValueMap<const Value*, Value*> VMap; + Function* duplicateFunction = CloneFunction(F, VMap); duplicateFunction->setLinkage(GlobalValue::InternalLinkage); F->getParent()->getFunctionList().push_back(duplicateFunction); - BasicBlock* newEntryBlock = cast<BasicBlock>(ValueMap[entryBlock]); - BasicBlock* newReturnBlock = cast<BasicBlock>(ValueMap[returnBlock]); - BasicBlock* newNonReturnBlock = cast<BasicBlock>(ValueMap[nonReturnBlock]); + BasicBlock* newEntryBlock = cast<BasicBlock>(VMap[entryBlock]); + BasicBlock* newReturnBlock = cast<BasicBlock>(VMap[returnBlock]); + BasicBlock* newNonReturnBlock = cast<BasicBlock>(VMap[nonReturnBlock]); // Go ahead and update all uses to the duplicate, so that we can just // use the inliner functionality when we're done hacking. diff --git a/lib/Transforms/IPO/PartialSpecialization.cpp b/lib/Transforms/IPO/PartialSpecialization.cpp index 084b94e53566..58e14481b0ed 100644 --- a/lib/Transforms/IPO/PartialSpecialization.cpp +++ b/lib/Transforms/IPO/PartialSpecialization.cpp @@ -32,6 +32,10 @@ using namespace llvm; STATISTIC(numSpecialized, "Number of specialized functions created"); +STATISTIC(numReplaced, "Number of callers replaced by specialization"); + +// Maximum number of arguments markable interested +static const int MaxInterests = 6; // Call must be used at least occasionally static const int CallsMin = 5; @@ -40,8 +44,9 @@ static const int CallsMin = 5; static const double ConstValPercent = .1; namespace { + typedef SmallVector<int, MaxInterests> InterestingArgVector; class PartSpec : public ModulePass { - void scanForInterest(Function&, SmallVector<int, 6>&); + void scanForInterest(Function&, InterestingArgVector&); int scanDistribution(Function&, int, std::map<Constant*, int>&); public : static char ID; // Pass identification, replacement for typeid @@ -59,13 +64,15 @@ X("partialspecialization", "Partial Specialization"); // a call to the specialized function. Returns the specialized function static Function* SpecializeFunction(Function* F, - DenseMap<const Value*, Value*>& replacements) { + ValueMap<const Value*, Value*>& replacements) { // arg numbers of deleted arguments - DenseSet<unsigned> deleted; - for (DenseMap<const Value*, Value*>::iterator + DenseMap<unsigned, const Argument*> deleted; + for (ValueMap<const Value*, Value*>::iterator repb = replacements.begin(), repe = replacements.end(); - repb != repe; ++repb) - deleted.insert(cast<Argument>(repb->first)->getArgNo()); + repb != repe; ++repb) { + Argument const *arg = cast<const Argument>(repb->first); + deleted[arg->getArgNo()] = arg; + } Function* NF = CloneFunction(F, replacements); NF->setLinkage(GlobalValue::InternalLinkage); @@ -80,9 +87,23 @@ SpecializeFunction(Function* F, if (CS.getCalledFunction() == F) { SmallVector<Value*, 6> args; - for (unsigned x = 0; x < CS.arg_size(); ++x) - if (!deleted.count(x)) - args.push_back(CS.getArgument(x)); + // Assemble the non-specialized arguments for the updated callsite. + // In the process, make sure that the specialized arguments are + // constant and match the specialization. If that's not the case, + // this callsite needs to call the original or some other + // specialization; don't change it here. + CallSite::arg_iterator as = CS.arg_begin(), ae = CS.arg_end(); + for (CallSite::arg_iterator ai = as; ai != ae; ++ai) { + DenseMap<unsigned, const Argument*>::iterator delit = deleted.find( + std::distance(as, ai)); + if (delit == deleted.end()) + args.push_back(cast<Value>(ai)); + else { + Constant *ci = dyn_cast<Constant>(ai); + if (!(ci && ci == replacements[delit->second])) + goto next_use; + } + } Value* NCall; if (CallInst *CI = dyn_cast<CallInst>(i)) { NCall = CallInst::Create(NF, args.begin(), args.end(), @@ -99,8 +120,11 @@ SpecializeFunction(Function* F, } CS.getInstruction()->replaceAllUsesWith(NCall); CS.getInstruction()->eraseFromParent(); + ++numReplaced; } } + next_use: + ; } return NF; } @@ -111,7 +135,7 @@ bool PartSpec::runOnModule(Module &M) { for (Module::iterator I = M.begin(); I != M.end(); ++I) { Function &F = *I; if (F.isDeclaration() || F.mayBeOverridden()) continue; - SmallVector<int, 6> interestingArgs; + InterestingArgVector interestingArgs; scanForInterest(F, interestingArgs); // Find the first interesting Argument that we can specialize on @@ -126,7 +150,7 @@ bool PartSpec::runOnModule(Module &M) { ee = distribution.end(); ii != ee; ++ii) if (total > ii->second && ii->first && ii->second > total * ConstValPercent) { - DenseMap<const Value*, Value*> m; + ValueMap<const Value*, Value*> m; Function::arg_iterator arg = F.arg_begin(); for (int y = 0; y < interestingArgs[x]; ++y) ++arg; @@ -143,7 +167,7 @@ bool PartSpec::runOnModule(Module &M) { /// scanForInterest - This function decides which arguments would be worth /// specializing on. -void PartSpec::scanForInterest(Function& F, SmallVector<int, 6>& args) { +void PartSpec::scanForInterest(Function& F, InterestingArgVector& args) { for(Function::arg_iterator ii = F.arg_begin(), ee = F.arg_end(); ii != ee; ++ii) { for(Value::use_iterator ui = ii->use_begin(), ue = ii->use_end(); diff --git a/lib/Transforms/IPO/StripSymbols.cpp b/lib/Transforms/IPO/StripSymbols.cpp index 6bc8e66943a7..12e8db8b4a54 100644 --- a/lib/Transforms/IPO/StripSymbols.cpp +++ b/lib/Transforms/IPO/StripSymbols.cpp @@ -73,6 +73,19 @@ namespace { AU.setPreservesAll(); } }; + + class StripDeadDebugInfo : public ModulePass { + public: + static char ID; // Pass identification, replacement for typeid + explicit StripDeadDebugInfo() + : ModulePass(&ID) {} + + virtual bool runOnModule(Module &M); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + }; } char StripSymbols::ID = 0; @@ -99,6 +112,14 @@ ModulePass *llvm::createStripDebugDeclarePass() { return new StripDebugDeclare(); } +char StripDeadDebugInfo::ID = 0; +static RegisterPass<StripDeadDebugInfo> +A("strip-dead-debug-info", "Strip debug info for unused symbols"); + +ModulePass *llvm::createStripDeadDebugInfoPass() { + return new StripDeadDebugInfo(); +} + /// OnlyUsedBy - Return true if V is only used by Usr. static bool OnlyUsedBy(Value *V, Value *Usr) { for(Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) { @@ -223,27 +244,27 @@ static bool StripDebugInfo(Module &M) { Changed = true; } - NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.gv"); - if (NMD) { - Changed = true; - NMD->eraseFromParent(); - } - - NMD = M.getNamedMetadata("llvm.dbg.lv"); - if (NMD) { - Changed = true; - NMD->eraseFromParent(); + for (Module::named_metadata_iterator NMI = M.named_metadata_begin(), + NME = M.named_metadata_end(); NMI != NME;) { + NamedMDNode *NMD = NMI; + ++NMI; + if (NMD->getName().startswith("llvm.dbg.")) { + NMD->eraseFromParent(); + Changed = true; + } } - + unsigned MDDbgKind = M.getMDKindID("dbg"); - for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) + for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI) for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; - ++BI) + ++BI) { + Changed = true; // FIXME: Only set if there was debug metadata. BI->setMetadata(MDDbgKind, 0); + } - return true; + return Changed; } bool StripSymbols::runOnModule(Module &M) { @@ -266,8 +287,8 @@ bool StripDebugDeclare::runOnModule(Module &M) { if (Declare) { while (!Declare->use_empty()) { CallInst *CI = cast<CallInst>(Declare->use_back()); - Value *Arg1 = CI->getOperand(1); - Value *Arg2 = CI->getOperand(2); + Value *Arg1 = CI->getArgOperand(0); + Value *Arg2 = CI->getArgOperand(1); assert(CI->use_empty() && "llvm.dbg intrinsic should have void result"); CI->eraseFromParent(); if (Arg1->use_empty()) { @@ -295,3 +316,83 @@ bool StripDebugDeclare::runOnModule(Module &M) { return true; } + +/// getRealLinkageName - If special LLVM prefix that is used to inform the asm +/// printer to not emit usual symbol prefix before the symbol name is used then +/// return linkage name after skipping this special LLVM prefix. +static StringRef getRealLinkageName(StringRef LinkageName) { + char One = '\1'; + if (LinkageName.startswith(StringRef(&One, 1))) + return LinkageName.substr(1); + return LinkageName; +} + +bool StripDeadDebugInfo::runOnModule(Module &M) { + bool Changed = false; + + // Debugging infomration is encoded in llvm IR using metadata. This is designed + // such a way that debug info for symbols preserved even if symbols are + // optimized away by the optimizer. This special pass removes debug info for + // such symbols. + + // llvm.dbg.gv keeps track of debug info for global variables. + if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.gv")) { + SmallVector<MDNode *, 8> MDs; + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) + if (DIGlobalVariable(NMD->getOperand(i)).Verify()) + MDs.push_back(NMD->getOperand(i)); + else + Changed = true; + NMD->eraseFromParent(); + NMD = NULL; + + for (SmallVector<MDNode *, 8>::iterator I = MDs.begin(), + E = MDs.end(); I != E; ++I) { + if (M.getGlobalVariable(DIGlobalVariable(*I).getGlobal()->getName(), + true)) { + if (!NMD) + NMD = M.getOrInsertNamedMetadata("llvm.dbg.gv"); + NMD->addOperand(*I); + } + else + Changed = true; + } + } + + // llvm.dbg.sp keeps track of debug info for subprograms. + if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) { + SmallVector<MDNode *, 8> MDs; + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) + if (DISubprogram(NMD->getOperand(i)).Verify()) + MDs.push_back(NMD->getOperand(i)); + else + Changed = true; + NMD->eraseFromParent(); + NMD = NULL; + + for (SmallVector<MDNode *, 8>::iterator I = MDs.begin(), + E = MDs.end(); I != E; ++I) { + bool FnIsLive = false; + if (Function *F = DISubprogram(*I).getFunction()) + if (M.getFunction(F->getName())) + FnIsLive = true; + if (FnIsLive) { + if (!NMD) + NMD = M.getOrInsertNamedMetadata("llvm.dbg.sp"); + NMD->addOperand(*I); + } else { + // Remove llvm.dbg.lv.fnname named mdnode which may have been used + // to hold debug info for dead function's local variables. + StringRef FName = DISubprogram(*I).getLinkageName(); + if (FName.empty()) + FName = DISubprogram(*I).getName(); + if (NamedMDNode *LVNMD = + M.getNamedMetadata(Twine("llvm.dbg.lv.", + getRealLinkageName(FName)))) + LVNMD->eraseFromParent(); + } + } + } + + return Changed; +} diff --git a/lib/Transforms/IPO/StructRetPromotion.cpp b/lib/Transforms/IPO/StructRetPromotion.cpp index 473e83cec45e..a74686f408b6 100644 --- a/lib/Transforms/IPO/StructRetPromotion.cpp +++ b/lib/Transforms/IPO/StructRetPromotion.cpp @@ -107,12 +107,12 @@ CallGraphNode *SRETPromotion::PromoteReturn(CallGraphNode *CGN) { // Check if it is ok to perform this promotion. if (isSafeToUpdateAllCallers(F) == false) { DEBUG(dbgs() << "SretPromotion: Not all callers can be updated\n"); - NumRejectedSRETUses++; + ++NumRejectedSRETUses; return 0; } DEBUG(dbgs() << "SretPromotion: sret argument will be promoted\n"); - NumSRET++; + ++NumSRET; // [1] Replace use of sret parameter AllocaInst *TheAlloca = new AllocaInst(STy, NULL, "mrv", F->getEntryBlock().begin()); @@ -171,16 +171,16 @@ bool SRETPromotion::isSafeToUpdateAllCallers(Function *F) { // Check FirstArg's users. for (Value::use_iterator ArgI = FirstArg->use_begin(), ArgE = FirstArg->use_end(); ArgI != ArgE; ++ArgI) { - + User *U = *ArgI; // If FirstArg user is a CallInst that does not correspond to current // call site then this function F is not suitable for sret promotion. - if (CallInst *CI = dyn_cast<CallInst>(ArgI)) { + if (CallInst *CI = dyn_cast<CallInst>(U)) { if (CI != Call) return false; } // 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)) { + else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) { // TODO : Use dom info and insert PHINodes to collect get results // from multiple call sites for this GEP. if (GEP->getParent() != Call->getParent()) |