diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/IR/DebugInfo.cpp | 309 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/StripNonLineTableDebugInfo.cpp | 42 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/Utils.cpp | 1 |
4 files changed, 353 insertions, 0 deletions
diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 1d3c8299255..e228a881eb3 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -287,6 +287,315 @@ bool llvm::StripDebugInfo(Module &M) { return Changed; } +namespace { + +/// Helper class to downgrade -g metadata to -gline-tables-only metadata. +class DebugTypeInfoRemoval { + DenseMap<Metadata *, Metadata *> Replacements; + +public: + /// The (void)() type. + MDNode *EmptySubroutineType; + +private: + /// Remember what linkage name we originally had before stripping. If we end + /// up making two subprograms identical who originally had different linkage + /// names, then we need to make one of them distinct, to avoid them getting + /// uniqued. Maps the new node to the old linkage name. + DenseMap<DISubprogram *, StringRef> NewToLinkageName; + + // TODO: Remember the distinct subprogram we created for a given linkage name, + // so that we can continue to unique whenever possible. Map <newly created + // node, old linkage name> to the first (possibly distinct) mdsubprogram + // created for that combination. This is not strictly needed for correctness, + // but can cut down on the number of MDNodes and let us diff cleanly with the + // output of -gline-tables-only. + +public: + DebugTypeInfoRemoval(LLVMContext &C) + : EmptySubroutineType(DISubroutineType::get(C, DINode::FlagZero, 0, + MDNode::get(C, {}))) {} + + Metadata *map(Metadata *M) { + if (!M) + return nullptr; + if (Replacements.count(M)) + return Replacements.lookup(M); + + return M; + } + MDNode *mapNode(Metadata *N) { return dyn_cast_or_null<MDNode>(map(N)); } + + /// Recursively remap N and all its referenced children. Does a DF post-order + /// traversal, so as to remap bottoms up. + void traverseAndRemap(MDNode *N) { traverse(N); } + +private: + // Create a new DISubprogram, to replace the one given. + DISubprogram *getReplacementSubprogram(DISubprogram *MDS) { + auto *FileAndScope = cast_or_null<DIFile>(map(MDS->getFile())); + StringRef LinkageName = MDS->getName().empty() ? MDS->getLinkageName() : ""; + DISubprogram *Declaration = nullptr; + auto *Type = cast_or_null<DISubroutineType>(map(MDS->getType())); + DITypeRef ContainingType(map(MDS->getContainingType())); + auto *Unit = cast_or_null<DICompileUnit>(map(MDS->getUnit())); + auto Variables = nullptr; + auto TemplateParams = nullptr; + + // Make a distinct DISubprogram, for situations that warrent it. + auto distinctMDSubprogram = [&]() { + return DISubprogram::getDistinct( + MDS->getContext(), FileAndScope, MDS->getName(), LinkageName, + FileAndScope, MDS->getLine(), Type, MDS->isLocalToUnit(), + MDS->isDefinition(), MDS->getScopeLine(), ContainingType, + MDS->getVirtuality(), MDS->getVirtualIndex(), + MDS->getThisAdjustment(), MDS->getFlags(), MDS->isOptimized(), Unit, + TemplateParams, Declaration, Variables); + }; + + if (MDS->isDistinct()) + return distinctMDSubprogram(); + + auto *NewMDS = DISubprogram::get( + MDS->getContext(), FileAndScope, MDS->getName(), LinkageName, + FileAndScope, MDS->getLine(), Type, MDS->isLocalToUnit(), + MDS->isDefinition(), MDS->getScopeLine(), ContainingType, + MDS->getVirtuality(), MDS->getVirtualIndex(), MDS->getThisAdjustment(), + MDS->getFlags(), MDS->isOptimized(), Unit, TemplateParams, Declaration, + Variables); + + StringRef OldLinkageName = MDS->getLinkageName(); + + // See if we need to make a distinct one. + auto OrigLinkage = NewToLinkageName.find(NewMDS); + if (OrigLinkage != NewToLinkageName.end()) { + if (OrigLinkage->second == OldLinkageName) + // We're good. + return NewMDS; + + // Otherwise, need to make a distinct one. + // TODO: Query the map to see if we already have one. + return distinctMDSubprogram(); + } + + NewToLinkageName.insert({NewMDS, MDS->getLinkageName()}); + return NewMDS; + } + + /// Create a new compile unit, to replace the one given + DICompileUnit *getReplacementCU(DICompileUnit *CU) { + // Drop skeleton CUs. + if (CU->getDWOId()) + return nullptr; + + auto *File = cast_or_null<DIFile>(map(CU->getFile())); + MDTuple *EnumTypes = nullptr; + MDTuple *RetainedTypes = nullptr; + MDTuple *GlobalVariables = nullptr; + MDTuple *ImportedEntities = nullptr; + return DICompileUnit::getDistinct( + CU->getContext(), CU->getSourceLanguage(), File, CU->getProducer(), + CU->isOptimized(), CU->getFlags(), CU->getRuntimeVersion(), + CU->getSplitDebugFilename(), DICompileUnit::LineTablesOnly, EnumTypes, + RetainedTypes, GlobalVariables, ImportedEntities, CU->getMacros(), + CU->getDWOId(), CU->getSplitDebugInlining()); + } + + DILocation *getReplacementMDLocation(DILocation *MLD) { + auto *Scope = map(MLD->getScope()); + auto *InlinedAt = map(MLD->getInlinedAt()); + if (MLD->isDistinct()) + return DILocation::getDistinct(MLD->getContext(), MLD->getLine(), + MLD->getColumn(), Scope, InlinedAt); + return DILocation::get(MLD->getContext(), MLD->getLine(), MLD->getColumn(), + Scope, InlinedAt); + } + + /// Create a new generic MDNode, to replace the one given + MDNode *getReplacementMDNode(MDNode *N) { + SmallVector<Metadata *, 8> Ops; + Ops.reserve(N->getNumOperands()); + for (auto &I : N->operands()) + if (I) + Ops.push_back(map(I)); + auto *Ret = MDNode::get(N->getContext(), Ops); + return Ret; + } + + /// Attempt to re-map N to a newly created node. + void remap(MDNode *N) { + if (Replacements.count(N)) + return; + + auto doRemap = [&](MDNode *N) -> MDNode * { + if (!N) + return nullptr; + if (auto *MDSub = dyn_cast<DISubprogram>(N)) { + remap(MDSub->getUnit()); + return getReplacementSubprogram(MDSub); + } + if (isa<DISubroutineType>(N)) + return EmptySubroutineType; + if (auto *CU = dyn_cast<DICompileUnit>(N)) + return getReplacementCU(CU); + if (isa<DIFile>(N)) + return N; + if (auto *MDLB = dyn_cast<DILexicalBlockBase>(N)) + // Remap to our referenced scope (recursively). + return mapNode(MDLB->getScope()); + if (auto *MLD = dyn_cast<DILocation>(N)) + return getReplacementMDLocation(MLD); + + // Otherwise, if we see these, just drop them now. Not strictly necessary, + // but this speeds things up a little. + if (isa<DINode>(N)) + return nullptr; + + return getReplacementMDNode(N); + }; + Replacements[N] = doRemap(N); + } + + /// Do the remapping traversal. + void traverse(MDNode *); +}; + +} // Anonymous namespace. + +void DebugTypeInfoRemoval::traverse(MDNode *N) { + if (!N || Replacements.count(N)) + return; + + // To avoid cycles, as well as for efficiency sake, we will sometimes prune + // parts of the graph. + auto prune = [](MDNode *Parent, MDNode *Child) { + if (auto *MDS = dyn_cast<DISubprogram>(Parent)) + return Child == MDS->getVariables().get(); + return false; + }; + + SmallVector<MDNode *, 16> ToVisit; + DenseSet<MDNode *> Opened; + + // Visit each node starting at N in post order, and map them. + ToVisit.push_back(N); + while (!ToVisit.empty()) { + auto *N = ToVisit.back(); + auto Result = Opened.insert(N); + if (!Result.second) { + // Close it. + remap(N); + ToVisit.pop_back(); + continue; + } + for (auto &I : N->operands()) + if (auto *MDN = dyn_cast_or_null<MDNode>(I)) + if (!Opened.count(MDN) && !Replacements.count(MDN) && !prune(N, MDN) && + !isa<DICompileUnit>(MDN)) + ToVisit.push_back(MDN); + } +} + +bool llvm::stripNonLineTableDebugInfo(Module &M) { + bool Changed = false; + + // First off, delete the debug intrinsics. + if (Function *Declare = M.getFunction("llvm.dbg.declare")) { + while (!Declare->use_empty()) { + auto *DDI = cast<DbgDeclareInst>(Declare->user_back()); + DDI->eraseFromParent(); + } + Declare->eraseFromParent(); + Changed = true; + } + if (Function *DbgVal = M.getFunction("llvm.dbg.value")) { + while (!DbgVal->use_empty()) { + auto *DVI = cast<DbgValueInst>(DbgVal->user_back()); + DVI->eraseFromParent(); + } + DbgVal->eraseFromParent(); + Changed = true; + } + + // Delete non-CU debug info named metadata nodes. + for (auto NMI = M.named_metadata_begin(), NME = M.named_metadata_end(); + NMI != NME;) { + NamedMDNode *NMD = &*NMI; + ++NMI; + // Specifically keep dbg.cu around. + if (NMD->getName() == "llvm.dbg.cu") + continue; + } + + // Drop all dbg attachments from global variables. + for (auto &GV : M.globals()) + GV.getContext().pImpl->GlobalObjectMetadata[&GV].erase(LLVMContext::MD_dbg); + + DebugTypeInfoRemoval Mapper(M.getContext()); + + // Rewrite the DebugLocs to be equivalent to what + // -gline-tables-only would have created. + for (auto &F : M) { + auto *SP = F.getSubprogram(); + if (SP) { + Mapper.traverseAndRemap(SP); + auto *NewSP = cast<DISubprogram>(Mapper.mapNode(SP)); + Changed |= SP != NewSP; + F.setSubprogram(NewSP); + } + for (auto &BB : F) { + for (auto &I : BB) { + if (I.getDebugLoc() == DebugLoc()) + continue; + + // Make a replacement. + auto &DL = I.getDebugLoc(); + auto *Scope = DL.getScope(); + auto *InlinedAt = DL.getInlinedAt(); + + // Remap scope. + if (Scope) { + Mapper.traverseAndRemap(Scope); + auto *NewScope = Mapper.mapNode(Scope); + Changed |= Scope != NewScope; + Scope = NewScope; + } + + // Remap inlinedAt. + if (InlinedAt) { + Mapper.traverseAndRemap(InlinedAt); + auto *NewIA = Mapper.mapNode(InlinedAt); + Changed |= InlinedAt != NewIA; + InlinedAt = cast_or_null<DILocation>(NewIA); + } + + I.setDebugLoc( + DebugLoc::get(DL.getLine(), DL.getCol(), Scope, InlinedAt)); + } + } + } + + // Create a new llvm.dbg.cu, which is equivalent to the one + // -gline-tables-only would have created. + for (auto &NMD : M.getNamedMDList()) { + SmallVector<MDNode *, 8> Ops; + for (MDNode *Op : NMD.operands()) { + Mapper.traverseAndRemap(Op); + auto *NewOp = Mapper.mapNode(Op); + Changed |= NewOp != Op; + Ops.push_back(NewOp); + } + + if (Changed) { + NMD.dropAllReferences(); + for (auto *Op : Ops) + if (Op) + NMD.addOperand(Op); + } + } + return Changed; +} + unsigned llvm::getDebugMetadataVersionFromModule(const Module &M) { if (auto *Val = mdconst::dyn_extract_or_null<ConstantInt>( M.getModuleFlag("Debug Info Version"))) diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt index a2b3882940c..a1f98ef8aa3 100644 --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -41,6 +41,7 @@ add_llvm_library(LLVMTransformUtils SimplifyInstructions.cpp SimplifyLibCalls.cpp SplitModule.cpp + StripNonLineTableDebugInfo.cpp SymbolRewriter.cpp UnifyFunctionExitNodes.cpp Utils.cpp diff --git a/llvm/lib/Transforms/Utils/StripNonLineTableDebugInfo.cpp b/llvm/lib/Transforms/Utils/StripNonLineTableDebugInfo.cpp new file mode 100644 index 00000000000..66dbf335cb9 --- /dev/null +++ b/llvm/lib/Transforms/Utils/StripNonLineTableDebugInfo.cpp @@ -0,0 +1,42 @@ +//===- StripNonLineTableDebugInfo.cpp -- Strip parts of Debug Info --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/IPO.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/Pass.h" +using namespace llvm; + +namespace { + +/// This pass strips all debug info that is not related line tables. +/// The result will be the same as if the program where compiled with +/// -gline-tables-only. +struct StripNonLineTableDebugInfo : public ModulePass { + static char ID; // Pass identification, replacement for typeid + StripNonLineTableDebugInfo() : ModulePass(ID) { + initializeStripNonLineTableDebugInfoPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + bool runOnModule(Module &M) override { + return llvm::stripNonLineTableDebugInfo(M); + } +}; +} + +char StripNonLineTableDebugInfo::ID = 0; +INITIALIZE_PASS(StripNonLineTableDebugInfo, "strip-nonlinetable-debuginfo", + "Strip all debug info except linetables", false, false) + +ModulePass *llvm::createStripNonLineTableDebugInfoPass() { + return new StripNonLineTableDebugInfo(); +} diff --git a/llvm/lib/Transforms/Utils/Utils.cpp b/llvm/lib/Transforms/Utils/Utils.cpp index aa23e805487..35502df37d3 100644 --- a/llvm/lib/Transforms/Utils/Utils.cpp +++ b/llvm/lib/Transforms/Utils/Utils.cpp @@ -30,6 +30,7 @@ void llvm::initializeTransformUtils(PassRegistry &Registry) { initializeLowerSwitchPass(Registry); initializeNameAnonGlobalLegacyPassPass(Registry); initializePromoteLegacyPassPass(Registry); + initializeStripNonLineTableDebugInfoPass(Registry); initializeUnifyFunctionExitNodesPass(Registry); initializeInstSimplifierPass(Registry); initializeMetaRenamerPass(Registry); |