[clang] d80fdc6 - [DebugMetadata][DwarfDebug] Fix DWARF emisson of function-local imported entities (3/7)

Vladislav Dzhidzhoev via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 15 08:18:40 PDT 2023


Author: Vladislav Dzhidzhoev
Date: 2023-06-15T17:17:53+02:00
New Revision: d80fdc6fc1a6e717af1bcd7a7313e65de433ba85

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

LOG: [DebugMetadata][DwarfDebug] Fix DWARF emisson of function-local imported entities (3/7)

RFC https://discourse.llvm.org/t/rfc-dwarfdebug-fix-and-improve-handling-imported-entities-types-and-static-local-in-subprogram-and-lexical-block-scopes/68544

Fixed PR51501 (tests from D112337).

1. Reuse of DISubprogram's 'retainedNodes' to track other function-local
   entities together with local variables and labels (this patch cares about
   function-local import while D144006 and D144008 use the same approach for
   local types and static variables). So, effectively this patch moves ownership
   of tracking local import from DICompileUnit's 'imports' field to DISubprogram's
   'retainedNodes' and adjusts DWARF emitter for the new layout. The old layout
   is considered unsupported (DwarfDebug would assert on such debug metadata).

   DICompileUnit's 'imports' field is supposed to track global imported
   declarations as it does before.

   This addresses various FIXMEs and simplifies the next part of the patch.

2. Postpone emission of function-local imported entities from
   `DwarfDebug::endFunctionImpl()` to `DwarfDebug::endModule()`.
   While in `DwarfDebug::endFunctionImpl()` we do not have all the
   information about a parent subprogram or a referring subprogram
   (whether a subprogram inlined or not), so we can't guarantee we emit
   an imported entity correctly and place it in a proper subprogram tree.
   So now, we just gather needed details about the import itself and its
   parent entity (either a Subprogram or a LexicalBlock) during
   processing in `DwarfDebug::endFunctionImpl()`, but all the real work is
   done in `DwarfDebug::endModule()` when we have all the required
   information to make proper emission.

Authored-by: Kristina Bessonova <kbessonova at accesssoftek.com>

Differential Revision: https://reviews.llvm.org/D144004

Added: 
    llvm/test/Bitcode/upgrade-cu-locals.ll
    llvm/test/Bitcode/upgrade-cu-locals.ll.bc
    llvm/test/DebugInfo/Generic/import-inlined-declaration.ll
    llvm/test/DebugInfo/Generic/split-dwarf-local-import.ll
    llvm/test/DebugInfo/Generic/split-dwarf-local-import2.ll
    llvm/test/DebugInfo/Generic/split-dwarf-local-import3.ll

Modified: 
    clang/test/CodeGenCXX/debug-info-namespace.cpp
    llvm/include/llvm/IR/DIBuilder.h
    llvm/lib/Bitcode/Reader/MetadataLoader.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
    llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
    llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
    llvm/lib/IR/DIBuilder.cpp
    llvm/lib/IR/Verifier.cpp
    llvm/lib/Linker/IRMover.cpp
    llvm/test/Bitcode/DIImportedEntity_backward.ll
    llvm/test/Bitcode/DIModule-fortran-external-module.ll
    llvm/test/CodeGen/Generic/DbgValueAggregate.ll
    llvm/test/DebugInfo/Generic/imported-name-inlined.ll
    llvm/test/DebugInfo/Generic/namespace.ll
    llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll
    llvm/test/DebugInfo/X86/dimodule-external-fortran.ll
    llvm/test/DebugInfo/X86/dwarfdump-DIImportedEntity_elements.ll
    llvm/test/DebugInfo/X86/fission-inline.ll
    llvm/test/DebugInfo/X86/fission-local-import.ll
    llvm/test/DebugInfo/X86/fission-no-inline-gsym.ll
    llvm/test/DebugInfo/X86/lexical-block-file-inline.ll
    llvm/test/DebugInfo/X86/namelist2.ll
    llvm/test/DebugInfo/omit-empty.ll
    llvm/test/Linker/pr26037.ll
    llvm/test/ThinLTO/X86/debuginfo-cu-import.ll

Removed: 
    


################################################################################
diff  --git a/clang/test/CodeGenCXX/debug-info-namespace.cpp b/clang/test/CodeGenCXX/debug-info-namespace.cpp
index be88feda1112f..e3cf6507e1611 100644
--- a/clang/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/clang/test/CodeGenCXX/debug-info-namespace.cpp
@@ -81,44 +81,43 @@ void C::c() {}
 // CHECK: !DINamespace(scope: null)
 // CHECK: [[CU:![0-9]+]] = distinct !DICompileUnit(
 // CHECK-SAME:                            imports: [[MODULES:![0-9]*]]
-// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]], [[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]
+// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]]}
 // CHECK: [[M1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CTXT]], entity: [[NS]], file: [[FOOCPP]], line: 15)
-
 // CHECK: [[M2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CU]], entity: [[CTXT]],
 // CHECK: [[M3]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "E", scope: [[CU]], entity: [[CTXT]], file: [[FOOCPP]], line: 19)
-// CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], file: [[FOOCPP]], line: 23)
+// CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]]
+// CHECK: [[F1:![0-9]+]] = distinct !DISubprogram(name: "f1",{{.*}} line: 4
+// CHECK-SAME:                           DISPFlagDefinition
+// CHECK: [[FUNC:![0-9]+]] = distinct !DISubprogram(name: "func",{{.*}} DISPFlagDefinition
+// CHECK-SAME:                             retainedNodes: [[FUNC_NODES:![0-9]*]]
+// CHECK: [[FUNC_NODES]] = !{[[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]}
+// CHECK: [[M5]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], file: [[FOOCPP]], line: 23)
 // CHECK: [[LEX2]] = distinct !DILexicalBlock(scope: [[LEX1:![0-9]+]], file: [[FOOCPP]],
 // CHECK: [[LEX1]] = distinct !DILexicalBlock(scope: [[FUNC:![0-9]+]], file: [[FOOCPP]],
-
-// CHECK: [[FUNC:![0-9]+]] = distinct !DISubprogram(name: "func",{{.*}} DISPFlagDefinition
-// CHECK: [[M5]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[FUNC]], entity: [[CTXT:![0-9]+]],
-// CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], file: [[FOOCPP]], line: 27)
+// CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[FUNC]], entity: [[CTXT]],
+// CHECK: [[M7]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], file: [[FOOCPP]], line: 27)
 // CHECK: [[FOO]] = !DICompositeType(tag: DW_TAG_structure_type, name: "foo",
 // CHECK-SAME:                               line: 5
 // CHECK-SAME:                               DIFlagFwdDecl
-// CHECK: [[M7]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAR:![0-9]+]]
+// CHECK: [[M8]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAR:![0-9]+]]
 // CHECK: [[BAR]] = !DICompositeType(tag: DW_TAG_structure_type, name: "bar",
 // CHECK-SAME:                               line: 6
 // CHECK-SAME:                               DIFlagFwdDecl
-
-// CHECK: [[M8]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[F1:![0-9]+]]
-// CHECK: [[F1:![0-9]+]] = distinct !DISubprogram(name: "f1",{{.*}} line: 4
-// CHECK-SAME:                           DISPFlagDefinition
-// CHECK: [[M9]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[I]]
-// CHECK: [[M10]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAZ:![0-9]+]]
+// CHECK: [[M9]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[F1]]
+// CHECK: [[M10]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[I]]
+// CHECK: [[M11]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAZ:![0-9]+]]
 // CHECK: [[BAZ]] = !DIDerivedType(tag: DW_TAG_typedef, name: "baz", scope: [[NS]], file: [[FOOCPP]],
 // CHECK-SAME:                     baseType: [[BAR]]
-// CHECK: [[M11]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "X", scope: [[FUNC]], entity: [[CTXT]]
-// CHECK: [[M12]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "Y", scope: [[FUNC]], entity: [[M11]]
-// CHECK: [[M13]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_DECL:![0-9]+]]
+// CHECK: [[M12]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "X", scope: [[FUNC]], entity: [[CTXT]]
+// CHECK: [[M13]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "Y", scope: [[FUNC]], entity: [[M12]]
+// CHECK: [[M14]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_DECL:![0-9]+]]
 // CHECK: [[VAR_DECL]] = !DIGlobalVariable(name: "var_decl", linkageName: "{{[^"]*var_decl[^"]*}}", scope: [[NS]],{{.*}} line: 8,
-// CHECK: [[M14]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_DECL:![0-9]+]]
+// CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_DECL:![0-9]+]]
 // CHECK: [[FUNC_DECL]] = !DISubprogram(name: "func_decl",
 // CHECK-SAME:                          scope: [[NS]], file: [[FOOCPP]], line: 9
-// CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]]
-// CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]]
+// CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]]
+// CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]]
 // CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 53,{{.*}} DISPFlagDefinition
-// CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]]
 // CHECK: distinct !DISubprogram(name: "c",{{.*}}, scope: ![[C:[0-9]+]],{{.*}}, line: 60,{{.*}} DISPFlagDefinition
 // CHECK: ![[C]] = !DINamespace(name: "C",
 

