[llvm] e3d8ebe - [llvm-dwarfdump][Statistics] Handle LTO cases with cross CU referencing

Djordje Todorovic via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 24 05:04:15 PST 2021


Author: Djordje Todorovic
Date: 2021-11-24T13:50:47+01:00
New Revision: e3d8ebe158562fb945d473319f4f5c2de25a9a02

URL: https://github.com/llvm/llvm-project/commit/e3d8ebe158562fb945d473319f4f5c2de25a9a02
DIFF: https://github.com/llvm/llvm-project/commit/e3d8ebe158562fb945d473319f4f5c2de25a9a02.diff

LOG: [llvm-dwarfdump][Statistics] Handle LTO cases with cross CU referencing

With link-time optimizations enabled, resulting DWARF mayend up containing
cross CU references (through the DW_AT_abstract_origin attribute).
Consider the following example:

// sum.c
__attribute__((always_inline)) int sum(int a, int b)
{
     return a + b;
}
// main.c
extern int sum(int, int);
int main()
{
     int a = 5, b = 10, c = sum(a, b);
     return 0;
}

Compiled as follows:

$ clang -g -flto -fuse-ld=lld main.c sum.c -o main

Results in the following DWARF:

-- sum.c CU: abstract instance tree
...
0x000000b0:   DW_TAG_subprogram
                DW_AT_name	("sum")
                DW_AT_decl_file	("sum.c")
                DW_AT_decl_line	(1)
                DW_AT_prototyped	(true)
                DW_AT_type	(0x000000d3 "int")
                DW_AT_external	(true)
                DW_AT_inline	(DW_INL_inlined)

0x000000bc:     DW_TAG_formal_parameter
                  DW_AT_name	("a")
                  DW_AT_decl_file	("sum.c")
                  DW_AT_decl_line	(1)
                  DW_AT_type	(0x000000d3 "int")

0x000000c7:     DW_TAG_formal_parameter
                  DW_AT_name	("b")
                  DW_AT_decl_file	("sum.c")
                  DW_AT_decl_line	(1)
                  DW_AT_type	(0x000000d3 "int")
...
-- main.c CU: concrete inlined instance tree
...
0x0000006d:     DW_TAG_inlined_subroutine
                  DW_AT_abstract_origin	(0x00000000000000b0 "sum")
                  DW_AT_low_pc	(0x00000000002016ef)
                  DW_AT_high_pc	(0x00000000002016f1)
                  DW_AT_call_file	("main.c")
                  DW_AT_call_line	(5)
                  DW_AT_call_column	(0x19)

0x00000081:       DW_TAG_formal_parameter
                    DW_AT_location	(DW_OP_reg0 RAX)
                    DW_AT_abstract_origin	(0x00000000000000bc "a")

0x00000088:       DW_TAG_formal_parameter
                    DW_AT_location	(DW_OP_reg2 RCX)
                    DW_AT_abstract_origin	(0x00000000000000c7 "b")
...

