Update StripDeadDebugInfo to use DebugInfoFinder so that it is no longer stale to the point of not working and more resilient to debug info changes.

The current version of StripDeadDebugInfo became stale and no longer actually
worked since it was expecting an older version of debug info.

This patch updates it to use DebugInfoFinder and the modern DebugInfo classes as
much as possible to make it more redundent to such changes. Additionally, the
only place where that was avoided (the code where we replace the old sets with
the new), I call verify on the DIContextUnit implying that if the format changes
and my live set changes no longer make sense an assert will be hit. In order to
ensure that that occurs I have included a test case.

The actual stripping of the dead debug info follows the same strategy as was
used before in this class: find the live set and replace the old set in the
given compile unit (which may contain dead global variables/functions) with the
new live one.

llvm-svn: 189078
This commit is contained in:
Michael Gottesman 2013-08-23 00:23:24 +00:00
parent 4a561c16f5
commit 823aaffd37
4 changed files with 150 additions and 113 deletions

View File

@ -332,76 +332,107 @@ bool StripDebugDeclare::runOnModule(Module &M) {
return true;
}
/// Remove any debug info for global variables/functions in the given module for
/// which said global variable/function no longer exists (i.e. is null).
///
/// Debugging information 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.
bool StripDeadDebugInfo::runOnModule(Module &M) {
bool Changed = false;
// Debugging information 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.
LLVMContext &C = M.getContext();
// 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 (NMD->getOperand(i)) {
assert(DIGlobalVariable(NMD->getOperand(i)).isGlobalVariable() &&
"A MDNode in llvm.dbg.gv should be a DIGlobalVariable.");
MDs.push_back(NMD->getOperand(i));
}
else
Changed = true;
NMD->eraseFromParent();
NMD = NULL;
// Find all debug info in F. This is actually overkill in terms of what we
// want to do, but we want to try and be as redundent as possible in the face
// of potential debug info changes by using the formal interfaces given to us
// as much as possible.
DebugInfoFinder F;
F.processModule(M);
for (SmallVectorImpl<MDNode *>::iterator I = MDs.begin(),
E = MDs.end(); I != E; ++I) {
GlobalVariable *GV = DIGlobalVariable(*I).getGlobal();
if (GV && M.getGlobalVariable(GV->getName(), true)) {
if (!NMD)
NMD = M.getOrInsertNamedMetadata("llvm.dbg.gv");
NMD->addOperand(*I);
}
// For each compile unit, find the live set of global variables/functions and
// replace the current list of potentially dead global variables/functions
// with the live list.
SmallVector<Value *, 64> LiveGlobalVariables;
SmallVector<Value *, 64> LiveSubprograms;
DenseSet<const MDNode *> VisitedSet;
for (DebugInfoFinder::iterator CI = F.compile_unit_begin(),
CE = F.compile_unit_end(); CI != CE; ++CI) {
// Create our compile unit.
DICompileUnit DIC(*CI);
assert(DIC.Verify() && "DIC must verify as a DICompileUnit.");
// Create our live subprogram list.
DIArray SPs = DIC.getSubprograms();
bool SubprogramChange = false;
for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) {
DISubprogram DISP(SPs.getElement(i));
assert(DISP.Verify() && "DISP must verify as a DISubprogram.");
// Make sure we visit each subprogram only once.
if (!VisitedSet.insert(DISP).second)
continue;
// If the function referenced by DISP is not null, the function is live.
if (DISP.getFunction())
LiveSubprograms.push_back(DISP);
else
Changed = true;
SubprogramChange = 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 (NMD->getOperand(i)) {
assert(DISubprogram(NMD->getOperand(i)).isSubprogram() &&
"A MDNode in llvm.dbg.sp should be a DISubprogram.");
MDs.push_back(NMD->getOperand(i));
}
// Create our live global variable list.
DIArray GVs = DIC.getGlobalVariables();
bool GlobalVariableChange = false;
for (unsigned i = 0, e = GVs.getNumElements(); i != e; ++i) {
DIGlobalVariable DIG(GVs.getElement(i));
assert(DIG.Verify() && "DIG must verify as DIGlobalVariable.");
// Make sure we only visit each global variable only once.
if (!VisitedSet.insert(DIG).second)
continue;
// If the global variable referenced by DIG is not null, the global
// variable is live.
if (DIG.getGlobal())
LiveGlobalVariables.push_back(DIG);
else
Changed = true;
NMD->eraseFromParent();
NMD = NULL;
for (SmallVectorImpl<MDNode *>::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(
"llvm.dbg.lv." + Function::getRealLinkageName(FName)))
LVNMD->eraseFromParent();
}
GlobalVariableChange = true;
}
// If we found dead subprograms or global variables, replace the current
// subprogram list/global variable list with our new live subprogram/global
// variable list.
if (SubprogramChange) {
// Make sure that 9 is still the index of the subprograms. This is to make
// sure that an assert is hit if the location of the subprogram array
// changes. This is just to make sure that this is updated if such an
// event occurs.
assert(DIC->getNumOperands() >= 10 &&
SPs == DIC->getOperand(9) &&
"DICompileUnits is expected to store Subprograms in operand "
"9.");
DIC->replaceOperandWith(9, MDNode::get(C, LiveSubprograms));
Changed = true;
}
if (GlobalVariableChange) {
// Make sure that 10 is still the index of global variables. This is to
// make sure that an assert is hit if the location of the subprogram array
// changes. This is just to make sure that this index is updated if such
// an event occurs.
assert(DIC->getNumOperands() >= 11 &&
GVs == DIC->getOperand(10) &&
"DICompileUnits is expected to store Global Variables in operand "
"10.");
DIC->replaceOperandWith(10, MDNode::get(C, LiveGlobalVariables));
Changed = true;
}
// Reset lists for the next iteration.
LiveSubprograms.clear();
LiveGlobalVariables.clear();
}
return Changed;