diff  --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h
index 90ba6a7d1110c..ecd6dd7b0a4f8 100644
--- a/llvm/include/llvm/IR/DIBuilder.h
+++ b/llvm/include/llvm/IR/DIBuilder.h
@@ -54,7 +54,7 @@ namespace llvm {
     SmallVector<TrackingMDNodeRef, 4> AllRetainTypes;
     SmallVector<DISubprogram *, 4> AllSubprograms;
     SmallVector<Metadata *, 4> AllGVs;
-    SmallVector<TrackingMDNodeRef, 4> AllImportedModules;
+    SmallVector<TrackingMDNodeRef, 4> ImportedModules;
     /// Map Macro parent (which can be DIMacroFile or nullptr) to a list of
     /// Metadata all of type DIMacroNode.
     /// DIMacroNode's with nullptr parent are DICompileUnit direct children.
@@ -64,7 +64,8 @@ namespace llvm {
     SmallVector<TrackingMDNodeRef, 4> UnresolvedNodes;
     bool AllowUnresolvedNodes;
 
-    /// Each subprogram's preserved local variables and labels.
+    /// Each subprogram's preserved local variables, labels and imported
+    /// entities.
     ///
     /// Do not use a std::vector.  Some versions of libc++ apparently copy
     /// instead of move on grow operations, and TrackingMDRef is expensive to
@@ -72,6 +73,12 @@ namespace llvm {
     DenseMap<DISubprogram *, SmallVector<TrackingMDNodeRef, 4>>
         SubprogramTrackedNodes;
 
+    SmallVectorImpl<TrackingMDNodeRef> &
+    getImportTrackingVector(const DIScope *S) {
+      return isa_and_nonnull<DILocalScope>(S)
+                 ? getSubprogramNodesTrackingVector(S)
+                 : ImportedModules;
+    }
     SmallVectorImpl<TrackingMDNodeRef> &
     getSubprogramNodesTrackingVector(const DIScope *S) {
       return SubprogramTrackedNodes[cast<DILocalScope>(S)->getSubprogram()];

diff  --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
index 4b5cfedaa99c1..f13c26e48989e 100644
--- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
+++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
@@ -15,6 +15,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
@@ -53,6 +54,7 @@
 #include <deque>
 #include <iterator>
 #include <limits>
+#include <map>
 #include <optional>
 #include <string>
 #include <tuple>
@@ -463,6 +465,9 @@ class MetadataLoader::MetadataLoaderImpl {
   bool NeedUpgradeToDIGlobalVariableExpression = false;
   bool NeedDeclareExpressionUpgrade = false;
 
+  /// Map DILocalScope to the enclosing DISubprogram, if any.
+  DenseMap<DILocalScope *, DISubprogram *> ParentSubprogram;
+
   /// True if metadata is being parsed for a module being ThinLTO imported.
   bool IsImporting = false;
 
@@ -521,6 +526,84 @@ class MetadataLoader::MetadataLoaderImpl {
     }
   }
 
+  DISubprogram *findEnclosingSubprogram(DILocalScope *S) {
+    if (!S)
+      return nullptr;
+    if (auto *SP = ParentSubprogram[S]) {
+      return SP;
+    }
+
+    DILocalScope *InitialScope = S;
+    DenseSet<DILocalScope *> Visited;
+    while (S && !isa<DISubprogram>(S)) {
+      S = dyn_cast_or_null<DILocalScope>(S->getScope());
+      if (Visited.contains(S))
+        break;
+      Visited.insert(S);
+    }
+    ParentSubprogram[InitialScope] = llvm::dyn_cast_or_null<DISubprogram>(S);
+
+    return ParentSubprogram[InitialScope];
+  }
+
+  /// Move local imports from DICompileUnit's 'imports' field to
+  /// DISubprogram's retainedNodes.
+  void upgradeCULocals() {
+    if (NamedMDNode *CUNodes = TheModule.getNamedMetadata("llvm.dbg.cu")) {
+      for (unsigned I = 0, E = CUNodes->getNumOperands(); I != E; ++I) {
+        auto *CU = dyn_cast<DICompileUnit>(CUNodes->getOperand(I));
+        if (!CU)
+          continue;
+
+        if (auto *RawImported = CU->getRawImportedEntities()) {
+          // Collect a set of imported entities to be moved.
+          SmallPtrSet<Metadata *, 8> EntitiesToRemove;
+          for (Metadata *Op : CU->getImportedEntities()->operands()) {
+            auto *IE = cast<DIImportedEntity>(Op);
+            if (auto *S = dyn_cast_or_null<DILocalScope>(IE->getScope())) {
+              EntitiesToRemove.insert(IE);
+            }
+          }
+
+          if (!EntitiesToRemove.empty()) {
+            // Make a new list of CU's 'imports'.
+            SmallVector<Metadata *> NewImports;
+            for (Metadata *Op : CU->getImportedEntities()->operands()) {
+              if (!EntitiesToRemove.contains(cast<DIImportedEntity>(Op))) {
+                NewImports.push_back(Op);
+              }
+            }
+
+            // Find DISubprogram corresponding to each entity.
+            std::map<DISubprogram *, SmallVector<Metadata *>> SPToEntities;
+            for (auto *I : EntitiesToRemove) {
+              auto *Entity = cast<DIImportedEntity>(I);
+              if (auto *SP = findEnclosingSubprogram(
+                      cast<DILocalScope>(Entity->getScope()))) {
+                SPToEntities[SP].push_back(Entity);
+              }
+            }
+
+            // Update DISubprograms' retainedNodes.
+            for (auto I = SPToEntities.begin(); I != SPToEntities.end(); ++I) {
+              auto *SP = I->first;
+              auto RetainedNodes = SP->getRetainedNodes();
+              SmallVector<Metadata *> MDs(RetainedNodes.begin(),
+                                          RetainedNodes.end());
+              MDs.append(I->second);
+              SP->replaceRetainedNodes(MDNode::get(Context, MDs));
+            }
+
+            // Remove entities with local scope from CU.
+            CU->replaceImportedEntities(MDTuple::get(Context, NewImports));
+          }
+        }
+      }
+    }
+
+    ParentSubprogram.clear();
+  }
+
   /// Remove a leading DW_OP_deref from DIExpressions in a dbg.declare that
   /// describes a function argument.
   void upgradeDeclareExpressions(Function &F) {
@@ -625,6 +708,7 @@ class MetadataLoader::MetadataLoaderImpl {
   void upgradeDebugInfo() {
     upgradeCUSubprograms();
     upgradeCUVariables();
+    upgradeCULocals();
   }
 
   void callMDTypeCallback(Metadata **Val, unsigned TypeID);

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index fd583a3693fe9..58ed21379d29b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -694,7 +694,7 @@ DIE *DwarfCompileUnit::constructInlinedScopeDIE(LexicalScope *Scope,
   auto *InlinedSP = getDISubprogram(DS);
   // Find the subprogram's DwarfCompileUnit in the SPMap in case the subprogram
   // was inlined from another compile unit.
-  DIE *OriginDIE = getAbstractSPDies()[InlinedSP];
+  DIE *OriginDIE = getAbstractScopeDIEs()[InlinedSP];
   assert(OriginDIE && "Unable to find original DIE for an inlined subprogram.");
 
   auto ScopeDIE = DIE::get(DIEValueAllocator, dwarf::DW_TAG_inlined_subroutine);
@@ -726,10 +726,20 @@ DIE *DwarfCompileUnit::constructInlinedScopeDIE(LexicalScope *Scope,
 DIE *DwarfCompileUnit::constructLexicalScopeDIE(LexicalScope *Scope) {
   if (DD->isLexicalScopeDIENull(Scope))
     return nullptr;
+  const auto *DS = Scope->getScopeNode();
 
   auto ScopeDIE = DIE::get(DIEValueAllocator, dwarf::DW_TAG_lexical_block);
-  if (Scope->isAbstractScope())
+  if (Scope->isAbstractScope()) {
+    assert(!getAbstractScopeDIEs().count(DS) &&
+           "Abstract DIE for this scope exists!");
+    getAbstractScopeDIEs()[DS] = ScopeDIE;
     return ScopeDIE;
+  }
+  if (!Scope->getInlinedAt()) {
+    assert(!LexicalBlockDIEs.count(DS) &&
+           "Concrete out-of-line DIE for this scope exists!");
+    LexicalBlockDIEs[DS] = ScopeDIE;
+  }
 
   attachRangesOrLowHighPC(*ScopeDIE, Scope->getRanges());
 
@@ -1097,35 +1107,35 @@ DIE *DwarfCompileUnit::createAndAddScopeChildren(LexicalScope *Scope,
   for (DbgVariable *DV : Locals)
     ScopeDIE.addChild(constructVariableDIE(*DV, *Scope, ObjectPointer));
 
-  // Emit imported entities (skipped in gmlt-like data).
-  if (!includeMinimalInlineScopes()) {
-    for (const auto *IE : ImportedEntities[Scope->getScopeNode()])
-      ScopeDIE.addChild(constructImportedEntityDIE(cast<DIImportedEntity>(IE)));
-  }
-
   // Emit labels.
   for (DbgLabel *DL : DU->getScopeLabels().lookup(Scope))
     ScopeDIE.addChild(constructLabelDIE(*DL, *Scope));
 
+  // Track other local entities (skipped in gmlt-like data).
+  // This creates mapping between CU and a set of local declarations that
+  // should be emitted for subprograms in this CU.
+  if (!includeMinimalInlineScopes() && !Scope->getInlinedAt()) {
+    auto &LocalDecls = DD->getLocalDeclsForScope(Scope->getScopeNode());
+    DeferredLocalDecls.insert(LocalDecls.begin(), LocalDecls.end());
+  }
+
   // Emit inner lexical scopes.
-  auto needToEmitLexicalScope = [this](LexicalScope *LS) {
-    if (isa<DISubprogram>(LS->getScopeNode()))
-      return true;
-    auto Vars = DU->getScopeVariables().lookup(LS);
+  auto skipLexicalScope = [this](LexicalScope *S) -> bool {
+    if (isa<DISubprogram>(S->getScopeNode()))
+      return false;
+    auto Vars = DU->getScopeVariables().lookup(S);
     if (!Vars.Args.empty() || !Vars.Locals.empty())
-      return true;
-    if (!includeMinimalInlineScopes() &&
-        !ImportedEntities[LS->getScopeNode()].empty())
-      return true;
-    return false;
+      return false;
+    return includeMinimalInlineScopes() ||
+           DD->getLocalDeclsForScope(S->getScopeNode()).empty();
   };
   for (LexicalScope *LS : Scope->getChildren()) {
     // If the lexical block doesn't have non-scope children, skip
     // its emission and put its children directly to the parent scope.
-    if (needToEmitLexicalScope(LS))
-      constructScopeDIE(LS, ScopeDIE);
-    else
+    if (skipLexicalScope(LS))
       createAndAddScopeChildren(LS, ScopeDIE);
+    else
+      constructScopeDIE(LS, ScopeDIE);
   }
 
   return ObjectPointer;
@@ -1133,11 +1143,9 @@ DIE *DwarfCompileUnit::createAndAddScopeChildren(LexicalScope *Scope,
 
 void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
     LexicalScope *Scope) {
-  DIE *&AbsDef = getAbstractSPDies()[Scope->getScopeNode()];
-  if (AbsDef)
-    return;
-
   auto *SP = cast<DISubprogram>(Scope->getScopeNode());
+  if (getAbstractScopeDIEs().count(SP))
+    return;
 
   DIE *ContextDIE;
   DwarfCompileUnit *ContextCU = this;
@@ -1161,14 +1169,19 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
 
   // Passing null as the associated node because the abstract definition
   // shouldn't be found by lookup.
-  AbsDef = &ContextCU->createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, nullptr);
-  ContextCU->applySubprogramAttributesToDefinition(SP, *AbsDef);
-  ContextCU->addSInt(*AbsDef, dwarf::DW_AT_inline,
+  DIE &AbsDef = ContextCU->createAndAddDIE(dwarf::DW_TAG_subprogram,
+                                           *ContextDIE, nullptr);
+
+  // Store the DIE before creating children.
+  ContextCU->getAbstractScopeDIEs()[SP] = &AbsDef;
+
+  ContextCU->applySubprogramAttributesToDefinition(SP, AbsDef);
+  ContextCU->addSInt(AbsDef, dwarf::DW_AT_inline,
                      DD->getDwarfVersion() <= 4 ? std::optional<dwarf::Form>()
                                                 : dwarf::DW_FORM_implicit_const,
                      dwarf::DW_INL_inlined);
-  if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, *AbsDef))
-    ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
+  if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, AbsDef))
+    ContextCU->addDIEEntry(AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
 }
 
 bool DwarfCompileUnit::useGNUAnalogForDwarf5Feature() const {
@@ -1312,12 +1325,20 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE(
     EntityDie = getOrCreateNameSpace(NS);
   else if (auto *M = dyn_cast<DIModule>(Entity))
     EntityDie = getOrCreateModule(M);
-  else if (auto *SP = dyn_cast<DISubprogram>(Entity))
-    EntityDie = getOrCreateSubprogramDIE(SP);
-  else if (auto *T = dyn_cast<DIType>(Entity))
+  else if (auto *SP = dyn_cast<DISubprogram>(Entity)) {
+    // If there is an abstract subprogram, refer to it. Note that this assumes
+    // that all the abstract subprograms have been already created (which is
+    // correct until imported entities get emitted in DwarfDebug::endModule()).
+    if (auto *AbsSPDie = getAbstractScopeDIEs().lookup(SP))
+      EntityDie = AbsSPDie;
+    else
+      EntityDie = getOrCreateSubprogramDIE(SP);
+  } else if (auto *T = dyn_cast<DIType>(Entity))
     EntityDie = getOrCreateTypeDIE(T);
   else if (auto *GV = dyn_cast<DIGlobalVariable>(Entity))
     EntityDie = getOrCreateGlobalVariableDIE(GV, {});
+  else if (auto *IE = dyn_cast<DIImportedEntity>(Entity))
+    EntityDie = getOrCreateImportedEntityDIE(IE);
   else
     EntityDie = getDIE(Entity);
   assert(EntityDie);
@@ -1348,9 +1369,24 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE(
   return IMDie;
 }
 
+DIE *DwarfCompileUnit::getOrCreateImportedEntityDIE(
+    const DIImportedEntity *IE) {
+
+  // Check for pre-existence.
+  if (DIE *Die = getDIE(IE))
+    return Die;
+
+  DIE *ContextDIE = getOrCreateContextDIE(IE->getScope());
+  assert(ContextDIE && "Empty scope for the imported entity!");
+
+  DIE *IMDie = constructImportedEntityDIE(IE);
+  ContextDIE->addChild(IMDie);
+  return IMDie;
+}
+
 void DwarfCompileUnit::finishSubprogramDefinition(const DISubprogram *SP) {
   DIE *D = getDIE(SP);
-  if (DIE *AbsSPDIE = getAbstractSPDies().lookup(SP)) {
+  if (DIE *AbsSPDIE = getAbstractScopeDIEs().lookup(SP)) {
     if (D)
       // If this subprogram has an abstract definition, reference that
       addDIEEntry(*D, dwarf::DW_AT_abstract_origin, *AbsSPDIE);
@@ -1644,3 +1680,29 @@ void DwarfCompileUnit::createBaseTypeDIEs() {
     Btr.Die = &Die;
   }
 }
+
+DIE *DwarfCompileUnit::getLexicalBlockDIE(const DILexicalBlock *LB) {
+  // Assume if there is an abstract tree all the DIEs are already emitted.
+  bool isAbstract = getAbstractScopeDIEs().count(LB->getSubprogram());
+  if (isAbstract && getAbstractScopeDIEs().count(LB))
+    return getAbstractScopeDIEs()[LB];
+  assert(!isAbstract && "Missed lexical block DIE in abstract tree!");
+
+  // Return a concrete DIE if it exists or nullptr otherwise.
+  return LexicalBlockDIEs.lookup(LB);
+}
+
+DIE *DwarfCompileUnit::getOrCreateContextDIE(const DIScope *Context) {
+  if (isa_and_nonnull<DILocalScope>(Context)) {
+    if (auto *LFScope = dyn_cast<DILexicalBlockFile>(Context))
+      Context = LFScope->getNonLexicalBlockFileScope();
+    if (auto *LScope = dyn_cast<DILexicalBlock>(Context))
+      return getLexicalBlockDIE(LScope);
+
+    // Otherwise the context must be a DISubprogram.
+    auto *SPScope = cast<DISubprogram>(Context);
+    if (getAbstractScopeDIEs().count(SPScope))
+      return getAbstractScopeDIEs()[SPScope];
+  }
+  return DwarfUnit::getOrCreateContextDIE(Context);
+}

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index 5581b9144bab7..6ef73ebd4f7f2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -61,11 +61,6 @@ class DwarfCompileUnit final : public DwarfUnit {
   /// The start of the unit macro info within macro section.
   MCSymbol *MacroLabelBegin;
 
-  using ImportedEntityList = SmallVector<const MDNode *, 8>;
-  using ImportedEntityMap = DenseMap<const MDNode *, ImportedEntityList>;
-
-  ImportedEntityMap ImportedEntities;
-
   /// GlobalNames - A map of globally visible named entities for this unit.
   StringMap<const DIE *> GlobalNames;
 
@@ -79,7 +74,20 @@ class DwarfCompileUnit final : public DwarfUnit {
   // ranges/locs.
   const MCSymbol *BaseAddress = nullptr;
 
-  DenseMap<const MDNode *, DIE *> AbstractSPDies;
+  using MDNodeSetVector =
+      SetVector<const MDNode *, SmallVector<const MDNode *, 4>,
+                SmallPtrSet<const MDNode *, 4>>;
+
+  // List of entities (either static locals, types or imports) that
+  // belong to subprograms within this CU.
+  MDNodeSetVector DeferredLocalDecls;
+
+  // List of concrete lexical block scopes belong to subprograms within this CU.
+  DenseMap<const DILocalScope *, DIE *> LexicalBlockDIEs;
+
+  // List of abstract local scopes (either DISubprogram or DILexicalBlock).
+  DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
+
   DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
 
   /// DWO ID for correlating skeleton and split units.
@@ -94,10 +102,10 @@ class DwarfCompileUnit final : public DwarfUnit {
 
   bool isDwoUnit() const override;
 
-  DenseMap<const MDNode *, DIE *> &getAbstractSPDies() {
+  DenseMap<const DILocalScope *, DIE *> &getAbstractScopeDIEs() {
     if (isDwoUnit() && !DD->shareAcrossDWOCUs())
-      return AbstractSPDies;
-    return DU->getAbstractSPDies();
+      return AbstractLocalScopeDIEs;
+    return DU->getAbstractScopeDIEs();
   }
 
   DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {
@@ -175,17 +183,6 @@ class DwarfCompileUnit final : public DwarfUnit {
 
   unsigned getOrCreateSourceID(const DIFile *File) override;
 
-  void addImportedEntity(const DIImportedEntity* IE) {
-    DIScope *Scope = IE->getScope();
-    assert(Scope && "Invalid Scope encoding!");
-    if (!isa<DILocalScope>(Scope))
-      // No need to add imported enities that are not local declaration.
-      return;
-
-    auto *LocalScope = cast<DILocalScope>(Scope)->getNonLexicalBlockFileScope();
-    ImportedEntities[LocalScope].push_back(IE);
-  }
-
   /// addRange - Add an address range to the list of ranges for this unit.
   void addRange(RangeSpan Range);
 
@@ -217,6 +214,11 @@ class DwarfCompileUnit final : public DwarfUnit {
   /// attach DW_AT_low_pc/DW_AT_high_pc labels.
   DIE *constructLexicalScopeDIE(LexicalScope *Scope);
 
+  /// Get a DIE for the given DILexicalBlock.
+  /// Note that this function assumes that the DIE has been already created
+  /// and it's an error, if it hasn't.
+  DIE *getLexicalBlockDIE(const DILexicalBlock *LB);
+
   /// constructVariableDIE - Construct a DIE for the given DbgVariable.
   DIE *constructVariableDIE(DbgVariable &DV, bool Abstract = false);
 
@@ -228,6 +230,10 @@ class DwarfCompileUnit final : public DwarfUnit {
 
   void createBaseTypeDIEs();
 
+  /// Construct a DIE for a given scope.
+  /// This instance of 'getOrCreateContextDIE()' can handle DILocalScope.
+  DIE *getOrCreateContextDIE(const DIScope *Ty) override;
+
   /// Construct a DIE for this subprogram scope.
   DIE &constructSubprogramScopeDIE(const DISubprogram *Sub,
                                    LexicalScope *Scope);
@@ -266,8 +272,9 @@ class DwarfCompileUnit final : public DwarfUnit {
   void constructCallSiteParmEntryDIEs(DIE &CallSiteDIE,
                                       SmallVector<DbgCallSiteParam, 4> &Params);
 
-  /// Construct import_module DIE.
-  DIE *constructImportedEntityDIE(const DIImportedEntity *Module);
+  /// Get or create a DIE for an imported entity.
+  DIE *getOrCreateImportedEntityDIE(const DIImportedEntity *IE);
+  DIE *constructImportedEntityDIE(const DIImportedEntity *IE);
 
   void finishSubprogramDefinition(const DISubprogram *SP);
   void finishEntityDefinition(const DbgEntity *Entity);
@@ -364,6 +371,8 @@ class DwarfCompileUnit final : public DwarfUnit {
   bool hasDwarfPubSections() const;
 
   void addBaseTypeRef(DIEValueList &Die, int64_t Idx);
+
+  MDNodeSetVector &getDeferredLocalDecls() { return DeferredLocalDecls; }
 };
 
 } // end namespace llvm

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 67af6e9f2cc92..50ce812eb9fac 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -507,7 +507,7 @@ void DwarfDebug::addSubprogramNames(const DICompileUnit &CU,
   // well into the name table. Only do that if we are going to actually emit
   // that name.
   if (SP->getLinkageName() != "" && SP->getName() != SP->getLinkageName() &&
-      (useAllLinkageNames() || InfoHolder.getAbstractSPDies().lookup(SP)))
+      (useAllLinkageNames() || InfoHolder.getAbstractScopeDIEs().lookup(SP)))
     addAccelName(CU, SP->getLinkageName(), Die);
 
   // If this is an Objective-C selector name add it to the ObjC accelerator
@@ -1105,9 +1105,6 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) {
   DwarfCompileUnit &NewCU = *OwnedUnit;
   InfoHolder.addUnit(std::move(OwnedUnit));
 
-  for (auto *IE : DIUnit->getImportedEntities())
-    NewCU.addImportedEntity(IE);
-
   // LTO with assembly output shares a single line table amongst multiple CUs.
   // To avoid the compilation directory being ambiguous, let the line table
   // explicitly describe the directory of all files, never relying on the
@@ -1130,14 +1127,6 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) {
   return NewCU;
 }
 
-void DwarfDebug::constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU,
-                                                  const DIImportedEntity *N) {
-  if (isa<DILocalScope>(N->getScope()))
-    return;
-  if (DIE *D = TheCU.getOrCreateContextDIE(N->getScope()))
-    D->addChild(TheCU.constructImportedEntityDIE(N));
-}
-
 /// Sort and unique GVEs by comparing their fragment offset.
 static SmallVectorImpl<DwarfCompileUnit::GlobalExpr> &
 sortGlobalExprs(SmallVectorImpl<DwarfCompileUnit::GlobalExpr> &GVEs) {
@@ -1215,16 +1204,8 @@ void DwarfDebug::beginModule(Module *M) {
   DebugLocs.setSym(Asm->createTempSymbol("loclists_table_base"));
 
   for (DICompileUnit *CUNode : M->debug_compile_units()) {
-    // FIXME: Move local imported entities into a list attached to the
-    // subprogram, then this search won't be needed and a
-    // getImportedEntities().empty() test should go below with the rest.
-    bool HasNonLocalImportedEntities = llvm::any_of(
-        CUNode->getImportedEntities(), [](const DIImportedEntity *IE) {
-          return !isa<DILocalScope>(IE->getScope());
-        });
-
-    if (!HasNonLocalImportedEntities && CUNode->getEnumTypes().empty() &&
-        CUNode->getRetainedTypes().empty() &&
+    if (CUNode->getImportedEntities().empty() &&
+        CUNode->getEnumTypes().empty() && CUNode->getRetainedTypes().empty() &&
         CUNode->getGlobalVariables().empty() && CUNode->getMacros().empty())
       continue;
 
@@ -1442,8 +1423,17 @@ void DwarfDebug::endModule() {
     DwarfCompileUnit *CU = &*P.second;
 
     // Emit imported entities.
-    for (auto *IE : CUNode->getImportedEntities())
-      constructAndAddImportedEntityDIE(*CU, IE);
+    for (auto *IE : CUNode->getImportedEntities()) {
+      assert(!isa_and_nonnull<DILocalScope>(IE->getScope()) &&
+             "Unexpected function-local entity in 'imports' CU field.");
+      CU->getOrCreateImportedEntityDIE(IE);
+    }
+    for (const auto *D : CU->getDeferredLocalDecls()) {
+      if (auto *IE = dyn_cast<DIImportedEntity>(D))
+        CU->getOrCreateImportedEntityDIE(IE);
+      else
+        llvm_unreachable("Unexpected local retained node!");
+    }
 
     // Emit base types.
     CU->createBaseTypeDIEs();
@@ -1520,16 +1510,6 @@ void DwarfDebug::endModule() {
   // FIXME: AbstractVariables.clear();
 }
 
-void DwarfDebug::ensureAbstractEntityIsCreated(DwarfCompileUnit &CU,
-                                               const DINode *Node,
-                                               const MDNode *ScopeNode) {
-  if (CU.getExistingAbstractEntity(Node))
-    return;
-
-  CU.createAbstractEntity(Node, LScopes.getOrCreateAbstractScope(
-                                       cast<DILocalScope>(ScopeNode)));
-}
-
 void DwarfDebug::ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU,
     const DINode *Node, const MDNode *ScopeNode) {
   if (CU.getExistingAbstractEntity(Node))
@@ -1540,6 +1520,21 @@ void DwarfDebug::ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU,
     CU.createAbstractEntity(Node, Scope);
 }
 
+static const DILocalScope *getRetainedNodeScope(const MDNode *N) {
+  const DIScope *S;
+  if (const auto *LV = dyn_cast<DILocalVariable>(N))
+    S = LV->getScope();
+  else if (const auto *L = dyn_cast<DILabel>(N))
+    S = L->getScope();
+  else if (const auto *IE = dyn_cast<DIImportedEntity>(N))
+    S = IE->getScope();
+  else
+    llvm_unreachable("Unexpected retained node!");
+
+  // Ensure the scope is not a DILexicalBlockFile.
+  return cast<DILocalScope>(S)->getNonLexicalBlockFileScope();
+}
+
 // Collect variable information from side table maintained by MF.
 void DwarfDebug::collectVariableInfoFromMFTable(
     DwarfCompileUnit &TheCU, DenseSet<InlinedEntity> &Processed) {
@@ -1984,19 +1979,18 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU,
     createConcreteEntity(TheCU, *Scope, Label, IL.second, Sym);
   }
 
-  // Collect info for variables/labels that were optimized out.
+  // Collect info for retained nodes.
   for (const DINode *DN : SP->getRetainedNodes()) {
-    if (!Processed.insert(InlinedEntity(DN, nullptr)).second)
-      continue;
-    LexicalScope *Scope = nullptr;
-    if (auto *DV = dyn_cast<DILocalVariable>(DN)) {
-      Scope = LScopes.findLexicalScope(DV->getScope());
-    } else if (auto *DL = dyn_cast<DILabel>(DN)) {
-      Scope = LScopes.findLexicalScope(DL->getScope());
+    const auto *LS = getRetainedNodeScope(DN);
+    if (isa<DILocalVariable>(DN) || isa<DILabel>(DN)) {
+      if (!Processed.insert(InlinedEntity(DN, nullptr)).second)
+        continue;
+      LexicalScope *LexS = LScopes.findLexicalScope(LS);
+      if (LexS)
+        createConcreteEntity(TheCU, *LexS, DN, nullptr);
+    } else {
+      LocalDeclsPerLS[LS].insert(DN);
     }
-
-    if (Scope)
-      createConcreteEntity(TheCU, *Scope, DN, nullptr);
   }
 }
 
@@ -2311,27 +2305,28 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
   }
 
 #ifndef NDEBUG
-  size_t NumAbstractScopes = LScopes.getAbstractScopesList().size();
+  size_t NumAbstractSubprograms = LScopes.getAbstractScopesList().size();
 #endif
-  // Construct abstract scopes.
   for (LexicalScope *AScope : LScopes.getAbstractScopesList()) {
     const auto *SP = cast<DISubprogram>(AScope->getScopeNode());
     for (const DINode *DN : SP->getRetainedNodes()) {
-      if (!Processed.insert(InlinedEntity(DN, nullptr)).second)
-        continue;
-
-      const MDNode *Scope = nullptr;
-      if (auto *DV = dyn_cast<DILocalVariable>(DN))
-        Scope = DV->getScope();
-      else if (auto *DL = dyn_cast<DILabel>(DN))
-        Scope = DL->getScope();
-      else
-        llvm_unreachable("Unexpected DI type!");
-
-      // Collect info for variables/labels that were optimized out.
-      ensureAbstractEntityIsCreated(TheCU, DN, Scope);
-      assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes
-             && "ensureAbstractEntityIsCreated inserted abstract scopes");
+      const auto *LS = getRetainedNodeScope(DN);
+      // Ensure LexicalScope is created for the scope of this node.
+      auto *LexS = LScopes.getOrCreateAbstractScope(LS);
+      assert(LexS && "Expected the LexicalScope to be created.");
+      if (isa<DILocalVariable>(DN) || isa<DILabel>(DN)) {
+        // Collect info for variables/labels that were optimized out.
+        if (!Processed.insert(InlinedEntity(DN, nullptr)).second ||
+            TheCU.getExistingAbstractEntity(DN))
+          continue;
+        TheCU.createAbstractEntity(DN, LexS);
+      } else {
+        // Remember the node if this is a local declarations.
+        LocalDeclsPerLS[LS].insert(DN);
+      }
+      assert(
+          LScopes.getAbstractScopesList().size() == NumAbstractSubprograms &&
+          "getOrCreateAbstractScope() inserted an abstract subprogram scope");
     }
     constructAbstractSubprogramScopeDIE(TheCU, AScope);
   }
@@ -2352,6 +2347,7 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
   // can be used cross-function)
   InfoHolder.getScopeVariables().clear();
   InfoHolder.getScopeLabels().clear();
+  LocalDeclsPerLS.clear();
   PrevLabel = nullptr;
   CurFn = nullptr;
 }

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 44b2f2447dfa7..1af4b643eb178 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -320,6 +320,13 @@ class DwarfDebug : public DebugHandlerBase {
   /// create DIEs.
   SmallSetVector<const DISubprogram *, 16> ProcessedSPNodes;
 
+  /// Map function-local imported entities to their parent local scope
+  /// (either DILexicalBlock or DISubprogram) for a processed function
+  /// (including inlined subprograms).
+  using MDNodeSet = SetVector<const MDNode *, SmallVector<const MDNode *, 2>,
+                              SmallPtrSet<const MDNode *, 2>>;
+  DenseMap<const DILocalScope *, MDNodeSet> LocalDeclsPerLS;
+
   /// If nonnull, stores the current machine function we're processing.
   const MachineFunction *CurFn = nullptr;
 
@@ -454,9 +461,6 @@ class DwarfDebug : public DebugHandlerBase {
 
   using InlinedEntity = DbgValueHistoryMap::InlinedEntity;
 
-  void ensureAbstractEntityIsCreated(DwarfCompileUnit &CU,
-                                     const DINode *Node,
-                                     const MDNode *Scope);
   void ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU,
                                              const DINode *Node,
                                              const MDNode *Scope);
@@ -596,10 +600,6 @@ class DwarfDebug : public DebugHandlerBase {
   void finishUnitAttributes(const DICompileUnit *DIUnit,
                             DwarfCompileUnit &NewCU);
 
-  /// Construct imported_module or imported_declaration DIE.
-  void constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU,
-                                        const DIImportedEntity *N);
-
   /// Register a source line with debug info. Returns the unique
   /// label that was emitted and which provides correspondence to the
   /// source line list.
@@ -838,6 +838,10 @@ class DwarfDebug : public DebugHandlerBase {
   /// If the \p File has an MD5 checksum, return it as an MD5Result
   /// allocated in the MCContext.
   std::optional<MD5::MD5Result> getMD5AsBytes(const DIFile *File) const;
+
+  MDNodeSet &getLocalDeclsForScope(const DILocalScope *S) {
+    return LocalDeclsPerLS[S];
+  }
 };
 
 } // end namespace llvm

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
index 79a6ce7801b70..464f4f048016d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
@@ -26,6 +26,7 @@ class DbgEntity;
 class DbgVariable;
 class DbgLabel;
 class DINode;
+class DILocalScope;
 class DwarfCompileUnit;
 class DwarfUnit;
 class LexicalScope;
@@ -87,7 +88,7 @@ class DwarfFile {
   DenseMap<LexicalScope *, LabelList> ScopeLabels;
 
   // Collection of abstract subprogram DIEs.
-  DenseMap<const MDNode *, DIE *> AbstractSPDies;
+  DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
   DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
 
   /// Maps MDNodes for type system with the corresponding DIEs. These DIEs can
@@ -162,8 +163,8 @@ class DwarfFile {
     return ScopeLabels;
   }
 
-  DenseMap<const MDNode *, DIE *> &getAbstractSPDies() {
-    return AbstractSPDies;
+  DenseMap<const DILocalScope *, DIE *> &getAbstractScopeDIEs() {
+    return AbstractLocalScopeDIEs;
   }
 
   DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index c11e3d2c9f832..d30f0ef7af348 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -1223,7 +1223,7 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP,
          "decl has a linkage name and it is 
diff erent");
   if (DeclLinkageName.empty() &&
       // Always emit it for abstract subprograms.
-      (DD->useAllLinkageNames() || DU->getAbstractSPDies().lookup(SP)))
+      (DD->useAllLinkageNames() || DU->getAbstractScopeDIEs().lookup(SP)))
     addLinkageName(SPDie, LinkageName);
 
   if (!DeclDie)

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
index 0caa6adbfa62d..8f17e94c2d1c3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
@@ -245,10 +245,10 @@ class DwarfUnit : public DIEUnit {
   DIE *createTypeDIE(const DIScope *Context, DIE &ContextDIE, const DIType *Ty);
 
   /// Find existing DIE or create new DIE for the given type.
-  DIE *getOrCreateTypeDIE(const MDNode *TyNode);
+  virtual DIE *getOrCreateTypeDIE(const MDNode *TyNode);
 
   /// Get context owner's DIE.
-  DIE *getOrCreateContextDIE(const DIScope *Context);
+  virtual DIE *getOrCreateContextDIE(const DIScope *Context);
 
   /// Construct DIEs for types that contain vtables.
   void constructContainingTypeDIEs();

diff  --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp
index 4fa61b87c379f..ae1a1a37d7c74 100644
--- a/llvm/lib/IR/DIBuilder.cpp
+++ b/llvm/lib/IR/DIBuilder.cpp
@@ -35,7 +35,7 @@ DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU)
     if (const auto &GVs = CUNode->getGlobalVariables())
       AllGVs.assign(GVs.begin(), GVs.end());
     if (const auto &IMs = CUNode->getImportedEntities())
-      AllImportedModules.assign(IMs.begin(), IMs.end());
+      ImportedModules.assign(IMs.begin(), IMs.end());
     if (const auto &MNs = CUNode->getMacros())
       AllMacrosPerParent.insert({nullptr, {MNs.begin(), MNs.end()}});
   }
@@ -93,10 +93,10 @@ void DIBuilder::finalize() {
   if (!AllGVs.empty())
     CUNode->replaceGlobalVariables(MDTuple::get(VMContext, AllGVs));
 
-  if (!AllImportedModules.empty())
+  if (!ImportedModules.empty())
     CUNode->replaceImportedEntities(MDTuple::get(
-        VMContext, SmallVector<Metadata *, 16>(AllImportedModules.begin(),
-                                               AllImportedModules.end())));
+        VMContext, SmallVector<Metadata *, 16>(ImportedModules.begin(),
+                                               ImportedModules.end())));
 
   for (const auto &I : AllMacrosPerParent) {
     // DIMacroNode's with nullptr parent are DICompileUnit direct children.
@@ -160,7 +160,7 @@ static DIImportedEntity *
 createImportedModule(LLVMContext &C, dwarf::Tag Tag, DIScope *Context,
                      Metadata *NS, DIFile *File, unsigned Line, StringRef Name,
                      DINodeArray Elements,
-                     SmallVectorImpl<TrackingMDNodeRef> &AllImportedModules) {
+                     SmallVectorImpl<TrackingMDNodeRef> &ImportedModules) {
   if (Line)
     assert(File && "Source location has line number but no file");
   unsigned EntitiesCount = C.pImpl->DIImportedEntitys.size();
@@ -169,7 +169,7 @@ createImportedModule(LLVMContext &C, dwarf::Tag Tag, DIScope *Context,
   if (EntitiesCount < C.pImpl->DIImportedEntitys.size())
     // A new Imported Entity was just added to the context.
     // Add it to the Imported Modules list.
-    AllImportedModules.emplace_back(M);
+    ImportedModules.emplace_back(M);
   return M;
 }
 
@@ -179,7 +179,7 @@ DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context,
                                                   DINodeArray Elements) {
   return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_module,
                                 Context, NS, File, Line, StringRef(), Elements,
-                                AllImportedModules);
+                                getImportTrackingVector(Context));
 }
 
 DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context,
@@ -188,7 +188,7 @@ DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context,
                                                   DINodeArray Elements) {
   return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_module,
                                 Context, NS, File, Line, StringRef(), Elements,
-                                AllImportedModules);
+                                getImportTrackingVector(Context));
 }
 
 DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, DIModule *M,
@@ -196,7 +196,7 @@ DIImportedEntity *DIBuilder::createImportedModule(DIScope *Context, DIModule *M,
                                                   DINodeArray Elements) {
   return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_module,
                                 Context, M, File, Line, StringRef(), Elements,
-                                AllImportedModules);
+                                getImportTrackingVector(Context));
 }
 
 DIImportedEntity *
@@ -207,7 +207,7 @@ DIBuilder::createImportedDeclaration(DIScope *Context, DINode *Decl,
   // types that have one.
   return ::createImportedModule(VMContext, dwarf::DW_TAG_imported_declaration,
                                 Context, Decl, File, Line, Name, Elements,
-                                AllImportedModules);
+                                getImportTrackingVector(Context));
 }
 
 DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory,

diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 4c96bae04a673..293d443d754a4 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1383,9 +1383,11 @@ void Verifier::visitDISubprogram(const DISubprogram &N) {
     auto *Node = dyn_cast<MDTuple>(RawNode);
     CheckDI(Node, "invalid retained nodes list", &N, RawNode);
     for (Metadata *Op : Node->operands()) {
-      CheckDI(Op && (isa<DILocalVariable>(Op) || isa<DILabel>(Op)),
-              "invalid retained nodes, expected DILocalVariable or DILabel", &N,
-              Node, Op);
+      CheckDI(Op && (isa<DILocalVariable>(Op) || isa<DILabel>(Op) ||
+                     isa<DIImportedEntity>(Op)),
+              "invalid retained nodes, expected DILocalVariable, DILabel or "
+              "DIImportedEntity",
+              &N, Node, Op);
     }
   }
   CheckDI(!hasConflictingReferenceFlags(N.getFlags()),

diff  --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp
index 97794ee7eb53e..df090c5990e6f 100644
--- a/llvm/lib/Linker/IRMover.cpp
+++ b/llvm/lib/Linker/IRMover.cpp
@@ -1211,39 +1211,7 @@ void IRLinker::prepareCompileUnitsForImport() {
     // size inefficient.
     CU->replaceGlobalVariables(nullptr);
 
-    // Imported entities only need to be mapped in if they have local
-    // scope, as those might correspond to an imported entity inside a
-    // function being imported (any locally scoped imported entities that
-    // don't end up referenced by an imported function will not be emitted
-    // into the object). Imported entities not in a local scope
-    // (e.g. on the namespace) only need to be emitted by the originating
-    // module. Create a list of the locally scoped imported entities, and
-    // replace the source CUs imported entity list with the new list, so
-    // only those are mapped in.
-    // FIXME: Locally-scoped imported entities could be moved to the
-    // functions they are local to instead of listing them on the CU, and
-    // we would naturally only link in those needed by function importing.
-    SmallVector<TrackingMDNodeRef, 4> AllImportedModules;
-    bool ReplaceImportedEntities = false;
-    for (auto *IE : CU->getImportedEntities()) {
-      DIScope *Scope = IE->getScope();
-      assert(Scope && "Invalid Scope encoding!");
-      if (isa<DILocalScope>(Scope))
-        AllImportedModules.emplace_back(IE);
-      else
-        ReplaceImportedEntities = true;
-    }
-    if (ReplaceImportedEntities) {
-      if (!AllImportedModules.empty())
-        CU->replaceImportedEntities(MDTuple::get(
-            CU->getContext(),
-            SmallVector<Metadata *, 16>(AllImportedModules.begin(),
-                                        AllImportedModules.end())));
-      else
-        // If there were no local scope imported entities, we can map
-        // the whole list to nullptr.
-        CU->replaceImportedEntities(nullptr);
-    }
+    CU->replaceImportedEntities(nullptr);
   }
 }
 

diff  --git a/llvm/test/Bitcode/DIImportedEntity_backward.ll b/llvm/test/Bitcode/DIImportedEntity_backward.ll
index fcdd554f08339..36bbb5af9c780 100644
--- a/llvm/test/Bitcode/DIImportedEntity_backward.ll
+++ b/llvm/test/Bitcode/DIImportedEntity_backward.ll
@@ -4,11 +4,11 @@
 ; RUN: llvm-dis -o - %s.bc | FileCheck %s
 
 ;Test whether DIImportedEntity are generated correctly.
-; CHECK: distinct !DICompileUnit(language: DW_LANG_Fortran90
-; CHECK-SAME:  imports: [[IMPORTS:![0-9]+]]
+; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "use_renamed"
+; CHECK-SAME:  retainedNodes: [[IMPORTS:![0-9]+]]
 ; CHECK: [[IMPORTS]] = !{[[IMPORT1:![0-9]+]], [[IMPORT2:![0-9]+]]}
-; CHECK: [[IMPORT1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: {{![0-9]+}}, entity: {{![0-9]+}}, file: {{![0-9]+}}, line: {{[0-9]+}})
-; CHECK: [[IMPORT2]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "var4", scope: {{![0-9]+}}, entity: {{![0-9]+}}, file: {{![0-9]+}}, line: {{[0-9]+}})
+; CHECK: [[IMPORT1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[SP]], entity: {{![0-9]+}}, file: {{![0-9]+}}, line: {{[0-9]+}})
+; CHECK: [[IMPORT2]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "var4", scope: [[SP]], entity: {{![0-9]+}}, file: {{![0-9]+}}, line: {{[0-9]+}})
 
 ; ModuleID = 'DIImportedEntity_backward.bc'
 source_filename = "/tmp/usemodulealias.ll"
@@ -58,7 +58,7 @@ declare void @fort_init(...)
 !1 = distinct !DIGlobalVariable(name: "var1", scope: !2, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true)
 !2 = !DIModule(scope: !4, name: "mymod", file: !3, line: 1)
 !3 = !DIFile(filename: "DIImportedEntity_backward.f90", directory: "/tmp")
-!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, flags: "'+flang usemodulealias.f90 -g -S -emit-llvm'", runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !12, nameTableKind: None)
+!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, flags: "'+flang usemodulealias.f90 -g -S -emit-llvm'", runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !5, nameTableKind: None)
 !5 = !{}
 !6 = !{!0, !7, !10}
 !7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression(DW_OP_plus_uconst, 4))
@@ -68,7 +68,7 @@ declare void @fort_init(...)
 !11 = distinct !DIGlobalVariable(name: "var3", scope: !2, file: !3, line: 4, type: !9, isLocal: false, isDefinition: true)
 !12 = !{!13, !19}
 !13 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !14, entity: !2, file: !3, line: 10)
-!14 = distinct !DISubprogram(name: "use_renamed", scope: !15, file: !3, line: 10, type: !18, scopeLine: 10, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !4)
+!14 = distinct !DISubprogram(name: "use_renamed", scope: !15, file: !3, line: 10, type: !18, scopeLine: 10, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !4, retainedNodes: !12)
 !15 = distinct !DISubprogram(name: "main", scope: !4, file: !3, line: 7, type: !16, scopeLine: 7, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !4)
 !16 = !DISubroutineType(cc: DW_CC_program, types: !17)
 !17 = !{null}

diff  --git a/llvm/test/Bitcode/DIModule-fortran-external-module.ll b/llvm/test/Bitcode/DIModule-fortran-external-module.ll
index a10804b1db60b..5ccb9dbd2e805 100644
--- a/llvm/test/Bitcode/DIModule-fortran-external-module.ll
+++ b/llvm/test/Bitcode/DIModule-fortran-external-module.ll
@@ -1,6 +1,6 @@
 ; RUN: llvm-as -o - %s | llvm-dis -o - | FileCheck %s
-; CHECK: DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: !11, file: !3, line: 2)
-; CHECK: DIModule(scope: !2, name: "external_module", isDecl: true)
+; CHECK: DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: ![[MOD:[0-9]+]], file: !3, line: 2)
+; CHECK: ![[MOD]] = !DIModule(scope: !2, name: "external_module", isDecl: true)
 
 ; ModuleID = 'em.f90'
 source_filename = "em.f90"

diff  --git a/llvm/test/Bitcode/upgrade-cu-locals.ll b/llvm/test/Bitcode/upgrade-cu-locals.ll
new file mode 100644
index 0000000000000..9a590f0fc0774
--- /dev/null
+++ b/llvm/test/Bitcode/upgrade-cu-locals.ll
@@ -0,0 +1,118 @@
+; Test moving of local imports from DICompileUnit's 'imports' to DISubprogram's 'retainedNodes'
+;
+; RUN: llvm-dis -o - %s.bc | FileCheck %s
+
+%"struct.ns::t1" = type { i8 }
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
+
+declare dso_local void @_Z3pinv() local_unnamed_addr
+
+define dso_local i32 @main() local_unnamed_addr !dbg !23 {
+entry:
+  call void @llvm.dbg.declare(metadata ptr undef, metadata !39, metadata !DIExpression()), !dbg !40
+  call void @_Z3pinv(), !dbg !42
+  ret i32 0, !dbg !43
+}
+
+define dso_local i32 @main2() local_unnamed_addr !dbg !29 {
+  ret i32 0
+}
+
+attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+
+!llvm.dbg.cu = !{!0, !16}
+!llvm.ident = !{!33, !33}
+!llvm.module.flags = !{!34, !35, !36, !37, !38}
+
+; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !2,
+; CHECK: !2 = !{!3}
+; CHECK: !3 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !4,
+; CHECK: !4 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t4"
+
+; CHECK: !5 = !{}
+; CHECK: !6 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !7, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !5, nameTableKind: GNU)
+
+; CHECK: !14 = distinct !DISubprogram(name: "main", scope: !7, file: !7, line: 2, type: !15, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !18)
+; CHECK: !18 = !{!19}
+; CHECK: !19 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !20, entity: !23,
+; CHECK: !20 = !DILexicalBlock(scope: !21, file: !7, line: 7, column: 35)
+; CHECK: !21 = !DILexicalBlock(scope: !22, file: !7, line: 7, column: 35)
+; CHECK: !22 = !DILexicalBlock(scope: !14, file: !7, line: 7, column: 35)
+; CHECK: !23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t5", scope: !20,
+
+; CHECK: !25 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 3, type: !26, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !28)
+; CHECK: !28 = !{!29, !32, !34}
+; CHECK: !29 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !25, entity: !30,
+; CHECK: !30 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1",
+; CHECK: !32 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !25, entity: !33,
+; CHECK: !33 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2",
+; CHECK: !34 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !25, entity: !35,
+; CHECK: !35 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t3",
+
+; CHECK: !40 = distinct !DISubprogram(name: "main2", scope: !7, file: !7, line: 10, type: !15, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !41)
+; CHECK: !41 = !{!42, !44}
+; CHECK: !42 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !40, entity: !43,
+; CHECK: !43 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t6"
+; CHECK: !44 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !40, entity: !45,
+; CHECK: !45 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t7",
+
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !2, nameTableKind: GNU)
+!1 = !DIFile(filename: "a.cpp", directory: "/")
+!2 = !{!3, !10, !12, !14}
+
+; Move t1 to DISubprogram f1
+!3 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !8, file: !1, line: 3)
+!4 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !7)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null}
+!7 = !{}
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", scope: !9, file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t1E")
+!9 = !DINamespace(name: "ns", scope: null)
+
+; Move t2 to DISubprogram f1
+!10 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !11, file: !1, line: 3)
+!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", scope: !9, file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t2E")
+
+; Move t3 to DISubprogram f1
+!12 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !13, file: !1, line: 3)
+!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t3", scope: !9, file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t3E")
+
+; Leave t4 in CU
+!14 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !15, file: !1, line: 3)
+!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t4", scope: !0, file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t4E")
+!16 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !17, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !18, nameTableKind: GNU)
+!17 = !DIFile(filename: "b.cpp", directory: "/")
+!18 = !{!19, !28, !31}
+
+; Move t5 to DISubprogram main
+!19 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !20, entity: !27, file: !1, line: 3)
+!20 = !DILexicalBlock(scope: !21, file: !17, line: 7, column: 35)
+!21 = !DILexicalBlock(scope: !22, file: !17, line: 7, column: 35)
+!22 = !DILexicalBlock(scope: !23, file: !17, line: 7, column: 35)
+!23 = distinct !DISubprogram(name: "main", scope: !17, file: !17, line: 2, type: !24, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !16, retainedNodes: !7)
+!24 = !DISubroutineType(types: !25)
+!25 = !{!26}
+!26 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t5", scope: !20, file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t5E")
+
+; Move t6 to DISubprogram main2
+!28 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !29, entity: !30, file: !17, line: 3)
+!29 = distinct !DISubprogram(name: "main2", scope: !17, file: !17, line: 10, type: !24, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !16, retainedNodes: !7)
+!30 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t6", scope: !29, file: !17, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t6E")
+
+; Move t7 to DISubprogram main2
+!31 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !29, entity: !32, file: !17, line: 3)
+!32 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t7", scope: !29, file: !17, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t7E")
+!33 = !{!"clang version 14.0.0"}
+!34 = !{i32 7, !"Dwarf Version", i32 4}
+!35 = !{i32 2, !"Debug Info Version", i32 3}
+!36 = !{i32 1, !"wchar_size", i32 4}
+!37 = !{i32 7, !"uwtable", i32 1}
+!38 = !{i32 7, !"frame-pointer", i32 2}
+!39 = !DILocalVariable(name: "v1", scope: !4, file: !1, line: 3, type: !8)
+!40 = !DILocation(line: 3, column: 37, scope: !4, inlinedAt: !41)
+!41 = distinct !DILocation(line: 3, column: 3, scope: !23)
+!42 = !DILocation(line: 3, column: 41, scope: !4, inlinedAt: !41)
+!43 = !DILocation(line: 4, column: 1, scope: !23)

