Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -455,8 +455,14 @@ // within the same scope, e.g. { namespace A = base; namespace B = A; } std::stable_sort(ScopesWithImportedEntities.begin(), ScopesWithImportedEntities.end(), less_first()); - for (auto *GV : CUNode->getGlobalVariables()) - CU.getOrCreateGlobalVariableDIE(GV); + for (auto *GV : CUNode->getGlobalVariables()) { + auto GVContext = GV->getScope(); + + // Skip, variables defined in a lexical block (e.g. static variables). We + // will revisit these variables after all lexical scope DIEs are created. + if (!GVContext || !DILexicalBlock::classof(GVContext)) + CU.getOrCreateGlobalVariableDIE(GV); + } for (auto *SP : CUNode->getSubprograms()) SPMap.insert(std::make_pair(SP, &CU)); for (auto *Ty : CUNode->getEnumTypes()) { @@ -529,6 +535,23 @@ void DwarfDebug::finalizeModuleInfo() { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + // Now, after we generated all lexical scope DIEs, it is time to + // run over variables defined in a lexical scope and collect them. + const Module *M = MMI->getModule(); + if (NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu")) { + for (MDNode *N : CU_Nodes->operands()) { + auto *TheCU = cast(N); + DwarfCompileUnit *SPCU = + static_cast(CUMap.lookup(TheCU)); + for (auto *GV : TheCU->getGlobalVariables()) { + auto GVContext = GV->getScope(); + + if (GVContext && DILexicalBlock::classof(GVContext)) + SPCU->getOrCreateGlobalVariableDIE(GV); + } + } + } + finishSubprogramDefinitions(); finishVariableDefinitions(); Index: test/DebugInfo/LB-class.ll =================================================================== --- test/DebugInfo/LB-class.ll +++ test/DebugInfo/LB-class.ll @@ -0,0 +1,158 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=obj -O0 < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s + +;; This test was generated by running following command: +;; clang -cc1 -O0 -g -emit-llvm class.cpp +;; Where class.cpp: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;int foo(int x) { +;; if(x) { +;; class X { +;; public: +;; char z; +;; X(int y) : z(y) {} +;; }; +;; { +;; X a(x); +;; return a.z; +;; } +;; } +;; return 0; +;;} +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +; CHECK: DW_TAG_subprogram +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name {{.*}} "foo" +; CHECK-NOT: NULL +; CHECK: DW_TAG_lexical_block +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_lexical_block +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_variable +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_name {{.*}} "a" +; CHECK: NULL +; CHECK-NOT: {{DW_|NULL}} +; CHECK: DW_TAG_class +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_name {{.*}} "X" + +%class.X = type { i8 } + +; Function Attrs: nounwind +define i32 @_Z3fooi(i32 %x) #0 { +entry: + %retval = alloca i32, align 4 + %x.addr = alloca i32, align 4 + %a = alloca %class.X, align 1 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !23, metadata !24), !dbg !25 + %0 = load i32, i32* %x.addr, align 4, !dbg !26 + %tobool = icmp ne i32 %0, 0, !dbg !26 + br i1 %tobool, label %if.then, label %if.end, !dbg !27 + +if.then: ; preds = %entry + call void @llvm.dbg.declare(metadata %class.X* %a, metadata !28, metadata !24), !dbg !30 + %1 = load i32, i32* %x.addr, align 4, !dbg !30 + call void @_ZZ3fooiEN1XC1Ei(%class.X* %a, i32 %1), !dbg !30 + %z = getelementptr inbounds %class.X, %class.X* %a, i32 0, i32 0, !dbg !31 + %2 = load i8, i8* %z, align 1, !dbg !31 + %conv = sext i8 %2 to i32, !dbg !31 + store i32 %conv, i32* %retval, !dbg !31 + br label %return, !dbg !31 + +if.end: ; preds = %entry + store i32 0, i32* %retval, !dbg !32 + br label %return, !dbg !32 + +return: ; preds = %if.end, %if.then + %3 = load i32, i32* %retval, !dbg !33 + ret i32 %3, !dbg !33 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind +define internal void @_ZZ3fooiEN1XC1Ei(%class.X* %this, i32 %y) unnamed_addr #0 align 2 { +entry: + %this.addr = alloca %class.X*, align 8 + %y.addr = alloca i32, align 4 + store %class.X* %this, %class.X** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.X** %this.addr, metadata !34, metadata !24), !dbg !36 + store i32 %y, i32* %y.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %y.addr, metadata !37, metadata !24), !dbg !38 + %this1 = load %class.X*, %class.X** %this.addr + %0 = load i32, i32* %y.addr, align 4, !dbg !38 + call void @_ZZ3fooiEN1XC2Ei(%class.X* %this1, i32 %0), !dbg !38 + ret void, !dbg !38 +} + +; Function Attrs: nounwind +define internal void @_ZZ3fooiEN1XC2Ei(%class.X* %this, i32 %y) unnamed_addr #0 align 2 { +entry: + %this.addr = alloca %class.X*, align 8 + %y.addr = alloca i32, align 4 + store %class.X* %this, %class.X** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.X** %this.addr, metadata !39, metadata !24), !dbg !40 + store i32 %y, i32* %y.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %y.addr, metadata !41, metadata !24), !dbg !42 + %this1 = load %class.X*, %class.X** %this.addr + %z = getelementptr inbounds %class.X, %class.X* %this1, i32 0, i32 0, !dbg !42 + %0 = load i32, i32* %y.addr, align 4, !dbg !42 + %conv = trunc i32 %0 to i8, !dbg !42 + store i8 %conv, i8* %z, align 1, !dbg !42 + ret void, !dbg !42 +} + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!20, !21} +!llvm.ident = !{!22} + +!0 = !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.7.0 (trunk 236102)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2) +!1 = !DIFile(filename: "class.cpp", directory: "/") +!2 = !{} +!3 = !{!4, !8, !19} +!4 = !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, function: i32 (i32)* @_Z3fooi, variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7} +!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !DISubprogram(name: "X", linkageName: "_ZZ3fooiEN1XC1Ei", scope: !9, file: !1, line: 6, type: !16, isLocal: true, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, function: void (%class.X*, i32)* @_ZZ3fooiEN1XC1Ei, declaration: !15, variables: !2) +!9 = !DICompositeType(tag: DW_TAG_class_type, name: "X", scope: !10, file: !1, line: 3, size: 8, align: 8, elements: !12) +!10 = distinct !DILexicalBlock(scope: !11, file: !1, line: 2) +!11 = distinct !DILexicalBlock(scope: !4, file: !1, line: 2) +!12 = !{!13, !15} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !9, file: !1, line: 5, baseType: !14, size: 8, align: 8, flags: DIFlagPublic) +!14 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!15 = !DISubprogram(name: "X", scope: !9, file: !1, line: 6, type: !16, isLocal: false, isDefinition: false, scopeLine: 6, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: false) +!16 = !DISubroutineType(types: !17) +!17 = !{null, !18, !7} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!19 = !DISubprogram(name: "X", linkageName: "_ZZ3fooiEN1XC2Ei", scope: !9, file: !1, line: 6, type: !16, isLocal: true, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, function: void (%class.X*, i32)* @_ZZ3fooiEN1XC2Ei, declaration: !15, variables: !2) +!20 = !{i32 2, !"Dwarf Version", i32 4} +!21 = !{i32 2, !"Debug Info Version", i32 3} +!22 = !{!"clang version 3.7.0 (trunk 236102)"} +!23 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "x", arg: 1, scope: !4, file: !1, line: 1, type: !7) +!24 = !DIExpression() +!25 = !DILocation(line: 1, scope: !4) +!26 = !DILocation(line: 2, scope: !11) +!27 = !DILocation(line: 2, scope: !4) +!28 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "a", scope: !29, file: !1, line: 9, type: !9) +!29 = distinct !DILexicalBlock(scope: !10, file: !1, line: 8) +!30 = !DILocation(line: 9, scope: !29) +!31 = !DILocation(line: 10, scope: !29) +!32 = !DILocation(line: 13, scope: !4) +!33 = !DILocation(line: 14, scope: !4) +!34 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !8, type: !35, flags: DIFlagArtificial | DIFlagObjectPointer) +!35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64, align: 64) +!36 = !DILocation(line: 0, scope: !8) +!37 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "y", arg: 2, scope: !8, file: !1, line: 6, type: !7) +!38 = !DILocation(line: 6, scope: !8) +!39 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !19, type: !35, flags: DIFlagArtificial | DIFlagObjectPointer) +!40 = !DILocation(line: 0, scope: !19) +!41 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "y", arg: 2, scope: !19, file: !1, line: 6, type: !7) +!42 = !DILocation(line: 6, scope: !19) Index: test/DebugInfo/LB-static.ll =================================================================== --- test/DebugInfo/LB-static.ll +++ test/DebugInfo/LB-static.ll @@ -0,0 +1,106 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=obj -O0 < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s + +;; This test was generated by running following command: +;; clang -cc1 -O0 -g -emit-llvm static.cpp +;; Where static.cpp: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;int foo(int x) { +;; if(x) { +;; static int bar = 0; +;; { +;; int a = bar++; +;; return a; +;; } +;; } +;; return 0; +;;} +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +; CHECK: DW_TAG_subprogram +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name {{.*}} "foo" +; CHECK-NOT: NULL +; CHECK: DW_TAG_lexical_block +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_lexical_block +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_variable +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_name {{.*}} "a" +; CHECK: NULL +; CHECK-NOT: {{DW_|NULL}} +; CHECK: DW_TAG_variable +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_name {{.*}} "bar" + + +@_ZZ3fooiE3bar = internal global i32 0, align 4 + +; Function Attrs: nounwind +define i32 @_Z3fooi(i32 %x) #0 { +entry: + %retval = alloca i32, align 4 + %x.addr = alloca i32, align 4 + %a = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !15, metadata !16), !dbg !17 + %0 = load i32, i32* %x.addr, align 4, !dbg !18 + %tobool = icmp ne i32 %0, 0, !dbg !18 + br i1 %tobool, label %if.then, label %if.end, !dbg !19 + +if.then: ; preds = %entry + call void @llvm.dbg.declare(metadata i32* %a, metadata !20, metadata !16), !dbg !22 + %1 = load i32, i32* @_ZZ3fooiE3bar, align 4, !dbg !22 + %inc = add nsw i32 %1, 1, !dbg !22 + store i32 %inc, i32* @_ZZ3fooiE3bar, align 4, !dbg !22 + store i32 %1, i32* %a, align 4, !dbg !22 + %2 = load i32, i32* %a, align 4, !dbg !23 + store i32 %2, i32* %retval, !dbg !23 + br label %return, !dbg !23 + +if.end: ; preds = %entry + store i32 0, i32* %retval, !dbg !24 + br label %return, !dbg !24 + +return: ; preds = %if.end, %if.then + %3 = load i32, i32* %retval, !dbg !25 + ret i32 %3, !dbg !25 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!12, !13} +!llvm.ident = !{!14} + +!0 = !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.7.0 (trunk 236102)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !8, imports: !2) +!1 = !DIFile(filename: "static.cpp", directory: "/") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, function: i32 (i32)* @_Z3fooi, variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7} +!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !{!9} +!9 = !DIGlobalVariable(name: "bar", scope: !10, file: !1, line: 3, type: !7, isLocal: true, isDefinition: true, variable: i32* @_ZZ3fooiE3bar) +!10 = distinct !DILexicalBlock(scope: !11, file: !1, line: 2) +!11 = distinct !DILexicalBlock(scope: !4, file: !1, line: 2) +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{!"clang version 3.7.0 (trunk 236102)"} +!15 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "x", arg: 1, scope: !4, file: !1, line: 1, type: !7) +!16 = !DIExpression() +!17 = !DILocation(line: 1, scope: !4) +!18 = !DILocation(line: 2, scope: !11) +!19 = !DILocation(line: 2, scope: !4) +!20 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "a", scope: !21, file: !1, line: 5, type: !7) +!21 = distinct !DILexicalBlock(scope: !10, file: !1, line: 4) +!22 = !DILocation(line: 5, scope: !21) +!23 = !DILocation(line: 6, scope: !21) +!24 = !DILocation(line: 9, scope: !4) +!25 = !DILocation(line: 10, scope: !4) Index: test/DebugInfo/LB-typedef.ll =================================================================== --- test/DebugInfo/LB-typedef.ll +++ test/DebugInfo/LB-typedef.ll @@ -0,0 +1,104 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=obj -O0 < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s + +;; This test was generated by running following command: +;; clang -cc1 -O0 -g -emit-llvm typedef.cpp +;; Where typedef.cpp +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;int foo(int x) { +;; if(x) { +;; typedef char X; +;; { +;; X a = x; +;; return a; +;; } +;; } +;; return 0; +;;} +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +; CHECK: DW_TAG_subprogram +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name {{.*}} "foo" +; CHECK-NOT: NULL +; CHECK: DW_TAG_lexical_block +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_lexical_block +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_TAG_variable +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_name {{.*}} "a" +; CHECK: NULL +; CHECK-NOT: {{DW_|NULL}} +; CHECK: DW_TAG_typedef +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_name {{.*}} "X" + + +; Function Attrs: nounwind +define i32 @_Z3fooi(i32 %x) #0 { +entry: + %retval = alloca i32, align 4 + %x.addr = alloca i32, align 4 + %a = alloca i8, align 1 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !11, metadata !12), !dbg !13 + %0 = load i32, i32* %x.addr, align 4, !dbg !14 + %tobool = icmp ne i32 %0, 0, !dbg !14 + br i1 %tobool, label %if.then, label %if.end, !dbg !16 + +if.then: ; preds = %entry + call void @llvm.dbg.declare(metadata i8* %a, metadata !17, metadata !12), !dbg !22 + %1 = load i32, i32* %x.addr, align 4, !dbg !22 + %conv = trunc i32 %1 to i8, !dbg !22 + store i8 %conv, i8* %a, align 1, !dbg !22 + %2 = load i8, i8* %a, align 1, !dbg !23 + %conv1 = sext i8 %2 to i32, !dbg !23 + store i32 %conv1, i32* %retval, !dbg !23 + br label %return, !dbg !23 + +if.end: ; preds = %entry + store i32 0, i32* %retval, !dbg !24 + br label %return, !dbg !24 + +return: ; preds = %if.end, %if.then + %3 = load i32, i32* %retval, !dbg !25 + ret i32 %3, !dbg !25 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9} +!llvm.ident = !{!10} + +!0 = !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.7.0 (trunk 236102)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2) +!1 = !DIFile(filename: "typedef.cpp", directory: "/") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, function: i32 (i32)* @_Z3fooi, variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7} +!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{!"clang version 3.7.0 (trunk 236102)"} +!11 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "x", arg: 1, scope: !4, file: !1, line: 1, type: !7) +!12 = !DIExpression() +!13 = !DILocation(line: 1, scope: !4) +!14 = !DILocation(line: 2, scope: !15) +!15 = distinct !DILexicalBlock(scope: !4, file: !1, line: 2) +!16 = !DILocation(line: 2, scope: !4) +!17 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "a", scope: !18, file: !1, line: 5, type: !20) +!18 = distinct !DILexicalBlock(scope: !19, file: !1, line: 4) +!19 = distinct !DILexicalBlock(scope: !15, file: !1, line: 2) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "X", scope: !19, file: !1, line: 3, baseType: !21) +!21 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!22 = !DILocation(line: 5, scope: !18) +!23 = !DILocation(line: 6, scope: !18) +!24 = !DILocation(line: 9, scope: !4) +!25 = !DILocation(line: 10, scope: !4)