Note that each entry within the concrete inlined instance tree in
the main.c CU has a DW_AT_abstract_origin attribute which
refers to a corresponding entry within the abstract instance
tree in the sum.c CU.
llvm-dwarfdump --statistics did not properly report
DW_TAG_formal_parameters/DW_TAG_variables from concrete inlined
instance trees which had 0% location coverage and which
referred to a different CU, mainly because information about abstract
instance trees and their parameters/variables was stored
locally - just for the currently processed CU,
rather than globally - for all CUs.
In particular, if the concrete inlined instance tree from
the example above was to look like this
(i.e. parameter b has 0% location coverage, hence why it's missing):

0x0000006d:     DW_TAG_inlined_subroutine
                  DW_AT_abstract_origin	(0x00000000000000b0 "sum")
                  DW_AT_low_pc	(0x00000000002016ef)
                  DW_AT_high_pc	(0x00000000002016f1)
                  DW_AT_call_file	("main.c")
                  DW_AT_call_line	(5)
                  DW_AT_call_column	(0x19)

0x00000081:       DW_TAG_formal_parameter
                    DW_AT_location	(DW_OP_reg0 RAX)
                    DW_AT_abstract_origin	(0x00000000000000bc "a")

llvm-dwarfdump --statistics would have not reported b as such.

Patch by Dimitrije Milosevic.

Differential revision: https://reviews.llvm.org/D113465

Added: 
    llvm/test/tools/llvm-dwarfdump/X86/LTO_CCU_zero_loc_cov.ll

Modified: 
    llvm/tools/llvm-dwarfdump/Statistics.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/LTO_CCU_zero_loc_cov.ll b/llvm/test/tools/llvm-dwarfdump/X86/LTO_CCU_zero_loc_cov.ll
new file mode 100644
index 0000000000000..64e788d58bcc5
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/LTO_CCU_zero_loc_cov.ll
@@ -0,0 +1,124 @@
+;; llc will generate additional 'empty' DW_TAG_subroutine in sum.c's CU.
+;; It will not be considered by the statistics.
+; RUN: llc %s -o - -filetype=obj \
+; RUN:   | llvm-dwarfdump -statistics - | FileCheck %s
+
+;; Instructions to regenerate IR:
+;; clang -g -flto -emit-llvm -S -o main.ll -c main.c
+;; clang -g -flto -emit-llvm -S -o sum.ll -c sum.c
+;; llvm-link -S -o linked.ll main.ll sum.ll
+;; opt -O1 linked.ll -S -o merged.ll
+;; Hard coded a call to llvm.dbg.value intrinsic, replacing %10 argument with undef, in order to have 0% location coverage for a CCU referencing DIE.
+
+;; Source files:
+;;main.c:
+;;extern int sum(int a, int b);
+;;
+;;int main()
+;;{
+;;	int a = 10, b = 5;
+;;	int c = sum(a,b);
+;; int d = c + sum(c,2);
+;;	return 0;
+;;}
+;;sum.c:
+;;__attribute__((always_inline)) int sum(int a, int b)
+;;{
+;;	int result = a + b;
+;;	return result;
+;;}
+
+; CHECK:      "#source variables with location": 10,
+; CHECK:      "#variables with 0% of parent scope covered by DW_AT_location": 1,
+; CHECK:      "#params with 0% of parent scope covered by DW_AT_location": 1,
+
+; ModuleID = 'linked.ll'
+source_filename = "llvm-link"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @main() local_unnamed_addr #0 !dbg !11 {
+  %1 = alloca i32, align 4
+  %2 = alloca i32, align 4
+  %3 = alloca i32, align 4
+  %4 = alloca i32, align 4
+  %5 = alloca i32, align 4
+  store i32 0, i32* %1, align 4
+  call void @llvm.dbg.declare(metadata i32* %2, metadata !15, metadata !DIExpression()), !dbg !16
+  store i32 10, i32* %2, align 4, !dbg !16
+  call void @llvm.dbg.declare(metadata i32* %3, metadata !17, metadata !DIExpression()), !dbg !16
+  store i32 5, i32* %3, align 4, !dbg !16
+  call void @llvm.dbg.declare(metadata i32* %4, metadata !19, metadata !DIExpression()), !dbg !16
+  %6 = load i32, i32* %2, align 4, !dbg !16
+  %7 = load i32, i32* %3, align 4, !dbg !16
+  call void @llvm.dbg.value(metadata i32 %6, metadata !23, metadata !DIExpression()), !dbg !27
+  call void @llvm.dbg.value(metadata i32 %7, metadata !29, metadata !DIExpression()), !dbg !27
+  %8 = add nsw i32 %7, %6, !dbg !27
+  call void @llvm.dbg.value(metadata i32 %8, metadata !31, metadata !DIExpression()), !dbg !27
+  store i32 %8, i32* %4, align 4, !dbg !16
+  call void @llvm.dbg.declare(metadata i32* %5, metadata !32, metadata !DIExpression()), !dbg !16
+  %9 = load i32, i32* %4, align 4, !dbg !16
+  %10 = load i32, i32* %4, align 4, !dbg !16
+  call void @llvm.dbg.value(metadata i32 undef, metadata !23, metadata !DIExpression()), !dbg !36 ;; Hard coded line: There was %10 instead of undef.
+  call void @llvm.dbg.value(metadata i32 2, metadata !29, metadata !DIExpression()), !dbg !36
+  %11 = add nsw i32 2, %10, !dbg !36
+  call void @llvm.dbg.value(metadata i32 %11, metadata !31, metadata !DIExpression()), !dbg !36
+  %12 = add nsw i32 %9, %11, !dbg !16
+  store i32 %12, i32* %5, align 4, !dbg !16
+  ret i32 0, !dbg !16
+}
+
+; Function Attrs: mustprogress nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+; Function Attrs: alwaysinline mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn
+define dso_local i32 @sum(i32 %0, i32 %1) local_unnamed_addr #2 !dbg !24 {
+  call void @llvm.dbg.value(metadata i32 %0, metadata !23, metadata !DIExpression()), !dbg !41
+  call void @llvm.dbg.value(metadata i32 %1, metadata !29, metadata !DIExpression()), !dbg !41
+  %3 = add nsw i32 %1, %0, !dbg !41
+  call void @llvm.dbg.value(metadata i32 %3, metadata !31, metadata !DIExpression()), !dbg !41
+  ret i32 %3, !dbg !41
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+attributes #0 = { noinline nounwind optnone uwtable }
+attributes #2 = { alwaysinline mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn }
+
+!llvm.dbg.cu = !{!0, !3}
+!llvm.ident = !{!5, !5}
+!llvm.module.flags = !{!6, !7, !8, !9, !10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "main.c", directory: "/dir")
+!2 = !{}
+!3 = distinct !DICompileUnit(language: DW_LANG_C99, file: !4, producer: "clang version 14.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!4 = !DIFile(filename: "sum.c", directory: "/dir")
+!5 = !{!"clang version 14.0.0"}
+!6 = !{i32 7, !"Dwarf Version", i32 4}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 4}
+!9 = !{i32 7, !"uwtable", i32 1}
+!10 = !{i32 7, !"frame-pointer", i32 2}
+!11 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !12, scopeLine: 4, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DILocalVariable(name: "a", scope: !11, file: !1, line: 5, type: !14)
+!16 = !DILocation(line: 5, column: 6, scope: !11)
+!17 = !DILocalVariable(name: "b", scope: !11, file: !1, line: 5, type: !14)
+!19 = !DILocalVariable(name: "c", scope: !11, file: !1, line: 6, type: !14)
+!23 = !DILocalVariable(name: "a", arg: 1, scope: !24, file: !4, line: 1, type: !14)
+!24 = distinct !DISubprogram(name: "sum", scope: !4, file: !4, line: 1, type: !25, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !3, retainedNodes: !2)
+!25 = !DISubroutineType(types: !26)
+!26 = !{!14, !14, !14}
+!27 = !DILocation(line: 0, scope: !24, inlinedAt: !28)
+!28 = distinct !DILocation(line: 6, column: 10, scope: !11)
+!29 = !DILocalVariable(name: "b", arg: 2, scope: !24, file: !4, line: 1, type: !14)
+!31 = !DILocalVariable(name: "result", scope: !24, file: !4, line: 3, type: !14)
+!32 = !DILocalVariable(name: "d", scope: !11, file: !1, line: 7, type: !14)
+!36 = !DILocation(line: 0, scope: !24, inlinedAt: !37)
+!37 = distinct !DILocation(line: 7, column: 14, scope: !11)
+!41 = !DILocation(line: 0, scope: !24)