diff  --git a/llvm/test/Bitcode/upgrade-cu-locals.ll.bc b/llvm/test/Bitcode/upgrade-cu-locals.ll.bc
new file mode 100644
index 0000000000000..9d0ea8fd9a370
Binary files /dev/null and b/llvm/test/Bitcode/upgrade-cu-locals.ll.bc 
diff er

diff  --git a/llvm/test/CodeGen/Generic/DbgValueAggregate.ll b/llvm/test/CodeGen/Generic/DbgValueAggregate.ll
index 1663fa774f2c9..29d408d2ebe93 100644
--- a/llvm/test/CodeGen/Generic/DbgValueAggregate.ll
+++ b/llvm/test/CodeGen/Generic/DbgValueAggregate.ll
@@ -21,12 +21,12 @@ attributes #1 = { nounwind readnone speculatable }
 !llvm.dbg.cu = !{!1}
 
 !0 = !{i32 2, !"Debug Info Version", i32 3}
-!1 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !2, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, retainedTypes: !3, globals: !3, imports: !4)
+!1 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !2, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, retainedTypes: !3, globals: !3)
 !2 = !DIFile(filename: "input", directory: "/")
 !3 = !{}
 !4 = !{!5}
 !5 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !6, entity: !9, file: !2, line: 18)
