Skip to content

Commit e542804

Browse files
committed
Add -strip-nonlinetable-debuginfo capability
This adds a new function to DebugInfo.cpp that takes an llvm::Module as input and removes all debug info metadata that is not directly needed for line tables, thus effectively stripping all type and variable information from the module. The primary motivation for this feature was the bitcode work flow (cf. http://lists.llvm.org/pipermail/llvm-dev/2016-June/100643.html for more background). This is not wired up yet, but will be in subsequent patches. For testing, the new functionality is exposed to opt with a -strip-nonlinetable-debuginfo option. The secondary use-case (and one that works right now!) is as a reduction pass in bugpoint. I added two new bugpoint options (-disable-strip-debuginfo and -disable-strip-debug-types) to control the new features. By default it will first attempt to remove all debug information, then only the type info, and then proceed to hack at any remaining MDNodes. Thanks to Adrian Prantl for stewarding this patch! llvm-svn: 285094
1 parent e325647 commit e542804

16 files changed

+576
-8
lines changed

llvm/include/llvm/IR/DebugInfo.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ DISubprogram *getDISubprogram(const MDNode *Scope);
4444
bool StripDebugInfo(Module &M);
4545
bool stripDebugInfo(Function &F);
4646

47+
/// Downgrade the debug info in a module to contain only line table information.
48+
///
49+
/// In order to convert debug info to what -gline-tables-only would have
50+
/// created, this does the following:
51+
/// 1) Delete all debug intrinsics.
52+
/// 2) Delete all non-CU named metadata debug info nodes.
53+
/// 3) Create new DebugLocs for each instruction.
54+
/// 4) Create a new CU debug info, and similarly for every metadata node
55+
/// that's reachable from the CU debug info.
56+
/// All debug type metadata nodes are unreachable and garbage collected.
57+
bool stripNonLineTableDebugInfo(Module &M);
58+
4759
/// \brief Return Debug Info Metadata Version by checking module flags.
4860
unsigned getDebugMetadataVersionFromModule(const Module &M);
4961

llvm/include/llvm/IR/Metadata.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,8 +1299,10 @@ class NamedMDNode : public ilist_node<NamedMDNode> {
12991299
/// \brief Drop all references and remove the node from parent module.
13001300
void eraseFromParent();
13011301

1302-
/// \brief Remove all uses and clear node vector.
1303-
void dropAllReferences();
1302+
/// Remove all uses and clear node vector.
1303+
void dropAllReferences() { clearOperands(); }
1304+
/// Drop all references to this node's operands.
1305+
void clearOperands();
13041306

13051307
~NamedMDNode();
13061308

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ void initializeStripDeadDebugInfoPass(PassRegistry&);
330330
void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&);
331331
void initializeStripDebugDeclarePass(PassRegistry&);
332332
void initializeStripNonDebugSymbolsPass(PassRegistry&);
333+
void initializeStripNonLineTableDebugInfoPass(PassRegistry&);
333334
void initializeStripSymbolsPass(PassRegistry&);
334335
void initializeStructurizeCFGPass(PassRegistry&);
335336
void initializeTailCallElimPass(PassRegistry&);

llvm/include/llvm/Transforms/IPO.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ ModulePass *createStripSymbolsPass(bool OnlyDebugInfo = false);
4343
//
4444
ModulePass *createStripNonDebugSymbolsPass();
4545

46+
/// This function returns a new pass that downgrades the debug info in the
47+
/// module to line tables only.
48+
ModulePass *createStripNonLineTableDebugInfoPass();
49+
4650
//===----------------------------------------------------------------------===//
4751
//
4852
// These pass removes llvm.dbg.declare intrinsics.

llvm/lib/IR/DebugInfo.cpp

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,299 @@ bool llvm::StripDebugInfo(Module &M) {
300300
return Changed;
301301
}
302302

303+
namespace {
304+
305+
/// Helper class to downgrade -g metadata to -gline-tables-only metadata.
306+
class DebugTypeInfoRemoval {
307+
DenseMap<Metadata *, Metadata *> Replacements;
308+
309+
public:
310+
/// The (void)() type.
311+
MDNode *EmptySubroutineType;
312+
313+
private:
314+
/// Remember what linkage name we originally had before stripping. If we end
315+
/// up making two subprograms identical who originally had different linkage
316+
/// names, then we need to make one of them distinct, to avoid them getting
317+
/// uniqued. Maps the new node to the old linkage name.
318+
DenseMap<DISubprogram *, StringRef> NewToLinkageName;
319+
320+
// TODO: Remember the distinct subprogram we created for a given linkage name,
321+
// so that we can continue to unique whenever possible. Map <newly created
322+
// node, old linkage name> to the first (possibly distinct) mdsubprogram
323+
// created for that combination. This is not strictly needed for correctness,
324+
// but can cut down on the number of MDNodes and let us diff cleanly with the
325+
// output of -gline-tables-only.
326+
327+
public:
328+
DebugTypeInfoRemoval(LLVMContext &C)
329+
: EmptySubroutineType(DISubroutineType::get(C, DINode::FlagZero, 0,
330+
MDNode::get(C, {}))) {}
331+
332+
Metadata *map(Metadata *M) {
333+
if (!M)
334+
return nullptr;
335+
auto Replacement = Replacements.find(M);
336+
if (Replacement != Replacements.end())
337+
return Replacement->second;
338+
339+
return M;
340+
}
341+
MDNode *mapNode(Metadata *N) { return dyn_cast_or_null<MDNode>(map(N)); }
342+
343+
/// Recursively remap N and all its referenced children. Does a DF post-order
344+
/// traversal, so as to remap bottoms up.
345+
void traverseAndRemap(MDNode *N) { traverse(N); }
346+
347+
private:
348+
// Create a new DISubprogram, to replace the one given.
349+
DISubprogram *getReplacementSubprogram(DISubprogram *MDS) {
350+
auto *FileAndScope = cast_or_null<DIFile>(map(MDS->getFile()));
351+
StringRef LinkageName = MDS->getName().empty() ? MDS->getLinkageName() : "";
352+
DISubprogram *Declaration = nullptr;
353+
auto *Type = cast_or_null<DISubroutineType>(map(MDS->getType()));
354+
DITypeRef ContainingType(map(MDS->getContainingType()));
355+
auto *Unit = cast_or_null<DICompileUnit>(map(MDS->getUnit()));
356+
auto Variables = nullptr;
357+
auto TemplateParams = nullptr;
358+
359+
// Make a distinct DISubprogram, for situations that warrent it.
360+
auto distinctMDSubprogram = [&]() {
361+
return DISubprogram::getDistinct(
362+
MDS->getContext(), FileAndScope, MDS->getName(), LinkageName,
363+
FileAndScope, MDS->getLine(), Type, MDS->isLocalToUnit(),
364+
MDS->isDefinition(), MDS->getScopeLine(), ContainingType,
365+
MDS->getVirtuality(), MDS->getVirtualIndex(),
366+
MDS->getThisAdjustment(), MDS->getFlags(), MDS->isOptimized(), Unit,
367+
TemplateParams, Declaration, Variables);
368+
};
369+
370+
if (MDS->isDistinct())
371+
return distinctMDSubprogram();
372+
373+
auto *NewMDS = DISubprogram::get(
374+
MDS->getContext(), FileAndScope, MDS->getName(), LinkageName,
375+
FileAndScope, MDS->getLine(), Type, MDS->isLocalToUnit(),
376+
MDS->isDefinition(), MDS->getScopeLine(), ContainingType,
377+
MDS->getVirtuality(), MDS->getVirtualIndex(), MDS->getThisAdjustment(),
378+
MDS->getFlags(), MDS->isOptimized(), Unit, TemplateParams, Declaration,
379+
Variables);
380+
381+
StringRef OldLinkageName = MDS->getLinkageName();
382+
383+
// See if we need to make a distinct one.
384+
auto OrigLinkage = NewToLinkageName.find(NewMDS);
385+
if (OrigLinkage != NewToLinkageName.end()) {
386+
if (OrigLinkage->second == OldLinkageName)
387+
// We're good.
388+
return NewMDS;
389+
390+
// Otherwise, need to make a distinct one.
391+
// TODO: Query the map to see if we already have one.
392+
return distinctMDSubprogram();
393+
}
394+
395+
NewToLinkageName.insert({NewMDS, MDS->getLinkageName()});
396+
return NewMDS;
397+
}
398+
399+
/// Create a new compile unit, to replace the one given
400+
DICompileUnit *getReplacementCU(DICompileUnit *CU) {
401+
// Drop skeleton CUs.
402+
if (CU->getDWOId())
403+
return nullptr;
404+
405+
auto *File = cast_or_null<DIFile>(map(CU->getFile()));
406+
MDTuple *EnumTypes = nullptr;
407+
MDTuple *RetainedTypes = nullptr;
408+
MDTuple *GlobalVariables = nullptr;
409+
MDTuple *ImportedEntities = nullptr;
410+
return DICompileUnit::getDistinct(
411+
CU->getContext(), CU->getSourceLanguage(), File, CU->getProducer(),
412+
CU->isOptimized(), CU->getFlags(), CU->getRuntimeVersion(),
413+
CU->getSplitDebugFilename(), DICompileUnit::LineTablesOnly, EnumTypes,
414+
RetainedTypes, GlobalVariables, ImportedEntities, CU->getMacros(),
415+
CU->getDWOId(), CU->getSplitDebugInlining());
416+
}
417+
418+
DILocation *getReplacementMDLocation(DILocation *MLD) {
419+
auto *Scope = map(MLD->getScope());
420+
auto *InlinedAt = map(MLD->getInlinedAt());
421+
if (MLD->isDistinct())
422+
return DILocation::getDistinct(MLD->getContext(), MLD->getLine(),
423+
MLD->getColumn(), Scope, InlinedAt);
424+
return DILocation::get(MLD->getContext(), MLD->getLine(), MLD->getColumn(),
425+
Scope, InlinedAt);
426+
}
427+
428+
/// Create a new generic MDNode, to replace the one given
429+
MDNode *getReplacementMDNode(MDNode *N) {
430+
SmallVector<Metadata *, 8> Ops;
431+
Ops.reserve(N->getNumOperands());
432+
for (auto &I : N->operands())
433+
if (I)
434+
Ops.push_back(map(I));
435+
auto *Ret = MDNode::get(N->getContext(), Ops);
436+
return Ret;
437+
}
438+
439+
/// Attempt to re-map N to a newly created node.
440+
void remap(MDNode *N) {
441+
if (Replacements.count(N))
442+
return;
443+
444+
auto doRemap = [&](MDNode *N) -> MDNode * {
445+
if (!N)
446+
return nullptr;
447+
if (auto *MDSub = dyn_cast<DISubprogram>(N)) {
448+
remap(MDSub->getUnit());
449+
return getReplacementSubprogram(MDSub);
450+
}
451+
if (isa<DISubroutineType>(N))
452+
return EmptySubroutineType;
453+
if (auto *CU = dyn_cast<DICompileUnit>(N))
454+
return getReplacementCU(CU);
455+
if (isa<DIFile>(N))
456+
return N;
457+
if (auto *MDLB = dyn_cast<DILexicalBlockBase>(N))
458+
// Remap to our referenced scope (recursively).
459+
return mapNode(MDLB->getScope());
460+
if (auto *MLD = dyn_cast<DILocation>(N))
461+
return getReplacementMDLocation(MLD);
462+
463+
// Otherwise, if we see these, just drop them now. Not strictly necessary,
464+
// but this speeds things up a little.
465+
if (isa<DINode>(N))
466+
return nullptr;
467+
468+
return getReplacementMDNode(N);
469+
};
470+
Replacements[N] = doRemap(N);
471+
}
472+
473+
/// Do the remapping traversal.
474+
void traverse(MDNode *);
475+
};
476+
477+
} // Anonymous namespace.
478+
479+
void DebugTypeInfoRemoval::traverse(MDNode *N) {
480+
if (!N || Replacements.count(N))
481+
return;
482+
483+
// To avoid cycles, as well as for efficiency sake, we will sometimes prune
484+
// parts of the graph.
485+
auto prune = [](MDNode *Parent, MDNode *Child) {
486+
if (auto *MDS = dyn_cast<DISubprogram>(Parent))
487+
return Child == MDS->getVariables().get();
488+
return false;
489+
};
490+
491+
SmallVector<MDNode *, 16> ToVisit;
492+
DenseSet<MDNode *> Opened;
493+
494+
// Visit each node starting at N in post order, and map them.
495+
ToVisit.push_back(N);
496+
while (!ToVisit.empty()) {
497+
auto *N = ToVisit.back();
498+
if (!Opened.insert(N).second) {
499+
// Close it.
500+
remap(N);
501+
ToVisit.pop_back();
502+
continue;
503+
}
504+
for (auto &I : N->operands())
505+
if (auto *MDN = dyn_cast_or_null<MDNode>(I))
506+
if (!Opened.count(MDN) && !Replacements.count(MDN) && !prune(N, MDN) &&
507+
!isa<DICompileUnit>(MDN))
508+
ToVisit.push_back(MDN);
509+
}
510+
}
511+
512+
bool llvm::stripNonLineTableDebugInfo(Module &M) {
513+
bool Changed = false;
514+
515+
// First off, delete the debug intrinsics.
516+
auto RemoveUses = [&](StringRef Name) {
517+
if (auto *DbgVal = M.getFunction(Name)) {
518+
while (!DbgVal->use_empty())
519+
cast<Instruction>(DbgVal->user_back())->eraseFromParent();
520+
DbgVal->eraseFromParent();
521+
Changed = true;
522+
}
523+
};
524+
RemoveUses("llvm.dbg.declare");
525+
RemoveUses("llvm.dbg.value");
526+
527+
// Delete non-CU debug info named metadata nodes.
528+
for (auto NMI = M.named_metadata_begin(), NME = M.named_metadata_end();
529+
NMI != NME;) {
530+
NamedMDNode *NMD = &*NMI;
531+
++NMI;
532+
// Specifically keep dbg.cu around.
533+
if (NMD->getName() == "llvm.dbg.cu")
534+
continue;
535+
}
536+
537+
// Drop all dbg attachments from global variables.
538+
for (auto &GV : M.globals())
539+
GV.eraseMetadata(LLVMContext::MD_dbg);
540+
541+
DebugTypeInfoRemoval Mapper(M.getContext());
542+
auto remap = [&](llvm::MDNode *Node) -> llvm::MDNode * {
543+
if (!Node)
544+
return nullptr;
545+
Mapper.traverseAndRemap(Node);
546+
auto *NewNode = Mapper.mapNode(Node);
547+
Changed |= Node != NewNode;
548+
Node = NewNode;
549+
return NewNode;
550+
};
551+
552+
// Rewrite the DebugLocs to be equivalent to what
553+
// -gline-tables-only would have created.
554+
for (auto &F : M) {
555+
if (auto *SP = F.getSubprogram()) {
556+
Mapper.traverseAndRemap(SP);
557+
auto *NewSP = cast<DISubprogram>(Mapper.mapNode(SP));
558+
Changed |= SP != NewSP;
559+
F.setSubprogram(NewSP);
560+
}
561+
for (auto &BB : F) {
562+
for (auto &I : BB) {
563+
if (I.getDebugLoc() == DebugLoc())
564+
continue;
565+
566+
// Make a replacement.
567+
auto &DL = I.getDebugLoc();
568+
auto *Scope = DL.getScope();
569+
MDNode *InlinedAt = DL.getInlinedAt();
570+
Scope = remap(Scope);
571+
InlinedAt = remap(InlinedAt);
572+
I.setDebugLoc(
573+
DebugLoc::get(DL.getLine(), DL.getCol(), Scope, InlinedAt));
574+
}
575+
}
576+
}
577+
578+
// Create a new llvm.dbg.cu, which is equivalent to the one
579+
// -gline-tables-only would have created.
580+
for (auto &NMD : M.getNamedMDList()) {
581+
SmallVector<MDNode *, 8> Ops;
582+
for (MDNode *Op : NMD.operands())
583+
Ops.push_back(remap(Op));
584+
585+
if (!Changed)
586+
continue;
587+
588+
NMD.clearOperands();
589+
for (auto *Op : Ops)
590+
if (Op)
591+
NMD.addOperand(Op);
592+
}
593+
return Changed;
594+
}
595+
303596
unsigned llvm::getDebugMetadataVersionFromModule(const Module &M) {
304597
if (auto *Val = mdconst::dyn_extract_or_null<ConstantInt>(
305598
M.getModuleFlag("Debug Info Version")))

llvm/lib/IR/Metadata.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,7 @@ void NamedMDNode::setOperand(unsigned I, MDNode *New) {
10541054

10551055
void NamedMDNode::eraseFromParent() { getParent()->eraseNamedMetadata(this); }
10561056

1057-
void NamedMDNode::dropAllReferences() { getNMDOps(Operands).clear(); }
1057+
void NamedMDNode::clearOperands() { getNMDOps(Operands).clear(); }
10581058

10591059
StringRef NamedMDNode::getName() const { return StringRef(Name); }
10601060

llvm/lib/Transforms/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ add_llvm_library(LLVMTransformUtils
4343
SimplifyInstructions.cpp
4444
SimplifyLibCalls.cpp
4545
SplitModule.cpp
46+
StripNonLineTableDebugInfo.cpp
4647
SymbolRewriter.cpp
4748
UnifyFunctionExitNodes.cpp
4849
Utils.cpp

0 commit comments

Comments
 (0)