diff  --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp
index b237e014038d4..5c08e43b4b093 100644
--- a/llvm/tools/llvm-dwarfdump/Statistics.cpp
+++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp
@@ -60,6 +60,19 @@ struct SaturatingUINT64 {
   }
 };
 
+/// Utility struct to store the full location of a DIE - its CU and offset.
+struct DIELocation {
+  DWARFUnit *DwUnit;
+  uint64_t DIEOffset;
+  DIELocation(DWARFUnit *_DwUnit, uint64_t _DIEOffset)
+      : DwUnit(_DwUnit), DIEOffset(_DIEOffset) {}
+};
+/// This represents DWARF locations of CrossCU referencing DIEs.
+using CrossCUReferencingDIELocationTy = llvm::SmallVector<DIELocation>;
+
+/// This maps function DIE offset to its DWARF CU.
+using FunctionDIECUTyMap = llvm::DenseMap<uint64_t, DWARFUnit *>;
+
 /// Holds statistics for one function (or other entity that has a PC range and
 /// contains variables, such as a compile unit).
 struct PerFunctionStats {
@@ -450,15 +463,18 @@ static void collectStatsForDie(DWARFDie Die, const std::string &FnPrefix,
 /// Recursively collect variables from subprogram with DW_AT_inline attribute.
 static void collectAbstractOriginFnInfo(
     DWARFDie Die, uint64_t SPOffset,
-    AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo) {
+    AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
+    AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo) {
   DWARFDie Child = Die.getFirstChild();
   while (Child) {
     const dwarf::Tag ChildTag = Child.getTag();
     if (ChildTag == dwarf::DW_TAG_formal_parameter ||
-        ChildTag == dwarf::DW_TAG_variable)
+        ChildTag == dwarf::DW_TAG_variable) {
       GlobalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset());
-    else if (ChildTag == dwarf::DW_TAG_lexical_block)
-      collectAbstractOriginFnInfo(Child, SPOffset, GlobalAbstractOriginFnInfo);
+      LocalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset());
+    } else if (ChildTag == dwarf::DW_TAG_lexical_block)
+      collectAbstractOriginFnInfo(Child, SPOffset, GlobalAbstractOriginFnInfo,
+                                  LocalAbstractOriginFnInfo);
     Child = Child.getSibling();
   }
 }