-!6 = distinct !DISubprogram(name: "p", scope: !1, file: !2, line: 18, type: !7, isLocal: false, isDefinition: true, scopeLine: 18, isOptimized: false, unit: !1)
+!6 = distinct !DISubprogram(name: "p", scope: !1, file: !2, line: 18, type: !7, isLocal: false, isDefinition: true, scopeLine: 18, isOptimized: false, unit: !1, retainedNodes: !4)
 !7 = !DISubroutineType(cc: DW_CC_program, types: !8)
 !8 = !{null}
 !9 = !DIModule(scope: !1, name: "mod")

diff  --git a/llvm/test/DebugInfo/Generic/import-inlined-declaration.ll b/llvm/test/DebugInfo/Generic/import-inlined-declaration.ll
new file mode 100644
index 0000000000000..dc57127dae18f
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/import-inlined-declaration.ll
@@ -0,0 +1,72 @@
+; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s
+
+; namespace ns {
+; inline __attribute__((always_inline))
+; void foo() { int a = 4; }
+; }
+;
+; void goo() {
+;   using ns::foo;
+;   foo();
+; }
+
+; Ensure that imported declarations reference the correct subprograms even if
+; those subprograms are inlined.
+
+; CHECK: DW_TAG_compile_unit
+; CHECK:   DW_TAG_namespace
+; CHECK:     DW_AT_name     ("ns")
+; CHECK: [[FOO:0x.*]]:     DW_TAG_subprogram
+; CHECK:       DW_AT_name   ("foo")
+; CHECK:       DW_TAG_variable
+; CHECK:       NULL
+; CHECK:     NULL
+; CHECK:   DW_TAG_base_type
+; CHECK:   DW_TAG_subprogram
+; CHECK:     DW_AT_name     ("goo")
+; CHECK:     DW_TAG_inlined_subroutine
+; CHECK:       DW_AT_abstract_origin ([[FOO]]
+; CHECK:       DW_TAG_variable
+; CHECK:       NULL
+; CHECK:     DW_TAG_imported_declaration
+; CHECK:       DW_AT_import ([[FOO]])
+; CHECK:     NULL
+; CHECK:   NULL
+
+; Function Attrs: mustprogress noinline optnone uwtable
+define dso_local void @_Z3goov() !dbg !4 {
+entry:
+  %a.i = alloca i32, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.i, metadata !16, metadata !DIExpression()), !dbg !18
+  store i32 4, i32* %a.i, align 4, !dbg !18
+  ret void, !dbg !20
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10, !11, !12, !13, !14}
+!llvm.ident = !{!15}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "imported-inlined-declaration.cpp", directory: "")
+!2 = !{!3}
+!3 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !8, file: !1, line: 7)
+!4 = distinct !DISubprogram(name: "goo", linkageName: "_Z3goov", scope: !1, file: !1, line: 6, type: !5, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null}
+!7 = !{}
+!8 = distinct !DISubprogram(name: "foo", linkageName: "_ZN2ns3fooEv", scope: !9, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !7)
+!9 = !DINamespace(name: "ns", scope: null)
+!10 = !{i32 7, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{i32 7, !"uwtable", i32 1}
+!14 = !{i32 7, !"frame-pointer", i32 2}
+!15 = !{!"clang version 14.0.0"}
+!16 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 3, type: !17)
+!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!18 = !DILocation(line: 3, column: 18, scope: !8, inlinedAt: !19)
+!19 = distinct !DILocation(line: 8, column: 2, scope: !4)
+!20 = !DILocation(line: 9, column: 1, scope: !4)

