Index: include/llvm/IR/DebugInfo.h =================================================================== --- include/llvm/IR/DebugInfo.h +++ include/llvm/IR/DebugInfo.h @@ -44,6 +44,18 @@ bool StripDebugInfo(Module &M); bool stripDebugInfo(Function &F); +/// Downgrade the debug info in a module to contain only line table information. +/// +/// In order to convert debug info to what -gline-tables-only would have +/// created, this does the following: +/// 1) Delete all debug intrinsics. +/// 2) Delete all non-CU named metadata debug info nodes. +/// 3) Create new DebugLocs for each instruction. +/// 4) Create a new CU debug info, and similarly for every metadata node +/// that's reachable from the CU debug info. +/// All debug type metadata nodes are unreachable and garbage collected. +bool stripNonLineTableDebugInfo(Module &M); + /// \brief Return Debug Info Metadata Version by checking module flags. unsigned getDebugMetadataVersionFromModule(const Module &M); Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -327,6 +327,7 @@ void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&); void initializeStripDebugDeclarePass(PassRegistry&); void initializeStripNonDebugSymbolsPass(PassRegistry&); +void initializeStripNonLineTableDebugInfoPass(PassRegistry&); void initializeStripSymbolsPass(PassRegistry&); void initializeStructurizeCFGPass(PassRegistry&); void initializeTailCallElimPass(PassRegistry&); Index: include/llvm/Transforms/IPO.h =================================================================== --- include/llvm/Transforms/IPO.h +++ include/llvm/Transforms/IPO.h @@ -43,6 +43,10 @@ // ModulePass *createStripNonDebugSymbolsPass(); +/// This function returns a new pass that downgrades the debug info in the +/// module to line tables only. +ModulePass *createStripNonLineTableDebugInfoPass(); + //===----------------------------------------------------------------------===// // // These pass removes llvm.dbg.declare intrinsics. Index: lib/IR/DebugInfo.cpp =================================================================== --- lib/IR/DebugInfo.cpp +++ lib/IR/DebugInfo.cpp @@ -287,6 +287,320 @@ return Changed; } +namespace { + +/// Helper class to downgrade -g metadata to -gline-tables-only metadata. +class DebugTypeInfoRemoval { + DenseMap 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 NewToLinkageName; + + // TODO: Remember the distinct subprogram we created for a given linkage name, + // so that we can continue to unique whenever possible. Map 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(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(map(MDS->getFile())); + StringRef LinkageName = MDS->getName().empty() ? MDS->getLinkageName() : ""; + DISubprogram *Declaration = nullptr; + auto *Type = cast_or_null(map(MDS->getType())); + DITypeRef ContainingType(map(MDS->getContainingType())); + auto *Unit = cast_or_null(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. + if (NewToLinkageName.count(NewMDS)) { + if (NewToLinkageName.lookup(NewMDS) == 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(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 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(N)) { + remap(MDSub->getUnit()); + return getReplacementSubprogram(MDSub); + } + if (isa(N)) + return EmptySubroutineType; + if (auto *CU = dyn_cast(N)) + return getReplacementCU(CU); + if (isa(N)) + return N; + if (auto *MDLB = dyn_cast(N)) + // Remap to our referenced scope (recursively). + return mapNode(MDLB->getScope()); + if (auto *MLD = dyn_cast(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(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(Parent)) + return Child == MDS->getVariables().get(); + return false; + }; + + SmallVector ToVisit; + DenseSet Opened; + + // Visit each node starting at N in post order, and map them + ToVisit.push_back(N); + while (!ToVisit.empty()) { + auto *N = ToVisit.back(); + if (Opened.count(N)) { + // Close it + remap(N); + ToVisit.pop_back(); + continue; + } + Opened.insert(N); + for (auto &I : N->operands()) + if (auto *MDN = dyn_cast_or_null(I)) + if (!Opened.count(MDN) && !Replacements.count(MDN) && !prune(N, MDN) && + !isa(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(Declare->user_back()); + DDI->eraseFromParent(); + } + Declare->eraseFromParent(); + Changed = true; + } + if (Function *DbgVal = M.getFunction("llvm.dbg.value")) { + while (!DbgVal->use_empty()) { + auto *DVI = cast(DbgVal->user_back()); + DVI->eraseFromParent(); + } + DbgVal->eraseFromParent(); + Changed = true; + } + + // Delete non-cu debug info named metadata nodes. + for (Module::named_metadata_iterator 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; + + if (NMD->getName().startswith("llvm.dbg.")) { + NMD->eraseFromParent(); + Changed = true; + } + } + + // 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(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(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 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( M.getModuleFlag("Debug Info Version"))) Index: lib/Transforms/Utils/CMakeLists.txt =================================================================== --- lib/Transforms/Utils/CMakeLists.txt +++ lib/Transforms/Utils/CMakeLists.txt @@ -41,6 +41,7 @@ SimplifyInstructions.cpp SimplifyLibCalls.cpp SplitModule.cpp + StripNonLineTableDebugInfo.cpp SymbolRewriter.cpp UnifyFunctionExitNodes.cpp Utils.cpp Index: lib/Transforms/Utils/Utils.cpp =================================================================== --- lib/Transforms/Utils/Utils.cpp +++ lib/Transforms/Utils/Utils.cpp @@ -30,6 +30,7 @@ initializeLowerSwitchPass(Registry); initializeNameAnonGlobalLegacyPassPass(Registry); initializePromoteLegacyPassPass(Registry); + initializeStripNonLineTableDebugInfoPass(Registry); initializeUnifyFunctionExitNodesPass(Registry); initializeInstSimplifierPass(Registry); initializeMetaRenamerPass(Registry); Index: test/BugPoint/metadata.ll =================================================================== --- test/BugPoint/metadata.ll +++ test/BugPoint/metadata.ll @@ -1,10 +1,22 @@ -; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -bugpoint-crashcalls -silence-passes -disable-namedmd-remove > /dev/null -; RUN: llvm-dis %t-reduced-simplified.bc -o - | FileCheck %s ; REQUIRES: loadable_module - +; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -bugpoint-crashcalls -silence-passes -disable-namedmd-remove -disable-strip-debuginfo -disable-strip-debug-types > /dev/null +; RUN: llvm-dis %t-reduced-simplified.bc -o - | FileCheck %s +; +; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t-nodebug -bugpoint-crashcalls -silence-passes -disable-namedmd-remove > /dev/null +; RUN: llvm-dis %t-nodebug-reduced-simplified.bc -o - | FileCheck %s --check-prefix=NODEBUG +; +; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t-notype -bugpoint-crashcalls -silence-passes -disable-namedmd-remove -disable-strip-debuginfo > /dev/null +; RUN: llvm-dis %t-notype-reduced-simplified.bc -o - | FileCheck %s --check-prefix=NOTYPE +; ; Bugpoint should keep the call's metadata attached to the call. ; CHECK: call void @foo(), !dbg ![[LOC:[0-9]+]], !attach ![[CALL:[0-9]+]] +; NODEBUG: call void @foo(), !attach ![[CALL:[0-9]+]] +; NOTYPE: call void @foo(), !dbg ![[LOC:[0-9]+]], !attach ![[CALL:[0-9]+]] +; NODEBUG-NOT: call void @foo(), !attach ![[CALL:[0-9]+]] +; NOTYPE-NOT: !DIBasicType +; NOTYPE: !DICompileUnit +; NOTYPE-NOT: !DIBasicType ; CHECK-DAG: ![[LOC]] = !DILocation(line: 104, column: 105, scope: ![[SCOPE:[0-9]+]]) ; CHECK-DAG: ![[SCOPE]] = distinct !DISubprogram(name: "test",{{.*}}file: ![[FILE:[0-9]+]] ; CHECK-DAG: ![[FILE]] = !DIFile(filename: "source.c", directory: "/dir") @@ -32,7 +44,7 @@ !4 = !{!"filler"} !8 = distinct !DICompileUnit(language: DW_LANG_C99, file: !15) -!9 = distinct !DISubprogram(name: "test", file: !15, unit: !8) +!9 = distinct !DISubprogram(name: "test", file: !15, type: !18, unit: !8) !10 = !DILocation(line: 100, column: 101, scope: !9) !11 = !DILocation(line: 102, column: 103, scope: !9) !12 = !DILocation(line: 104, column: 105, scope: !9) @@ -41,3 +53,6 @@ !15 = !DIFile(filename: "source.c", directory: "/dir") !16 = !{} !17 = !{i32 1, !"Debug Info Version", i32 3} +!18 = !DISubroutineType(types: !19) +!19 = !{!20, !20} +!20 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) Index: test/BugPoint/named-md.ll =================================================================== --- test/BugPoint/named-md.ll +++ test/BugPoint/named-md.ll @@ -1,4 +1,4 @@ -; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -bugpoint-crash-too-many-cus -silence-passes > /dev/null +; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -bugpoint-crash-too-many-cus -silence-passes -disable-strip-debuginfo > /dev/null ; RUN: llvm-dis %t-reduced-simplified.bc -o - | FileCheck %s ; RUN-DISABLE: bugpoint -disable-namedmd-remove -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -bugpoint-crash-too-many-cus -silence-passes > /dev/null ; RUN-DISABLE: llvm-dis %t-reduced-simplified.bc -o - | FileCheck %s Index: test/Transforms/Util/strip-nonlinetable-debuginfo.ll =================================================================== --- /dev/null +++ test/Transforms/Util/strip-nonlinetable-debuginfo.ll @@ -0,0 +1,22 @@ +; RUN: opt -S -strip-nonlinetable-debuginfo %s -o - | FileCheck %s +!llvm.dbg.cu = !{!2, !6} +!llvm.gcov = !{!3} +!llvm.module.flags = !{!7} + +!1 = !DIFile(filename: "path/to/file", directory: "/path/to/dir") +; CHECK: !llvm.dbg.cu = !{![[CU:[0-9]+]]} +; CHECK: ![[CU]] = distinct !DICompileUnit({{.*}}"abc.debug"{{.*}}LineTablesOnly +; CHECK-NOT: retainedTypes: +; CHECK-SAME: ) +; CHECK-NOT: DICompositeType +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", + isOptimized: true, flags: "-O2", runtimeVersion: 2, + splitDebugFilename: "abc.debug", emissionKind: FullDebug, + retainedTypes: !4) +!3 = !{!"path/to/file.o", !2} +!4 = !{!5} +!5 = !DICompositeType(tag: DW_TAG_structure_type, file: !1, identifier: "ThisWillBeStripped") +!6 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", + splitDebugFilename: "abc.dwo", emissionKind: FullDebug, + dwoId: 1234) +!7 = !{i32 1, !"Debug Info Version", i32 3} Index: test/Transforms/Util/strip-nonlinetable-debuginfo2.ll =================================================================== --- /dev/null +++ test/Transforms/Util/strip-nonlinetable-debuginfo2.ll @@ -0,0 +1,35 @@ +; RUN: opt -S -strip-nonlinetable-debuginfo -arm-assume-misaligned-load-store=false %s -o - | FileCheck %s +; CHECK: define void @f() !dbg ![[F:[0-9]+]] +define void @f() !dbg !4 { +entry: + %i = alloca i32, align 4 + call void @llvm.dbg.declare(metadata i32* %i, metadata !11, metadata !13), !dbg !14 + store i32 42, i32* %i, align 4, !dbg !14 + ret void, !dbg !15 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2) +!1 = !DIFile(filename: "f.c", directory: "/") +!2 = !{} +; CHECK: ![[F]] = distinct !DISubprogram(name: "f" +; CHECK-NOT: variables: +; CHECK-NOT: distinct !DISubprogram(name: "f" +!4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null} +!7 = !{i32 2, !"Dwarf Version", i32 2} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"PIC Level", i32 2} +!10 = !{!"LLVM"} +!11 = !DILocalVariable(name: "i", scope: !4, file: !1, line: 1, type: !12) +!12 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!13 = !DIExpression() +!14 = !DILocation(line: 1, column: 16, scope: !4) +!15 = !DILocation(line: 1, column: 24, scope: !4) Index: test/Transforms/Util/strip-nonlinetable-debuginfo3.ll =================================================================== --- /dev/null +++ test/Transforms/Util/strip-nonlinetable-debuginfo3.ll @@ -0,0 +1,21 @@ +; RUN: opt -S -strip-nonlinetable-debuginfo %s -o - | FileCheck %s +define internal i32 @"__hidden#2878_"() #0 !dbg !12 { + ret i32 0, !dbg !634 +} +!llvm.dbg.cu = !{!18} +!llvm.module.flags = !{!482} +!5 = !{} +!2 = !{!12} +; CHECK-NOT: DICompositeType +; CHECK: distinct !DISubprogram(name: "f", {{.*}}, type: ![[FNTY:[0-9]+]] +; CHECK: ![[FNTY]] = !DISubroutineType(types: ![[VOID:[0-9]+]]) +; CHECK: ![[VOID]] = !{} +; CHECK-NOT: DICompositeType +!12 = distinct !DISubprogram(name: "f", scope: !16, file: !16, line: 133, type: !13, isLocal: true, isDefinition: true, scopeLine: 133, flags: DIFlagPrototyped, isOptimized: true, unit: !18, variables: !5) +!13 = !DISubroutineType(types: !14) +!14 = !{!17} +!16 = !DIFile(filename: "f.m", directory: "/") +!17 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "e", scope: !18, file: !16, line: 13, size: 32, align: 32, flags: DIFlagFwdDecl) +!18 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !16, producer: "clang", isOptimized: true, runtimeVersion: 2, emissionKind: 1, enums: !14, retainedTypes: !14, globals: !5, imports: !5) +!482 = !{i32 2, !"Debug Info Version", i32 3} +!634 = !DILocation(line: 143, column: 5, scope: !12) Index: test/Transforms/Util/strip-nonlinetable-debuginfo4.ll =================================================================== --- /dev/null +++ test/Transforms/Util/strip-nonlinetable-debuginfo4.ll @@ -0,0 +1,237 @@ +; RUN: opt -S -strip-nonlinetable-debuginfo %s -o - | FileCheck %s +; Generated from: +; struct A { +; virtual ~A(); +; }; +; struct B : A {}; +; B b; + +; CHECK-NOT: !DICompositeType + +source_filename = "t.cpp" +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.12.0" + +%struct.B = type { %struct.A } +%struct.A = type { i32 (...)** } + +@b = global %struct.B zeroinitializer, align 8, !dbg !0 +@__dso_handle = external global i8 +@_ZTV1B = linkonce_odr unnamed_addr constant [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1B to i8*), i8* bitcast (void (%struct.B*)* @_ZN1BD1Ev to i8*), i8* bitcast (void (%struct.B*)* @_ZN1BD0Ev to i8*)], align 8 +@_ZTVN10__cxxabiv120__si_class_type_infoE = external global i8* +@_ZTS1B = linkonce_odr constant [3 x i8] c"1B\00" +@_ZTI1A = external constant i8* +@_ZTI1B = linkonce_odr constant { i8*, i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0), i8* bitcast (i8** @_ZTI1A to i8*) } +@_ZTV1A = external unnamed_addr constant [4 x i8*] +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_t.cpp, i8* null }] + +; Function Attrs: ssp uwtable +define internal void @__cxx_global_var_init() #0 section "__TEXT,__StaticInit,regular,pure_instructions" !dbg !24 { +entry: + call void @_ZN1BC1Ev(%struct.B* @b) #3, !dbg !27 + %0 = call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.B*)* @_ZN1BD1Ev to void (i8*)*), i8* bitcast (%struct.B* @b to i8*), i8* @__dso_handle) #3, !dbg !28 + ret void, !dbg !27 +} + +; Function Attrs: inlinehint nounwind ssp uwtable +define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr #1 align 2 !dbg !30 { +entry: + %this.addr = alloca %struct.B*, align 8 + store %struct.B* %this, %struct.B** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %struct.B** %this.addr, metadata !35, metadata !37), !dbg !38 + %this1 = load %struct.B*, %struct.B** %this.addr, align 8 + call void @_ZN1BC2Ev(%struct.B* %this1) #3, !dbg !39 + ret void, !dbg !39 +} + +; Function Attrs: inlinehint ssp uwtable +define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr #2 align 2 !dbg !40 { +entry: + %this.addr = alloca %struct.B*, align 8 + store %struct.B* %this, %struct.B** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %struct.B** %this.addr, metadata !42, metadata !37), !dbg !43 + %this1 = load %struct.B*, %struct.B** %this.addr, align 8 + call void @_ZN1BD2Ev(%struct.B* %this1), !dbg !44 + ret void, !dbg !44 +} + +; Function Attrs: nounwind +declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*) #3 + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #4 + +; Function Attrs: inlinehint nounwind ssp uwtable +define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr #1 align 2 !dbg !45 { +entry: + %this.addr = alloca %struct.B*, align 8 + store %struct.B* %this, %struct.B** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %struct.B** %this.addr, metadata !46, metadata !37), !dbg !47 + %this1 = load %struct.B*, %struct.B** %this.addr, align 8 + %0 = bitcast %struct.B* %this1 to %struct.A*, !dbg !48 + call void @_ZN1AC2Ev(%struct.A* %0) #3, !dbg !48 + %1 = bitcast %struct.B* %this1 to i32 (...)***, !dbg !48 + store i32 (...)** bitcast (i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @_ZTV1B, i32 0, i32 2) to i32 (...)**), i32 (...)*** %1, align 8, !dbg !48 + ret void, !dbg !48 +} + +; Function Attrs: inlinehint nounwind ssp uwtable +define linkonce_odr void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr #1 align 2 !dbg !49 { +entry: + %this.addr = alloca %struct.A*, align 8 + store %struct.A* %this, %struct.A** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %struct.A** %this.addr, metadata !51, metadata !37), !dbg !53 + %this1 = load %struct.A*, %struct.A** %this.addr, align 8 + %0 = bitcast %struct.A* %this1 to i32 (...)***, !dbg !54 + store i32 (...)** bitcast (i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @_ZTV1A, i32 0, i32 2) to i32 (...)**), i32 (...)*** %0, align 8, !dbg !54 + ret void, !dbg !54 +} + +; Function Attrs: inlinehint ssp uwtable +define linkonce_odr void @_ZN1BD0Ev(%struct.B* %this) unnamed_addr #2 align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !55 { +entry: + %this.addr = alloca %struct.B*, align 8 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + store %struct.B* %this, %struct.B** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %struct.B** %this.addr, metadata !56, metadata !37), !dbg !57 + %this1 = load %struct.B*, %struct.B** %this.addr, align 8 + invoke void @_ZN1BD1Ev(%struct.B* %this1) + to label %invoke.cont unwind label %lpad, !dbg !58 + +invoke.cont: ; preds = %entry + %0 = bitcast %struct.B* %this1 to i8*, !dbg !59 + call void @_ZdlPv(i8* %0) #7, !dbg !59 + ret void, !dbg !59 + +lpad: ; preds = %entry + %1 = landingpad { i8*, i32 } + cleanup, !dbg !61 + %2 = extractvalue { i8*, i32 } %1, 0, !dbg !61 + store i8* %2, i8** %exn.slot, align 8, !dbg !61 + %3 = extractvalue { i8*, i32 } %1, 1, !dbg !61 + store i32 %3, i32* %ehselector.slot, align 4, !dbg !61 + %4 = bitcast %struct.B* %this1 to i8*, !dbg !61 + call void @_ZdlPv(i8* %4) #7, !dbg !61 + br label %eh.resume, !dbg !61 + +eh.resume: ; preds = %lpad + %exn = load i8*, i8** %exn.slot, align 8, !dbg !63 + %sel = load i32, i32* %ehselector.slot, align 4, !dbg !63 + %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0, !dbg !63 + %lpad.val2 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1, !dbg !63 + resume { i8*, i32 } %lpad.val2, !dbg !63 +} + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: nobuiltin nounwind +declare void @_ZdlPv(i8*) #5 + +; Function Attrs: inlinehint ssp uwtable +define linkonce_odr void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr #2 align 2 !dbg !65 { +entry: + %this.addr = alloca %struct.B*, align 8 + store %struct.B* %this, %struct.B** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %struct.B** %this.addr, metadata !66, metadata !37), !dbg !67 + %this1 = load %struct.B*, %struct.B** %this.addr, align 8 + %0 = bitcast %struct.B* %this1 to %struct.A*, !dbg !68 + call void @_ZN1AD2Ev(%struct.A* %0), !dbg !68 + ret void, !dbg !70 +} + +declare void @_ZN1AD2Ev(%struct.A*) unnamed_addr + +; Function Attrs: ssp uwtable +define internal void @_GLOBAL__sub_I_t.cpp() #0 section "__TEXT,__StaticInit,regular,pure_instructions" !dbg !71 { +entry: + call void @__cxx_global_var_init(), !dbg !73 + ret void +} + +attributes #0 = { ssp uwtable } +attributes #1 = { inlinehint nounwind ssp uwtable } +attributes #2 = { inlinehint ssp uwtable } +attributes #3 = { nounwind } +attributes #4 = { nounwind readnone } +attributes #5 = { nobuiltin nounwind } +attributes #7 = { builtin nounwind } + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!20, !21, !22} +!llvm.ident = !{!23} + +!0 = distinct !DIGlobalVariable(name: "b", scope: !1, file: !2, line: 5, type: !5, isLocal: false, isDefinition: true) +!1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "clang version 4.0.0 (trunk 282583) (llvm/trunk 282611)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !4) +!2 = !DIFile(filename: "t.cpp", directory: "/") +!3 = !{} +!4 = !{!0} +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "B", file: !2, line: 4, size: 64, align: 64, elements: !6, vtableHolder: !8, identifier: "_ZTS1B") +!6 = !{!7} +!7 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !5, baseType: !8) +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !2, line: 1, size: 64, align: 64, elements: !9, vtableHolder: !8, identifier: "_ZTS1A") +!9 = !{!10, !16} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$A", scope: !2, file: !2, baseType: !11, size: 64, flags: DIFlagArtificial) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: !13, size: 64) +!13 = !DISubroutineType(types: !14) +!14 = !{!15} +!15 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!16 = !DISubprogram(name: "~A", scope: !8, file: !2, line: 2, type: !17, isLocal: false, isDefinition: false, scopeLine: 2, containingType: !8, virtuality: DW_VIRTUALITY_virtual, virtualIndex: 0, flags: DIFlagPrototyped, isOptimized: false) +!17 = !DISubroutineType(types: !18) +!18 = !{null, !19} +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!20 = !{i32 2, !"Dwarf Version", i32 4} +!21 = !{i32 2, !"Debug Info Version", i32 3} +!22 = !{i32 1, !"PIC Level", i32 2} +!23 = !{!"clang version 4.0.0 (trunk 282583) (llvm/trunk 282611)"} +!24 = distinct !DISubprogram(name: "__cxx_global_var_init", scope: !2, file: !2, line: 5, type: !25, isLocal: true, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, unit: !1, variables: !3) +!25 = !DISubroutineType(types: !26) +!26 = !{null} +!27 = !DILocation(line: 5, column: 3, scope: !24) +!28 = !DILocation(line: 5, column: 3, scope: !29) +!29 = !DILexicalBlockFile(scope: !24, file: !2, discriminator: 1) +!30 = distinct !DISubprogram(name: "B", linkageName: "_ZN1BC1Ev", scope: !5, file: !2, line: 4, type: !31, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !1, declaration: !34, variables: !3) +!31 = !DISubroutineType(types: !32) +!32 = !{null, !33} +!33 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!34 = !DISubprogram(name: "B", scope: !5, type: !31, isLocal: false, isDefinition: false, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false) +!35 = !DILocalVariable(name: "this", arg: 1, scope: !30, type: !36, flags: DIFlagArtificial | DIFlagObjectPointer) +!36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, align: 64) +!37 = !DIExpression() +!38 = !DILocation(line: 0, scope: !30) +!39 = !DILocation(line: 4, column: 8, scope: !30) +!40 = distinct !DISubprogram(name: "~B", linkageName: "_ZN1BD1Ev", scope: !5, file: !2, line: 4, type: !31, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !1, declaration: !41, variables: !3) +!41 = !DISubprogram(name: "~B", scope: !5, type: !31, isLocal: false, isDefinition: false, containingType: !5, virtuality: DW_VIRTUALITY_virtual, virtualIndex: 0, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false) +!42 = !DILocalVariable(name: "this", arg: 1, scope: !40, type: !36, flags: DIFlagArtificial | DIFlagObjectPointer) +!43 = !DILocation(line: 0, scope: !40) +!44 = !DILocation(line: 4, column: 8, scope: !40) +!45 = distinct !DISubprogram(name: "B", linkageName: "_ZN1BC2Ev", scope: !5, file: !2, line: 4, type: !31, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !1, declaration: !34, variables: !3) +!46 = !DILocalVariable(name: "this", arg: 1, scope: !45, type: !36, flags: DIFlagArtificial | DIFlagObjectPointer) +!47 = !DILocation(line: 0, scope: !45) +!48 = !DILocation(line: 4, column: 8, scope: !45) +!49 = distinct !DISubprogram(name: "A", linkageName: "_ZN1AC2Ev", scope: !8, file: !2, line: 1, type: !17, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !1, declaration: !50, variables: !3) +!50 = !DISubprogram(name: "A", scope: !8, type: !17, isLocal: false, isDefinition: false, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false) +!51 = !DILocalVariable(name: "this", arg: 1, scope: !49, type: !52, flags: DIFlagArtificial | DIFlagObjectPointer) +!52 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64, align: 64) +!53 = !DILocation(line: 0, scope: !49) +!54 = !DILocation(line: 1, column: 8, scope: !49) +!55 = distinct !DISubprogram(name: "~B", linkageName: "_ZN1BD0Ev", scope: !5, file: !2, line: 4, type: !31, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !1, declaration: !41, variables: !3) +!56 = !DILocalVariable(name: "this", arg: 1, scope: !55, type: !36, flags: DIFlagArtificial | DIFlagObjectPointer) +!57 = !DILocation(line: 0, scope: !55) +!58 = !DILocation(line: 4, column: 8, scope: !55) +!59 = !DILocation(line: 4, column: 8, scope: !60) +!60 = !DILexicalBlockFile(scope: !55, file: !2, discriminator: 1) +!61 = !DILocation(line: 4, column: 8, scope: !62) +!62 = !DILexicalBlockFile(scope: !55, file: !2, discriminator: 2) +!63 = !DILocation(line: 4, column: 8, scope: !64) +!64 = !DILexicalBlockFile(scope: !55, file: !2, discriminator: 3) +!65 = distinct !DISubprogram(name: "~B", linkageName: "_ZN1BD2Ev", scope: !5, file: !2, line: 4, type: !31, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !1, declaration: !41, variables: !3) +!66 = !DILocalVariable(name: "this", arg: 1, scope: !65, type: !36, flags: DIFlagArtificial | DIFlagObjectPointer) +!67 = !DILocation(line: 0, scope: !65) +!68 = !DILocation(line: 4, column: 8, scope: !69) +!69 = distinct !DILexicalBlock(scope: !65, file: !2, line: 4, column: 8) +!70 = !DILocation(line: 4, column: 8, scope: !65) +!71 = distinct !DISubprogram(linkageName: "_GLOBAL__sub_I_t.cpp", scope: !2, file: !2, type: !72, isLocal: true, isDefinition: true, flags: DIFlagArtificial, isOptimized: false, unit: !1, variables: !3) +!72 = !DISubroutineType(types: !3) +!73 = !DILocation(line: 0, scope: !71) Index: tools/bugpoint/CrashDebugger.cpp =================================================================== --- tools/bugpoint/CrashDebugger.cpp +++ tools/bugpoint/CrashDebugger.cpp @@ -19,6 +19,7 @@ #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LegacyPassManager.h" @@ -54,6 +55,12 @@ cl::opt NoNamedMDRM("disable-namedmd-remove", cl::desc("Do not remove global named metadata"), cl::init(false)); +cl::opt NoStripDebugInfo("disable-strip-debuginfo", + cl::desc("Do not strip debug info metadata"), + cl::init(false)); +cl::opt NoStripDebugTypeInfo("disable-strip-debug-types", + cl::desc("Do not strip debug type info metadata"), + cl::init(false)); cl::opt VerboseErrors("verbose-errors", cl::desc("Print the output of crashing program"), cl::init(false)); @@ -1123,6 +1130,30 @@ if (Error E = ReduceInsts(BD, TestFn)) return E; + if (!NoStripDebugInfo) { + if (!BugpointIsInterrupted) { + outs() << "\n*** Attempting to strip the debug info: "; + Module *M = CloneModule(BD.getProgram()).release(); + StripDebugInfo(*M); + if (TestFn(BD, M)) + BD.setNewProgram(M); + else + delete M; + } + } + + if (!NoStripDebugTypeInfo) { + if (!BugpointIsInterrupted) { + outs() << "\n*** Attempting to strip the debug type info: "; + Module *M = CloneModule(BD.getProgram()).release(); + stripNonLineTableDebugInfo(*M); + if (TestFn(BD, M)) + BD.setNewProgram(M); + else + delete M; + } + } + if (!NoNamedMDRM) { if (!BugpointIsInterrupted) { // Try to reduce the amount of global metadata (particularly debug info),