@@ -468,8 +484,9 @@ static void collectStatsRecursive(
     DWARFDie Die, std::string FnPrefix, std::string VarPrefix,
     uint64_t BytesInScope, uint32_t InlineDepth,
     StringMap<PerFunctionStats> &FnStatMap, GlobalStats &GlobalStats,
-    LocationStats &LocStats,
+    LocationStats &LocStats, FunctionDIECUTyMap &AbstractOriginFnCUs,
     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
+    AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo,
     FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed,
     AbstractOriginVarsTy *AbstractOriginVarsPtr = nullptr) {
   // Skip NULL nodes.
@@ -499,11 +516,12 @@ static void collectStatsRecursive(
     auto OffsetFn = Die.find(dwarf::DW_AT_abstract_origin);
     if (OffsetFn) {
       uint64_t OffsetOfInlineFnCopy = (*OffsetFn).getRawUValue();
-      if (GlobalAbstractOriginFnInfo.count(OffsetOfInlineFnCopy)) {
-        AbstractOriginVars = GlobalAbstractOriginFnInfo[OffsetOfInlineFnCopy];
+      if (LocalAbstractOriginFnInfo.count(OffsetOfInlineFnCopy)) {
+        AbstractOriginVars = LocalAbstractOriginFnInfo[OffsetOfInlineFnCopy];
         AbstractOriginVarsPtr = &AbstractOriginVars;
       } else {
-        // This means that the DW_AT_inline fn copy is out of order,
+        // This means that the DW_AT_inline fn copy is out of order
+        // or that the abstract_origin references another CU,
         // so this abstract origin instance will be processed later.
         FnsWithAbstractOriginToBeProcessed.push_back(Die.getOffset());
         AbstractOriginVarsPtr = nullptr;
@@ -543,7 +561,9 @@ static void collectStatsRecursive(
       // for inlined instancies.
       if (Die.find(dwarf::DW_AT_inline)) {
         uint64_t SPOffset = Die.getOffset();
-        collectAbstractOriginFnInfo(Die, SPOffset, GlobalAbstractOriginFnInfo);
+        AbstractOriginFnCUs[SPOffset] = Die.getDwarfUnit();
+        collectAbstractOriginFnInfo(Die, SPOffset, GlobalAbstractOriginFnInfo,
+                                    LocalAbstractOriginFnInfo);
         return;
       }
 
@@ -597,8 +617,9 @@ static void collectStatsRecursive(
 
     collectStatsRecursive(
         Child, FnPrefix, ChildVarPrefix, BytesInScope, InlineDepth, FnStatMap,
-        GlobalStats, LocStats, GlobalAbstractOriginFnInfo,
-        FnsWithAbstractOriginToBeProcessed, AbstractOriginVarsPtr);
+        GlobalStats, LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
+        LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed,
+        AbstractOriginVarsPtr);
     Child = Child.getSibling();
   }
 
@@ -733,16 +754,24 @@ static void updateVarsWithAbstractOriginLocCovInfo(
 /// the DW_TAG_subprogram) with an abstract_origin attribute.
 static void collectZeroLocCovForVarsWithAbstractOrigin(
     DWARFUnit *DwUnit, GlobalStats &GlobalStats, LocationStats &LocStats,
-    AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
+    AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo,
     FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed) {
+  // The next variable is used to filter out functions that have been processed,
+  // leaving FnsWithAbstractOriginToBeProcessed with just CrossCU references.
+  FunctionsWithAbstractOriginTy ProcessedFns;
   for (auto FnOffset : FnsWithAbstractOriginToBeProcessed) {
     DWARFDie FnDieWithAbstractOrigin = DwUnit->getDIEForOffset(FnOffset);
     auto FnCopy = FnDieWithAbstractOrigin.find(dwarf::DW_AT_abstract_origin);
     AbstractOriginVarsTy AbstractOriginVars;
     if (!FnCopy)
       continue;
-
-    AbstractOriginVars = GlobalAbstractOriginFnInfo[(*FnCopy).getRawUValue()];
+    uint64_t FnCopyRawUValue = (*FnCopy).getRawUValue();
+    // If there is no entry within LocalAbstractOriginFnInfo for the given
+    // FnCopyRawUValue, function isn't out-of-order in DWARF. Rather, we have
+    // CrossCU referencing.
+    if (!LocalAbstractOriginFnInfo.count(FnCopyRawUValue))
+      continue;
+    AbstractOriginVars = LocalAbstractOriginFnInfo[FnCopyRawUValue];
     updateVarsWithAbstractOriginLocCovInfo(FnDieWithAbstractOrigin,
                                            AbstractOriginVars);
 
@@ -758,6 +787,46 @@ static void collectZeroLocCovForVarsWithAbstractOrigin(
         LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
       }
     }
+    ProcessedFns.push_back(FnOffset);
+  }
+  for (auto ProcessedFn : ProcessedFns)
+    llvm::erase_value(FnsWithAbstractOriginToBeProcessed, ProcessedFn);
+}
+
+/// Collect zero location coverage for inlined variables which refer to
+/// a DW_AT_inline copy of subprogram that is in a 
diff erent CU.
+static void collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin(
+    LocationStats &LocStats, FunctionDIECUTyMap AbstractOriginFnCUs,
+    AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
+    CrossCUReferencingDIELocationTy &CrossCUReferencesToBeResolved) {
+  for (const auto &CrossCUReferenceToBeResolved :
+       CrossCUReferencesToBeResolved) {
+    DWARFUnit *DwUnit = CrossCUReferenceToBeResolved.DwUnit;
+    DWARFDie FnDIEWithCrossCUReferencing =
+        DwUnit->getDIEForOffset(CrossCUReferenceToBeResolved.DIEOffset);
+    auto FnCopy =
+        FnDIEWithCrossCUReferencing.find(dwarf::DW_AT_abstract_origin);
+    if (!FnCopy)
+      continue;
+    uint64_t FnCopyRawUValue = (*FnCopy).getRawUValue();
+    AbstractOriginVarsTy AbstractOriginVars =
+        GlobalAbstractOriginFnInfo[FnCopyRawUValue];
+    updateVarsWithAbstractOriginLocCovInfo(FnDIEWithCrossCUReferencing,
+                                           AbstractOriginVars);
+    for (auto Offset : AbstractOriginVars) {
+      LocStats.NumVarParam++;
+      LocStats.VarParamLocStats[ZeroCoverageBucket]++;
+      auto Tag = (AbstractOriginFnCUs[FnCopyRawUValue])
+                     ->getDIEForOffset(Offset)
+                     .getTag();
+      if (Tag == dwarf::DW_TAG_formal_parameter) {
+        LocStats.NumParam++;
+        LocStats.ParamLocStats[ZeroCoverageBucket]++;
+      } else if (Tag == dwarf::DW_TAG_variable) {
+        LocStats.NumVar++;
+        LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
+      }
+    }
   }
 }
 
@@ -778,28 +847,46 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
   GlobalStats GlobalStats;
   LocationStats LocStats;
   StringMap<PerFunctionStats> Statistics;
+  // This variable holds variable information for functions with
+  // abstract_origin globally, across all CUs.
+  AbstractOriginVarsTyMap GlobalAbstractOriginFnInfo;
+  // This variable holds information about the CU of a function with
+  // abstract_origin.
+  FunctionDIECUTyMap AbstractOriginFnCUs;
+  CrossCUReferencingDIELocationTy CrossCUReferencesToBeResolved;
   for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) {
     if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) {
-      // These variables are being reset for each CU, since there could be
-      // a situation where we have two subprogram DIEs with the same offsets
-      // in two diferent CUs, and we can end up using wrong variables info
-      // when trying to resolve abstract_origin attribute.
-      // TODO: Handle LTO cases where the abstract origin of
-      // the function is in a 
diff erent CU than the one it's
-      // referenced from or inlined into.
-      AbstractOriginVarsTyMap GlobalAbstractOriginFnInfo;
+      // This variable holds variable information for functions with
+      // abstract_origin, but just for the current CU.
+      AbstractOriginVarsTyMap LocalAbstractOriginFnInfo;
       FunctionsWithAbstractOriginTy FnsWithAbstractOriginToBeProcessed;
 
-      collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats,
-                            LocStats, GlobalAbstractOriginFnInfo,
-                            FnsWithAbstractOriginToBeProcessed);
+      collectStatsRecursive(
+          CUDie, "/", "g", 0, 0, Statistics, GlobalStats, LocStats,
+          AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
+          LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed);
 
+      // collectZeroLocCovForVarsWithAbstractOrigin will filter out all
+      // out-of-order DWARF functions that have been processed within it,
+      // leaving FnsWithAbstractOriginToBeProcessed with only CrossCU
+      // references.
       collectZeroLocCovForVarsWithAbstractOrigin(
           CUDie.getDwarfUnit(), GlobalStats, LocStats,
-          GlobalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed);
+          LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed);
+
+      // Collect all CrossCU references into CrossCUReferencesToBeResolved.
+      for (auto CrossCUReferencingDIEOffset :
+           FnsWithAbstractOriginToBeProcessed)
+        CrossCUReferencesToBeResolved.push_back(
+            DIELocation(CUDie.getDwarfUnit(), CrossCUReferencingDIEOffset));
     }
   }
 
+  /// Resolve CrossCU references.
+  collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin(
+      LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
+      CrossCUReferencesToBeResolved);
+
   /// Collect the sizes of debug sections.
   SectionSizes Sizes;
   calculateSectionSizes(Obj, Sizes, Filename);


        


More information about the llvm-commits mailing list