diff  --git a/llvm/test/DebugInfo/Generic/imported-name-inlined.ll b/llvm/test/DebugInfo/Generic/imported-name-inlined.ll
index a3aaaff66f851..50255df8b52b0 100644
--- a/llvm/test/DebugInfo/Generic/imported-name-inlined.ll
+++ b/llvm/test/DebugInfo/Generic/imported-name-inlined.ll
@@ -13,21 +13,17 @@
 ; Ensure that top level imported declarations don't produce an extra degenerate
 ; concrete subprogram definition.
 
-; FIXME: imported entities should only be emitted to the abstract origin if one is present
-
 ; CHECK: DW_TAG_compile_unit
 ; CHECK:   DW_TAG_subprogram
 ; CHECK:     DW_AT_name ("f1")
 ; CHECK:     DW_TAG_imported_declaration
 ; CHECK:     NULL
-; CHECK:   DW_TAG_namespace
-; CHECK:     DW_TAG_subprogram
-; CHECK:     NULL
 ; CHECK:   DW_TAG_subprogram
 ; CHECK:     DW_AT_name ("f2")
 ; CHECK:     DW_TAG_inlined_subroutine
-; CHECK:       DW_TAG_imported_declaration
-; CHECK:       NULL
+; CHECK:     NULL
+; CHECK:   DW_TAG_namespace
+; CHECK:     DW_TAG_subprogram
 ; CHECK:     NULL
 ; CHECK:   NULL
 