View File

@ -1,49 +0,0 @@
; RUN: opt -strip-dead-debug-info < %s | llvm-dis -o %t.ll
; RUN: grep -v bar %t.ll
; RUN: grep -v abcd %t.ll
@xyz = global i32 2 ; <i32*> [#uses=1]
declare void @llvm.dbg.value(metadata, i64, metadata) nounwind readnone
define i32 @fn() nounwind readnone ssp {
entry:
ret i32 0, !dbg !17
}
define i32 @foo(i32 %i) nounwind readonly ssp {
entry:
tail call void @llvm.dbg.value(metadata !{i32 %i}, i64 0, metadata !14), !dbg !19
%.0 = load i32* @xyz, align 4 ; <i32> [#uses=1]
ret i32 %.0, !dbg !20
}
!llvm.dbg.cu = !{!2}
!llvm.dbg.sp = !{!0, !5, !9}
!llvm.dbg.lv.bar = !{!12}
!llvm.dbg.lv.foo = !{!14}
!llvm.dbg.gv = !{!15, !16}
!0 = metadata !{i32 524334, metadata !22, null, metadata !"bar", metadata !"bar", metadata !"", i32 5, metadata !3, i1 true, i1 true, i32 0, i32 0, null, i1 false, i1 true, null, null, null, null, i32 0} ; [ DW_TAG_subprogram ]
!1 = metadata !{i32 524329, metadata !22} ; [ DW_TAG_file_type ]
!2 = metadata !{i32 524305, metadata !22, i32 1, metadata !"4.2.1 (Based on Apple Inc. build 5658) (LLVM build)", i1 true, metadata !"", i32 0, metadata !4, metadata !4, null, null, null, metadata !""} ; [ DW_TAG_compile_unit ]
!3 = metadata !{i32 524309, metadata !22, metadata !1, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !4, i32 0, null} ; [ DW_TAG_subroutine_type ]
!4 = metadata !{null}
!5 = metadata !{i32 524334, metadata !22, null, metadata !"fn", metadata !"fn", metadata !"fn", i32 6, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i1 false, i1 true, i32 ()* @fn, null, null, null, i32 0} ; [ DW_TAG_subprogram ]
!6 = metadata !{i32 524309, metadata !22, metadata !1, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null} ; [ DW_TAG_subroutine_type ]
!7 = metadata !{metadata !8}
!8 = metadata !{i32 524324, metadata !22, metadata !1, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ]
!9 = metadata !{i32 524334, metadata !22, null, metadata !"foo", metadata !"foo", metadata !"foo", i32 7, metadata !10, i1 false, i1 true, i32 0, i32 0, null, i1 false, i1 true, i32 (i32)* @foo, null, null, null, i32 0} ; [ DW_TAG_subprogram ]
!10 = metadata !{i32 524309, metadata !22, metadata !1, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !11, i32 0, null} ; [ DW_TAG_subroutine_type ]
!11 = metadata !{metadata !8, metadata !8}
!12 = metadata !{i32 524544, metadata !13, metadata !"bb", metadata !1, i32 5, metadata !8} ; [ DW_TAG_auto_variable ]
!13 = metadata !{i32 524299, metadata !22, metadata !0, i32 5, i32 0, i32 0} ; [ DW_TAG_lexical_block ]
!14 = metadata !{i32 524545, metadata !9, metadata !"i", metadata !1, i32 7, metadata !8} ; [ DW_TAG_arg_variable ]
!15 = metadata !{i32 524340, i32 0, metadata !1, metadata !"abcd", metadata !"abcd", metadata !"", metadata !1, i32 2, metadata !8, i1 true, i1 true, null} ; [ DW_TAG_variable ]
!16 = metadata !{i32 524340, i32 0, metadata !1, metadata !"xyz", metadata !"xyz", metadata !"", metadata !1, i32 3, metadata !8, i1 false, i1 true, i32* @xyz} ; [ DW_TAG_variable ]
!17 = metadata !{i32 6, i32 0, metadata !18, null}
!18 = metadata !{i32 524299, metadata !22, metadata !5, i32 6, i32 0, i32 0} ; [ DW_TAG_lexical_block ]
!19 = metadata !{i32 7, i32 0, metadata !9, null}
!20 = metadata !{i32 10, i32 0, metadata !21, null}
!21 = metadata !{i32 524299, metadata !22, metadata !9, i32 7, i32 0, i32 0} ; [ DW_TAG_lexical_block ]
!22 = metadata !{metadata !"g.c", metadata !"/tmp/"}

View File

@ -5,18 +5,18 @@ entry:
}
!llvm.dbg.cu = !{!2}
!llvm.dbg.sp = !{!0}
!llvm.dbg.gv = !{!6}
!0 = metadata !{i32 524334, metadata !10, metadata !1, metadata !"foo", metadata !"foo", metadata !"foo", i32 3, metadata !3, i1 false, i1 true, i32 0, i32 0, null, i1 false, i1 false, i32 ()* @foo, null, null, null, i32 0} ; [ DW_TAG_subprogram ]
!1 = metadata !{i32 524329, metadata !10} ; [ DW_TAG_file_type ]
!2 = metadata !{i32 524305, metadata !10, i32 12, metadata !"clang version 2.8 (trunk 112062)", i1 true, metadata !"", i32 0, metadata !11, metadata !11, null, null, null, metadata !""} ; [ DW_TAG_compile_unit ]
!2 = metadata !{i32 524305, metadata !10, i32 12, metadata !"clang version 2.8 (trunk 112062)", i1 true, metadata !"", i32 0, metadata !11, metadata !11, metadata !12, metadata !13, null, metadata !""} ; [ DW_TAG_compile_unit ]
!3 = metadata !{i32 524309, metadata !10, metadata !1, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !4, i32 0, null} ; [ DW_TAG_subroutine_type ]
!4 = metadata !{metadata !5}
!5 = metadata !{i32 524324, metadata !10, metadata !1, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ]
!6 = metadata !{i32 524340, i32 0, metadata !1, metadata !"i", metadata !"i", metadata !"i", metadata !1, i32 2, metadata !7, i1 true, i1 true, i32 0} ; [ DW_TAG_variable ]
!6 = metadata !{i32 524340, i32 0, metadata !1, metadata !"i", metadata !"i", metadata !"i", metadata !1, i32 2, metadata !7, i1 true, i1 true, i32 0, null} ; [ DW_TAG_variable ]
!7 = metadata !{i32 524326, metadata !10, metadata !1, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, metadata !5} ; [ DW_TAG_const_type ]
!8 = metadata !{i32 3, i32 13, metadata !9, null}
!9 = metadata !{i32 524299, metadata !10, metadata !0, i32 3, i32 11, i32 0} ; [ DW_TAG_lexical_block ]
!10 = metadata !{metadata !"/tmp/a.c", metadata !"/Volumes/Lalgate/clean/D.CW"}
!11 = metadata !{i32 0}
!12 = metadata !{metadata !0}
!13 = metadata !{metadata !6}

View File

@ -0,0 +1,55 @@
; RUN: opt -strip-dead-debug-info -verify %s -S | FileCheck %s
; CHECK-NOT: bar
; CHECK-NOT: abcd
@xyz = global i32 2
; Function Attrs: nounwind readnone
declare void @llvm.dbg.value(metadata, i64, metadata) #0
; Function Attrs: nounwind readnone ssp
define i32 @fn() #1 {
entry:
ret i32 0, !dbg !18
}
; Function Attrs: nounwind readonly ssp
define i32 @foo(i32 %i) #2 {
entry:
tail call void @llvm.dbg.value(metadata !{i32 %i}, i64 0, metadata !15), !dbg !20
%.0 = load i32* @xyz, align 4
ret i32 %.0, !dbg !21
}
attributes #0 = { nounwind readnone }
attributes #1 = { nounwind readnone ssp }
attributes #2 = { nounwind readonly ssp }
!llvm.dbg.cu = !{!0}
!0 = metadata !{i32 524305, metadata !1, i32 1, metadata !"4.2.1 (Based on Apple Inc. build 5658) (LLVM build)", i1 true, metadata !"", i32 0, metadata !2, metadata !2, metadata !23, metadata !24, null, metadata !""} ; [ DW_TAG_compile_unit ] [/tmp//g.c] [DW_LANG_C89]
!1 = metadata !{metadata !"g.c", metadata !"/tmp/"}
!2 = metadata !{null}
!3 = metadata !{i32 524334, metadata !1, null, metadata !"bar", metadata !"bar", metadata !"", i32 5, metadata !4, i1 true, i1 true, i32 0, i32 0, null, i1 false, i1 true, null, null, null, null, i32 0} ; [ DW_TAG_subprogram ] [line 5] [local] [def] [scope 0] [bar]
!4 = metadata !{i32 524309, metadata !1, metadata !5, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !2, i32 0, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
!5 = metadata !{i32 524329, metadata !1} ; [ DW_TAG_file_type ] [/tmp//g.c]
!6 = metadata !{i32 524334, metadata !1, null, metadata !"fn", metadata !"fn", metadata !"fn", i32 6, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i1 false, i1 true, i32 ()* @fn, null, null, null, i32 0} ; [ DW_TAG_subprogram ] [line 6] [def] [scope 0] [fn]
!7 = metadata !{i32 524309, metadata !1, metadata !5, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
!8 = metadata !{metadata !9}
!9 = metadata !{i32 524324, metadata !1, metadata !5, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
!10 = metadata !{i32 524334, metadata !1, null, metadata !"foo", metadata !"foo", metadata !"foo", i32 7, metadata !11, i1 false, i1 true, i32 0, i32 0, null, i1 false, i1 true, i32 (i32)* @foo, null, null, null, i32 0} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 0] [foo]
!11 = metadata !{i32 524309, metadata !1, metadata !5, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !12, i32 0, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
!12 = metadata !{metadata !9, metadata !9}
!13 = metadata !{i32 524544, metadata !14, metadata !"bb", metadata !5, i32 5, metadata !9}
!14 = metadata !{i32 524299, metadata !1, metadata !3, i32 5, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [/tmp//g.c]
!15 = metadata !{i32 524545, metadata !10, metadata !"i", metadata !5, i32 7, metadata !9}
!16 = metadata !{i32 524340, i32 0, metadata !5, metadata !"abcd", metadata !"abcd", metadata !"", metadata !5, i32 2, metadata !9, i1 true, i1 true, null, null}
!17 = metadata !{i32 524340, i32 0, metadata !5, metadata !"xyz", metadata !"xyz", metadata !"", metadata !5, i32 3, metadata !9, i1 false, i1 true, i32* @xyz, null}
!18 = metadata !{i32 6, i32 0, metadata !19, null}
!19 = metadata !{i32 524299, metadata !1, metadata !6, i32 6, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [/tmp//g.c]
!20 = metadata !{i32 7, i32 0, metadata !10, null}
!21 = metadata !{i32 10, i32 0, metadata !22, null}
!22 = metadata !{i32 524299, metadata !1, metadata !10, i32 7, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [/tmp//g.c]
!23 = metadata !{metadata !3, metadata !6, metadata !10}
!24 = metadata !{metadata !16, metadata !17}