Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -196,6 +196,10 @@ /// \brief Keep track of the metadata nodes that have been checked already. SmallPtrSet MDNodes; + /// Track whether we should have already already seen all DISubprogram + /// definitions and added them to the above set. + bool DoneVisitingSPDefinitions; + /// \brief Track unresolved string-based type references. SmallDenseMap UnresolvedTypeRefs; @@ -221,8 +225,8 @@ const Instruction *I); public: explicit Verifier(raw_ostream &OS) - : VerifierSupport(OS), Context(nullptr), LandingPadResultTy(nullptr), - SawFrameEscape(false) {} + : VerifierSupport(OS), Context(nullptr), DoneVisitingSPDefinitions(false), + LandingPadResultTy(nullptr), SawFrameEscape(false) {} bool verify(const Function &F) { M = F.getParent(); @@ -269,6 +273,10 @@ Context = &M.getContext(); Broken = false; + // Go through the CUs first to make sure we catch debug info that's used + // but not referenced from a toplevel CU + visitDICUs(); + // Scan through, checking all of the external function's linkage now... for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) { visitGlobalValue(*I); @@ -304,6 +312,9 @@ // Verify type referneces last. verifyTypeRefs(); + // Clean up + DoneVisitingSPDefinitions = false; + return !Broken; } @@ -317,6 +328,7 @@ const GlobalAlias &A, const Constant &C); void visitNamedMDNode(const NamedMDNode &NMD); void visitMDNode(const MDNode &MD); + void visitMDNodeOperands(const MDNode &MD); void visitMetadataAsValue(const MetadataAsValue &MD, Function *F); void visitValueAsMetadata(const ValueAsMetadata &MD, Function *F); void visitComdat(const Comdat &C); @@ -444,6 +456,7 @@ void verifySiblingFuncletUnwinds(); // Module-level debug info verification... + void visitDICUs(); void verifyTypeRefs(); template void verifyDIExpression(const DbgInfoIntrinsic &I, const MapTy &TypeRefs); @@ -662,10 +675,6 @@ for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i) { MDNode *MD = NMD.getOperand(i); - if (NMD.getName() == "llvm.dbg.cu") { - Assert(MD && isa(MD), "invalid compile unit", &NMD, MD); - } - if (!MD) continue; @@ -673,6 +682,36 @@ } } +void Verifier::visitDICUs() { + auto *CUs = M->getNamedMetadata("llvm.dbg.cu"); + if (!CUs) { + DoneVisitingSPDefinitions = true; + return; + } + // We want to collect all subprogram's referenced from any compile unit and + // visit them now, such that we can detect any subprogram definition that is + // referenced somewhere else but not declared here. + std::set SPs; + for (MDNode *Op : CUs->operands()) { + Assert(Op && isa(Op), "invalid compile unit", CUs, Op); + auto *CU = cast(Op); + for (auto *SP : CU->getSubprograms()) { + visitDISubprogram(*SP); + MDNodes.insert(SP); + SPs.insert(SP); + } + } + + // From now on it's an error to reach a DISubprogram that's a definition, + // because all such should have been found above and inserted into MDNodes + DoneVisitingSPDefinitions = true; + + // Make sure to visit the DISubprogram's operands, otherwise, we'd never get + // to them. + for (auto *SP : SPs) + visitMDNodeOperands(*SP); +} + void Verifier::visitMDNode(const MDNode &MD) { // Only visit each node once. Metadata can be mutually recursive, so this // avoids infinite recursion here, as well as being an optimization. @@ -691,6 +730,14 @@ #include "llvm/IR/Metadata.def" } + visitMDNodeOperands(MD); + + // Check these last, so we diagnose problems in operands first. + Assert(!MD.isTemporary(), "Expected no forward declarations!", &MD); + Assert(MD.isResolved(), "All nodes should be resolved!", &MD); +} + +void Verifier::visitMDNodeOperands(const MDNode &MD) { for (unsigned i = 0, e = MD.getNumOperands(); i != e; ++i) { Metadata *Op = MD.getOperand(i); if (!Op) @@ -706,10 +753,6 @@ continue; } } - - // Check these last, so we diagnose problems in operands first. - Assert(!MD.isTemporary(), "Expected no forward declarations!", &MD); - Assert(MD.isResolved(), "All nodes should be resolved!", &MD); } void Verifier::visitValueAsMetadata(const ValueAsMetadata &MD, Function *F) { @@ -1001,8 +1044,12 @@ Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", &N); - if (N.isDefinition()) + if (N.isDefinition()) { Assert(N.isDistinct(), "subprogram definitions must be distinct", &N); + Assert(!DoneVisitingSPDefinitions, "All subprogram definitions must be " + "referenced from llvm.dbg.cu metadata", + &N); + } } void Verifier::visitDILexicalBlockBase(const DILexicalBlockBase &N) { Index: test/Assembler/diimportedentity.ll =================================================================== --- test/Assembler/diimportedentity.ll +++ test/Assembler/diimportedentity.ll @@ -6,7 +6,7 @@ ; CHECK: !0 = distinct !DISubprogram({{.*}}) ; CHECK-NEXT: !1 = !DICompositeType({{.*}}) -!0 = distinct !DISubprogram(name: "foo") +!0 = distinct !DISubprogram(name: "foo", isDefinition: false) !1 = !DICompositeType(tag: DW_TAG_structure_type, name: "Class", size: 32, align: 32) ; CHECK-NEXT: !2 = !DIImportedEntity(tag: DW_TAG_imported_module, name: "foo", scope: !0, entity: !1, line: 7) @@ -17,4 +17,3 @@ !3 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !0) !4 = !DIImportedEntity(tag: DW_TAG_imported_module, name: "", scope: !0, entity: null, line: 0) - Index: test/Assembler/dilexicalblock.ll =================================================================== --- test/Assembler/dilexicalblock.ll +++ test/Assembler/dilexicalblock.ll @@ -5,7 +5,7 @@ !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9} !0 = distinct !{} -!1 = distinct !DISubprogram(name: "foo", scope: !2) +!1 = distinct !DISubprogram(name: "foo", scope: !2, isDefinition: false) !2 = !DIFile(filename: "path/to/file", directory: "/path/to/dir") ; CHECK: !3 = !DILexicalBlock(scope: !1, file: !2, line: 7, column: 35) Index: test/Assembler/dilocalvariable-arg-large.ll =================================================================== --- test/Assembler/dilocalvariable-arg-large.ll +++ test/Assembler/dilocalvariable-arg-large.ll @@ -4,7 +4,7 @@ ; CHECK: !named = !{!0, !1} !named = !{!0, !1} -!0 = distinct !DISubprogram() +!0 = distinct !DISubprogram(isDefinition: false) ; CHECK: !1 = !DILocalVariable(name: "foo", arg: 65535, scope: !0) !1 = !DILocalVariable(name: "foo", arg: 65535, scope: !0) Index: test/Assembler/dilocalvariable.ll =================================================================== --- test/Assembler/dilocalvariable.ll +++ test/Assembler/dilocalvariable.ll @@ -6,7 +6,7 @@ ; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8} !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8} -!0 = distinct !DISubprogram() +!0 = distinct !DISubprogram(isDefinition: false) !1 = distinct !{} !2 = !DIFile(filename: "path/to/file", directory: "/path/to/dir") !3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) Index: test/Assembler/dilocation.ll =================================================================== --- test/Assembler/dilocation.ll +++ test/Assembler/dilocation.ll @@ -5,7 +5,7 @@ !named = !{!0, !1, !2, !3, !4, !5, !6, !7} ; CHECK: !0 = distinct !DISubprogram( -!0 = distinct !DISubprogram() +!0 = distinct !DISubprogram(isDefinition: false) ; CHECK-NEXT: !1 = !DILocation(line: 3, column: 7, scope: !0) !1 = !DILocation(line: 3, column: 7, scope: !0) Index: test/Assembler/disubprogram.ll =================================================================== --- test/Assembler/disubprogram.ll +++ test/Assembler/disubprogram.ll @@ -32,4 +32,7 @@ templateParams: !5, declaration: !8, variables: !6) !10 = !{i32 1, !"Debug Info Version", i32 3} +!11 = distinct !DICompileUnit(subprograms: !12, language: DW_LANG_C, file: !2) +!12 = !{!7} !llvm.module.flags = !{!10} +!llvm.dbg.cu = !{!11} Index: test/Assembler/metadata.ll =================================================================== --- test/Assembler/metadata.ll +++ test/Assembler/metadata.ll @@ -30,7 +30,7 @@ } !0 = !DILocation(line: 662302, column: 26, scope: !1) -!1 = distinct !DISubprogram(name: "foo") +!1 = distinct !DISubprogram(name: "foo", isDefinition: false) !2 = distinct !{} !3 = distinct !{} !4 = distinct !{} Index: test/Bitcode/DILocalVariable-explicit-tags.ll =================================================================== --- test/Bitcode/DILocalVariable-explicit-tags.ll +++ test/Bitcode/DILocalVariable-explicit-tags.ll @@ -10,7 +10,7 @@ !named = !{!0} -!0 = distinct !DISubprogram(name: "foo", variables: !1) +!0 = distinct !DISubprogram(name: "foo", variables: !1, isDefinition: false) !1 = !{!2, !3} !2 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "param", arg: 1, scope: !0) !3 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "auto", scope: !0) Index: test/DebugInfo/Generic/2010-07-19-Crash.ll =================================================================== --- test/DebugInfo/Generic/2010-07-19-Crash.ll +++ test/DebugInfo/Generic/2010-07-19-Crash.ll @@ -25,6 +25,6 @@ !10 = distinct !DILexicalBlock(line: 3, column: 11, file: !12, scope: !0) !11 = !DISubprogram(name: "foo", linkageName: "foo", line: 7, isLocal: true, isDefinition: false, virtualIndex: 6, isOptimized: true, file: !12, scope: !1, type: !3) !12 = !DIFile(filename: "one.c", directory: "/private/tmp") -!13 = !{!0} +!13 = !{!0, !6} !14 = !{} !15 = !{i32 1, !"Debug Info Version", i32 3} Index: test/Linker/Inputs/mdlocation.ll =================================================================== --- test/Linker/Inputs/mdlocation.ll +++ test/Linker/Inputs/mdlocation.ll @@ -1,6 +1,6 @@ !named = !{!0, !1, !2, !3, !4, !5} -!0 = distinct !DISubprogram() ; Use this as a scope. +!0 = distinct !DISubprogram(isDefinition: false) ; Use this as a scope. !1 = !DILocation(line: 3, column: 7, scope: !0) !2 = !DILocation(line: 3, column: 7, scope: !0, inlinedAt: !1) !3 = !DILocation(line: 3, column: 7, scope: !0, inlinedAt: !2) Index: test/Linker/mdlocation.ll =================================================================== --- test/Linker/mdlocation.ll +++ test/Linker/mdlocation.ll @@ -17,7 +17,7 @@ ; CHECK-NEXT: !9 = !DILocation(line: 3, column: 7, scope: !6, inlinedAt: !8) ; CHECK-NEXT: !10 = distinct !DILocation(line: 3, column: 7, scope: !6) ; CHECK-NEXT: !11 = distinct !DILocation(line: 3, column: 7, scope: !6, inlinedAt: !10) -!0 = distinct !DISubprogram() ; Use this as a scope. +!0 = distinct !DISubprogram(isDefinition: false) ; Use this as a scope. !1 = !DILocation(line: 3, column: 7, scope: !0) !2 = !DILocation(line: 3, column: 7, scope: !0, inlinedAt: !1) !3 = !DILocation(line: 3, column: 7, scope: !0, inlinedAt: !2) Index: test/Transforms/LICM/debug-value.ll =================================================================== --- test/Transforms/LICM/debug-value.ll +++ test/Transforms/LICM/debug-value.ll @@ -34,7 +34,7 @@ declare void @llvm.dbg.value(metadata, i64, metadata, metadata) nounwind readnone !llvm.module.flags = !{!26} -!llvm.dbg.sp = !{!0, !6, !9, !10} +!llvm.dbg.cu = !{!27} !0 = distinct !DISubprogram(name: "idamax", line: 112, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !25, scope: !1, type: !3) !1 = !DIFile(filename: "/Volumes/Lalgate/work/llvm/projects/llvm-test/SingleSource/Benchmarks/CoyoteBench/lpbench.c", directory: "/private/tmp") @@ -63,3 +63,5 @@ !24 = !DILocation(line: 313, column: 1, scope: !14) !25 = !DIFile(filename: "/Volumes/Lalgate/work/llvm/projects/llvm-test/SingleSource/Benchmarks/CoyoteBench/lpbench.c", directory: "/private/tmp") !26 = !{i32 1, !"Debug Info Version", i32 3} +!27 = distinct !DICompileUnit(subprograms: !28, language: DW_LANG_C, file: !1) +!28 = !{!0, !6, !9, !10}