@@ -44,12 +40,12 @@ declare void @_ZN2ns1fEv()
 !llvm.module.flags = !{!10, !11, !12}
 !llvm.ident = !{!13}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 6.0.0 (trunk 309061) (llvm/trunk 309076)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, imports: !3)
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 6.0.0 (trunk 309061) (llvm/trunk 309076)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
 !1 = !DIFile(filename: "imported-name-inlined.cpp", directory: "/usr/local/google/home/blaikie/dev/scratch")
 !2 = !{}
 !3 = !{!4}
 !4 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !8, file: !1, line: 5)
-!5 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 4, type: !6, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!5 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 4, type: !6, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !3)
 !6 = !DISubroutineType(types: !7)
 !7 = !{null}
 !8 = !DISubprogram(name: "f", linkageName: "_ZN2ns1fEv", scope: !9, file: !1, line: 2, type: !6, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: false)

diff  --git a/llvm/test/DebugInfo/Generic/namespace.ll b/llvm/test/DebugInfo/Generic/namespace.ll
index 8e184ae0d665e..2db69f13704a5 100644
--- a/llvm/test/DebugInfo/Generic/namespace.ll
+++ b/llvm/test/DebugInfo/Generic/namespace.ll
@@ -33,6 +33,10 @@
 ; CHECK:   DW_TAG_formal_parameter
 ; CHECK:   NULL
 
+; CHECK: [[FUNC_FWD:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+; CHECK:   DW_AT_name ("func_fwd")
+; CHECK-NOT: DW_AT_declaration
+
 ; CHECK: [[BAZ:0x[0-9a-f]*]]:{{.*}}DW_TAG_typedef
 ; CHECK:   DW_AT_name ("baz")
 
@@ -43,10 +47,6 @@
 ; CHECK: [[FUNC_DECL:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
 ; CHECK:   DW_AT_name ("func_decl")
 ; CHECK:   DW_AT_declaration
-
-; CHECK: [[FUNC_FWD:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
-; CHECK:   DW_AT_name ("func_fwd")
-; CHECK-NOT: DW_AT_declaration
 ; CHECK: NULL
 
 ; CHECK: DW_TAG_imported_module
@@ -63,6 +63,12 @@
 ; CHECK:   DW_AT_MIPS_linkage_name
 ; CHECK:   DW_AT_name ("func")
 ; CHECK:   DW_TAG_formal_parameter
+; CHECK:   DW_TAG_lexical_block
+; CHECK:     DW_TAG_imported_module
+; CHECK:       DW_AT_decl_file ([[F2]])
+; CHECK:       DW_AT_decl_line (23)
+; CHECK:       DW_AT_import {{.*}}
+; CHECK:     NULL
 ; CHECK:   DW_TAG_imported_module
 ; CHECK:     DW_AT_decl_file ([[F2:.*]])
 ; CHECK:     DW_AT_decl_line (26)
@@ -113,12 +119,6 @@
 ; CHECK:     DW_AT_decl_file ([[F2]])
 ; CHECK:     DW_AT_decl_line (37)
 ; CHECK:     DW_AT_import ([[FUNC_FWD]])
-; CHECK:   DW_TAG_lexical_block
-; CHECK:     DW_TAG_imported_module
-; CHECK:       DW_AT_decl_file ([[F2]])
-; CHECK:       DW_AT_decl_line (23)
-; CHECK:       DW_AT_import {{.*}}
-; CHECK:     NULL
 ; CHECK:   NULL
 
 ; CHECK: DW_TAG_subprogram
@@ -293,7 +293,7 @@ attributes #1 = { nounwind readnone }
 !18 = !DIFile(filename: "foo.cpp", directory: "/tmp")
 !19 = !DISubroutineType(types: !20)
 !20 = !{null}
-!21 = distinct !DISubprogram(name: "func", linkageName: "_Z4funcb", line: 21, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 21, file: !5, scope: !18, type: !22, retainedNodes: !2)
+!21 = distinct !DISubprogram(name: "func", linkageName: "_Z4funcb", line: 21, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 21, file: !5, scope: !18, type: !22, retainedNodes: !77)
 !22 = !DISubroutineType(types: !23)
 !23 = !{!13, !24}
 !24 = !DIBasicType(tag: DW_TAG_base_type, name: "bool", size: 8, align: 8, encoding: DW_ATE_boolean)
@@ -305,7 +305,7 @@ attributes #1 = { nounwind readnone }
 !30 = !{!131, !132}
 !31 = !DIGlobalVariable(name: "i", linkageName: "_ZN1A1B1iE", line: 20, isLocal: false, isDefinition: true, scope: !6, file: !18, type: !13)
 !32 = !DIGlobalVariable(name: "var_fwd", linkageName: "_ZN1A1B7var_fwdE", line: 44, isLocal: false, isDefinition: true, scope: !6, file: !18, type: !13)
-!33 = !{!34, !35, !36, !37, !40, !41, !42, !43, !44, !45, !47, !48, !49, !51, !54, !55, !56}
+!33 = !{!34, !35, !36, !56}
 !34 = !DIImportedEntity(tag: DW_TAG_imported_module, file: !5, line: 15, scope: !7, entity: !6)
 !35 = !DIImportedEntity(tag: DW_TAG_imported_module, file: !5, line: 18, scope: !0, entity: !7)
 !36 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 19, name: "E", scope: !0, entity: !7)
@@ -348,5 +348,6 @@ attributes #1 = { nounwind readnone }
 !73 = !DILocation(line: 47, column: 21, scope: !26)
 !74 = !DILocation(line: 0, scope: !75)
 !75 = !DILexicalBlockFile(discriminator: 0, file: !5, scope: !27)
+!77 = !{!37, !40, !41, !42, !43, !44, !45, !47, !48, !49, !51, !54, !55}
 !131 = !DIGlobalVariableExpression(var: !31, expr: !DIExpression())
 !132 = !DIGlobalVariableExpression(var: !32, expr: !DIExpression())

diff  --git a/llvm/test/DebugInfo/Generic/split-dwarf-local-import.ll b/llvm/test/DebugInfo/Generic/split-dwarf-local-import.ll
new file mode 100644
index 0000000000000..1a41f3f348ca0
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/split-dwarf-local-import.ll
@@ -0,0 +1,75 @@
+; REQUIRES: x86-registered-target
+; RUN: %llc_dwarf -O1 -filetype=obj -split-dwarf-file=%t.dwo < %s | llvm-dwarfdump -debug-info - | FileCheck %s --implicit-check-not "{{DW_TAG|NULL}}"
+
+; CHECK-LABEL: debug_info contents
+; CHECK: DW_TAG_compile_unit
+; CHECK:   DW_AT_GNU_dwo_name
+; CHECK:   DW_AT_GNU_dwo_id
+; CHECK:   DW_TAG_subprogram
+; CHECK:   DW_TAG_subprogram
+; CHECK:     DW_TAG_inlined_subroutine
+; CHECK:     NULL
+; CHECK:   NULL
+
+; CHECK-LABEL: debug_info.dwo contents
+
+; CHECK: DW_TAG_compile_unit
+; CHECK:   DW_TAG_subprogram
+; CHECK:     DW_TAG_imported_declaration
+; CHECK:     NULL
+; CHECK:   DW_TAG_subprogram
+; CHECK:     DW_TAG_inlined_subroutine
+; CHECK:     NULL
+; CHECK:   DW_TAG_namespace
+; CHECK:     DW_TAG_structure_type
+; CHECK:     NULL
+; CHECK:   DW_TAG_base_type
+; CHECK:   NULL
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%"struct.ns::t1" = type { i8 }
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+declare dso_local void @_Z3pinv() local_unnamed_addr
+
+define dso_local i32 @main() local_unnamed_addr !dbg !18 {
+entry:
+  call void @llvm.dbg.declare(metadata %"struct.ns::t1"* undef, metadata !22, metadata !DIExpression()), !dbg !23
+  call void @_Z3pinv(), !dbg !25
+  ret i32 0, !dbg !26
+}
+
+!llvm.dbg.cu = !{!0, !10}
+!llvm.ident = !{!12, !12}
+!llvm.module.flags = !{!13, !14, !15, !16, !17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: true, nameTableKind: GNU)
+!1 = !DIFile(filename: "a.cpp", directory: "/")
+!2 = !{!3}
+!3 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !8, file: !1, line: 3)
+!4 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null}
+!7 = !{}
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", scope: !9, file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t1E")
+!9 = !DINamespace(name: "ns", scope: null)
+!10 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !11, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: true, nameTableKind: GNU)
+!11 = !DIFile(filename: "b.cpp", directory: "/")
+!12 = !{!"clang version 14.0.0"}
+!13 = !{i32 7, !"Dwarf Version", i32 4}
+!14 = !{i32 2, !"Debug Info Version", i32 3}
+!15 = !{i32 1, !"wchar_size", i32 4}
+!16 = !{i32 7, !"uwtable", i32 1}
+!17 = !{i32 7, !"frame-pointer", i32 2}
+!18 = distinct !DISubprogram(name: "main", scope: !11, file: !11, line: 2, type: !19, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !7)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!21}
+!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!22 = !DILocalVariable(name: "v1", scope: !4, file: !1, line: 3, type: !8)
+!23 = !DILocation(line: 3, column: 37, scope: !4, inlinedAt: !24)
+!24 = distinct !DILocation(line: 3, column: 3, scope: !18)
+!25 = !DILocation(line: 3, column: 41, scope: !4, inlinedAt: !24)
+!26 = !DILocation(line: 4, column: 1, scope: !18)

