X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTransforms%2FIPO%2FStripSymbols.cpp;h=c6c4fde0a2bdd2d2ba0900bda22025a1db84e485;hp=4c0b35a1a4e78ee597c6d5fd1f602b4765000d04;hb=9ccaf53ada99c63737547c0235baeb8454b04e80;hpb=9133fe28954d498fc4de13064c7d65bd811de02c diff --git a/lib/Transforms/IPO/StripSymbols.cpp b/lib/Transforms/IPO/StripSymbols.cpp index 4c0b35a1a4e..c6c4fde0a2b 100644 --- a/lib/Transforms/IPO/StripSymbols.cpp +++ b/lib/Transforms/IPO/StripSymbols.cpp @@ -2,23 +2,21 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // -// This file implements stripping symbols out of symbol tables. +// The StripSymbols transformation implements code stripping. Specifically, it +// can delete: +// +// * names for virtual registers +// * symbols for internal globals and functions +// * debug information // -// Specifically, this allows you to strip all of the symbols out of: -// * All functions in a module -// * All non-essential symbols in a module (all function symbols + all module -// scope symbols) -// * Debug information. -// -// Notice that: -// * This pass makes code much less readable, so it should only be used in -// situations where the 'strip' utility would be used (such as reducing -// code size, and making it harder to reverse engineer code). +// Note that this transformation makes code much less readable, so it should +// only be used in situations where the 'strip' utility would be used, such as +// reducing code size or making it harder to reverse engineer code. // //===----------------------------------------------------------------------===// @@ -28,16 +26,59 @@ #include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/Pass.h" +#include "llvm/Analysis/DebugInfo.h" #include "llvm/ValueSymbolTable.h" #include "llvm/TypeSymbolTable.h" -#include "llvm/Support/Compiler.h" +#include "llvm/Transforms/Utils/Local.h" +#include "llvm/ADT/SmallPtrSet.h" using namespace llvm; namespace { - class VISIBILITY_HIDDEN StripSymbols : public ModulePass { + class StripSymbols : public ModulePass { bool OnlyDebugInfo; public: - StripSymbols(bool ODI = false) : OnlyDebugInfo(ODI) {} + static char ID; // Pass identification, replacement for typeid + explicit StripSymbols(bool ODI = false) + : ModulePass(ID), OnlyDebugInfo(ODI) {} + + virtual bool runOnModule(Module &M); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + }; + + class StripNonDebugSymbols : public ModulePass { + public: + static char ID; // Pass identification, replacement for typeid + explicit StripNonDebugSymbols() + : ModulePass(ID) {} + + virtual bool runOnModule(Module &M); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + }; + + class StripDebugDeclare : public ModulePass { + public: + static char ID; // Pass identification, replacement for typeid + explicit StripDebugDeclare() + : ModulePass(ID) {} + + virtual bool runOnModule(Module &M); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + }; + + class StripDeadDebugInfo : public ModulePass { + public: + static char ID; // Pass identification, replacement for typeid + explicit StripDeadDebugInfo() + : ModulePass(ID) {} virtual bool runOnModule(Module &M); @@ -45,137 +86,315 @@ namespace { AU.setPreservesAll(); } }; - RegisterPass X("strip", "Strip all symbols from a module"); } +char StripSymbols::ID = 0; +INITIALIZE_PASS(StripSymbols, "strip", + "Strip all symbols from a module", false, false); + ModulePass *llvm::createStripSymbolsPass(bool OnlyDebugInfo) { return new StripSymbols(OnlyDebugInfo); } +char StripNonDebugSymbols::ID = 0; +INITIALIZE_PASS(StripNonDebugSymbols, "strip-nondebug", + "Strip all symbols, except dbg symbols, from a module", + false, false); + +ModulePass *llvm::createStripNonDebugSymbolsPass() { + return new StripNonDebugSymbols(); +} + +char StripDebugDeclare::ID = 0; +INITIALIZE_PASS(StripDebugDeclare, "strip-debug-declare", + "Strip all llvm.dbg.declare intrinsics", false, false); + +ModulePass *llvm::createStripDebugDeclarePass() { + return new StripDebugDeclare(); +} + +char StripDeadDebugInfo::ID = 0; +INITIALIZE_PASS(StripDeadDebugInfo, "strip-dead-debug-info", + "Strip debug info for unused symbols", false, false); + +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) { + User *U = *I; + if (U != Usr) + return false; + } + return true; +} + static void RemoveDeadConstant(Constant *C) { assert(C->use_empty() && "Constant is not dead!"); - std::vector Operands; + SmallPtrSet Operands; for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) if (isa(C->getOperand(i)->getType()) && - C->getOperand(i)->hasOneUse()) - Operands.push_back(C->getOperand(i)); + OnlyUsedBy(C->getOperand(i), C)) + Operands.insert(cast(C->getOperand(i))); if (GlobalVariable *GV = dyn_cast(C)) { - if (!GV->hasInternalLinkage()) return; // Don't delete non static globals. + if (!GV->hasLocalLinkage()) return; // Don't delete non static globals. GV->eraseFromParent(); } else if (!isa(C)) - C->destroyConstant(); + if (isa(C->getType())) + C->destroyConstant(); // If the constant referenced anything, see if we can delete it as well. - while (!Operands.empty()) { - RemoveDeadConstant(Operands.back()); - Operands.pop_back(); + for (SmallPtrSet::iterator OI = Operands.begin(), + OE = Operands.end(); OI != OE; ++OI) + RemoveDeadConstant(*OI); +} + +// Strip the symbol table of its names. +// +static void StripSymtab(ValueSymbolTable &ST, bool PreserveDbgInfo) { + for (ValueSymbolTable::iterator VI = ST.begin(), VE = ST.end(); VI != VE; ) { + Value *V = VI->getValue(); + ++VI; + if (!isa(V) || cast(V)->hasLocalLinkage()) { + if (!PreserveDbgInfo || !V->getName().startswith("llvm.dbg")) + // Set name to "", removing from symbol table! + V->setName(""); + } } } -bool StripSymbols::runOnModule(Module &M) { - // If we're not just stripping debug info, strip all symbols from the - // functions and the names from any internal globals. - if (!OnlyDebugInfo) { - for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) - if (I->hasInternalLinkage()) - I->setName(""); // Internal symbols can't participate in linkage +// Strip the symbol table of its names. +static void StripTypeSymtab(TypeSymbolTable &ST, bool PreserveDbgInfo) { + for (TypeSymbolTable::iterator TI = ST.begin(), E = ST.end(); TI != E; ) { + if (PreserveDbgInfo && StringRef(TI->first).startswith("llvm.dbg")) + ++TI; + else + ST.remove(TI++); + } +} - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { - if (I->hasInternalLinkage()) +/// Find values that are marked as llvm.used. +static void findUsedValues(GlobalVariable *LLVMUsed, + SmallPtrSet &UsedValues) { + if (LLVMUsed == 0) return; + UsedValues.insert(LLVMUsed); + + ConstantArray *Inits = dyn_cast(LLVMUsed->getInitializer()); + if (Inits == 0) return; + + for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) + if (GlobalValue *GV = + dyn_cast(Inits->getOperand(i)->stripPointerCasts())) + UsedValues.insert(GV); +} + +/// StripSymbolNames - Strip symbol names. +static bool StripSymbolNames(Module &M, bool PreserveDbgInfo) { + + SmallPtrSet llvmUsedValues; + findUsedValues(M.getGlobalVariable("llvm.used"), llvmUsedValues); + findUsedValues(M.getGlobalVariable("llvm.compiler.used"), llvmUsedValues); + + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) { + if (I->hasLocalLinkage() && llvmUsedValues.count(I) == 0) + if (!PreserveDbgInfo || !I->getName().startswith("llvm.dbg")) I->setName(""); // Internal symbols can't participate in linkage - I->getValueSymbolTable().strip(); - } - - // Remove all names from types. - M.getTypeSymbolTable().strip(); } + + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { + if (I->hasLocalLinkage() && llvmUsedValues.count(I) == 0) + if (!PreserveDbgInfo || !I->getName().startswith("llvm.dbg")) + I->setName(""); // Internal symbols can't participate in linkage + StripSymtab(I->getValueSymbolTable(), PreserveDbgInfo); + } + + // Remove all names from types. + StripTypeSymtab(M.getTypeSymbolTable(), PreserveDbgInfo); - // Strip debug info in the module if it exists. To do this, we remove - // llvm.dbg.func.start, llvm.dbg.stoppoint, and llvm.dbg.region.end calls, and - // any globals they point to if now dead. - Function *FuncStart = M.getFunction("llvm.dbg.func.start"); - Function *StopPoint = M.getFunction("llvm.dbg.stoppoint"); - Function *RegionStart = M.getFunction("llvm.dbg.region.start"); - Function *RegionEnd = M.getFunction("llvm.dbg.region.end"); - Function *Declare = M.getFunction("llvm.dbg.declare"); - if (!FuncStart && !StopPoint && !RegionStart && !RegionEnd && !Declare) - return true; + return true; +} - std::vector DeadGlobals; +// StripDebugInfo - Strip debug info in the module if it exists. +// To do this, we remove llvm.dbg.func.start, llvm.dbg.stoppoint, and +// llvm.dbg.region.end calls, and any globals they point to if now dead. +static bool StripDebugInfo(Module &M) { + + bool Changed = false; // Remove all of the calls to the debugger intrinsics, and remove them from // the module. - if (FuncStart) { - while (!FuncStart->use_empty()) { - CallInst *CI = cast(FuncStart->use_back()); - Value *Arg = CI->getOperand(1); - assert(CI->use_empty() && "llvm.dbg intrinsic should have void result"); - CI->eraseFromParent(); - if (Arg->use_empty()) - if (GlobalVariable *GV = dyn_cast(Arg)) - DeadGlobals.push_back(GV); - } - FuncStart->eraseFromParent(); - } - if (StopPoint) { - while (!StopPoint->use_empty()) { - CallInst *CI = cast(StopPoint->use_back()); - Value *Arg = CI->getOperand(3); - assert(CI->use_empty() && "llvm.dbg intrinsic should have void result"); + if (Function *Declare = M.getFunction("llvm.dbg.declare")) { + while (!Declare->use_empty()) { + CallInst *CI = cast(Declare->use_back()); CI->eraseFromParent(); - if (Arg->use_empty()) - if (GlobalVariable *GV = dyn_cast(Arg)) - DeadGlobals.push_back(GV); } - StopPoint->eraseFromParent(); + Declare->eraseFromParent(); + Changed = true; } - if (RegionStart) { - while (!RegionStart->use_empty()) { - CallInst *CI = cast(RegionStart->use_back()); - Value *Arg = CI->getOperand(1); - assert(CI->use_empty() && "llvm.dbg intrinsic should have void result"); + + if (Function *DbgVal = M.getFunction("llvm.dbg.value")) { + while (!DbgVal->use_empty()) { + CallInst *CI = cast(DbgVal->use_back()); CI->eraseFromParent(); - if (Arg->use_empty()) - if (GlobalVariable *GV = dyn_cast(Arg)) - DeadGlobals.push_back(GV); } - RegionStart->eraseFromParent(); + DbgVal->eraseFromParent(); + Changed = true; } - if (RegionEnd) { - while (!RegionEnd->use_empty()) { - CallInst *CI = cast(RegionEnd->use_back()); - Value *Arg = CI->getOperand(1); - assert(CI->use_empty() && "llvm.dbg intrinsic should have void result"); - CI->eraseFromParent(); - if (Arg->use_empty()) - if (GlobalVariable *GV = dyn_cast(Arg)) - DeadGlobals.push_back(GV); + + 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; } - RegionEnd->eraseFromParent(); } + + 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) { + if (!BI->getDebugLoc().isUnknown()) { + Changed = true; + BI->setDebugLoc(DebugLoc()); + } + } + + return Changed; +} + +bool StripSymbols::runOnModule(Module &M) { + bool Changed = false; + Changed |= StripDebugInfo(M); + if (!OnlyDebugInfo) + Changed |= StripSymbolNames(M, false); + return Changed; +} + +bool StripNonDebugSymbols::runOnModule(Module &M) { + return StripSymbolNames(M, true); +} + +bool StripDebugDeclare::runOnModule(Module &M) { + + Function *Declare = M.getFunction("llvm.dbg.declare"); + std::vector DeadConstants; + if (Declare) { while (!Declare->use_empty()) { CallInst *CI = cast(Declare->use_back()); - Value *Arg = 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 (Arg->use_empty()) - if (GlobalVariable *GV = dyn_cast(Arg)) - DeadGlobals.push_back(GV); + if (Arg1->use_empty()) { + if (Constant *C = dyn_cast(Arg1)) + DeadConstants.push_back(C); + else + RecursivelyDeleteTriviallyDeadInstructions(Arg1); + } + if (Arg2->use_empty()) + if (Constant *C = dyn_cast(Arg2)) + DeadConstants.push_back(C); } Declare->eraseFromParent(); } - // Finally, delete any internal globals that were only used by the debugger - // intrinsics. - while (!DeadGlobals.empty()) { - GlobalVariable *GV = DeadGlobals.back(); - DeadGlobals.pop_back(); - if (GV->hasInternalLinkage()) - RemoveDeadConstant(GV); + while (!DeadConstants.empty()) { + Constant *C = DeadConstants.back(); + DeadConstants.pop_back(); + if (GlobalVariable *GV = dyn_cast(C)) { + if (GV->hasLocalLinkage()) + RemoveDeadConstant(GV); + } else + RemoveDeadConstant(C); } 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 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::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 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::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; +}