Skip to content

Commit d0a4db7

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. llvm-svn: 283473
1 parent 9a605f9 commit d0a4db7

File tree

14 files changed

+584
-5
lines changed

14 files changed

+584
-5
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/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ void initializeStripDeadDebugInfoPass(PassRegistry&);
328328
void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&);
329329
void initializeStripDebugDeclarePass(PassRegistry&);
330330
void initializeStripNonDebugSymbolsPass(PassRegistry&);
331+
void initializeStripNonLineTableDebugInfoPass(PassRegistry&);
331332
void initializeStripSymbolsPass(PassRegistry&);
332333
void initializeStructurizeCFGPass(PassRegistry&);
333334
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: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,315 @@ bool llvm::StripDebugInfo(Module &M) {
287287
return Changed;
288288
}
289289

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

llvm/lib/Transforms/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ add_llvm_library(LLVMTransformUtils
4141
SimplifyInstructions.cpp
4242
SimplifyLibCalls.cpp
4343
SplitModule.cpp
44+
StripNonLineTableDebugInfo.cpp
4445
SymbolRewriter.cpp
4546
UnifyFunctionExitNodes.cpp
4647
Utils.cpp

0 commit comments

Comments
 (0)