diff  --git a/llvm/test/DebugInfo/Generic/split-dwarf-local-import2.ll b/llvm/test/DebugInfo/Generic/split-dwarf-local-import2.ll
new file mode 100644
index 0000000000000..0057f675f9b31
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/split-dwarf-local-import2.ll
@@ -0,0 +1,44 @@
+; REQUIRES: x86-registered-target
+; RUN: %llc_dwarf -split-dwarf-file=%t.dwo < %s | FileCheck %s
+
+; Ensure function-local DW_TAG_imported_declaration get skipped if its parent subprogram was not emitted.
+; CHECK-NOT: DW_TAG_imported_declaration
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f1() !dbg !13 {
+lbl:
+  ret void, !dbg !16
+}
+
+define void @f2() !dbg !22 {
+lbl:
+  ret void, !dbg !23
+}
+
+!llvm.dbg.cu = !{!0, !2, !10}
+!llvm.module.flags = !{!12}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, emissionKind: FullDebug)
+!1 = !DIFile(filename: "a.cc", directory: "")
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, emissionKind: FullDebug)
+!3 = !DIFile(filename: "b.cc", directory: "")
+!4 = !{!5}
+!5 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !6, entity: !7)
+!6 = !DISubprogram(scope: null, spFlags: DISPFlagOptimized, retainedNodes: !4)
+!7 = !DINamespace(scope: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{}
+!10 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !11, emissionKind: FullDebug)
+!11 = !DIFile(filename: "c.cc", directory: "")
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = distinct !DISubprogram(scope: null, type: !8, spFlags: DISPFlagDefinition, unit: !0)
+!16 = !DILocation(line: 0, scope: !17, inlinedAt: !18)
+!17 = distinct !DISubprogram(scope: null, unit: !10)
+!18 = !DILocation(line: 0, scope: !21)
+!21 = !DILexicalBlockFile(scope: !13, discriminator: 0)
+!22 = distinct !DISubprogram(scope: null, type: !8, spFlags: DISPFlagDefinition, unit: !0)
+!23 = !DILocation(line: 0, scope: !24, inlinedAt: !25)
+!24 = distinct !DISubprogram(scope: null, unit: !2)
+!25 = !DILocation(line: 0, scope: !22)

diff  --git a/llvm/test/DebugInfo/Generic/split-dwarf-local-import3.ll b/llvm/test/DebugInfo/Generic/split-dwarf-local-import3.ll
new file mode 100644
index 0000000000000..0aedadab99adb
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/split-dwarf-local-import3.ll
@@ -0,0 +1,71 @@
+; UNSUPPORTED: target={{.*}}-aix{{.*}}
+; REQUIRES: x86-registered-target
+; RUN: %llc_dwarf -O1 -filetype=obj -split-dwarf-file=%t.dwo < %s \
+; RUN:   | llvm-dwarfdump -debug-info -                           \
+; RUN:   | FileCheck %s --implicit-check-not "{{DW_TAG|NULL}}"
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Ensure that the imported entity 'nn::A' gets emitted in 'foo()'s abstract tree
+; in the destination (where 'foo()' was inlined) compile unit.
+
+; CHECK-LABEL: .debug_info contents
+; CHECK: DW_TAG_skeleton_unit
+; CHECK:   DW_AT_dwo_name
+
+; CHECK-LABEL: .debug_info.dwo contents:
+; CHECK: DW_TAG_compile_unit
+; CHECK:   DW_AT_name ("test.cpp")
+; CHECK:   DW_AT_dwo_name
+
+; CHECK:   [[ABSTRACT_FOO:0x[0-9a-f]+]]: DW_TAG_subprogram
+; CHECK:     DW_AT_name	("foo")
+; CHECK:     DW_TAG_imported_declaration
+; CHECK:       DW_AT_import  ([[A:0x[0-9a-f]+]])
+; CHECK:     NULL
+
+; CHECK:   DW_TAG_base_type
+; CHECK:     DW_AT_name	("int")
+
+; CHECK:   DW_TAG_subprogram
+; CHECK:     DW_AT_name	("main")
+; CHECK:     DW_TAG_inlined_subroutine
+; CHECK:       DW_AT_abstract_origin ([[ABSTRACT_FOO]] "_Z3foov")
+; CHECK:     NULL
+
+; CHECK:   DW_TAG_namespace
+; CHECK:     DW_AT_name	("nn")
+; CHECK:     [[A]]: DW_TAG_variable
+; CHECK:       DW_AT_name	("A")
+; CHECK:     NULL
+; CHECK:   NULL
+
+define dso_local noundef i32 @main() local_unnamed_addr !dbg !20 {
+entry:
+  ret i32 42, !dbg !21
+}
+
+!llvm.dbg.cu = !{!0, !2}
+!llvm.module.flags = !{!13, !14}
+!llvm.ident = !{!19, !19}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 15.0.0", isOptimized: true, runtimeVersion: 0, splitDebugFilename: "test.dwo", emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: GNU)
+!1 = !DIFile(filename: "test.cpp", directory: "/", checksumkind: CSK_MD5, checksum: "e7c2808ee27614e496499d55e4b37962")
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: true, runtimeVersion: 0, splitDebugFilename: "cu1.dwo", emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: GNU)
+!3 = !DIFile(filename: "cu1.cpp", directory: "/", checksumkind: CSK_MD5, checksum: "c0b84240ef5682b87083b33cf9038171")
+!4 = !{!5}
+!5 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !6, entity: !11, file: !3, line: 5)
+!6 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 5, type: !7, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4)
+!7 = !DISubroutineType(types: !8)
+!8 = !{!9}
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !{}
+!11 = distinct !DIGlobalVariable(name: "A", linkageName: "_ZN2nn1AE", scope: !12, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true)
+!12 = !DINamespace(name: "nn", scope: null)
+!13 = !{i32 7, !"Dwarf Version", i32 5}
+!14 = !{i32 2, !"Debug Info Version", i32 3}
+!19 = !{!"clang version 15.0.0"}
+!20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !7, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
+!21 = !DILocation(line: 4, column: 3, scope: !6, inlinedAt: !22)
+!22 = !DILocation(line: 4, column: 3, scope: !20)

diff  --git a/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll b/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll
index 4ea2c4fd2dabc..6d4d0e93d38f9 100644
--- a/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll
+++ b/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll
@@ -38,7 +38,7 @@ define void @invalid_subprogram_declaration() !dbg !9 { ret void }
 define void @invalid_retained_nodes_list() !dbg !10 { ret void }
 !10 = distinct !DISubprogram(retainedNodes: !0)
 
-; CHECK: invalid retained nodes, expected DILocalVariable or DILabel
+; CHECK: invalid retained nodes, expected DILocalVariable, DILabel or DIImportedEntity
 define void @invalid_retained_nodes_expected() !dbg !11 { ret void }
 !11 = distinct !DISubprogram(retainedNodes: !{!0})
 

diff  --git a/llvm/test/DebugInfo/X86/dimodule-external-fortran.ll b/llvm/test/DebugInfo/X86/dimodule-external-fortran.ll
index a8266fc4bb1ce..810feca0c8175 100644
--- a/llvm/test/DebugInfo/X86/dimodule-external-fortran.ll
+++ b/llvm/test/DebugInfo/X86/dimodule-external-fortran.ll
@@ -73,13 +73,13 @@ attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
 !3 = !DIFile(filename: "em.f90", directory: "tests")
 !4 = !DISubroutineType(types: !5)
 !5 = !{null}
-!6 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3, producer: "Intel(R) Fortran 21.0-2165", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !7, globals: !8, imports: !9, splitDebugInlining: false, nameTableKind: None)
+!6 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3, producer: "Intel(R) Fortran 21.0-2165", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !7, globals: !8, splitDebugInlining: false, nameTableKind: None)
 !7 = !{}
 !8 = !{!0}
-!9 = !{!10}
+!9 = !{}
 !10 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !2, entity: !11, file: !3, line: 2)
 !11 = !DIModule(scope: !2, name: "external_module", isDecl: true)
-!12 = !{!13}
+!12 = !{!10, !13}
 !13 = !DILocalVariable(name: "x", scope: !2, file: !3, line: 5, type: !14)
 !14 = !DIBasicType(name: "REAL*4", size: 32, encoding: DW_ATE_float)
 !15 = !{i32 2, !"Debug Info Version", i32 3}

diff  --git a/llvm/test/DebugInfo/X86/dwarfdump-DIImportedEntity_elements.ll b/llvm/test/DebugInfo/X86/dwarfdump-DIImportedEntity_elements.ll
index ff2370d7626da..09591dbdb9774 100644
--- a/llvm/test/DebugInfo/X86/dwarfdump-DIImportedEntity_elements.ll
+++ b/llvm/test/DebugInfo/X86/dwarfdump-DIImportedEntity_elements.ll
@@ -81,7 +81,7 @@ declare void @fort_init(...)
 !1 = distinct !DIGlobalVariable(name: "var1", scope: !2, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true)
 !2 = !DIModule(scope: !4, name: "mymod", file: !3, line: 1)
 !3 = !DIFile(filename: "DIImportedEntity_elements.f90", directory: "/tmp")
-!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, flags: "'+flang usemodulealias.f90 -g -S -emit-llvm'", runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !12, nameTableKind: None)
+!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, flags: "'+flang usemodulealias.f90 -g -S -emit-llvm'", runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, nameTableKind: None)
 !5 = !{}
 !6 = !{!0, !7, !10}
 !7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression(DW_OP_plus_uconst, 4))
@@ -91,7 +91,7 @@ declare void @fort_init(...)
 !11 = distinct !DIGlobalVariable(name: "var3", scope: !2, file: !3, line: 4, type: !9, isLocal: false, isDefinition: true)
 !12 = !{!13}
 !13 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !14, entity: !2, file: !3, line: 10, elements: !19)
-!14 = distinct !DISubprogram(name: "use_renamed", scope: !15, file: !3, line: 10, type: !18, scopeLine: 10, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !4)
+!14 = distinct !DISubprogram(name: "use_renamed", scope: !15, file: !3, line: 10, type: !18, scopeLine: 10, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !4, retainedNodes: !12)
 !15 = distinct !DISubprogram(name: "main", scope: !4, file: !3, line: 7, type: !16, scopeLine: 7, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !4)
 !16 = !DISubroutineType(cc: DW_CC_program, types: !17)
 !17 = !{null}

diff  --git a/llvm/test/DebugInfo/X86/fission-inline.ll b/llvm/test/DebugInfo/X86/fission-inline.ll
index 35d2b2794a015..a8c74ce719850 100644
--- a/llvm/test/DebugInfo/X86/fission-inline.ll
+++ b/llvm/test/DebugInfo/X86/fission-inline.ll
@@ -97,7 +97,7 @@ attributes #1 = { "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp
 !llvm.module.flags = !{!22, !23}
 !llvm.ident = !{!24}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.6.0 ", isOptimized: false, splitDebugFilename: "fission-inline.dwo", emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !3, globals: !2, imports: !18)
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.6.0 ", isOptimized: false, splitDebugFilename: "fission-inline.dwo", emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !3, globals: !2)
 !1 = !DIFile(filename: "fission-inline.cpp", directory: "/tmp/dbginfo")
 !2 = !{}
 !3 = !{!4}
@@ -106,7 +106,7 @@ attributes #1 = { "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp
 !6 = !DISubprogram(name: "f3", linkageName: "_ZN3foo2f3Ez", line: 4, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 4, file: !1, scope: !4, type: !7)
 !7 = !DISubroutineType(types: !8)
 !8 = !{null, null}
-!10 = distinct !DISubprogram(name: "f3", linkageName: "_ZN3foo2f3Ez", line: 15, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 15, file: !1, scope: !4, type: !7, declaration: !6, retainedNodes: !2)
+!10 = distinct !DISubprogram(name: "f3", linkageName: "_ZN3foo2f3Ez", line: 15, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 15, file: !1, scope: !4, type: !7, declaration: !6, retainedNodes: !18)
 !11 = distinct !DISubprogram(name: "f2<int>", linkageName: "_ZN3foo2f2IiEEvv", line: 10, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 10, file: !1, scope: !4, type: !12, templateParams: !14, declaration: !17, retainedNodes: !2)
 !12 = !DISubroutineType(types: !13)
 !13 = !{null}

diff  --git a/llvm/test/DebugInfo/X86/fission-local-import.ll b/llvm/test/DebugInfo/X86/fission-local-import.ll
index 4f43a22b70889..d063c9bfb7079 100644
--- a/llvm/test/DebugInfo/X86/fission-local-import.ll
+++ b/llvm/test/DebugInfo/X86/fission-local-import.ll
@@ -16,12 +16,12 @@ entry:
 !llvm.module.flags = !{!9, !10, !11}
 !llvm.ident = !{!12}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 (trunk 349508) (llvm/trunk 349520)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, imports: !3, nameTableKind: None)
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 (trunk 349508) (llvm/trunk 349520)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
 !1 = !DIFile(filename: "test.cpp", directory: "/usr/local/google/home/blaikie/dev/scratch")
 !2 = !{}
 !3 = !{!4}
 !4 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !5, entity: !8, file: !1, line: 2)
-!5 = distinct !DISubprogram(name: "test", linkageName: "_Z4testv", scope: !1, file: !1, line: 2, type: !6, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!5 = distinct !DISubprogram(name: "test", linkageName: "_Z4testv", scope: !1, file: !1, line: 2, type: !6, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !3)
 !6 = !DISubroutineType(types: !7)
 !7 = !{null}
 !8 = !DINamespace(name: "ns1", scope: null)

diff  --git a/llvm/test/DebugInfo/X86/fission-no-inline-gsym.ll b/llvm/test/DebugInfo/X86/fission-no-inline-gsym.ll
index fde2403effac7..6c9885feaf756 100644
--- a/llvm/test/DebugInfo/X86/fission-no-inline-gsym.ll
+++ b/llvm/test/DebugInfo/X86/fission-no-inline-gsym.ll
@@ -53,7 +53,7 @@ attributes #1 = { "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp
 !llvm.module.flags = !{!22, !23}
 !llvm.ident = !{!24}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.6.0 ", isOptimized: false, splitDebugFilename: "fission-inline.dwo",  emissionKind: FullDebug, splitDebugInlining: false, file: !1, enums: !2, retainedTypes: !3, globals: !2, imports: !18)
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.6.0 ", isOptimized: false, splitDebugFilename: "fission-inline.dwo",  emissionKind: FullDebug, splitDebugInlining: false, file: !1, enums: !2, retainedTypes: !3, globals: !2)
 !1 = !DIFile(filename: "fission-inline.cpp", directory: "")
 !2 = !{}
 !3 = !{!4}
@@ -62,7 +62,7 @@ attributes #1 = { "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp
 !6 = !DISubprogram(name: "f3", linkageName: "_ZN3foo2f3Ez", line: 4, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 4, file: !1, scope: !4, type: !7)
 !7 = !DISubroutineType(types: !8)
 !8 = !{null, null}
-!10 = distinct !DISubprogram(name: "f3", linkageName: "_ZN3foo2f3Ez", line: 15, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 15, file: !1, scope: !4, type: !7, declaration: !6, retainedNodes: !2)
+!10 = distinct !DISubprogram(name: "f3", linkageName: "_ZN3foo2f3Ez", line: 15, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 15, file: !1, scope: !4, type: !7, declaration: !6, retainedNodes: !18)
 !11 = distinct !DISubprogram(name: "f2<int>", linkageName: "_ZN3foo2f2IiEEvv", line: 10, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 10, file: !1, scope: !4, type: !12, templateParams: !14, declaration: !17, retainedNodes: !2)
 !12 = !DISubroutineType(types: !13)
 !13 = !{null}

diff  --git a/llvm/test/DebugInfo/X86/lexical-block-file-inline.ll b/llvm/test/DebugInfo/X86/lexical-block-file-inline.ll
index 0e4a5d59603a8..15d0785bde93d 100644
--- a/llvm/test/DebugInfo/X86/lexical-block-file-inline.ll
+++ b/llvm/test/DebugInfo/X86/lexical-block-file-inline.ll
@@ -119,10 +119,10 @@ attributes #2 = { nounwind }
 !llvm.module.flags = !{!15, !16}
 !llvm.ident = !{!17}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 264349)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, imports: !10)
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 264349)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2)
 !1 = !DIFile(filename: "test.cpp", directory: "/")
 !2 = !{}
-!4 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!4 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !10)
 !5 = !DISubroutineType(types: !6)
 !6 = !{!7}
 !7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)

diff  --git a/llvm/test/DebugInfo/X86/namelist2.ll b/llvm/test/DebugInfo/X86/namelist2.ll
index cd2e3e99f1323..615adac9cbcd6 100644
--- a/llvm/test/DebugInfo/X86/namelist2.ll
+++ b/llvm/test/DebugInfo/X86/namelist2.ll
@@ -41,7 +41,7 @@ source_filename = "namelist2.ll"
 !1 = distinct !DIGlobalVariable(name: "aa", scope: !2, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true)
 !2 = !DIModule(scope: !4, name: "mm", file: !3, line: 1)
 !3 = !DIFile(filename: "namelist2.f90", directory: "/dir")
-!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, flags: "'+flang -g namelist2.f90 -S -emit-llvm'", runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !14, nameTableKind: None)
+!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, flags: "'+flang -g namelist2.f90 -S -emit-llvm'", runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, nameTableKind: None)
 !5 = !{}
 !6 = !{!0, !7, !10}
 !7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression(DW_OP_plus_uconst, 4))
@@ -53,7 +53,7 @@ source_filename = "namelist2.ll"
 !13 = !{!1, !8}
 !14 = !{!15}
 !15 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !16, entity: !2, file: !3, line: 6)
-!16 = distinct !DISubprogram(name: "test", scope: !4, file: !3, line: 6, type: !17, scopeLine: 6, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition, unit: !4)
+!16 = distinct !DISubprogram(name: "test", scope: !4, file: !3, line: 6, type: !17, scopeLine: 6, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition, unit: !4, retainedNodes: !14)
 !17 = !DISubroutineType(types: !18)
 !18 = !{null}
 !19 = !{i32 2, !"Dwarf Version", i32 4}

diff  --git a/llvm/test/DebugInfo/omit-empty.ll b/llvm/test/DebugInfo/omit-empty.ll
index d2b0e25e14fbe..0267ec5556f11 100644
--- a/llvm/test/DebugInfo/omit-empty.ll
+++ b/llvm/test/DebugInfo/omit-empty.ll
@@ -6,15 +6,15 @@
 !llvm.dbg.cu = !{!0, !5}
 !llvm.module.flags = !{!3, !4}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2)
 !1 = !DIFile(filename: "<stdin>", directory: "/")
 !2 = !{}
 !3 = !{i32 2, !"Dwarf Version", i32 4}
 !4 = !{i32 2, !"Debug Info Version", i32 3}
-!5 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !6)
+!5 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
 !6 = !{!7}
 !7 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !8, entity: !8, file: !1, line: 3)
-!8 = distinct !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !5, retainedNodes: !2)
+!8 = distinct !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !5, retainedNodes: !6)
 !9 = !DISubroutineType(types: !10)
 !10 = !{null}
 !11 = !DINamespace(name: "ns", scope: null)

diff  --git a/llvm/test/Linker/pr26037.ll b/llvm/test/Linker/pr26037.ll
index bcce0598ebda7..56fc6af1ddf49 100644
--- a/llvm/test/Linker/pr26037.ll
+++ b/llvm/test/Linker/pr26037.ll
@@ -2,12 +2,11 @@
 ; RUN: llvm-as %p/Inputs/pr26037.ll -o %t2.bc
 ; RUN: llvm-link -S -only-needed %t2.bc %t.bc | FileCheck %s
 
-; CHECK: !DIImportedEntity({{.*}}, scope: ![[B:[0-9]+]], entity: ![[A:[0-9]+]]
-; CHECK: ![[B]] = distinct !DISubprogram(name: "b"
+; CHECK: ![[CU_MAIN:[0-9]+]] = distinct !DICompileUnit(
+; CHECK: ![[CU:[0-9]+]] = distinct !DICompileUnit(
+; CHECK: !DIImportedEntity({{.*}}, scope: ![[CU]], entity: ![[A:[0-9]+]]
 ; CHECK: ![[A]] = distinct !DISubprogram(name: "a"
-; CHECK: !DIImportedEntity({{.*}}, scope: ![[LBC:[0-9]+]], entity: ![[LBD:[0-9]+]]
-; CHECK: ![[LBC]] = distinct !DILexicalBlock(scope: ![[C:[0-9]+]]
-; CHECK: ![[C]] = distinct !DISubprogram(name: "c"
+; CHECK: !DIImportedEntity({{.*}}, scope: ![[CU]], entity: ![[LBD:[0-9]+]]
 ; CHECK: ![[LBD]] = distinct !DILexicalBlock(scope: ![[D:[0-9]+]]
 ; CHECK: ![[D]] = distinct !DISubprogram(name: "d"
 
@@ -16,16 +15,6 @@ entry:
   ret void, !dbg !14
 }
 
-define void @_ZN1A1bEv() #0 !dbg !8 {
-entry:
-  ret void, !dbg !15
-}
-
-define void @_ZN1A1cEv() #0 !dbg !18 {
-entry:
-  ret void, !dbg !21
-}
-
 define void @_ZN1A1dEv() #0 !dbg !20 {
 entry:
   ret void, !dbg !22
@@ -42,18 +31,13 @@ entry:
 !5 = !DINamespace(name: "A", scope: null)
 !6 = !DISubroutineType(types: !7)
 !7 = !{null}
-!8 = distinct !DISubprogram(name: "b", linkageName: "_ZN1A1bEv", scope: !5, file: !1, line: 8, type: !6, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
 !9 = !{!10, !16}
-!10 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !8, entity: !4, file: !1, line: 8)
+!10 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !4, file: !1, line: 8)
 !11 = !{i32 2, !"Dwarf Version", i32 4}
 !12 = !{i32 2, !"Debug Info Version", i32 3}
 !13 = !{!"clang version 3.8.0 (trunk 256934) (llvm/trunk 256936)"}
 !14 = !DILocation(line: 7, column: 12, scope: !4)
-!15 = !DILocation(line: 8, column: 24, scope: !8)
-!16 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !17, entity: !19, file: !1, line: 8)
-!17 = distinct !DILexicalBlock(scope: !18, file: !1, line: 9, column: 8)
-!18 = distinct !DISubprogram(name: "c", linkageName: "_ZN1A1cEv", scope: !5, file: !1, line: 9, type: !6, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!16 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !19, file: !1, line: 8)
 !19 = distinct !DILexicalBlock(scope: !20, file: !1, line: 10, column: 8)
 !20 = distinct !DISubprogram(name: "d", linkageName: "_ZN1A1dEv", scope: !5, file: !1, line: 10, type: !6, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
-!21 = !DILocation(line: 9, column: 8, scope: !18)
 !22 = !DILocation(line: 10, column: 8, scope: !20)

diff  --git a/llvm/test/ThinLTO/X86/debuginfo-cu-import.ll b/llvm/test/ThinLTO/X86/debuginfo-cu-import.ll
index 1f07f96f3239c..850ef09b1c2f0 100644
--- a/llvm/test/ThinLTO/X86/debuginfo-cu-import.ll
+++ b/llvm/test/ThinLTO/X86/debuginfo-cu-import.ll
@@ -5,15 +5,13 @@
 ; RUN: opt -module-summary %p/Inputs/debuginfo-cu-import.ll -o %t2.bc
 ; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc
 
-; Don't import enums, macros, retainedTypes or globals lists.
-; Only import local scope imported entities.
+; Don't import enums, macros, retainedTypes, globals or imports lists.
 ; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t.index.bc -o - | llvm-dis -o - | FileCheck %s
 ; CHECK-NOT: DICompileUnit{{.*}} enums:
 ; CHECK-NOT: DICompileUnit{{.*}} macros:
 ; CHECK-NOT: DICompileUnit{{.*}} retainedTypes:
 ; CHECK-NOT: DICompileUnit{{.*}} globals:
-; CHECK: DICompileUnit{{.*}} imports: ![[IMP:[0-9]+]]
-; CHECK: ![[IMP]] = !{!{{[0-9]+}}}
+; CHECK-NOT: DICompileUnit{{.*}} imports:
 
 ; ModuleID = 'debuginfo-cu-import.c'
 source_filename = "debuginfo-cu-import.c"
@@ -50,14 +48,14 @@ entry:
 !8 = !{!9}
 !9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression())
 !10 = !DIGlobalVariable(name: "version", scope: !4, file: !1, line: 2, type: !7, isLocal: false, isDefinition: true)
-!11 = !{!12, !16}
+!11 = !{!12}
 !12 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !13, file: !1, line: 8)
 !13 = distinct !DISubprogram(name: "a", linkageName: "_ZN1A1aEv", scope: !4, file: !1, line: 7, type: !14, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !5)
 !14 = !DISubroutineType(types: !15)
 !15 = !{null}
 !16 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !17, entity: !19, file: !1, line: 8)
 !17 = distinct !DILexicalBlock(scope: !18, file: !1, line: 9, column: 8)
-!18 = distinct !DISubprogram(name: "c", linkageName: "_ZN1A1cEv", scope: !4, file: !1, line: 9, type: !14, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !5)
+!18 = distinct !DISubprogram(name: "c", linkageName: "_ZN1A1cEv", scope: !4, file: !1, line: 9, type: !14, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !33)
 !19 = distinct !DILexicalBlock(scope: !20, file: !1, line: 10, column: 8)
 !20 = distinct !DISubprogram(name: "d", linkageName: "_ZN1A1dEv", scope: !4, file: !1, line: 10, type: !14, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !5)
 !21 = !{!22}
@@ -72,4 +70,4 @@ entry:
 !30 = !DILocation(line: 7, column: 12, scope: !13)
 !31 = distinct !DISubprogram(name: "b", linkageName: "_ZN1A1bEv", scope: !4, file: !1, line: 8, type: !14, isLocal: true, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !5)
 !32 = !DILocation(line: 8, column: 24, scope: !31)
-
+!33 = !{!16}


        


More information about the cfe-commits mailing list