[llvm] [llvm-debuginfo-analyzer] Add support for LLVM IR format. (PR #135440)

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 13 04:06:03 PST 2026


https://github.com/CarlosAlbertoEnciso updated https://github.com/llvm/llvm-project/pull/135440

>From 2ace506037a291ef18e6cc4225811b0d785be527 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Fri, 11 Apr 2025 21:52:56 +0100
Subject: [PATCH 01/13] [llvm-debuginfo-analyzer] Add support for LLVM IR
 format.

Add support for the LLVM IR format and be able to generate
logical views.

Both textual representation (.ll) and bitcode (.bc) format
are supported.

Note: This patch requires:

  Add DebugSSAUpdater class to track debug value liveness
  https://github.com/llvm/llvm-project/pull/135349
---
 .../CommandGuide/llvm-debuginfo-analyzer.rst  |  169 +-
 .../DebugInfo/LogicalView/Core/LVSupport.h    |   13 +
 .../DebugInfo/LogicalView/LVReaderHandler.h   |   12 +-
 .../LogicalView/Readers/LVBinaryReader.h      |    1 +
 .../LogicalView/Readers/LVIRReader.h          |  300 +++
 llvm/lib/DebugInfo/LogicalView/CMakeLists.txt |    2 +
 .../DebugInfo/LogicalView/Core/LVElement.cpp  |   12 +-
 .../DebugInfo/LogicalView/Core/LVReader.cpp   |   27 +
 .../DebugInfo/LogicalView/LVReaderHandler.cpp |   45 +-
 .../LogicalView/Readers/LVDWARFReader.cpp     |   10 +-
 .../LogicalView/Readers/LVIRReader.cpp        | 2348 +++++++++++++++++
 .../IR/01-ir-compare-logical-elements.test    |  121 +
 .../IR/01-ir-print-basic-details.test         |   76 +
 .../IR/01-ir-select-logical-elements.test     |  122 +
 .../IR/02-ir-logical-lines.test               |   60 +
 ...03-ir-incorrect-lexical-scope-typedef.test |  131 +
 .../IR/04-ir-missing-nested-enumerators.test  |  144 +
 ...5-ir-incorrect-lexical-scope-variable.test |  113 +
 .../IR/06-ir-full-logical-view.test           |  118 +
 .../IR/07-ir-debug-formats.test               |   48 +
 .../IR/Inputs/hello-world-clang.ll            |   49 +
 .../IR/Inputs/pr-43860-clang.ll               |   92 +
 .../IR/Inputs/pr-44884-clang.ll               |   98 +
 .../IR/Inputs/pr-46466-clang.ll               |   44 +
 .../IR/Inputs/test-clang-intrinsics.ll        |   87 +
 .../IR/Inputs/test-clang.ll                   |   83 +
 .../llvm-debuginfo-analyzer/CMakeLists.txt    |    2 +
 .../DebugInfo/LogicalView/CMakeLists.txt      |    3 +
 .../DebugInfo/LogicalView/IRReaderTest.cpp    |  355 +++
 .../DebugInfo/LogicalView/Inputs/README.md    |   11 +
 .../LogicalView/Inputs/test-clang.bc          |  Bin 0 -> 3260 bytes
 .../LogicalView/Inputs/test-clang.ll          |   83 +
 32 files changed, 4756 insertions(+), 23 deletions(-)
 create mode 100644 llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
 create mode 100644 llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/hello-world-clang.ll
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-43860-clang.ll
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-44884-clang.ll
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-46466-clang.ll
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang-intrinsics.ll
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang.ll
 create mode 100644 llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
 create mode 100644 llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.bc
 create mode 100644 llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.ll

diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index 6fcf8423e8125..3d1b971d31db6 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -13,10 +13,11 @@ SYNOPSIS
 DESCRIPTION
 -----------
 :program:`llvm-debuginfo-analyzer` parses debug and text sections in
-binary object files and prints their contents in a logical view, which
-is a human-readable representation that closely matches the structure
-of the original user source code. Supported object file formats include
-ELF, Mach-O, WebAssembly, PDB and COFF.
+binary object files and textual IR representations and prints their
+contents in a logical view, which is a human readable representation
+that closely matches the structure of the original user source code.
+Supported object file formats include ELF, Mach-O, WebAssembly, PDB,
+COFF, IR (textual representation and bitcode).
 
 The **logical view** abstracts the complexity associated with the
 different low-level representations of the debugging information that
@@ -2131,6 +2132,138 @@ layout and given the number of matches.
   -----------------------------
   Total           71          8
 
+IR (Textual representation and bitcode) SUPPORT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The below example is used to show the IR output generated by
+:program:`llvm-debuginfo-analyzer`. We compiled the example for a
+IR 64-bit target with Clang (-O0 -g --target=x86_64-linux):
+
+.. code-block:: c++
+
+  1  using INTPTR = const int *;
+  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+  3    if (ParamBool) {
+  4      typedef int INTEGER;
+  5      const INTEGER CONSTANT = 7;
+  6      return CONSTANT;
+  7    }
+  8    return ParamUnsigned;
+  9  }
+
+PRINT BASIC DETAILS
+^^^^^^^^^^^^^^^^^^^
+The following command prints basic details for all the logical elements
+sorted by the debug information internal offset; it includes its lexical
+level and debug info format.
+
+.. code-block:: none
+
+  llvm-debuginfo-analyzer --attribute=level,format
+                          --output-sort=offset
+                          --print=scopes,symbols,types,lines,instructions
+                          test-clang.ll
+
+or
+
+.. code-block:: none
+
+  llvm-debuginfo-analyzer --attribute=level,format
+                          --output-sort=offset
+                          --print=elements
+                          test-clang.ll
+
+Each row represents an element that is present within the debug
+information. The first column represents the scope level, followed by
+the associated line number (if any), and finally the description of
+the element.
+
+.. code-block:: none
+
+  Logical View:
+  [000]           {File} 'test-clang.ll' -> Textual IR
+
+  [001]             {CompileUnit} 'test.cpp'
+  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+  [003]                 {Block}
+  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+  [004]     5             {Line}
+  [004]                   {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
+  [004]     6             {Line}
+  [004]                   {Code} 'store i32 7, ptr %retval, align 4, !dbg !33'
+  [004]     6             {Line}
+  [004]                   {Code} 'br label %return, !dbg !33'
+  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+  [003]     2           {Parameter} 'ParamBool' -> 'bool'
+  [003]     4           {TypeAlias} 'INTEGER' -> 'int'
+  [003]     2           {Line}
+  [003]                 {Code} '%retval = alloca i32, align 4'
+  [003]                 {Code} '%ParamPtr.addr = alloca ptr, align 8'
+  [003]                 {Code} '%ParamUnsigned.addr = alloca i32, align 4'
+  [003]                 {Code} '%ParamBool.addr = alloca i8, align 1'
+  [003]                 {Code} '%CONSTANT = alloca i32, align 4'
+  [003]                 {Code} 'store ptr %ParamPtr, ptr %ParamPtr.addr, align 8'
+  [003]                 {Code} 'store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4'
+  [003]                 {Code} '%storedv = zext i1 %ParamBool to i8'
+  [003]                 {Code} 'store i8 %storedv, ptr %ParamBool.addr, align 1'
+  [003]     8           {Line}
+  [003]                 {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34'
+  [003]     8           {Line}
+  [003]                 {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35'
+  [003]     8           {Line}
+  [003]                 {Code} 'br label %return, !dbg !35'
+  [003]     9           {Line}
+  [003]                 {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36'
+  [003]     9           {Line}
+  [003]                 {Code} 'ret i32 %2, !dbg !36'
+  [003]     3           {Line}
+  [003]     3           {Line}
+  [003]     3           {Line}
+  [003]                 {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
+  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+
+SELECT LOGICAL ELEMENTS
+^^^^^^^^^^^^^^^^^^^^^^^
+The following prints all *instructions*, *symbols* and *types* that
+contain **'block'** or **'.store'** in their names or types, using a tab
+layout and given the number of matches.
+
+.. code-block:: none
+
+  llvm-debuginfo-analyzer --attribute=level
+                          --select-nocase --select-regex
+                          --select=LOAD --select=store
+                          --report=list
+                          --print=symbols,types,instructions,summary
+                          test-clang.ll
+
+  Logical View:
+  [000]           {File} 'test-clang.ll'
+
+  [001]           {CompileUnit} 'test.cpp'
+  [003]           {Code} '%0 = load i8, ptr %ParamBool.addr, align 1, !dbg !26'
+  [003]           {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34'
+  [003]           {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36'
+  [004]           {Code} '%loadedv = trunc i8 %0 to i1, !dbg !26'
+  [003]           {Code} '%storedv = zext i1 %ParamBool to i8'
+  [003]           {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
+  [003]           {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35'
+  [003]           {Code} 'store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4'
+  [004]           {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
+  [004]           {Code} 'store i32 7, ptr %retval, align 4, !dbg !33'
+  [003]           {Code} 'store i8 %storedv, ptr %ParamBool.addr, align 1'
+  [003]           {Code} 'store ptr %ParamPtr, ptr %ParamPtr.addr, align 8'
+
+  -----------------------------
+  Element      Total    Printed
+  -----------------------------
+  Scopes           5          0
+  Symbols          4          0
+  Types            2          0
+  Lines           22         12
+  -----------------------------
+  Total           33         12
+
 COMPARISON MODE
 ^^^^^^^^^^^^^^^
 Given the previous example we found the above debug information issue
@@ -2204,6 +2337,34 @@ giving more context by swapping the reference and target object files.
 The output shows the merging view path (reference and target) with the
 missing and added elements.
 
+.. code-block:: none
+
+  llvm-debuginfo-analyzer --attribute=level,format
+                          --compare=types
+                          --report=view
+                          --print=symbols,types
+                          test-clang.bc test-dwarf-gcc.o
+
+  Reference: 'test-clang.bc'
+  Target:    'test-dwarf-gcc.o'
+
+  Logical View:
+   [000]           {File} 'test-clang.bc' -> Bitcode IR
+
+   [001]             {CompileUnit} 'test.cpp'
+   [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+   [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+   [003]                 {Block}
+   [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+  +[004]     4             {TypeAlias} 'INTEGER' -> 'int'
+   [003]     2           {Parameter} 'ParamBool' -> 'bool'
+   [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+   [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+  -[003]     4           {TypeAlias} 'INTEGER' -> 'int'
+
+The same output but this time comparing the Clang bitcode with the
+binary object (DWARF) generated by GCC.
+
 LOGICAL ELEMENTS
 """"""""""""""""
 It compares individual logical elements without considering if their
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
index 058ca2da9a960..bd1b7238f6137 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -119,6 +119,19 @@ template <typename T> class LVProperties {
 #define KIND_3(ENUM, FIELD, F1, F2, F3)                                        \
   BOOL_BIT_3(Kinds, ENUM, FIELD, F1, F2, F3)
 
+const int DEC_WIDTH = 8;
+inline FormattedNumber decValue(uint64_t N, unsigned Width = DEC_WIDTH) {
+  return format_decimal(N, Width);
+}
+
+// Output the decimal representation of 'Value'.
+inline std::string decString(uint64_t Value, size_t Width = DEC_WIDTH) {
+  std::string String;
+  raw_string_ostream Stream(String);
+  Stream << decValue(Value, Width);
+  return Stream.str();
+}
+
 const int HEX_WIDTH = 12;
 inline FormattedNumber hexValue(uint64_t N, unsigned Width = HEX_WIDTH,
                                 bool Upper = false) {
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
index f6dc65f39c7ac..fc2b89b2ef421 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
@@ -17,6 +17,7 @@
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/Object/Archive.h"
+#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Compiler.h"
@@ -30,7 +31,9 @@ namespace logicalview {
 
 using LVReaders = std::vector<std::unique_ptr<LVReader>>;
 using ArgVector = std::vector<std::string>;
-using PdbOrObj = PointerUnion<object::ObjectFile *, pdb::PDBFile *>;
+using PdbOrObjOrIr =
+    PointerUnion<object::ObjectFile *, pdb::PDBFile *, object::IRObjectFile *,
+                 MemoryBufferRef *, StringRef *>;
 
 // This class performs the following tasks:
 // - Creates a logical reader for every binary file in the command line,
@@ -61,9 +64,12 @@ class LVReaderHandler {
                      object::Binary &Binary);
   Error handleObject(LVReaders &Readers, StringRef Filename, StringRef Buffer,
                      StringRef ExePath);
+  Error handleObject(LVReaders &Readers, StringRef Filename,
+                     MemoryBufferRef Buffer);
 
-  Error createReader(StringRef Filename, LVReaders &Readers, PdbOrObj &Input,
-                     StringRef FileFormatName, StringRef ExePath = {});
+  Error createReader(StringRef Filename, LVReaders &Readers,
+                     PdbOrObjOrIr &Input, StringRef FileFormatName,
+                     StringRef ExePath = {});
 
 public:
   LVReaderHandler() = delete;
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
index cc8dda2f82bee..f4c1245cfb801 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
@@ -25,6 +25,7 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Object/COFF.h"
+#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/ObjectFile.h"
 
 namespace llvm {
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
new file mode 100644
index 0000000000000..5c70ec9077791
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
@@ -0,0 +1,300 @@
+//===-- LVIRReader.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the LVIRReader class, which is used to describe a
+// LLVM IR reader.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVIRREADER_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVIRREADER_H
+
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/Transforms/Utils/DebugSSAUpdater.h"
+
+namespace llvm {
+class DIFile;
+class DINode;
+class DILocation;
+class DIScope;
+class DISubprogram;
+class DIVariable;
+class BasicBlock;
+
+namespace object {
+class IRObjectFile;
+}
+
+namespace logicalview {
+
+class LVElement;
+class LVLine;
+class LVScopeCompileUnit;
+class LVSymbol;
+class LVType;
+
+class LVIRReader final : public LVReader {
+  object::IRObjectFile *BitCodeIR = nullptr;
+  MemoryBufferRef *TextualIR = nullptr;
+
+  // Symbols with locations for current compile unit.
+  LVSymbols SymbolsWithLocations;
+
+  LVSectionIndex SectionIndex = 0;
+
+  const DICompileUnit *CUNode = nullptr;
+
+  // The Dwarf Version (from the module flags).
+  unsigned DwarfVersion;
+
+  // Location index for global variables.
+  uint64_t PoolAddressIndex = 0;
+
+  // Whether to emit all linkage names, or just abstract subprograms.
+  bool UseAllLinkageNames = true;
+
+  // Dependencies on external options (llc, etc).
+  bool includeMinimalInlineScopes() const;
+  bool useAllLinkageNames() const { return UseAllLinkageNames; }
+
+  bool LanguageIsFortran = false;
+  void mapFortranLanguage(unsigned DWLang);
+  bool moduleIsInFortran() const { return LanguageIsFortran; }
+
+  // Generate logical debug line before prologue.
+  bool GenerateLineBeforePrologue = true;
+
+  // We assume a constante increase between instructions.
+  const unsigned OffsetIncrease = 4;
+  void updateLineOffset() { CurrentOffset += OffsetIncrease; }
+
+  // An anonymous type for index type.
+  LVType *NodeIndexType = nullptr;
+
+  std::unique_ptr<DbgValueRangeTable> DbgValueRanges;
+
+  // Record the last assigned file index for each compile unit.
+  using LVIndexFiles = std::map<LVScopeCompileUnit *, size_t>;
+  LVIndexFiles IndexFiles;
+
+  void updateFileIndex(LVScopeCompileUnit *CompileUnit, size_t FileIndex) {
+    LVIndexFiles::iterator Iter = IndexFiles.find(CompileUnit);
+    if (Iter == IndexFiles.end())
+      IndexFiles.emplace(CompileUnit, FileIndex);
+    else
+      Iter->second = FileIndex;
+  }
+
+  // Get the current assigned index file for the given compile unit.
+  size_t getFileIndex(LVScopeCompileUnit *CompileUnit) {
+    size_t FileIndex = 0;
+    LVIndexFiles::iterator Iter = IndexFiles.find(CompileUnit);
+    if (Iter != IndexFiles.end())
+      FileIndex = Iter->second;
+    return FileIndex;
+  }
+
+  // Collect the compile unit metadata files.
+  using LVCompileUnitFiles = std::map<const DIFile *, size_t>;
+  LVCompileUnitFiles CompileUnitFiles;
+
+  size_t getOrCreateSourceID(const DIFile *File);
+
+  // Associate the logical elements to metadata objects.
+  using LVMDObjects = std::map<const MDNode *, LVElement *>;
+  LVMDObjects MDObjects;
+
+  void addMD(const MDNode *MD, LVElement *Element) {
+    if (MDObjects.find(MD) == MDObjects.end())
+      MDObjects.emplace(MD, Element);
+  }
+  LVElement *getElementForSeenMD(const MDNode *MD) const {
+    LVMDObjects::const_iterator Iter = MDObjects.find(MD);
+    return Iter != MDObjects.end() ? Iter->second : nullptr;
+  }
+  LVScope *getScopeForSeenMD(const MDNode *MD) const {
+    return static_cast<LVScope *>(getElementForSeenMD(MD));
+  }
+  LVSymbol *getSymbolForSeenMD(const MDNode *MD) const {
+    return static_cast<LVSymbol *>(getElementForSeenMD(MD));
+  }
+  LVType *getTypeForSeenMD(const MDNode *MD) const {
+    return static_cast<LVType *>(getElementForSeenMD(MD));
+  }
+  LVType *getLineForSeenMD(const MDNode *MD) const {
+    return static_cast<LVType *>(getElementForSeenMD(MD));
+  }
+
+  // Inlined concrete scopes with its associated inlined abstract scopes.
+  // When creating abstract scopes, there is no direct information to find
+  // the correct lexical scope.
+  using LVInlinedScopes = std::map<LVScope *, LVScope *>;
+  LVInlinedScopes InlinedScopes;
+
+  void addInlinedScope(LVScope *ConcreteScope, LVScope *AbstractScope) {
+    if (InlinedScopes.find(ConcreteScope) == InlinedScopes.end())
+      InlinedScopes.emplace(ConcreteScope, AbstractScope);
+  }
+  LVScope *getInlinedScope(LVScope *ConcreteScope) const {
+    LVInlinedScopes::const_iterator Iter = InlinedScopes.find(ConcreteScope);
+    return Iter != InlinedScopes.end() ? Iter->second : nullptr;
+  }
+
+  const DIFile *getMDFile(const MDNode *MD) const;
+  StringRef getMDName(const DINode *DN) const;
+  const DIScope *getMDScope(const DINode *DN) const;
+
+  LVType *getIndexType();
+
+  const DICompileUnit *getCUNode() const { return CUNode; }
+
+  LVScope *getParentScopeImpl(const DIScope *Context);
+  LVScope *getParentScope(const DINode *DN);
+  LVScope *getParentScope(const DILocation *DL);
+  LVScope *traverseParentScope(const DIScope *Context);
+
+  void constructRange(LVScope *Scope, LVAddress LowPC, LVAddress HighPC);
+  void constructRange(LVScope *Scope);
+
+  void processBasicBlocks(Function &F, const DISubprogram *SP);
+
+  void addGlobalName(StringRef Name, LVElement *Element,
+                     const DIScope *Context);
+
+  void addAccess(LVElement *Element, DINode::DIFlags Flags);
+
+  void addConstantValue(LVElement *Element, const DIExpression *DIExpr);
+  void addConstantValue(LVElement *Element, const ConstantInt *CI,
+                        const DIType *Ty);
+  void addConstantValue(LVElement *Element, const APInt &Value,
+                        const DIType *Ty);
+  void addConstantValue(LVElement *Element, const APInt &Value, bool Unsigned);
+  void addConstantValue(LVElement *Element, uint64_t Value, const DIType *Ty);
+  void addConstantValue(LVElement *Element, bool Unsigned, uint64_t Value);
+
+  void addString(LVElement *Element, StringRef Str);
+
+  void addTemplateParams(LVElement *Element, const DINodeArray TParams);
+
+  // Add location information to specified logical element.
+  void addSourceLine(LVElement *Element, unsigned Line, const DIFile *File);
+  void addSourceLine(LVElement *Element, const DIGlobalVariable *GV);
+  void addSourceLine(LVElement *Element, const DIImportedEntity *IE);
+  void addSourceLine(LVElement *Element, const DILabel *L);
+  void addSourceLine(LVElement *Element, const DILocalVariable *LV);
+  void addSourceLine(LVElement *Element, const DILocation *DL);
+  void addSourceLine(LVElement *Element, const DIObjCProperty *Ty);
+  void addSourceLine(LVElement *Element, const DISubprogram *SP);
+  void addSourceLine(LVElement *Element, const DIType *Ty);
+
+  void applySubprogramAttributes(LVScope *Function, const DISubprogram *SP,
+                                 bool SkipSPAttributes = false);
+  bool applySubprogramDefinitionAttributes(LVScope *Function,
+                                           const DISubprogram *SP,
+                                           bool Minimal = false);
+  void applySubprogramAttributesToDefinition(LVScope *Function,
+                                             const DISubprogram *SP);
+
+  void constructAggregate(LVScopeAggregate *Aggregate,
+                          const DICompositeType *CTy);
+  void constructArray(LVScopeArray *Array, const DICompositeType *CTy);
+  void constructEnum(LVScopeEnumeration *Enumeration,
+                     const DICompositeType *CTy);
+  void constructGenericSubrange(LVScopeArray *Array,
+                                const DIGenericSubrange *GSR,
+                                LVType *IndexType);
+  void constructImportedEntity(LVElement *Element, const DIImportedEntity *IE);
+
+  void constructLine(LVScope *Scope, const DISubprogram *SP, Instruction &I);
+
+  LVSymbol *getOrCreateMember(LVScope *Aggregate, const DIDerivedType *DT);
+  LVSymbol *getOrCreateStaticMember(LVScope *Aggregate,
+                                    const DIDerivedType *DT);
+
+  LVScope *getOrCreateNamespace(const DINamespace *NS);
+  LVScope *getOrCreateScope(const DIScope *Context);
+  void constructScope(LVElement *Element, const DIScope *Context);
+
+  LVScope *getOrCreateSubprogram(const DISubprogram *SP, bool Minimal = false);
+  LVScope *getOrCreateSubprogram(LVScope *Function, const DISubprogram *SP,
+                                 bool Minimal = false);
+  void constructSubprogramArguments(LVScope *Function,
+                                    const DITypeRefArray Args);
+
+  LVScope *getOrCreateInlinedScope(LVScope *Parent, const DILocation *DL);
+  LVScope *getOrCreateAbstractScope(LVScope *OriginScope, const DILocation *DL);
+
+  void constructSubrange(LVScopeArray *Array, const DISubrange *GSR,
+                         LVType *IndexType);
+
+  void constructTemplateTypeParameter(LVElement *Element,
+                                      const DITemplateTypeParameter *TTP);
+  void constructTemplateValueParameter(LVElement *Element,
+                                       const DITemplateValueParameter *TVP);
+
+  LVElement *getOrCreateType(const DIType *Ty, LVScope *Scope = nullptr);
+  void constructType(LVScope *Scope, const DICompositeType *CTy);
+  void constructType(LVElement *Element, const DIDerivedType *DT);
+  void constructType(LVScope *Function, const DISubroutineType *SPTy);
+
+  LVSymbol *getOrCreateVariable(const DIGlobalVariableExpression *GVE);
+  LVSymbol *getOrCreateVariable(const DIVariable *Var,
+                                const DILocation *DL = nullptr);
+  LVSymbol *getOrCreateAbstractVariable(LVSymbol *OriginSymbol,
+                                        const DILocation *DL);
+
+  LVElement *constructElement(const DINode *DN);
+
+  void removeEmptyScopes();
+  void processLocationGaps();
+  void processScopes();
+
+  // These functions are only for development.
+  void checkScopes(LVScope *Scope);
+
+protected:
+  Error createScopes() override;
+  void sortScopes() override;
+
+public:
+  LVIRReader() = delete;
+  LVIRReader(StringRef Filename, StringRef FileFormatName,
+             object::IRObjectFile *Obj, ScopedPrinter &W)
+      : LVReader(Filename, FileFormatName, W, LVBinaryType::ELF),
+        BitCodeIR(Obj), DbgValueRanges(new DbgValueRangeTable()) {}
+  LVIRReader(StringRef Filename, StringRef FileFormatName, MemoryBufferRef *Obj,
+             ScopedPrinter &W)
+      : LVReader(Filename, FileFormatName, W, LVBinaryType::ELF),
+        TextualIR(Obj), DbgValueRanges(new DbgValueRangeTable()) {}
+  LVIRReader(const LVIRReader &) = delete;
+  LVIRReader &operator=(const LVIRReader &) = delete;
+  ~LVIRReader() = default;
+
+  const LVSymbols &GetSymbolsWithLocations() const {
+    return SymbolsWithLocations;
+  }
+
+  std::string getRegisterName(LVSmall Opcode,
+                              ArrayRef<uint64_t> Operands) override;
+
+  void print(raw_ostream &OS) const;
+#ifdef LLVM_DEBUG
+  void printAllInstructions(BasicBlock *BB);
+#else
+#define printAllInstructions(...) (void *)0
+#endif
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const { print(dbgs()); }
+#endif
+};
+
+} // end namespace logicalview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVIRREADER_H
diff --git a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
index 462857ef93063..0ad95dc05c12e 100644
--- a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
@@ -26,6 +26,7 @@ add_lv_impl_folder(Readers
   Readers/LVCodeViewReader.cpp
   Readers/LVCodeViewVisitor.cpp
   Readers/LVDWARFReader.cpp
+  Readers/LVIRReader.cpp
   )
 
 list(APPEND LIBLV_ADDITIONAL_HEADER_DIRS
@@ -41,6 +42,7 @@ add_llvm_component_library(LLVMDebugInfoLogicalView
   ${LIBLV_ADDITIONAL_HEADER_DIRS}
 
   LINK_COMPONENTS
+  AsmPrinter
   BinaryFormat
   Demangle
   Object
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
index c6fb405baed1d..b61907c7bc3d3 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -555,10 +555,14 @@ void LVElement::printLinkageName(raw_ostream &OS, bool Full,
 void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
                                  LVScope *Scope) const {
   if (options().getPrintFormatting() && options().getAttributeLinkage()) {
-    LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
-    std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) +
-                        Twine(" '") + Twine(getLinkageName()) + Twine("'"))
-                           .str();
+    // Include the section index only if '--attribute=offset', as the
+    // index can be different depending on the specific reader.
+    std::string Section;
+    if (options().getAttributeOffset()) {
+      LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
+      Section = (Twine(" 0x" + Twine::utohexstr(SectionIndex) + " ")).str();
+    }
+    std::string Text = (Twine(Section + "'" + getLinkageName() + "'")).str();
     printAttributes(OS, Full, "{Linkage} ", Parent, Text,
                     /*UseQuotes=*/false, /*PrintRef=*/false);
   }
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
index d973a47f68732..de2c2bb502800 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
@@ -22,6 +22,30 @@ using namespace llvm::logicalview;
 
 #define DEBUG_TYPE "Reader"
 
+// Traverse all the logical elements and print its basic information.
+void printCollectedElements(LVScope *Root) {
+  std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) {
+    // Print the elements.
+    auto Print = [&](const auto &Set) {
+      if (Set)
+        for (const auto &Entry : *Set)
+          Entry->print(dbgs());
+    };
+
+    Print(Parent->getChildren());
+    Print(Parent->getLines());
+    Print(Parent->getRanges());
+    if (const LVScopes *Scopes = Parent->getScopes())
+      for (LVScope *Scope : *Scopes)
+        TraverseScope(Scope);
+  };
+
+  // Start traversing the scopes root.
+  dbgs() << "\n** Collected logical elements **\n";
+  Root->print(dbgs());
+  TraverseScope(Root);
+}
+
 // Detect elements that are inserted more than once at different scopes,
 // causing a crash on the reader destruction, as the element is already
 // deleted from other scope. Helper for CodeView reader.
@@ -61,6 +85,9 @@ bool checkIntegrityScopesTree(LVScope *Root) {
     Traverse(Parent->getLines());
   };
 
+  // Print collected elements.
+  printCollectedElements(Root);
+
   // Start traversing the scopes root and print any duplicates.
   TraverseScope(Root);
   bool PassIntegrity = true;
diff --git a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
index 69513f2b9882c..a1721a3a8e624 100644
--- a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
@@ -14,8 +14,10 @@
 #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
 #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h"
 #include "llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h"
+#include "llvm/DebugInfo/LogicalView/Readers/LVIRReader.h"
 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
 #include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/Object/COFF.h"
 
 using namespace llvm;
@@ -25,6 +27,8 @@ using namespace llvm::logicalview;
 
 #define DEBUG_TYPE "ReaderHandler"
 
+static const StringRef IRFileFormat = "Textual IR";
+
 Error LVReaderHandler::process() {
   if (Error Err = createReaders())
     return Err;
@@ -37,7 +41,8 @@ Error LVReaderHandler::process() {
 }
 
 Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
-                                    PdbOrObj &Input, StringRef FileFormatName,
+                                    PdbOrObjOrIr &Input,
+                                    StringRef FileFormatName,
                                     StringRef ExePath) {
   auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> {
     if (isa<ObjectFile *>(Input)) {
@@ -56,6 +61,17 @@ Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
       return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, Pdb,
                                                 W, ExePath);
     }
+    if (isa<IRObjectFile *>(Input)) {
+      IRObjectFile *Ir = cast<IRObjectFile *>(Input);
+      return std::make_unique<LVIRReader>(Filename, FileFormatName, Ir, W);
+    }
+    if (isa<MemoryBufferRef *>(Input)) {
+      // If the filename extension is '.ll' create a IR reader.
+      const StringRef IRFileExt = ".ll";
+      MemoryBufferRef *MemBuf = cast<MemoryBufferRef *>(Input);
+      if (llvm::sys::path::extension(Filename) == IRFileExt)
+        return std::make_unique<LVIRReader>(Filename, IRFileFormat, MemBuf, W);
+    }
     return nullptr;
   };
 
@@ -190,11 +206,11 @@ Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,
     return handleFile(Readers, PdbPath.get(), Filename);
   }
 
-  Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer);
+  LLVMContext Context;
+  Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer, &Context);
   if (errorToErrorCode(BinOrErr.takeError())) {
-    return createStringError(errc::not_supported,
-                             "Binary object format in '%s' is not supported.",
-                             Filename.str().c_str());
+    // Assume it is textual representation (IR or C/C++ source code).
+    return handleObject(Readers, Filename, Buffer);
   }
   return handleObject(Readers, Filename, *BinOrErr.get());
 }
@@ -224,7 +240,7 @@ Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
     if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =
             ObjForArch.getAsObjectFile()) {
       MachOObjectFile &Obj = **MachOOrErr;
-      PdbOrObj Input = &Obj;
+      PdbOrObjOrIr Input = &Obj;
       if (Error Err =
               createReader(Filename, Readers, Input, Obj.getFileFormatName()))
         return Err;
@@ -244,7 +260,7 @@ Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
 
 Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
                                     Binary &Binary) {
-  if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary))
+  if (PdbOrObjOrIr Input = dyn_cast<ObjectFile>(&Binary))
     return createReader(Filename, Readers, Input,
                         cast<ObjectFile *>(Input)->getFileFormatName());
 
@@ -254,6 +270,9 @@ Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
   if (Archive *Arch = dyn_cast<Archive>(&Binary))
     return handleArchive(Readers, Filename, *Arch);
 
+  if (PdbOrObjOrIr Input = dyn_cast<IRObjectFile>(&Binary))
+    return createReader(Filename, Readers, Input, "Bitcode IR");
+
   return createStringError(errc::not_supported,
                            "Binary object format in '%s' is not supported.",
                            Filename.str().c_str());
@@ -268,7 +287,7 @@ Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
 
   std::unique_ptr<NativeSession> PdbSession;
   PdbSession.reset(static_cast<NativeSession *>(Session.release()));
-  PdbOrObj Input = &PdbSession->getPDBFile();
+  PdbOrObjOrIr Input = &PdbSession->getPDBFile();
   StringRef FileFormatName;
   size_t Pos = Buffer.find_first_of("\r\n");
   if (Pos)
@@ -276,6 +295,16 @@ Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
   return createReader(Filename, Readers, Input, FileFormatName, ExePath);
 }
 
+Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
+                                    MemoryBufferRef Buffer) {
+  if (PdbOrObjOrIr Input = dyn_cast<MemoryBufferRef>(&Buffer))
+    return createReader(Filename, Readers, Input, IRFileFormat);
+
+  return createStringError(errc::not_supported,
+                           "Binary object format in '%s' is not supported.",
+                           Filename.str().c_str());
+}
+
 Error LVReaderHandler::createReaders() {
   LLVM_DEBUG(dbgs() << "createReaders\n");
   for (std::string &Object : Objects) {
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
index 772d821dcda81..2a1dd08b6bc58 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
@@ -528,14 +528,16 @@ void LVDWARFReader::createLineAndFileRecords(
     for (const DWARFDebugLine::FileNameEntry &Entry :
          Lines->Prologue.FileNames) {
       std::string Directory;
-      if (Lines->getDirectoryForEntry(Entry, Directory))
-        Directory = transformPath(Directory);
+      Lines->getDirectoryForEntry(Entry, Directory);
       if (Directory.empty())
         Directory = std::string(CompileUnit->getCompilationDirectory());
-      std::string File = transformPath(dwarf::toStringRef(Entry.Name));
+      // Take just the filename component, as it may be contain the full
+      // path that would be added to the already existing path in Directory.
+      StringRef File =
+          llvm::sys::path::filename(dwarf::toStringRef(Entry.Name));
       std::string String;
       raw_string_ostream(String) << Directory << "/" << File;
-      CompileUnit->addFilename(String);
+      CompileUnit->addFilename(transformPath(String));
     }
 
   // In DWARF5 the file indexes start at 0;
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
new file mode 100644
index 0000000000000..d8a9a18afce90
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -0,0 +1,2348 @@
+//===-- LVIRReader.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This implements the LVIRReader class.
+// It supports LLVM text IR and bitcode format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Readers/LVIRReader.h"
+#include "llvm/CodeGen/DebugHandlerBase.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/SourceMgr.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "IRReader"
+
+// Extra debug traces. Default is false
+#define DEBUG_ALL
+
+// These flavours of DINodes are not handled:
+//   DW_TAG_APPLE_property   = 19896
+//   DW_TAG_atomic_type      = 71
+//   DW_TAG_common_block     = 26
+//   DW_TAG_file_type        = 41
+//   DW_TAG_friend           = 42
+//   DW_TAG_generic_subrange = 69
+//   DW_TAG_immutable_type   = 75
+//   DW_TAG_module           = 30
+
+// Create a logical element and setup the following information:
+// - Name, DWARF tag, line
+// - Collect any file information
+LVElement *LVIRReader::constructElement(const DINode *DN) {
+  dwarf::Tag Tag = DN->getTag();
+  LVElement *Element = createElement(Tag);
+  if (Element) {
+    Element->setTag(Tag);
+    addMD(DN, Element);
+
+    StringRef Name = getMDName(DN);
+    if (!Name.empty())
+      Element->setName(Name);
+
+    // Record any file information.
+    if (const DIFile *File = getMDFile(DN))
+      getOrCreateSourceID(File);
+  }
+
+  return Element;
+}
+
+void LVIRReader::mapFortranLanguage(unsigned DWLang) {
+  switch (DWLang) {
+  case dwarf::DW_LANG_Fortran77:
+  case dwarf::DW_LANG_Fortran90:
+  case dwarf::DW_LANG_Fortran95:
+  case dwarf::DW_LANG_Fortran03:
+  case dwarf::DW_LANG_Fortran08:
+  case dwarf::DW_LANG_Fortran18:
+    LanguageIsFortran = true;
+    break;
+  default:
+    LanguageIsFortran = false;
+  }
+}
+
+// Looking at IR generated with the '-gdwarf -gsplit-dwarf=split' the only
+// difference is setting the 'DICompileUnit::splitDebugFilename' to the
+// name of the split filename: "xxx.dwo".
+bool LVIRReader::includeMinimalInlineScopes() const {
+  return getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly;
+}
+
+// For the given 'DIFile' generate an index 1-based to indicate the
+// source file where the logical element is declared.
+// In DWARF v4, the files are 1-indexed.
+// In DWARF v5, the files are 0-indexed.
+// The IR reader expects the indexes as 1-indexed.
+// Each compile unit, keeps track of the last assigned index.
+size_t LVIRReader::getOrCreateSourceID(const DIFile *File) {
+  if (!File)
+    return 0;
+
+#ifdef DEBUG_ALL
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateSourceID] DIFile\n";
+    File->dump();
+  });
+#endif
+
+  addMD(File, CompileUnit);
+
+  LLVM_DEBUG({
+    dbgs() << "Directory: '" << File->getDirectory() << "'\n";
+    dbgs() << "Filename:  '" << File->getFilename() << "'\n";
+  });
+  size_t FileIndex = 0;
+  LVCompileUnitFiles::iterator Iter = CompileUnitFiles.find(File);
+  if (Iter == CompileUnitFiles.cend()) {
+    FileIndex = getFileIndex(CompileUnit);
+    std::string Directory(File->getDirectory());
+    if (Directory.empty())
+      Directory = std::string(CompileUnit->getCompilationDirectory());
+
+    std::string FullName;
+    raw_string_ostream Out(FullName);
+    Out << Directory << "/" << llvm::sys::path::filename(File->getFilename());
+    CompileUnit->addFilename(transformPath(FullName));
+    CompileUnitFiles.emplace(File, ++FileIndex);
+    updateFileIndex(CompileUnit, FileIndex);
+  } else {
+    FileIndex = Iter->second;
+  }
+
+  LLVM_DEBUG({ dbgs() << "FileIndex: " << FileIndex << "\n"; });
+  return FileIndex;
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, unsigned Line,
+                               const DIFile *File) {
+  if (Line == 0)
+    return;
+
+  // After the scopes are created, the generic reader traverses the 'Children'
+  // and perform additional setting tasks (resolve types names, references,
+  // etc.). One of those tasks is select the correct string pool index based on
+  // the commmand line options: --attribute=filename or --attribute=pathname.
+  // As the 'Children' do not include logical lines, do that selection now,
+  // by calling 'setFilename' if the logical element is a line.
+  size_t FileID = getOrCreateSourceID(File);
+  if (Element->getIsLine())
+    Element->setFilename(CompileUnit->getFilename(FileID));
+  else
+    Element->setFilenameIndex(FileID);
+  Element->setLineNumber(Line);
+
+  LLVM_DEBUG({
+    dbgs() << "\n[addSourceLine]\n";
+    File->dump();
+    dbgs() << "FileIndex: " << Element->getFilenameIndex() << ", ";
+    dbgs() << "ID:   " << Element->getID() << ", ";
+    dbgs() << "Kind: " << Element->kind() << ", ";
+    dbgs() << "Line: " << Element->getLineNumber() << ", ";
+    dbgs() << "Name: " << Element->getName() << "\n";
+  });
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIGlobalVariable *G) {
+  assert(G);
+  addSourceLine(Element, G->getLine(), G->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIImportedEntity *IE) {
+  assert(IE);
+  addSourceLine(Element, IE->getLine(), IE->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILabel *L) {
+  assert(L);
+  addSourceLine(Element, L->getLine(), L->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILocalVariable *V) {
+  assert(V);
+  addSourceLine(Element, V->getLine(), V->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILocation *DL) {
+  assert(DL);
+  addSourceLine(Element, DL->getLine(), DL->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIObjCProperty *Ty) {
+  assert(Ty);
+  addSourceLine(Element, Ty->getLine(), Ty->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DISubprogram *SP) {
+  assert(SP);
+  addSourceLine(Element, SP->getLine(), SP->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIType *Ty) {
+  assert(Ty);
+  addSourceLine(Element, Ty->getLine(), Ty->getFile());
+}
+
+void LVIRReader::addConstantValue(LVElement *Element,
+                                  const DIExpression *DIExpr) {
+  std::optional<DIExpression::SignedOrUnsignedConstant> Constant =
+      DIExpr->isConstant();
+  std::stringstream Stream;
+  if (DIExpression::SignedOrUnsignedConstant::SignedConstant == Constant) {
+    int64_t Value = DIExpr->getElement(1);
+    if (Value < 0) {
+      Stream << "-";
+      Value = std::abs(Value);
+    }
+    Stream << hexString(Value, 2);
+    Element->setValue(Stream.str());
+  } else if (DIExpression::SignedOrUnsignedConstant::UnsignedConstant ==
+             Constant) {
+    uint64_t Value = DIExpr->getElement(1);
+    Stream << hexString(Value, 2);
+    Element->setValue(Stream.str());
+  }
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const ConstantInt *CI,
+                                  const DIType *Ty) {
+  addConstantValue(Element, CI->getValue(), Ty);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, uint64_t Val,
+                                  const DIType *Ty) {
+  addConstantValue(Element, DebugHandlerBase::isUnsignedDIType(Ty), Val);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, bool Unsigned,
+                                  uint64_t Val) {
+  addConstantValue(Element, llvm::APInt(64, Val, Unsigned), Unsigned);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const APInt &Val,
+                                  const DIType *Ty) {
+  addConstantValue(Element, Val, DebugHandlerBase::isUnsignedDIType(Ty));
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const APInt &Value,
+                                  bool Unsigned) {
+  SmallString<128> StringValue;
+  Value.toString(StringValue, /*Radix=*/16, /*Signed=*/!Unsigned,
+                 /*formatAsCLiteral=*/true, /*UpperCase=*/false,
+                 /*InsertSeparators=*/false);
+  Element->setValue(StringValue.str());
+}
+
+void LVIRReader::addString(LVElement *Element, StringRef String) {
+  Element->setValue(String);
+}
+
+void LVIRReader::processLocationGaps() {
+  if (options().getAttributeAnyLocation())
+    for (LVSymbol *Symbol : SymbolsWithLocations)
+      Symbol->fillLocationGaps();
+}
+
+void LVIRReader::processScopes() {
+  // - Calculate their location ranges.
+  // - Assign unique offset to the logical scopes, symbols and types,
+  //   as the code the handles public names, expects them to have one.
+  //   Use an arbitrary increment of 4.
+  // - Resolve any line pattern match.
+  LVOffset Offset = 0;
+  auto SetOffset = [&](LVElement *Element) {
+    Element->setOffset(Offset);
+    Offset += OffsetIncrease;
+  };
+
+  std::function<void(LVScope *)> TraverseScope = [&](LVScope *Current) {
+    LVOffset Lower = Offset;
+    SetOffset(Current);
+    constructRange(Current);
+
+    if (const LVScopes *Scopes = Current->getScopes())
+      for (LVScope *Scope : *Scopes)
+        TraverseScope(Scope);
+
+    // Set an arbitrary 'Offset' for symbols and types.
+    if (const LVSymbols *Symbols = Current->getSymbols())
+      for (LVSymbol *Symbol : *Symbols)
+        SetOffset(Symbol);
+    if (const LVTypes *Types = Current->getTypes())
+      for (LVType *Type : *Types)
+        SetOffset(Type);
+
+    // Resolve any given pattern.
+    if (const LVLines *Lines = Current->getLines())
+      for (LVLine *Line : *Lines)
+        patterns().resolvePatternMatch(Line);
+
+    // Calculate contributions to the debug info.
+    LVOffset Upper = Offset;
+    if (options().getPrintSizes())
+      CompileUnit->addSize(Current, Lower, Upper);
+  };
+
+  TraverseScope(CompileUnit);
+}
+
+std::string LVIRReader::getRegisterName(LVSmall Opcode,
+                                        ArrayRef<uint64_t> Operands) {
+  // At this point we are operating on a logical view item, with no access
+  // to the underlying DWARF data used by LLVM.
+  // We do not support DW_OP_regval_type here.
+  if (Opcode == dwarf::DW_OP_regval_type)
+    return {};
+
+  if (Opcode == dwarf::DW_OP_regx || Opcode == dwarf::DW_OP_bregx) {
+    // If the following trace is enabled, its output will be intermixed
+    // with the logical view output, causing some confusion.
+    // Leaving it here, just for any specific needs.
+    // LLVM_DEBUG({
+    //   dbgs() << "Printing Value: " << Operands[0] << " - "
+    //          << DbgValueRanges->getVariableName(Operands[0]) << "\n";
+    // });
+    return DbgValueRanges->getVariableName(Operands[0]);
+  }
+
+  llvm_unreachable("We shouldn't actually have any other reg types here!");
+}
+
+LVScope *LVIRReader::getParentScopeImpl(const DIScope *Context) {
+  if (!Context)
+    return CompileUnit;
+
+#ifdef DEBUG_ALL
+  LLVM_DEBUG({
+    dbgs() << "\n[getParentScopeImpl] DIScope\n";
+    Context->dump();
+  });
+#endif
+
+  // Check for an already seen scope parent.
+  if (LVScope *Parent = getScopeForSeenMD(Context))
+    return Parent;
+
+  // Traverse the scope hierarchy and construct the required scopes.
+  return traverseParentScope(Context);
+}
+
+// Get the logical parent for the given metadata node.
+LVScope *LVIRReader::getParentScope(const DILocation *DL) {
+  assert(DL && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+  LLVM_DEBUG({
+    dbgs() << "\n[getParentScope] DILocation\n";
+    DL->dump();
+  });
+#endif
+
+  return getParentScopeImpl(cast<DIScope>(DL->getScope()));
+}
+
+// Get the logical parent for the given metadata node.
+LVScope *LVIRReader::getParentScope(const DINode *DN) {
+  assert(DN && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+  LLVM_DEBUG({
+    dbgs() << "\n[getParentScope] DINode\n";
+    DN->dump();
+  });
+#endif
+
+  return getParentScopeImpl(getMDScope(DN));
+}
+
+// Traverse the scope hierarchy and create each node in the hierarchy.
+LVScope *LVIRReader::traverseParentScope(const DIScope *Context) {
+  if (!Context)
+    return CompileUnit;
+
+#ifdef DEBUG_ALL
+  LLVM_DEBUG({
+    dbgs() << "\n[traverseParentScope] DIScope\n";
+    Context->dump();
+  });
+#endif
+
+  // Check if the metadata is already seen.
+  if (LVScope *Parent = getScopeForSeenMD(Context))
+    return Parent;
+
+  // Create the scope parent.
+  LVElement *Element = constructElement(Context);
+  if (Element) {
+    const DIScope *ParentContext = nullptr;
+    if (const auto *SP = dyn_cast<DISubprogram>(Context)) {
+      // Check for a specific 'Unit'.
+      if (DICompileUnit *CU = SP->getUnit())
+        ParentContext = getMDScope(SP->getDeclaration() ? CU : Context);
+    } else {
+      ParentContext = getMDScope(Context);
+    }
+    LVScope *Parent = traverseParentScope(ParentContext);
+    if (Parent) {
+      Parent->addElement(Element);
+      constructScope(Element, Context);
+    }
+  }
+
+  return static_cast<LVScope *>(Element);
+}
+
+// DW_TAG_base_type
+//   DW_AT_name	("__ARRAY_SIZE_TYPE__")
+//   DW_AT_byte_size	(0x08)
+//   DW_AT_encoding	(DW_ATE_unsigned)
+LVType *LVIRReader::getIndexType() {
+  if (NodeIndexType)
+    return NodeIndexType;
+
+  // Construct an integer type to use for indexes.
+  NodeIndexType = static_cast<LVType *>(createElement(dwarf::DW_TAG_base_type));
+  if (NodeIndexType) {
+    NodeIndexType->setIsFinalized();
+    NodeIndexType->setName("__ARRAY_SIZE_TYPE__");
+    CompileUnit->addElement(NodeIndexType);
+  }
+
+  return NodeIndexType;
+}
+
+// addGlobalName - Add a new global name to the compile unit.
+void LVIRReader::addGlobalName(StringRef Name, LVElement *Element,
+                               const DIScope *Context) {
+  assert(Element && "Invalid logical element.");
+  LLVM_DEBUG({
+    dbgs() << "\n[addGlobalName] DIScope\n";
+    Context->dump();
+  });
+}
+
+// Add accessibility info if available.
+void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) {
+  assert(Element && "Invalid logical element.");
+  LLVM_DEBUG({ dbgs() << "\n[addAccess] DIFlags " << Flags << "\n"; });
+
+  if ((Flags & DINode::FlagAccessibility) == DINode::FlagZero) {
+    LVScope *Parent = Element->getParentScope();
+    if (Parent->getIsClass())
+      Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
+    else if (Parent->getIsStructure() || Parent->getIsUnion())
+      Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
+    return;
+  }
+
+  if ((Flags & DINode::FlagAccessibility) == DINode::FlagProtected)
+    Element->setAccessibilityCode(dwarf::DW_ACCESS_protected);
+  else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPrivate)
+    Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
+  else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPublic)
+    Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
+};
+
+// getFile()
+//   DIScope
+//   DILocation
+//   DIVariable
+//   DICommonBlock
+//   DILabel
+//   DIObjCProperty
+//   DIImportedEntity
+//   DIMacroFile
+const DIFile *LVIRReader::getMDFile(const MDNode *MD) const {
+  assert(MD && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+  LLVM_DEBUG({
+    dbgs() << "\n[getMDFile] MDNode\n";
+    MD->dump();
+  });
+#endif
+
+  if (auto *T = dyn_cast<DIScope>(MD))
+    return T->getFile();
+
+  if (auto *T = dyn_cast<DILocation>(MD))
+    return T->getFile();
+
+  if (auto *T = dyn_cast<DIVariable>(MD))
+    return T->getFile();
+
+  if (auto *T = dyn_cast<DICommonBlock>(MD))
+    return T->getFile();
+
+  if (auto *T = dyn_cast<DILabel>(MD))
+    return T->getFile();
+
+  if (auto *T = dyn_cast<DIObjCProperty>(MD))
+    return T->getFile();
+
+  if (auto *T = dyn_cast<DIImportedEntity>(MD))
+    return T->getFile();
+
+  if (auto *T = dyn_cast<DIMacroFile>(MD))
+    return T->getFile();
+
+  return nullptr;
+}
+
+// getName()
+//   DIScope
+//   DIType
+//   DISubprogram
+//   DINamespace
+//   DIModule
+//   DITemplateParameter
+//   DIVariable
+//   DICommonBlock
+//   DILabel
+//   DIObjCProperty
+//   DIImportedEntity
+//   DIMacro
+//   DIEnumerator
+StringRef LVIRReader::getMDName(const DINode *DN) const {
+  assert(DN && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+  LLVM_DEBUG({
+    dbgs() << "\n[getMDName] DINode\n";
+    DN->dump();
+  });
+#endif
+
+  if (auto *T = dyn_cast<DIType>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DISubprogram>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DINamespace>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DICommonBlock>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DIModule>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DIImportedEntity>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DICompositeType>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DIDerivedType>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DILexicalBlockBase>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DIEnumerator>(DN))
+    return T->getName();
+
+  if (/*auto *T = */ dyn_cast<DISubrange>(DN))
+    return StringRef();
+
+  if (auto *T = dyn_cast<DIVariable>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DIScope>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DITemplateParameter>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DILabel>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DIObjCProperty>(DN))
+    return T->getName();
+
+  if (auto *T = dyn_cast<DIMacro>(DN))
+    return T->getName();
+
+  assert((isa<DIFile>(DN) || isa<DICompileUnit>(DN)) && "Unhandled DINode.");
+  return StringRef();
+}
+
+const DIScope *LVIRReader::getMDScope(const DINode *DN) const {
+  assert(DN && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+  LLVM_DEBUG({
+    dbgs() << "\n[getMDScope] DINode\n";
+    DN->dump();
+  });
+#endif
+
+  if (dyn_cast<DIBasicType>(DN))
+    return getCUNode();
+
+  if (auto *T = dyn_cast<DINamespace>(DN)) {
+    // The scope for global namespaces is nullptr.
+    const DIScope *Context = T->getScope();
+    if (!Context)
+      Context = getCUNode();
+    return Context;
+  }
+
+  if (auto *T = dyn_cast<DIImportedEntity>(DN))
+    return T->getScope();
+
+  if (auto *T = dyn_cast<DIVariable>(DN))
+    return T->getScope();
+
+  if (auto *T = dyn_cast<DIScope>(DN))
+    return T->getScope();
+
+  assert((isa<DIFile>(DN) || isa<DICompileUnit>(DN)) && "Unhandled DINode.");
+
+  // Assume the scope to be the compile unit.
+  return getCUNode();
+}
+
+//===----------------------------------------------------------------------===//
+// Logical elements construction using IR metadata.
+//===----------------------------------------------------------------------===//
+void LVIRReader::addTemplateParams(LVElement *Element,
+                                   const DINodeArray TParams) {
+  assert(Element && "Invalid logical element");
+  // assert(TParams && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[addTemplateParams] DINodeArray\n";
+    // TParams->dump();
+    for (const auto *Entry : TParams)
+      Entry->dump();
+  });
+
+  // Add template parameters.
+  for (const auto *Entry : TParams) {
+    if (const auto *TTP = dyn_cast<DITemplateTypeParameter>(Entry))
+      constructTemplateTypeParameter(Element, TTP);
+    else if (const auto *TVP = dyn_cast<DITemplateValueParameter>(Entry))
+      constructTemplateValueParameter(Element, TVP);
+  }
+}
+
+// DISubprogram
+void LVIRReader::applySubprogramAttributes(LVScope *Function,
+                                           const DISubprogram *SP,
+                                           bool SkipSPAttributes) {
+  assert(Function && "Invalid logical element");
+  assert(SP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[applySubprogramAttributes] DISubprogram\n";
+    SP->dump();
+  });
+
+  // If -fdebug-info-for-profiling is enabled, need to emit the subprogram
+  // and its source location.
+  bool SkipSPSourceLocation =
+      SkipSPAttributes && !getCUNode()->getDebugInfoForProfiling();
+  if (!SkipSPSourceLocation)
+    if (applySubprogramDefinitionAttributes(Function, SP, SkipSPAttributes))
+      return;
+
+  if (!SkipSPSourceLocation)
+    addSourceLine(Function, SP);
+
+  // Skip the rest of the attributes under -gmlt to save space.
+  if (SkipSPAttributes)
+    return;
+
+  DITypeRefArray Args;
+  if (const DISubroutineType *SPTy = SP->getType())
+    Args = SPTy->getTypeArray();
+
+  // Construct subprogram return type.
+  if (Args.size()) {
+    LVElement *ElementType = getOrCreateType(Args[0]);
+    Function->setType(ElementType);
+  }
+
+  // Add virtuality info if available.
+  Function->setVirtualityCode(SP->getVirtuality());
+
+  if (!SP->isDefinition()) {
+    // Add arguments. Do not add arguments for subprogram definition. They will
+    // be handled while processing variables.
+    constructSubprogramArguments(Function, Args);
+  }
+
+  if (SP->isArtificial())
+    Function->setIsArtificial();
+
+  if (!SP->isLocalToUnit())
+    Function->setIsExternal();
+
+  // Add accessibility info if available.
+  addAccess(Function, SP->getFlags());
+}
+
+// DISubprogram
+bool LVIRReader::applySubprogramDefinitionAttributes(LVScope *Function,
+                                                     const DISubprogram *SP,
+                                                     bool Minimal) {
+  assert(Function && "Invalid logical element");
+  assert(SP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[applySubprogramDefinitionAttributes] DISubprogram\n";
+    SP->dump();
+  });
+
+  LVScope *Reference = nullptr;
+  StringRef DeclLinkageName;
+  if (const DISubprogram *SPDecl = SP->getDeclaration()) {
+    if (!Minimal) {
+      DITypeRefArray DeclArgs, DefinitionArgs;
+      DeclArgs = SPDecl->getType()->getTypeArray();
+      DefinitionArgs = SP->getType()->getTypeArray();
+
+      if (DeclArgs.size() && DefinitionArgs.size())
+        if (DefinitionArgs[0] != nullptr && DeclArgs[0] != DefinitionArgs[0]) {
+          LVElement *ElementType = getOrCreateType(DefinitionArgs[0]);
+          Function->setType(ElementType);
+        }
+
+      Reference = getScopeForSeenMD(SPDecl);
+      assert(Reference && "Scope should've already been constructed.");
+      // Look at the Decl's linkage name only if we emitted it.
+      if (useAllLinkageNames())
+        DeclLinkageName = SPDecl->getLinkageName();
+      unsigned DeclID = getOrCreateSourceID(SPDecl->getFile());
+      unsigned DefID = getOrCreateSourceID(SP->getFile());
+      if (DeclID != DefID)
+        Function->setFilenameIndex(DefID);
+
+      if (SP->getLine() != SPDecl->getLine())
+        Function->setLineNumber(SP->getLine());
+    }
+  }
+
+  // Add function template parameters.
+  addTemplateParams(Function, SP->getTemplateParams());
+
+  // Add the linkage name if we have one and it isn't in the Decl.
+  StringRef LinkageName = SP->getLinkageName();
+  assert(((LinkageName.empty() || DeclLinkageName.empty()) ||
+          LinkageName == DeclLinkageName) &&
+         "decl has a linkage name and it is different");
+  if (DeclLinkageName.empty() && (useAllLinkageNames()))
+    // Always emit it for abstract subprograms.
+    Function->setLinkageName(LinkageName);
+
+  if (!Reference)
+    return false;
+
+  // Refer to the function declaration where all the other attributes will be
+  // found.
+  Function->setReference(Reference);
+  Function->setHasReferenceSpecification();
+
+  return true;
+}
+
+void LVIRReader::applySubprogramAttributesToDefinition(LVScope *Function,
+                                                       const DISubprogram *SP) {
+  assert(Function && "Invalid logical element");
+  assert(SP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[applySubprogramAttributesToDefinition] DISubprogram\n";
+    SP->dump();
+  });
+
+  applySubprogramAttributes(Function, SP, includeMinimalInlineScopes());
+}
+
+// DICompositeType
+void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate,
+                                    const DICompositeType *CTy) {
+  assert(Aggregate && "Invalid logical element");
+  assert(CTy && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructAggregate] DICompositeType\n";
+    CTy->dump();
+  });
+
+  if (Aggregate->getIsFinalized())
+    return;
+  Aggregate->setIsFinalized();
+
+  dwarf::Tag Tag = Aggregate->getTag();
+  if (Tag == dwarf::DW_TAG_variant_part) {
+  }
+
+  // Add template parameters to a class, structure or union types.
+  if (Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type ||
+      Tag == dwarf::DW_TAG_union_type)
+    addTemplateParams(Aggregate, CTy->getTemplateParams());
+
+  // Add elements to aggregate type.
+  for (const auto Member : CTy->getElements()) {
+    if (!Member)
+      continue;
+    LLVM_DEBUG({
+      dbgs() << "\nAggregate Element\n";
+      Member->dump();
+    });
+    if (const auto *SP = dyn_cast<DISubprogram>(Member))
+      getOrCreateSubprogram(SP);
+    else if (const DIDerivedType *DT = dyn_cast<DIDerivedType>(Member)) {
+      dwarf::Tag Tag = Member->getTag();
+      if (Tag == dwarf::DW_TAG_member || Tag == dwarf::DW_TAG_variable) {
+        if (DT->isStaticMember())
+          getOrCreateStaticMember(Aggregate, DT);
+        else
+          getOrCreateMember(Aggregate, DT);
+      } else {
+        getOrCreateType(DT, Aggregate);
+      }
+    }
+  }
+}
+
+// DICompositeType
+void LVIRReader::constructArray(LVScopeArray *Array,
+                                const DICompositeType *CTy) {
+  assert(Array && "Invalid logical element");
+  assert(CTy && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructArray] DICompositeType\n";
+    CTy->dump();
+  });
+
+  if (Array->getIsFinalized())
+    return;
+  Array->setIsFinalized();
+
+  if (LVElement *BaseType = getOrCreateType(CTy->getBaseType()))
+    Array->setType(BaseType);
+
+  // Get an anonymous type for index type.
+  LVType *IndexType = getIndexType();
+
+  // Add subranges to array type.
+  DINodeArray Entries = CTy->getElements();
+  for (DINode *DN : Entries) {
+    if (auto *SR = dyn_cast_or_null<DINode>(DN)) {
+      if (SR->getTag() == dwarf::DW_TAG_subrange_type)
+        constructSubrange(Array, cast<DISubrange>(SR), IndexType);
+      else if (SR->getTag() == dwarf::DW_TAG_generic_subrange)
+        constructGenericSubrange(Array, cast<DIGenericSubrange>(SR), IndexType);
+    }
+  }
+}
+
+// DICompositeType
+void LVIRReader::constructEnum(LVScopeEnumeration *Enumeration,
+                               const DICompositeType *CTy) {
+  assert(Enumeration && "Invalid logical element");
+  assert(CTy && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructEnum] DICompositeType\n";
+    CTy->dump();
+  });
+
+  if (Enumeration->getIsFinalized())
+    return;
+  Enumeration->setIsFinalized();
+
+  const DIType *Ty = CTy->getBaseType();
+  bool IsUnsigned = Ty && DebugHandlerBase::isUnsignedDIType(Ty);
+
+  if (LVElement *BaseType = getOrCreateType(Ty))
+    Enumeration->setType(BaseType);
+
+  if (CTy->getFlags() & DINode::FlagEnumClass)
+    Enumeration->setIsEnumClass();
+
+  // Add enumerators to enumeration type.
+  DINodeArray Entries = CTy->getElements();
+  for (const DINode *DN : Entries) {
+    if (auto *Enum = dyn_cast_or_null<DIEnumerator>(DN)) {
+      if (LVElement *Enumerator = constructElement(Enum)) {
+        Enumerator->setIsFinalized();
+        Enumeration->addElement(Enumerator);
+        addConstantValue(Enumerator, Enum->getValue(), IsUnsigned);
+      }
+    }
+  }
+}
+
+void LVIRReader::constructGenericSubrange(LVScopeArray *Array,
+                                          const DIGenericSubrange *GSR,
+                                          LVType *IndexType) {
+  assert(Array && "Invalid logical element");
+  assert(GSR && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructGenericSubrange] DIGenericSubrange\n";
+    GSR->dump();
+  });
+
+  LLVM_DEBUG({ dbgs() << "\nNot implemented\n"; });
+}
+
+// DIImportedEntity
+void LVIRReader::constructImportedEntity(LVElement *Element,
+                                         const DIImportedEntity *IE) {
+  assert(Element && "Invalid logical element");
+  assert(IE && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructImportedEntity] DIImportedEntity\n";
+    IE->dump();
+  });
+
+  if (LVElement *Import = constructElement(IE)) {
+    Import->setIsFinalized();
+    addSourceLine(Import, IE);
+    LVScope *Parent = getParentScope(IE);
+    Parent->addElement(Import);
+
+    const DINode *Entity = IE->getEntity();
+    LVElement *Target = getElementForSeenMD(Entity);
+    if (!Target) {
+      if (const auto *Ty = dyn_cast<DIType>(Entity))
+        Target = getOrCreateType(Ty);
+      else if (const auto *SP = dyn_cast<DISubprogram>(Entity))
+        Target = getOrCreateSubprogram(SP);
+      else if (const auto *NS = dyn_cast<DINamespace>(Entity))
+        Target = getOrCreateNamespace(NS);
+      else if (const auto *M = dyn_cast<DIModule>(Entity))
+        Target = getOrCreateScope(M);
+    }
+    Import->setType(Target);
+  }
+}
+
+LVScope *LVIRReader::getOrCreateAbstractScope(LVScope *OriginScope,
+                                              const DILocation *DL) {
+  assert(OriginScope && "Invalid logical element");
+  assert(DL && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateAbstractScope] DILocation\n";
+    DL->dump();
+  });
+
+  const DILocation *InlinedAt = DL->getInlinedAt();
+  DILocalScope *Context = DL->getScope();
+  LLVM_DEBUG({
+    dbgs() << "\nParent Scope:\n";
+    OriginScope->getParentScope()->dump();
+    dbgs() << "\nOriginScope:\n";
+    OriginScope->dump();
+    dbgs() << "\nInlinedAt:\n";
+    InlinedAt->dump();
+    dbgs() << "\nContext:\n";
+    Context->dump();
+  });
+
+  dwarf::Tag Tag = OriginScope->getTag();
+  if (OriginScope->getIsFunction() || OriginScope->getIsInlinedFunction()) {
+    Tag = dwarf::DW_TAG_inlined_subroutine;
+    OriginScope->setInlineCode(dwarf::DW_INL_inlined);
+  }
+  LVScope *AbstractScope = static_cast<LVScope *>(createElement(Tag));
+  if (AbstractScope) {
+    addInlinedScope(OriginScope, AbstractScope);
+    AbstractScope->setTag(Tag);
+    AbstractScope->setIsFinalized();
+    AbstractScope->setName(OriginScope->getName());
+    AbstractScope->setType(OriginScope->getType());
+
+    AbstractScope->setCallLineNumber(InlinedAt->getLine());
+    AbstractScope->setCallFilenameIndex(
+        getOrCreateSourceID(InlinedAt->getFile()));
+
+    AbstractScope->setReference(OriginScope);
+    AbstractScope->setHasReferenceAbstract();
+
+    // Get or create the parent scope for the inlined subprogram.
+    LVScope *Parent = AbstractScope->getIsLexicalBlock()
+                          ? getInlinedScope(OriginScope->getParentScope())
+                          : getOrCreateScope(InlinedAt->getScope());
+    assert(Parent && "Parent scope is NULL.");
+    Parent->addElement(AbstractScope);
+  }
+
+  return AbstractScope;
+}
+
+LVScope *LVIRReader::getOrCreateInlinedScope(LVScope *Parent,
+                                             const DILocation *DL) {
+  assert(Parent && "Invalid logical element");
+  assert(DL && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateInlinedScope] DILocation\n";
+    DL->dump();
+    dbgs() << "Parent Logical Scope:\n";
+    Parent->dump();
+  });
+
+  // Get the 'origin' and 'abstract' debug locations.
+  const DILocation *InlinedAt = DL->getInlinedAt();
+  if (!InlinedAt)
+    return nullptr;
+
+  DILocalScope *Context = DL->getScope();
+  assert(Context && "Context is null.");
+  if (!Context)
+    return nullptr;
+
+  LLVM_DEBUG({
+    dbgs() << "\nInlinedAt:\n";
+    InlinedAt->dump();
+    dbgs() << "\nContext:\n";
+    Context->dump();
+  });
+
+  // Get the seed scope to be used to create the inlined scope.
+  LLVM_DEBUG({
+    LVScope *ParentScope = getOrCreateSubprogram(
+        static_cast<DISubprogram *>(InlinedAt->getScope()));
+    assert((Parent == ParentScope) && "Scopes don't match.");
+  });
+
+  // Check if we have seen the scope.
+  LVScope *OriginScope = getScopeForSeenMD(Context);
+  if (!OriginScope) {
+    // Create the 'origin' scope.
+    if (isa<DISubprogram>(Context)) {
+      OriginScope = getOrCreateSubprogram(static_cast<DISubprogram *>(Context));
+      OriginScope->setInlineCode(dwarf::DW_INL_inlined);
+    } else if (isa<DILexicalBlock>(Context)) {
+      OriginScope = getOrCreateScope(static_cast<DIScope *>(Context));
+    }
+    LLVM_DEBUG({
+      dbgs() << "\nParent Scope:\n";
+      OriginScope->getParentScope()->dump();
+      dbgs() << "Inlined (Origin) Logical Scope:\n";
+      OriginScope->dump();
+    });
+
+    // Create the 'abstract' scope.
+    LVScope *InlinedScope = getOrCreateAbstractScope(OriginScope, DL);
+    assert(InlinedScope && "InlinedScope is null.");
+    LLVM_DEBUG({
+      dbgs() << "\nParent Scope:\n";
+      InlinedScope->getParentScope()->dump();
+      dbgs() << "\nInlined (Abstract) Logical Scope:\n";
+      InlinedScope->dump();
+    });
+  }
+
+  return OriginScope;
+}
+
+void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
+                               Instruction &I) {
+  assert(Scope && "Invalid logical element");
+  assert(SP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructLine] Instruction\n";
+    I.dump();
+    dbgs() << "Logical Scope:\n";
+    Scope->dump();
+  });
+
+  auto AddDebugLine = [&](LVScope *Parent, unsigned ID) -> LVLine * {
+    assert(Parent && "Invalid logical element");
+    assert(ID == Metadata::DILocationKind && "Invalid Metadata Object");
+
+    LVLine *Line = createLineDebug();
+    if (Line) {
+      Parent->addElement(Line);
+
+      Line->setIsFinalized();
+      Line->setAddress(CurrentOffset);
+
+      // FIXME: How to get discrimination flags:
+      // IsStmt, BasicBlock, EndSequence, EpilogueBegin, PrologueEnd.
+
+      // Add mapping for this debug line.
+      CompileUnit->addMapping(Line, SectionIndex);
+
+      // Replicate the DWARF reader functionality of adding a linkage
+      // name to a function with ranges (logical lines), regardless if
+      // the declaration has already one.
+      if (!Parent->getLinkageNameIndex() &&
+          Parent->getHasReferenceSpecification()) {
+        Parent->setLinkageName(Parent->getReference()->getLinkageName());
+      }
+      GenerateLineBeforePrologue = false;
+    }
+
+    return Line;
+  };
+
+  auto AddAssemblerLine = [&](LVScope *Parent) {
+    assert(Parent && "Invalid logical element");
+
+    static const char *WhiteSpace = " \t\n\r\f\v";
+    static std::string Metadata("metadata ");
+
+    auto RemoveAll = [](std::string &Input, std::string &Pattern) {
+      std::string::size_type Len = Pattern.length();
+      for (std::string::size_type Index = Input.find(Pattern);
+           Index != std::string::npos; Index = Input.find(Pattern))
+        Input.erase(Index, Len);
+    };
+
+    std::string InstructionText;
+    raw_string_ostream Stream(InstructionText);
+    Stream << I;
+    // Remove the 'metadata ' pattern from the instruction text.
+    RemoveAll(InstructionText, Metadata);
+    std::string_view Text(InstructionText);
+    const auto pos(Text.find_first_not_of(WhiteSpace));
+    Text.remove_prefix(std::min(pos, Text.length()));
+
+    // Create an instruction line at the given scope.
+    if (LVLineAssembler *Line = createLineAssembler()) {
+      Line->setIsFinalized();
+      Line->setAddress(CurrentOffset);
+      Line->setName(Text);
+      Parent->addElement(Line);
+
+      DbgValueRanges->addLine(I.getIterator(), CurrentOffset);
+    }
+  };
+
+  LVScope *Parent = Scope;
+  if (const DebugLoc DbgLoc = I.getDebugLoc()) {
+    const DILocation *DL = DbgLoc.get();
+    Parent = getParentScope(DL);
+    if (DL->getInlinedAt())
+      Parent = getInlinedScope(Parent);
+
+    LLVM_DEBUG({
+      dbgs() << "\n[constructLine] DILocation\n";
+      DL->dump();
+    });
+
+    if (options().getPrintLines() && DL->getLine()) {
+      if (LVLine *Line = AddDebugLine(Parent, DL->getMetadataID())) {
+        addMD(DL, Line);
+        addSourceLine(Line, DL);
+        GenerateLineBeforePrologue = false;
+      }
+    }
+  }
+
+  // Generate a logical line before the function prologue.
+  if (options().getPrintLines() && GenerateLineBeforePrologue) {
+    if (LVLine *Line = AddDebugLine(Parent, Metadata::DILocationKind)) {
+      addSourceLine(Line, SP);
+      GenerateLineBeforePrologue = false;
+    }
+  }
+
+  // Create assembler line.
+  if (options().getPrintInstructions())
+    AddAssemblerLine(Parent);
+}
+
+LVSymbol *LVIRReader::getOrCreateMember(LVScope *Aggregate,
+                                        const DIDerivedType *DT) {
+  assert(Aggregate && "Invalid logical element");
+  assert(DT && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateMember] DIDerivedType\n";
+    DT->dump();
+  });
+
+  LVSymbol *Member = getSymbolForSeenMD(DT);
+  if (Member && Member->getIsFinalized())
+    return Member;
+
+  if (!options().getPrintSymbols()) {
+    // Just create the symbol type.
+    getOrCreateType(DT->getBaseType());
+    return nullptr;
+  }
+
+  if (!Member)
+    Member = static_cast<LVSymbol *>(getOrCreateType(DT, Aggregate));
+  if (Member) {
+    Member->setIsFinalized();
+    addSourceLine(Member, DT);
+    if (DT->getTag() == dwarf::DW_TAG_inheritance && DT->isVirtual()) {
+      Member->addLocation(dwarf::DW_AT_data_member_location, /*LowPC=*/0,
+                          /*HighPC=*/-1, /*SectionOffset=*/0,
+                          /*OffsetOnEntry=*/0);
+    } else {
+      uint64_t OffsetInBytes = 0;
+
+      bool IsBitfield = DT->isBitField();
+      if (IsBitfield) {
+        Member->setBitSize(DT->getSizeInBits());
+      } else {
+        // This is not a bitfield.
+        OffsetInBytes = DT->getOffsetInBits() / 8;
+      }
+
+      if (DwarfVersion <= 2) {
+        // DW_AT_data_member_location:
+        //   DW_FORM_data1, DW_OP_plus_uconst, DW_FORM_udata, OffsetInBytes
+        Member->addLocation(dwarf::DW_AT_data_member_location, /*LowPC=*/0,
+                            /*HighPC=*/-1, /*SectionOffset=*/0,
+                            /*OffsetOnEntry=*/0);
+        Member->addLocationOperands(dwarf::DW_OP_plus_uconst, {OffsetInBytes});
+      } else if (!IsBitfield || DwarfVersion < 4) {
+        // DW_AT_data_member_location:
+        //   DW_FORM_udata, OffsetInBytes
+        Member->addLocationConstant(dwarf::DW_AT_data_member_location,
+                                    OffsetInBytes,
+                                    /*OffsetOnEntry=*/0);
+      }
+    }
+  }
+
+  // Add accessibility info if available.
+  if (!DT->isStaticMember())
+    addAccess(Member, DT->getFlags());
+
+  if (DT->isVirtual())
+    Member->setVirtualityCode(dwarf::DW_VIRTUALITY_virtual);
+
+  if (DT->isArtificial())
+    Member->setIsArtificial();
+
+  return Member;
+}
+
+// DIBasicType
+// DICommonBlock
+// DICompileUnit
+// DICompositeType
+// DIDerivedType
+// DIFile
+// DILexicalBlock
+// DILexicalBlockFile
+// DIModule
+// DINamespace
+// DISubprogram
+// DISubroutineType
+// DIStringType
+void LVIRReader::constructScope(LVElement *Element, const DIScope *Context) {
+  assert(Element && "Invalid logical element");
+  assert(Context && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructScope] DIScope\n";
+    Context->dump();
+  });
+
+  if (Context && isa<DICompositeType>(Context)) {
+    const DICompositeType *CTy = cast<DICompositeType>(Context);
+    constructType(static_cast<LVScope *>(Element), CTy);
+  } else if (Context && isa<DIDerivedType>(Context)) {
+    const DIDerivedType *DT = cast<DIDerivedType>(Context);
+    constructType(Element, DT);
+  } else if (Context && isa<DISubprogram>(Context)) {
+    const DISubprogram *SP = cast<DISubprogram>(Context);
+    getOrCreateSubprogram(static_cast<LVScope *>(Element), SP);
+  } else if (Context && isa<DINamespace>(Context)) {
+    Element->setIsFinalized();
+  } else if (Context && isa<DILexicalBlock>(Context)) {
+    Element->setIsFinalized();
+  }
+}
+
+LVSymbol *LVIRReader::getOrCreateStaticMember(LVScope *Aggregate,
+                                              const DIDerivedType *DT) {
+  assert(Aggregate && "Invalid logical element");
+  assert(DT && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateStaticMember] DIDerivedType\n";
+    DT->dump();
+  });
+
+  LVSymbol *Member = getSymbolForSeenMD(DT);
+  if (Member && Member->getIsFinalized())
+    return Member;
+
+  if (!options().getPrintSymbols()) {
+    // Just create the symbol type.
+    getOrCreateType(DT->getBaseType());
+    return nullptr;
+  }
+
+  if (!Member)
+    Member = static_cast<LVSymbol *>(getOrCreateType(DT, Aggregate));
+  if (Member) {
+    Member->setIsFinalized();
+    addSourceLine(Member, DT);
+    Member->setIsExternal();
+  }
+
+  return Member;
+}
+
+// DISubprogram
+LVScope *LVIRReader::getOrCreateSubprogram(const DISubprogram *SP,
+                                           bool Minimal) {
+  assert(SP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateSubprogram] DISubprogram\n";
+    SP->dump();
+  });
+
+  LVScope *Function = getScopeForSeenMD(SP);
+  if (Function && Function->getIsFinalized())
+    return Function;
+
+  if (!Function)
+    Function = static_cast<LVScope *>(constructElement(SP));
+  if (Function) {
+    // For both member functions (declaration and definition) its parent
+    // is the containing class. The 'definition' points back to its
+    // 'declaration' via the 'getDeclaration' return value.
+    LVScope *Parent = SP->getDeclaration()
+                          ? SP->isLocalToUnit() || SP->isDefinition()
+                                ? CompileUnit
+                                : getParentScope(SP)->getParentScope()
+                          : getParentScope(SP);
+    // The 'getParentScope' traverses the scope hierarchy and it creates
+    // the scope chain and any associated types.
+    // Check that the 'Function' is not already in the parent.
+    if (!Function->getParent())
+      Parent->addElement(Function);
+
+    getOrCreateSubprogram(Function, SP, Minimal);
+  }
+
+  return Function;
+}
+
+// DISubprogram
+LVScope *LVIRReader::getOrCreateSubprogram(LVScope *Function,
+                                           const DISubprogram *SP,
+                                           bool Minimal) {
+  assert(Function && "Invalid logical element");
+  assert(SP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateSubprogram] DISubprogram\n";
+    SP->dump();
+  });
+
+  if (Function->getIsFinalized())
+    return Function;
+  Function->setIsFinalized();
+
+  // Get 'declaration' node in order to generate the DW_AT_specification.
+  if (const DISubprogram *SPDecl = SP->getDeclaration()) {
+    if (!Minimal) {
+      // Build the declaration now to ensure it precedes the definition.
+      getOrCreateSubprogram(SPDecl);
+    }
+  }
+
+  // Check for additional retained nodes.
+  for (const DINode *DN : SP->getRetainedNodes()) {
+    if (const auto *IE = dyn_cast<DIImportedEntity>(DN))
+      constructImportedEntity(Function, IE);
+    else if (const auto *TTP = dyn_cast<DITemplateTypeParameter>(DN))
+      constructTemplateTypeParameter(Function, TTP);
+    else if (const auto *TVP = dyn_cast<DITemplateValueParameter>(DN))
+      constructTemplateValueParameter(Function, TVP);
+  }
+
+  applySubprogramAttributes(Function, SP);
+
+  // Check if we are dealing with the Global Init/Cleanup Function.
+  if (SP->isArtificial() && SP->isLocalToUnit() && SP->isDefinition() &&
+      SP->getName().empty())
+    Function->setName(SP->getLinkageName());
+
+  return Function;
+}
+
+void LVIRReader::constructSubprogramArguments(LVScope *Function,
+                                              const DITypeRefArray Args) {
+  assert(Function && "Invalid logical element");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructSubprogramArguments] DITypeRefArray\n";
+    for (unsigned i = 1, N = Args.size(); i < N; ++i) {
+      if (const DIType *Ty = Args[i])
+        Ty->dump();
+    }
+  });
+
+  for (unsigned I = 1, N = Args.size(); I < N; ++I) {
+    const DIType *Ty = Args[I];
+    LVElement *Parameter = nullptr;
+    if (Ty) {
+      // Create a formal parameter.
+      LVElement *ParameterType = getOrCreateType(Ty);
+      Parameter = createElement(dwarf::DW_TAG_formal_parameter);
+      if (Parameter) {
+        Parameter->setType(ParameterType);
+        if (Ty->isArtificial())
+          Parameter->setIsArtificial();
+      }
+    } else {
+      // Add an unspecified parameter.
+      Parameter = createElement(dwarf::DW_TAG_unspecified_parameters);
+    }
+    if (Parameter) {
+      Function->addElement(Parameter);
+      Parameter->setIsFinalized();
+    }
+  }
+}
+
+// DISubrange
+void LVIRReader::constructSubrange(LVScopeArray *Array, const DISubrange *GSR,
+                                   LVType *IndexType) {
+  assert(Array && "Invalid logical element");
+  assert(GSR && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructSubrange] DISubrange\n";
+    GSR->dump();
+  });
+
+  // The DISubrange can be shared between different arrays, when they are
+  // the same. We need to create independent logical elements for each one,
+  // as they are going to be added to different arrays.
+  if (LVTypeSubrange *Subrange =
+          static_cast<LVTypeSubrange *>(constructElement(GSR))) {
+    Subrange->setIsFinalized();
+    Array->addElement(Subrange);
+    Subrange->setType(IndexType);
+
+    int64_t Count = -1;
+    // If Subrange has a Count field, use it.
+    // Otherwise, if it has an upperboud, use (upperbound - lowerbound + 1),
+    // where lowerbound is from the LowerBound field of the Subrange,
+    // or the language default lowerbound if that field is unspecified.
+    if (auto *CI = dyn_cast_if_present<ConstantInt *>(GSR->getCount()))
+      Count = CI->getSExtValue();
+    else if (auto *UI =
+                 dyn_cast_if_present<ConstantInt *>(GSR->getUpperBound())) {
+      // Fortran uses 1 as the default lowerbound; other languages use 0.
+      int64_t Lowerbound = (moduleIsInFortran()) ? 1 : 0;
+      auto *LI = dyn_cast_if_present<ConstantInt *>(GSR->getLowerBound());
+      Lowerbound = (LI) ? LI->getSExtValue() : Lowerbound;
+      Count = UI->getSExtValue() - Lowerbound + 1;
+    }
+
+    if (Count == -1)
+      Count = 0;
+    Subrange->setCount(Count);
+  }
+}
+
+// DITemplateTypeParameter
+void LVIRReader::constructTemplateTypeParameter(
+    LVElement *Element, const DITemplateTypeParameter *TTP) {
+  assert(Element && "Invalid logical element");
+  assert(TTP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructTemplateTypeParameter] DITemplateTypeParameter\n";
+    TTP->dump();
+  });
+
+  // The DITemplateTypeParameter can be shared between different subprogram
+  // in their DITemplateParameterArray describing the template parameters.
+  // We need to create independent logical elements for each one, as they are
+  // going to be added to different function.
+  if (LVElement *Parameter = constructElement(TTP)) {
+    Parameter->setIsFinalized();
+    // Add element to parent (always the given Element).
+    LVScope *Parent = static_cast<LVScope *>(Element);
+    Parent->addElement(Parameter);
+    // Mark the parent as template.
+    Parent->setIsTemplate();
+
+    // Add the type if it exists, it could be void and therefore no type.
+    if (const DIType *Ty = TTP->getType()) {
+      LVElement *Type = getElementForSeenMD(Ty);
+      if (!Type)
+        Type = getOrCreateType(Ty);
+      Parameter->setType(Type);
+    }
+  }
+}
+
+// DITemplateValueParameter
+void LVIRReader::constructTemplateValueParameter(
+    LVElement *Element, const DITemplateValueParameter *TVP) {
+  assert(Element && "Invalid logical element");
+  assert(TVP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructTemplateValueParameter] DITemplateValueParameter\n";
+    TVP->dump();
+  });
+
+  // The DITemplateValueParameter can be shared between different subprogram
+  // in their DITemplateParameterArray describing the template parameters.
+  // We need to create independent logical elements for each one, as they are
+  // going to be added to different function.
+  if (LVElement *Parameter = constructElement(TVP)) {
+    Parameter->setIsFinalized();
+    // Add element to parent (always the given Element).
+    LVScope *Parent = static_cast<LVScope *>(Element);
+    Parent->addElement(Parameter);
+    // Mark the parent as template.
+    Parent->setIsTemplate();
+
+    // Add the type if there is one, template template and template parameter
+    // packs will not have a type.
+    if (TVP->getTag() == dwarf::DW_TAG_template_value_parameter) {
+      LVElement *Type = getOrCreateType(TVP->getType());
+      Parameter->setType(Type);
+    }
+    if (Metadata *Value = TVP->getValue()) {
+      if (ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Value))
+        addConstantValue(Parameter, CI, TVP->getType());
+      else if (GlobalValue *GV = mdconst::dyn_extract<GlobalValue>(Value)) {
+        // We cannot describe the location of dllimport'd entities: the
+        // computation of their address requires loads from the IAT.
+        if (!GV->hasDLLImportStorageClass()) {
+        }
+      } else if (TVP->getTag() == dwarf::DW_TAG_GNU_template_template_param) {
+        assert(isa<MDString>(Value));
+        // Add the value for dwarf::DW_AT_GNU_template_name.
+        Parameter->setValue(cast<MDString>(Value)->getString());
+      } else if (TVP->getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
+        addTemplateParams(Parameter, cast<MDTuple>(Value));
+      }
+    }
+  }
+}
+
+// DICompositeType
+//   DW_TAG_array_type
+//   DW_TAG_class_type
+//   DW_TAG_enumeration_type
+//   DW_TAG_structure_type
+//   DW_TAG_union_type
+void LVIRReader::constructType(LVScope *Scope, const DICompositeType *CTy) {
+  assert(Scope && "Invalid logical element");
+  assert(CTy && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructType] DICompositeType\n";
+    CTy->dump();
+  });
+
+  dwarf::Tag Tag = Scope->getTag();
+  switch (Tag) {
+  case dwarf::DW_TAG_array_type:
+    constructArray(static_cast<LVScopeArray *>(Scope), CTy);
+    break;
+  case dwarf::DW_TAG_enumeration_type:
+    constructEnum(static_cast<LVScopeEnumeration *>(Scope), CTy);
+    break;
+  // FIXME: Not implemented.
+  case dwarf::DW_TAG_variant_part:
+  case dwarf::DW_TAG_namelist:
+    break;
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_union_type:
+  case dwarf::DW_TAG_class_type: {
+    constructAggregate(static_cast<LVScopeAggregate *>(Scope), CTy);
+    break;
+  }
+  default:
+    break;
+  }
+
+  if (Tag == dwarf::DW_TAG_enumeration_type ||
+      Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type ||
+      Tag == dwarf::DW_TAG_union_type) {
+    // Add accessibility info if available.
+    addAccess(Scope, CTy->getFlags());
+
+    // Add source line info if available.
+    if (!CTy->isForwardDecl())
+      addSourceLine(Scope, CTy);
+  }
+}
+
+// DIDerivedType
+//   DW_TAG_atomic_type
+//   DW_TAG_const_type
+//   DW_TAG_friend
+//   DW_TAG_inheritance
+//   DW_TAG_member
+//   DW_TAG_immutable_type
+//   DW_TAG_pointer_type
+//   DW_TAG_ptr_to_member_type
+//   DW_TAG_reference_type
+//   DW_TAG_restrict_type
+//   DW_TAG_typedef
+//   DW_TAG_volatile_type
+void LVIRReader::constructType(LVElement *Element, const DIDerivedType *DT) {
+  assert(Element && "Invalid logical element");
+  assert(DT && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructType] DIDerivedType\n";
+    DT->dump();
+  });
+
+  // For DW_TAG_member, the flag is set during the construction of the
+  // aggregate type (DICompositeType).
+  if (DT->getTag() != dwarf::DW_TAG_member)
+    Element->setIsFinalized();
+
+  LVElement *BaseType = getOrCreateType(DT->getBaseType());
+  Element->setType(BaseType);
+
+  // Add accessibility info if available.
+  if (!DT->isStaticMember())
+    addAccess(Element, DT->getFlags());
+
+  if (DT->isVirtual())
+    Element->setVirtualityCode(dwarf::DW_VIRTUALITY_virtual);
+
+  if (DT->isArtificial())
+    Element->setIsArtificial();
+
+  // Add source line info if available and TyDesc is not a forward declaration.
+  if (!DT->isForwardDecl())
+    addSourceLine(Element, DT);
+}
+
+// DISubroutineType
+void LVIRReader::constructType(LVScope *Function,
+                               const DISubroutineType *SPTy) {
+  assert(Function && "Invalid logical element");
+  assert(SPTy && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructType] DISubroutineType\n";
+    SPTy->dump();
+  });
+
+  if (Function->getIsFinalized())
+    return;
+  Function->setIsFinalized();
+
+  // For DISubprogram, the DISubroutineType contains the types for:
+  //   return type, param 1 type, ..., param n type
+  DITypeRefArray Args = SPTy->getTypeArray();
+  if (Args.size()) {
+    LVElement *ElementType = getOrCreateType(Args[0]);
+    Function->setType(ElementType);
+  }
+
+  constructSubprogramArguments(Function, Args);
+}
+
+// DINamespace
+LVScope *LVIRReader::getOrCreateNamespace(const DINamespace *NS) {
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateNamespace] DINamespace\n";
+    NS->dump();
+  });
+
+  LVScope *Scope = getOrCreateScope(NS);
+  if (Scope) {
+    StringRef Name = NS->getName();
+    if (Name.empty())
+      Scope->setName("(anonymous namespace)");
+  }
+
+  return Scope;
+}
+
+LVScope *LVIRReader::getOrCreateScope(const DIScope *Context) {
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateScope] DIScope\n";
+    Context->dump();
+  });
+
+  // Check if the scope is already created.
+  LVScope *Scope = getScopeForSeenMD(Context);
+  if (Scope)
+    return Scope;
+
+  Scope = static_cast<LVScope *>(constructElement(Context));
+  if (Scope) {
+    // Add element to parent.
+    LVScope *Parent = getParentScope(Context);
+    Parent->addElement(Scope);
+  }
+
+  return Scope;
+}
+
+// DICompositeType
+// DIDerivedType
+// DISubroutineType
+LVElement *LVIRReader::getOrCreateType(const DIType *Ty, LVScope *Scope) {
+  if (!Ty)
+    return nullptr;
+
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateType] DIType\n";
+    Ty->dump();
+  });
+
+  // Check if the element is already created.
+  LVElement *Element = getElementForSeenMD(Ty);
+  if (Element)
+    return Element;
+
+  Element = constructElement(Ty);
+  if (Element) {
+    // Add element to parent.
+    LVScope *Parent = Scope ? Scope : getParentScope(Ty);
+    Parent->addElement(Element);
+
+    if (/*const DIBasicType *BT =*/dyn_cast<DIBasicType>(Ty)) {
+      Element->setIsFinalized();
+    } else if (const DIDerivedType *DT = dyn_cast<DIDerivedType>(Ty)) {
+      constructType(Element, DT);
+    } else if (const DICompositeType *CTy = dyn_cast<DICompositeType>(Ty)) {
+      constructType(static_cast<LVScope *>(Element), CTy);
+    } else if (const DISubroutineType *SPTy = dyn_cast<DISubroutineType>(Ty)) {
+      constructType(static_cast<LVScope *>(Element), SPTy);
+    }
+  }
+
+  return Element;
+}
+
+// DIGlobalVariableExpression
+LVSymbol *
+LVIRReader::getOrCreateVariable(const DIGlobalVariableExpression *GVE) {
+  assert(GVE && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateVariable] DIGlobalVariableExpression\n";
+    GVE->dump();
+  });
+
+  const DIGlobalVariable *DIGV = GVE->getVariable();
+  LVSymbol *Symbol = getSymbolForSeenMD(DIGV);
+  if (!Symbol)
+    Symbol = getOrCreateVariable(DIGV);
+
+  if (Symbol) {
+    // Add location and operation entries.
+    Symbol->addLocation(dwarf::DW_AT_location, /*LowPC=*/0, /*HighPC=*/-1,
+                        /*SectionOffset=*/0, /*OffsetOnEntry=*/0);
+    Symbol->addLocationOperands(dwarf::DW_OP_addrx, PoolAddressIndex++);
+    if (const DIExpression *DIExpr = GVE->getExpression())
+      addConstantValue(Symbol, DIExpr);
+  }
+  return Symbol;
+}
+
+LVSymbol *LVIRReader::getOrCreateAbstractVariable(LVSymbol *OriginSymbol,
+                                                  const DILocation *DL) {
+  assert(OriginSymbol && "Invalid logical element");
+  assert(DL && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateAbstractVariable] DIVariable\n";
+    DL->dump();
+  });
+
+  const DILocation *InlinedAt = DL->getInlinedAt();
+  if (!InlinedAt) {
+    return nullptr;
+  }
+
+  dwarf::Tag Tag = OriginSymbol->getTag();
+  LVSymbol *AbstractSymbol = static_cast<LVSymbol *>(createElement(Tag));
+  if (AbstractSymbol) {
+    AbstractSymbol->setTag(Tag);
+    AbstractSymbol->setIsFinalized();
+    AbstractSymbol->setName(OriginSymbol->getName());
+    AbstractSymbol->setType(OriginSymbol->getType());
+
+    AbstractSymbol->setCallLineNumber(InlinedAt->getLine());
+    AbstractSymbol->setCallFilenameIndex(
+        getOrCreateSourceID(InlinedAt->getFile()));
+
+    OriginSymbol->setInlineCode(dwarf::DW_INL_inlined);
+    AbstractSymbol->setReference(OriginSymbol);
+    AbstractSymbol->setHasReferenceAbstract();
+
+    if (OriginSymbol->getIsParameter())
+      AbstractSymbol->setIsParameter();
+
+    LVScope *OriginScope = OriginSymbol->getParentScope();
+    assert(OriginScope && "Invalid logical element");
+    LVScope *AbstractScope = getInlinedScope(OriginScope);
+    if (!AbstractScope)
+      AbstractScope = getOrCreateAbstractScope(OriginScope, DL);
+
+    assert(AbstractScope && "Parent scope is NULL.");
+    AbstractScope->addElement(AbstractSymbol);
+  }
+
+  return AbstractSymbol;
+}
+
+// DIGlobalVariable
+// DILocalVariable
+LVSymbol *LVIRReader::getOrCreateVariable(const DIVariable *Var,
+                                          const DILocation *DL) {
+  assert(Var && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateVariable] DIVariable\n";
+    Var->dump();
+    if (DL) {
+      dbgs() << "DILocation\n";
+      DL->dump();
+    }
+  });
+
+  LVSymbol *Symbol = getSymbolForSeenMD(Var);
+  if (Symbol && Symbol->getIsFinalized())
+    return Symbol;
+
+  if (!options().getPrintSymbols()) {
+    // Just create the symbol type.
+    getOrCreateType(Var->getType());
+    if (const DIGlobalVariable *GV = dyn_cast<DIGlobalVariable>(Var)) {
+      if (MDTuple *TP = GV->getTemplateParams())
+        addTemplateParams(Symbol, DINodeArray(TP));
+    }
+    return nullptr;
+  }
+
+  if (!Symbol)
+    Symbol = static_cast<LVSymbol *>(constructElement(Var));
+  if (Symbol) {
+    Symbol->setIsFinalized();
+    LVScope *Parent = getParentScope(Var);
+    Parent->addElement(Symbol);
+
+    Symbol->setName(Var->getName());
+
+    // Create symbol type.
+    if (LVElement *SymbolType = getOrCreateType(Var->getType()))
+      Symbol->setType(SymbolType);
+
+    if (const DILocalVariable *LV = dyn_cast<DILocalVariable>(Var)) {
+      // Add line number info.
+      addSourceLine(Symbol, LV);
+      if (LV->isParameter()) {
+        Symbol->setIsParameter();
+        if (LV->isArtificial())
+          Symbol->setIsArtificial();
+      }
+    } else {
+      const DIGlobalVariable *GV = dyn_cast<DIGlobalVariable>(Var);
+      if (useAllLinkageNames())
+        Symbol->setLinkageName(GV->getLinkageName());
+
+      // Get 'declaration' node in order to generate the DW_AT_specification.
+      if (const DIDerivedType *GVDecl = GV->getStaticDataMemberDeclaration()) {
+        LVSymbol *Reference = static_cast<LVSymbol *>(getOrCreateType(GVDecl));
+        if (Reference) {
+          Symbol->setReference(Reference);
+          Symbol->setHasReferenceSpecification();
+        }
+      } else {
+        if (!GV->isLocalToUnit())
+          Symbol->setIsExternal();
+        // Add line number info.
+        addSourceLine(Symbol, GV);
+      }
+
+      if (MDTuple *TP = GV->getTemplateParams())
+        addTemplateParams(Symbol, DINodeArray(TP));
+    }
+
+    // Create the 'abstract' symbol.
+    if (DL)
+      getOrCreateAbstractVariable(Symbol, DL);
+  }
+
+  return Symbol;
+}
+
+#ifdef LLVM_DEBUG
+void LVIRReader::printAllInstructions(BasicBlock *BB) {
+  LLVM_DEBUG({
+    dbgs() << "\nBegin all instructions:\n";
+    for (Instruction &I : *BB) {
+      dbgs() << "Instruction: '" << I << "'\n";
+      for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
+        DVR.getVariable()->dump();
+    }
+    dbgs() << "End all instructions:\n\n";
+  });
+}
+#endif
+
+void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
+  assert(SP && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[processBasicBlocks] DISubprogram\n";
+    SP->dump();
+  });
+
+  // Check if we need to add a dwarf::DW_TAG_unspecified_parameters.
+  bool AddUnspecifiedParameters = false;
+  if (const DISubroutineType *SPTy = SP->getType()) {
+    DITypeRefArray Args = SPTy->getTypeArray();
+    unsigned N = Args.size();
+    if (N > 1) {
+      const DIType *Ty = Args[N - 1];
+      if (!Ty)
+        AddUnspecifiedParameters = true;
+    }
+  }
+
+  LVScope *Scope = getOrCreateSubprogram(SP);
+
+  SmallVector<DebugVariableAggregate> SeenVars;
+
+  // Handle dbg.values and dbg.declare.
+  auto HandleDbgVariable = [&](Instruction &I, auto *DbgVar) {
+    LLVM_DEBUG({
+      dbgs() << "\n[HandleDbgVariable]\n";
+      DbgVar->dump();
+    });
+
+    DebugVariableAggregate DVA(DbgVar);
+    if (!DbgValueRanges->hasVariableEntry(DVA)) {
+      DbgValueRanges->addVariable(&F, DVA);
+      SeenVars.push_back(DVA);
+    }
+
+    // Skip undefined values.
+    if (!DbgVar->isKillLocation())
+      getOrCreateVariable(DbgVar->getVariable(), DbgVar->getDebugLoc().get());
+
+    if (const auto *DL =
+            cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg))) {
+      getOrCreateInlinedScope(Scope, DL);
+    }
+  };
+
+  GenerateLineBeforePrologue = true;
+  for (BasicBlock &BB : F) {
+    printAllInstructions(&BB);
+
+    for (Instruction &I : BB) {
+      LLVM_DEBUG(dbgs() << "\nInstruction: '" << I << "'\n");
+
+      for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
+        HandleDbgVariable(I, &DVR);
+
+      if (options().getPrintAnyLine())
+        constructLine(Scope, SP, I);
+
+      // Update code offset.
+      updateLineOffset();
+    }
+    DbgValueRanges->addLine(BB.end(), CurrentOffset);
+  }
+  GenerateLineBeforePrologue = false;
+
+  if (AddUnspecifiedParameters) {
+    LVElement *Parameter = createElement(dwarf::DW_TAG_unspecified_parameters);
+    if (Parameter) {
+      Parameter->setIsFinalized();
+      Scope->addElement(Parameter);
+    }
+  }
+
+  LLVM_DEBUG({ dbgs() << "Traverse seen debug variables\n"; });
+  for (auto DVA : SeenVars) {
+    LLVM_DEBUG({ DbgValueRanges->printValues(DVA, dbgs()); });
+    DILocalVariable *LV = const_cast<DILocalVariable *>(DVA.getVariable());
+    LVSymbol *Symbol = getSymbolForSeenMD(LV);
+    // Undefined only value, ignore.
+    if (!Symbol)
+      continue;
+
+    DIType *Ty = LV->getType();
+    uint64_t Size = Ty ? Ty->getSizeInBits() / CHAR_BIT : 1;
+    LLVM_DEBUG({
+      LV->dump();
+      Ty->dump();
+      dbgs() << "Type size: " << Size << "\n";
+    });
+
+    auto AddLocationOp = [&](Value *V, bool IsMem) {
+      uint64_t RegValue = DbgValueRanges->addVariableName(V, Size);
+      if (IsMem)
+        Symbol->addLocationOperands(dwarf::DW_OP_bregx, {RegValue, 0});
+      else
+        Symbol->addLocationOperands(dwarf::DW_OP_regx, RegValue);
+    };
+
+    auto AddLocation = [&](DbgValueDef DV) {
+      bool IsMem = DV.IsMemory;
+      DIExpression *CanonicalExpr = const_cast<DIExpression *>(
+          DIExpression::convertToVariadicExpression(DV.Expression));
+      RawLocationWrapper Locations(DV.Locations);
+      for (DIExpression::ExprOperand ExprOp : CanonicalExpr->expr_ops()) {
+        if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg) {
+          AddLocationOp(Locations.getVariableLocationOp(ExprOp.getArg(0)),
+                        IsMem);
+        } else {
+          if (ExprOp.getOp() > std::numeric_limits<uint8_t>::max())
+            LLVM_DEBUG(dbgs() << "Bad DWARF op: " << ExprOp.getOp() << "\n");
+          uint8_t ShortOp = (uint8_t)ExprOp.getOp();
+          Symbol->addLocationOperands(
+              ShortOp,
+              ArrayRef<uint64_t>(std::next(ExprOp.get()), ExprOp.getNumArgs()));
+        }
+      }
+    };
+
+    if (DbgValueRanges->hasSingleLocEntry(DVA)) {
+      DbgValueDef DV = DbgValueRanges->getSingleLoc(DVA);
+      Symbol->addLocation(llvm::dwarf::DW_AT_location, /*LowPC=*/0,
+                          /*HighPC=*/-1, /*SectionOffset=*/0,
+                          /*OffsetOnEntry=*/0);
+      assert(DV.IsMemory && "Single location should be memory!");
+      AddLocation(DV);
+    } else {
+      for (DbgRangeEntry Entry : DbgValueRanges->getVariableRanges(DVA)) {
+        LVOffset Start = DbgValueRanges->getLine(Entry.Start);
+        LVOffset End = DbgValueRanges->getLine(Entry.End);
+        Symbol->addLocation(llvm::dwarf::DW_AT_location, Start, End,
+                            /*SectionOffset=*/0, /*OffsetOnEntry=*/0);
+        DbgValueDef DV = Entry.Value;
+        AddLocation(DV);
+      }
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// IR Reader entry point.
+//===----------------------------------------------------------------------===//
+Error LVIRReader::createScopes() {
+  LLVM_DEBUG({
+    W.startLine() << "\n";
+    W.printString("File", getFilename());
+    W.printString("Format", FileFormatName);
+  });
+
+  // The IR Reader supports only debug records.
+  // We identify the debug input format and if it is intrinsics, it is
+  // converted to the debug records.
+  if (Error Err = LVReader::createScopes())
+    return Err;
+
+  LLVMContext Context;
+  SMDiagnostic Err;
+  std::unique_ptr<Module> M = parseIR(
+      BitCodeIR ? BitCodeIR->getMemoryBufferRef() : *TextualIR, Err, Context);
+  if (!M)
+    return createStringError(errc::invalid_argument,
+                             "Could not create IR information: %s",
+                             getFilename().str().c_str());
+
+  if (!M->getNamedMetadata("llvm.dbg.cu")) {
+    LLVM_DEBUG(dbgs() << "Skipping module without debug info\n");
+    return Error::success();
+  }
+
+  DwarfVersion = M->getDwarfVersion();
+
+  LLVM_DEBUG({ dbgs() << "\nProcess CompileUnits\n"; });
+  for (const DICompileUnit *CU : M->debug_compile_units()) {
+    LLVM_DEBUG({
+      dbgs() << "\nDICompileUnit:\n";
+      CU->dump();
+    });
+
+    // Record if the current source language is Fortran.
+    mapFortranLanguage(CU->getSourceLanguage());
+
+    CompileUnit = static_cast<LVScopeCompileUnit *>(constructElement(CU));
+    CUNode = const_cast<DICompileUnit *>(CU);
+
+    const DIFile *File = CU->getFile();
+    CompileUnit->setName(File->getFilename());
+    CompileUnit->setCompilationDirectory(File->getDirectory());
+    CompileUnit->setIsFinalized();
+
+    Root->addElement(CompileUnit);
+
+    if (options().getAttributeProducer())
+      CompileUnit->setProducer(CU->getProducer());
+
+    // Global Variables.
+    LLVM_DEBUG({ dbgs() << "\nGlobal Variables\n"; });
+    for (const DIGlobalVariableExpression *GVE : CU->getGlobalVariables())
+      getOrCreateVariable(GVE);
+
+    // The enumeration types need to be created, regardless if they are
+    // nested to any other aggregate type, as they are not included in
+    // their elements. But their scope is correct (aggregate).
+    LLVM_DEBUG({ dbgs() << "\nEnumeration Types\n"; });
+    for (auto *ET : CU->getEnumTypes())
+      getOrCreateType(ET);
+
+    // Retained types.
+    LLVM_DEBUG({ dbgs() << "\nRetained Types\n"; });
+    for (const auto *RT : CU->getRetainedTypes()) {
+      if (const auto *Ty = dyn_cast<DIType>(RT)) {
+        getOrCreateType(Ty);
+      } else {
+        getOrCreateSubprogram(cast<DISubprogram>(RT));
+      }
+    }
+
+    // Imported entities.
+    LLVM_DEBUG({ dbgs() << "\nImported Entities\n"; });
+    for (const auto *IE : CU->getImportedEntities())
+      constructImportedEntity(CompileUnit, IE);
+  }
+
+  // Traverse Functions.
+  LLVM_DEBUG({
+    dbgs() << "\nFunctions\n";
+    for (Function &F : M->getFunctionList())
+      if (const auto *SP = cast_or_null<DISubprogram>(F.getSubprogram()))
+        SP->dump();
+  });
+
+  for (Function &F : M->getFunctionList())
+    if (const auto *SP = cast_or_null<DISubprogram>(F.getSubprogram()))
+      processBasicBlocks(F, SP);
+
+  // Perform extra tasks on the created scopes.
+  removeEmptyScopes();
+  processLocationGaps();
+  processScopes();
+
+  if (options().getInternalIntegrity())
+    checkScopes(CompileUnit);
+
+  return Error::success();
+}
+
+void LVIRReader::constructRange(LVScope *Scope, LVAddress LowPC,
+                                LVAddress HighPC) {
+  assert(Scope && "Invalid logical element");
+  LLVM_DEBUG({
+    dbgs() << "\n[constructRange]\n";
+    dbgs() << "ID: " << hexString(Scope->getID()) << " ";
+    dbgs() << "LowPC: " << hexString(LowPC) << " ";
+    dbgs() << "HighPC: " << hexString(HighPC) << " ";
+    dbgs() << "Name: " << Scope->getName() << "\n";
+  });
+
+  // Process ranges base on logical lines.
+  Scope->addObject(LowPC, HighPC);
+  if (!Scope->getIsCompileUnit()) {
+    // If the scope is a function, add it to the public names.
+    if ((options().getAttributePublics() || options().getPrintAnyLine()) &&
+        Scope->getIsFunction() && !Scope->getIsInlinedFunction())
+      CompileUnit->addPublicName(Scope, LowPC, HighPC);
+  }
+  addSectionRange(SectionIndex, Scope, LowPC, HighPC);
+
+  // Replicate DWARF reader funtionality of processing DW_AT_ranges for
+  // the compilation unit.
+  CompileUnit->addObject(LowPC, HighPC);
+  addSectionRange(SectionIndex, CompileUnit, LowPC, HighPC);
+}
+
+// Create the location ranges for the given scope and in the case of
+// functions, generate an entry in the public names set.
+void LVIRReader::constructRange(LVScope *Scope) {
+  LLVM_DEBUG({
+    dbgs() << "\n[constructRange]\n";
+    dbgs() << "ID: " << hexString(Scope->getID()) << " ";
+    dbgs() << "Name: " << Scope->getName() << "\n\n";
+  });
+
+  auto NextRange = [&](LVAddress Offset) -> LVAddress {
+    return Offset + OffsetIncrease - 1;
+  };
+
+  // Get any logical lines.
+  const LVLines *Lines = Scope->getLines();
+  if (!Lines)
+    return;
+
+  // Traverse the logical lines and build the logical ranges.
+  LVAddress Lower = 0;
+  LVAddress Upper = 0;
+  LVAddress Current = 0;
+  LVAddress Previous = 0;
+  for (const LVLine *Line : *Lines) {
+    LLVM_DEBUG({
+      dbgs() << "[" << hexString(Line->getAddress()) << "] ";
+      dbgs() << "LineNo: " << decString(Line->getLineNumber()) << "\n";
+      dbgs() << "Lower: " << hexString(Lower) << " ";
+      dbgs() << "Upper: " << hexString(Upper) << " ";
+      dbgs() << "Previous: " << hexString(Previous) << " ";
+      dbgs() << "Current: " << hexString(Current) << "\n";
+    });
+    if (!Upper) {
+      // First line in range.
+      Lower = Line->getAddress();
+      Upper = NextRange(Lower);
+      Current = Lower;
+      continue;
+    }
+    Previous = Current;
+    Current = Line->getAddress();
+    if (Current == Previous) {
+      // Contiguous lines at the same address (Debug and its assembler).
+      continue;
+    }
+    if (Current == Upper + 1) {
+      // There is no gap.
+      Upper = NextRange(Current);
+    } else {
+      // There is a gap.
+      constructRange(Scope, Lower, Upper);
+      Lower = Current;
+      Upper = NextRange(Lower);
+    }
+  }
+  constructRange(Scope, Lower, Upper);
+}
+
+// At this point, all scopes for the compile unit has been created.
+// The following aditional steps need to be performed on them:
+// - If the lexical block doesn't have non-scope children, skip its
+//   emission and put its children directly to the parent scope.
+// The '--internal=id' is turned on just for debugging traces. Then
+// it is turned to its previous state.
+void LVIRReader::removeEmptyScopes() {
+  // Preserve current setting for '--internal=id'.
+  bool InternalID = options().getInternalID();
+
+  SmallVector<LVScope *> EmptyScopes;
+
+  // Delete lexically empty scopes.
+  auto DeleteEmptyScopes = [&]() {
+    if (EmptyScopes.empty())
+      return;
+
+    LLVM_DEBUG({
+      dbgs() << "\n** Collected empty scopes **\n";
+      for (auto Scope : EmptyScopes)
+        Scope->print(dbgs());
+    });
+
+    LVScope *Parent = nullptr;
+    for (auto Scope : EmptyScopes) {
+      Parent = Scope->getParentScope();
+      LLVM_DEBUG({
+        dbgs() << "Scope: " << Scope->getID() << ", ";
+        dbgs() << "Parent: " << Parent->getID() << "\n";
+      });
+
+      // If the target scope has lines, move them to the scope parent.
+      const LVLines *Lines = Scope->getLines();
+      if (Lines) {
+        for (LVLine *Line : *Lines) {
+          if (Scope->removeElement(Line)) {
+            LLVM_DEBUG({ dbgs() << "Line: " << Line->getID() << "\n"; });
+            Line->resetParent();
+            Parent->addElement(Line);
+            Line->updateLevel(Parent, /*Moved=*/false);
+          }
+        }
+      }
+
+      if (Parent->removeElement(Scope)) {
+        const LVScopes *Scopes = Scope->getScopes();
+        if (Scopes)
+          for (LVScope *Child : *Scopes) {
+            LLVM_DEBUG({ dbgs() << "Child: " << Child->getID() << "\n"; });
+            Child->resetParent();
+            Parent->addElement(Child);
+            Child->updateLevel(Parent, /*Moved=*/false);
+          }
+      }
+    }
+  };
+
+  // Traverse the scopes tree and collect those lexical blocks that does not
+  // have non-scope children. Do not include the lines as they are included
+  // in the logical view as a way to show their associated logical scope.
+  std::function<void(LVScope *)> TraverseScope = [&](LVScope *Current) {
+    auto IsEmpty = [](LVScope *Scope) -> bool {
+      return !Scope->getSymbols() && !Scope->getTypes() && !Scope->getRanges();
+    };
+
+    if (const LVScopes *Scopes = Current->getScopes()) {
+      for (LVScope *Scope : *Scopes) {
+        if (Scope->getIsLexicalBlock() && IsEmpty(Scope))
+          EmptyScopes.push_back(Scope);
+        TraverseScope(Scope);
+      }
+    }
+  };
+
+  TraverseScope(CompileUnit);
+  DeleteEmptyScopes();
+
+  // Restore setting for '--internal=id'.
+  if (InternalID)
+    options().setInternalID();
+}
+
+// During the IR Reader development, traverse all the logical elements
+// to check if they have been properly constructed (finalized).
+void LVIRReader::checkScopes(LVScope *Scope) {
+  auto PrintElement = [](LVElement *Element) {
+    LLVM_DEBUG({
+      dwarf::Tag Tag = Element->getTag();
+      size_t ID = Element->getID();
+      const char *Kind = Element->kind();
+      StringRef Name = Element->getName();
+      uint32_t LineNumber = Element->getLineNumber();
+      dbgs() << "Tag: "
+             << formatv("{0} ", fmt_align(Tag, AlignStyle::Left, 35));
+      dbgs() << "ID: " << formatv("{0} ", fmt_align(ID, AlignStyle::Left, 5));
+      dbgs() << "Kind: "
+             << formatv("{0} ", fmt_align(Kind, AlignStyle::Left, 15));
+      dbgs() << "Line: "
+             << formatv("{0} ", fmt_align(LineNumber, AlignStyle::Left, 5));
+      dbgs() << "Name: '" << std::string(Name) << "' ";
+      dbgs() << "\n";
+    });
+  };
+
+  std::function<void(LVScope * Parent)> Traverse = [&](LVScope *Current) {
+    auto Check = [&](const auto &Set) {
+      if (Set)
+        for (const auto &Entry : *Set)
+          if (!Entry->getIsFinalized())
+            PrintElement(Entry);
+    };
+
+    Check(Current->getChildren());
+
+    if (Current->getScopes())
+      for (LVScope *Scope : *Current->getScopes())
+        Traverse(Scope);
+  };
+
+  // Start traversing the scopes root and check its integrity.
+  Traverse(Scope);
+}
+
+void LVIRReader::sortScopes() { Root->sort(); }
+
+void LVIRReader::print(raw_ostream &OS) const {
+  OS << "LVIRReader\n";
+  LLVM_DEBUG(dbgs() << "CreateReaders\n");
+}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test
new file mode 100644
index 0000000000000..0c2741b1a0adb
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test
@@ -0,0 +1,121 @@
+; REQUIRES: x86-registered-target
+
+; Test case 1 - General options
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; Compare mode - Logical view.
+; The output shows in view form the 'missing (-), added (+)' elements,
+; giving more context by swapping the reference and target object files.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=view \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/test-clang.ll \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Reference: 'test-clang.ll'
+; ONE-NEXT: Target:    'test-dwarf-gcc.o'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT:  [000]           {File} 'test-clang.ll'
+; ONE-EMPTY:
+; ONE-NEXT:  [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT:  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+; ONE-NEXT:  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT:  [003]                 {Block}
+; ONE-NEXT:  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: +[004]     4             {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: -[003]     4           {TypeAlias} 'INTEGER' -> 'int'
+
+; Compare mode - Logical elements.
+; The output shows in tabular form the 'missing (-), added (+)' elements,
+; giving more context by swapping the reference and target object files.
+
+; RUN: llvm-as %p/Inputs/test-clang.ll -o %t.test-clang.bc
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %t.test-clang.bc \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Reference: '{{.*}}test-clang.bc'
+; TWO-NEXT: Target:    'test-dwarf-gcc.o'
+; TWO-EMPTY:
+; TWO-NEXT: (1) Missing Scopes:
+; TWO-NEXT: -[003]           {Block}
+; TWO-EMPTY:
+; TWO-NEXT: (1) Missing Types:
+; TWO-NEXT: -[003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: (1) Added Types:
+; TWO-NEXT: +[004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Element   Expected    Missing      Added
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Scopes           6          1          0
+; TWO-NEXT: Symbols          0          0          0
+; TWO-NEXT: Types            2          1          1
+; TWO-NEXT: Lines            0          0          0
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Total            8          2          1
+
+; Changing the 'Reference' and 'Target' order:
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o \
+; RUN:                         %p/Inputs/test-clang.ll 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THREE %s
+
+; THREE:      Reference: 'test-dwarf-gcc.o'
+; THREE-NEXT: Target:    'test-clang.ll'
+; THREE-EMPTY:
+; THREE-NEXT: (1) Missing Types:
+; THREE-NEXT: -[004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; THREE-EMPTY:
+; THREE-NEXT: (1) Added Scopes:
+; THREE-NEXT: +[003]           {Block}
+; THREE-EMPTY:
+; THREE-NEXT: (1) Added Types:
+; THREE-NEXT: +[003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; THREE-EMPTY:
+; THREE-NEXT: ----------------------------------------
+; THREE-NEXT: Element   Expected    Missing      Added
+; THREE-NEXT: ----------------------------------------
+; THREE-NEXT: Scopes           4          0          1
+; THREE-NEXT: Symbols          0          0          0
+; THREE-NEXT: Types            2          1          1
+; THREE-NEXT: Lines            0          0          0
+; THREE-NEXT: ----------------------------------------
+; THREE-NEXT: Total            6          1          2
+
+; Comparing IR and DWARF:
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o \
+; RUN:                         %p/Inputs/test-clang.ll 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THREE %s
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test
new file mode 100644
index 0000000000000..064b0ef626417
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test
@@ -0,0 +1,76 @@
+; REQUIRES: x86-registered-target
+
+; Test case 1 - General options.
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; Print basic details.
+; The following command prints basic details for all the logical elements
+; sorted by the debug information internal offset; it includes its lexical
+; level and debug info format.
+
+; RUN: llvm-as %p/Inputs/test-clang.ll -o %t.test-clang.bc
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=offset \
+; RUN:                         --print=scopes,symbols,types,lines,instructions \
+; RUN:                         %t.test-clang.bc 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=offset \
+; RUN:                         --print=elements \
+; RUN:                         %t.test-clang.bc 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} '{{.*}}test-clang.bc' -> Bitcode IR
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: [004]     5             {Line}
+; ONE-NEXT: [004]                   {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
+; ONE-NEXT: [004]     6             {Line}
+; ONE-NEXT: [004]                   {Code} 'store i32 7, ptr %retval, align 4, !dbg !33'
+; ONE-NEXT: [004]     6             {Line}
+; ONE-NEXT: [004]                   {Code} 'br label %return, !dbg !33'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT: [003]     2           {Line}
+; ONE-NEXT: [003]                 {Code} '%retval = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} '%ParamPtr.addr = alloca ptr, align 8'
+; ONE-NEXT: [003]                 {Code} '%ParamUnsigned.addr = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} '%ParamBool.addr = alloca i8, align 1'
+; ONE-NEXT: [003]                 {Code} '%CONSTANT = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} 'store ptr %ParamPtr, ptr %ParamPtr.addr, align 8'
+; ONE-NEXT: [003]                 {Code} 'store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4'
+; ONE-NEXT: [003]                 {Code} '%storedv = zext i1 %ParamBool to i8'
+; ONE-NEXT: [003]                 {Code} 'store i8 %storedv, ptr %ParamBool.addr, align 1'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} 'br label %return, !dbg !35'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret i32 %2, !dbg !36'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
+; ONE-NEXT: [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test
new file mode 100644
index 0000000000000..48466d1bd5aa3
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test
@@ -0,0 +1,122 @@
+; REQUIRES: x86-registered-target
+
+; Test case 1 - General options
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; Select logical elements.
+; The following prints all 'instructions', 'symbols' and 'types' that
+; contain 'LOAD' or 'store' in their names or types, using a tab layout
+; and given the number of matches.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --select-nocase --select-regex \
+; RUN:                         --select=LOAD --select=store \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,instructions,summary \
+; RUN:                         %p/Inputs/test-clang.ll 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'test-clang.ll'
+; ONE-EMPTY:
+; ONE-NEXT: [001]           {CompileUnit} 'test.cpp'
+; ONE-NEXT: [003]           {Code} '%0 = load i8, ptr %ParamBool.addr, align 1, !dbg !26'
+; ONE-NEXT: [003]           {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34'
+; ONE-NEXT: [003]           {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36'
+; ONE-NEXT: [003]           {Code} '%storedv = zext i1 %ParamBool to i8'
+; ONE-NEXT: [003]           {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
+; ONE-NEXT: [003]           {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35'
+; ONE-NEXT: [003]           {Code} 'store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4'
+; ONE-NEXT: [004]           {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
+; ONE-NEXT: [004]           {Code} 'store i32 7, ptr %retval, align 4, !dbg !33'
+; ONE-NEXT: [003]           {Code} 'store i8 %storedv, ptr %ParamBool.addr, align 1'
+; ONE-NEXT: [003]           {Code} 'store ptr %ParamPtr, ptr %ParamPtr.addr, align 8'
+; ONE-EMPTY:
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Element      Total    Printed
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Scopes           5          0
+; ONE-NEXT: Symbols          4          0
+; ONE-NEXT: Types            2          0
+; ONE-NEXT: Lines           22         11
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Total           33         11
+
+; RUN: llvm-as %p/Inputs/test-clang.ll -o %t.test-clang.bc
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --select-regex --select-nocase \
+; RUN:                         --select=INTe \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types \
+; RUN:                         %t.test-clang.bc \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} '{{.*}}test-clang.bc'
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'test.cpp'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'test-dwarf-gcc.o'
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'test.cpp'
+; TWO-NEXT: [004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
+
+; Select logical elements based on linkage names.
+; The following prints all symbols that contain "_Z3fooPKijb" in their
+; linkage names, using a tab layout and given the number of matches.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --select=_Z3fooPKijb \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,summary \
+; RUN:                         %p/Inputs/test-clang.ll \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THREE %s
+
+; THREE:      Logical View:
+; THREE-NEXT: [000]           {File} 'test-clang.ll'
+; THREE-EMPTY:
+; THREE-NEXT: [001]           {CompileUnit} 'test.cpp'
+; THREE-NEXT: [002]     2     {Function} extern not_inlined 'foo' -> 'int'
+; THREE-EMPTY:
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Element      Total    Printed
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Scopes           5          1
+; THREE-NEXT: Symbols          4          0
+; THREE-NEXT: Types            2          0
+; THREE-NEXT: Lines            0          0
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Total           11          1
+; THREE-EMPTY:
+; THREE-NEXT: Logical View:
+; THREE-NEXT: [000]           {File} 'test-dwarf-gcc.o'
+; THREE-EMPTY:
+; THREE-NEXT: [001]           {CompileUnit} 'test.cpp'
+; THREE-NEXT: [002]     2     {Function} extern not_inlined 'foo' -> 'int'
+; THREE-EMPTY:
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Element      Total    Printed
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Scopes           3          1
+; THREE-NEXT: Symbols          4          0
+; THREE-NEXT: Types            2          0
+; THREE-NEXT: Lines            0          0
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Total            9          1
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test
new file mode 100644
index 0000000000000..f8470e5bf27ae
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test
@@ -0,0 +1,60 @@
+; REQUIRES: x86-registered-target
+
+; Test case 2 - Assembler instructions.
+
+; hello-world.cpp
+;  1  extern int printf(const char * format, ... );
+;  2
+;  3  int main()
+;  4  {
+;  5    printf("Hello, World\n");
+;  6    return 0;
+;  7  }
+
+; Logical lines.
+; The logical views shows the intermixed lines and assembler instructions,
+; allowing to compare the code generated at different stages.
+
+; RUN: llvm-as %p/Inputs/hello-world-clang.ll -o %t.hello-world-clang.bc
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --print=lines,instructions \
+; RUN:                         %t.hello-world-clang.bc \
+; RUN:                         %p/../DWARF/Inputs/hello-world-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} '{{.*}}hello-world-clang.bc' -> Bitcode IR
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 20{{.*}}'
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'main' -> 'int'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} '%retval = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} 'store i32 0, ptr %retval, align 4'
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]                 {Code} '%call = call noundef i32 (ptr, ...) @_Z6printfPKcz(ptr noundef @.str), !dbg !22'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret i32 0, !dbg !23'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'hello-world-dwarf-clang.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 15{{.*}}'
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'main' -> 'int'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [003]                 {Code} 'subq	$0x10, %rsp'
+; ONE-NEXT: [003]                 {Code} 'movl	$0x0, -0x4(%rbp)'
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]                 {Code} 'leaq	(%rip), %rdi'
+; ONE-NEXT: [003]                 {Code} 'movb	$0x0, %al'
+; ONE-NEXT: [003]                 {Code} 'callq	0x0'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [003]                 {Code} 'xorl	%eax, %eax'
+; ONE-NEXT: [003]                 {Code} 'addq	$0x10, %rsp'
+; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'retq'
+; ONE-NEXT: [003]     6           {Line}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
new file mode 100644
index 0000000000000..008d6b5e37b91
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
@@ -0,0 +1,131 @@
+; REQUIRES: x86-registered-target
+
+; Test case 3 - Incorrect lexical scope for typedef.
+
+; pr-44884.cpp
+;  1  int bar(float Input) { return (int)Input; }
+;  2
+;  3  unsigned foo(char Param) {
+;  4    typedef int INT;                // ** Definition for INT **
+;  5    INT Value = Param;
+;  6    {
+;  7      typedef float FLOAT;          // ** Definition for FLOAT **
+;  8      {
+;  9        FLOAT Added = Value + Param;
+; 10        Value = bar(Added);
+; 11      }
+; 12    }
+; 13    return Value + Param;
+; 14  }
+
+; The lines 4 and 7 contains 2 typedefs, defined at different lexical
+; scopes.
+
+; The above test is used to illustrates a scope issue found in the
+; Clang compiler.
+; PR44884: https://bugs.llvm.org/show_bug.cgi?id=44884
+; PR44229: https://github.com/llvm/llvm-project/issues/44229
+
+; In the following logical views, we can see that the Clang compiler
+; emits both typedefs at the same lexical scope (3), which is wrong.
+; GCC emit correct lexical scope for both typedefs.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=kind \
+; RUN:                         --print=symbols,types,lines \
+; RUN:                         %p/Inputs/pr-44884-clang.ll \
+; RUN:                         %p/../DWARF/Inputs/pr-44884-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-44884-clang.ll' -> Textual IR
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 20{{.*}}'
+; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
+; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'foo' -> 'unsigned int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     9             {Variable} 'Added' -> 'FLOAT'
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [003]     3           {Parameter} 'Param' -> 'char'
+; ONE-NEXT: [003]     7           {TypeAlias} 'FLOAT' -> 'float'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INT' -> 'int'
+; ONE-NEXT: [003]     5           {Variable} 'Value' -> 'INT'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14{{.*}}'
+; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
+; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'foo' -> 'unsigned int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]     9               {Variable} 'Added' -> 'FLOAT'
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]    10               {Line}
+; ONE-NEXT: [005]    13               {Line}
+; ONE-NEXT: [004]     7             {TypeAlias} 'FLOAT' -> 'float'
+; ONE-NEXT: [003]     3           {Parameter} 'Param' -> 'char'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INT' -> 'int'
+; ONE-NEXT: [003]     5           {Variable} 'Value' -> 'INT'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    14           {Line}
+; ONE-NEXT: [003]    14           {Line}
+
+; Using the selection facilities, we can produce a simple tabular
+; output showing just the logical types that are 'Typedef'.
+
+; RUN: llvm-as %p/Inputs/pr-44884-clang.ll -o %t.pr-44884-clang.bc
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Typedef \
+; RUN:                         --report=list \
+; RUN:                         --print=types \
+; RUN:                         %t.pr-44884-clang.bc %p/Inputs/pr-44884-clang.ll 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} '{{.*}}pr-44884-clang.bc' -> Bitcode IR
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-44884.cpp'
+; TWO-NEXT: [003]     7     {TypeAlias} 'FLOAT' -> 'float'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INT' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-44884-clang.ll' -> Textual IR
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-44884.cpp'
+; TWO-NEXT: [003]     7     {TypeAlias} 'FLOAT' -> 'float'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INT' -> 'int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test
new file mode 100644
index 0000000000000..811065437b02f
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test
@@ -0,0 +1,144 @@
+; REQUIRES: x86-registered-target
+
+; Test case 4 - Missing nested enumerations.
+
+; pr-46466.cpp
+;   1  struct Struct {
+;   2    union Union {
+;   3      enum NestedEnum { RED, BLUE };
+;   4    };
+;   5    Union U;
+;   6  };
+;   7
+;   8  Struct S;
+;   9  int test() {
+;  10    return S.U.BLUE;
+;  11  }
+
+; The above test is used to illustrate a scope issue found in the Clang
+; compiler.
+; PR46466: https://bugs.llvm.org/show_bug.cgi?id=46466
+; PR45811: https://github.com/llvm/llvm-project/issues/45811
+
+; In the following logical views, we can see that the debug
+; information generated by the Clang compiler does not include any
+; references to the enumerators 'RED' and 'BLUE'. The DWARF generated
+; by GCC, does include such references.
+
+; RUN: llvm-as %p/Inputs/pr-46466-clang.ll -o %t.pr-46466-clang.bc
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=name \
+; RUN:                         --print=symbols,types \
+; RUN:                         %t.pr-46466-clang.bc \
+; RUN:                         %p/../DWARF/Inputs/pr-46466-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} '{{.*}}pr-46466-clang.bc' -> Bitcode IR
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 20{{.*}}'
+; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
+; ONE-NEXT: [002]     1         {Struct} 'Struct'
+; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14{{.*}}'
+; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
+; ONE-NEXT: [002]     1         {Struct} 'Struct'
+; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
+; ONE-NEXT: [003]     2           {Union} 'Union'
+; ONE-NEXT: [004]     3             {Enumeration} 'NestedEnum' -> 'unsigned int'
+; ONE-NEXT: [005]                     {Enumerator} 'BLUE' = '0x1'
+; ONE-NEXT: [005]                     {Enumerator} 'RED' = '0x0'
+
+; Using the selection facilities, we can produce a logical view
+; showing just the logical types that are 'Enumerator' and its
+; parents. The logical view is sorted by the types name.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Enumerator \
+; RUN:                         --report=parents \
+; RUN:                         --print=types \
+; RUN:                         %p/Inputs/pr-46466-clang.ll \
+; RUN:                         %p/../DWARF/Inputs/pr-46466-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-46466-clang.ll' -> Textual IR
+; TWO-EMPTY:
+; TWO-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; TWO-NEXT: [002]     1         {Struct} 'Struct'
+; TWO-NEXT: [003]     2           {Union} 'Union'
+; TWO-NEXT: [004]     3             {Enumeration} 'NestedEnum' -> 'unsigned int'
+; TWO-NEXT: [005]                     {Enumerator} 'BLUE' = '0x1'
+; TWO-NEXT: [005]                     {Enumerator} 'RED' = '0x0'
+
+; Using the selection facilities, we can produce a simple tabular output
+; including a summary for the logical types that are 'Enumerator'. The
+; logical view is sorted by the types name.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Enumerator \
+; RUN:                         --print=types,summary \
+; RUN:                         %t.pr-46466-clang.bc %p/Inputs/pr-46466-clang.ll \
+; RUN:                         %p/../DWARF/Inputs/pr-46466-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THREE %s
+
+; THREE:      Logical View:
+; THREE-NEXT: [000]           {File} '{{.*}}pr-46466-clang.bc' -> Bitcode IR
+; THREE-EMPTY:
+; THREE-NEXT: [001]           {CompileUnit} 'pr-46466.cpp'
+; THREE-EMPTY:
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Element      Total    Printed
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Scopes           4          0
+; THREE-NEXT: Symbols          0          0
+; THREE-NEXT: Types            0          0
+; THREE-NEXT: Lines            0          0
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Total            4          0
+; THREE-EMPTY:
+; THREE-NEXT: Logical View:
+; THREE-NEXT: [000]           {File} 'pr-46466-clang.ll' -> Textual IR
+; THREE-EMPTY:
+; THREE-NEXT: [001]           {CompileUnit} 'pr-46466.cpp'
+; THREE-EMPTY:
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Element      Total    Printed
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Scopes           4          0
+; THREE-NEXT: Symbols          0          0
+; THREE-NEXT: Types            0          0
+; THREE-NEXT: Lines            0          0
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Total            4          0
+; THREE-EMPTY:
+; THREE-NEXT: Logical View:
+; THREE-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; THREE-EMPTY:
+; THREE-NEXT: [001]           {CompileUnit} 'pr-46466.cpp'
+; THREE-NEXT: [005]           {Enumerator} 'BLUE' = '0x1'
+; THREE-NEXT: [005]           {Enumerator} 'RED' = '0x0'
+; THREE-EMPTY:
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Element      Total    Printed
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Scopes           5          0
+; THREE-NEXT: Symbols          0          0
+; THREE-NEXT: Types            2          2
+; THREE-NEXT: Lines            0          0
+; THREE-NEXT: -----------------------------
+; THREE-NEXT: Total            7          2
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test
new file mode 100644
index 0000000000000..cd7150d4608a9
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test
@@ -0,0 +1,113 @@
+; REQUIRES: x86-registered-target
+
+; Test case 5 - Incorrect lexical scope variable.
+
+; pr-43860.cpp
+;  1  #include "definitions.h"
+;  2  forceinline int InlineFunction(int Param) {
+;  3    int Var_1 = Param;
+;  4    {
+;  5      int Var_2 = Param + Var_1;
+;  6      Var_1 = Var_2;
+;  7    }
+;  8    return Var_1;
+;  9  }
+; 10
+; 11  int test(int Param_1, int Param_2) {
+; 12    int A = Param_1;
+; 13    A += InlineFunction(Param_2);
+; 14    return A;
+; 15  }
+
+; The above test is used to illustrate a variable issue found in the
+; Clang compiler.
+; PR43860: https://bugs.llvm.org/show_bug.cgi?id=43860
+; PR43205: https://github.com/llvm/llvm-project/issues/43205
+
+; In the following logical views, we can see that the debug
+; information generated by the Clang compiler shows the variables
+; 'Var_1' and 'Var_2' are at the same lexical scope (4) in the function
+; 'InlineFuction'.
+; The debug information generated by GCC/Clang show those variables at
+; the correct lexical scope: '3' and '4' respectively.
+
+; RUN: llvm-as %p/Inputs/pr-43860-clang.ll -o %t.pr-43860-clang.bc
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=name \
+; RUN:                         --print=symbols \
+; RUN:                         %t.pr-43860-clang.bc \
+; RUN:                         %p/../DWARF/Inputs/pr-43860-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} '{{.*}}pr-43860-clang.bc' -> Bitcode IR
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 20{{.*}}'
+; ONE-NEXT: [002]     2         {Function} extern inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [002]    11         {Function} extern not_inlined 'test' -> 'int'
+; ONE-NEXT: [003]    12           {Variable} 'A' -> 'int'
+; ONE-NEXT: [003]    13           {InlinedFunction} inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]                     {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [004]                   {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [004]                   {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_2' -> 'int'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14{{.*}}'
+; ONE-NEXT: [002]     2         {Function} extern declared_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [002]    11         {Function} extern not_inlined 'test' -> 'int'
+; ONE-NEXT: [003]    12           {Variable} 'A' -> 'int'
+; ONE-NEXT: [003]    13           {InlinedFunction} declared_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]                     {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [004]                   {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [004]                   {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_2' -> 'int'
+
+; Using the selection facilities, we can produce a simple tabular output
+; showing just the logical elements that have in their name the 'var'
+; pattern. The logical view is sorted by the variables name.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-regex --select-nocase \
+; RUN:                         --select=Var \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols \
+; RUN:                         %p/Inputs/pr-43860-clang.ll \
+; RUN:                         %p/../DWARF/Inputs/pr-43860-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-43860-clang.ll' -> Textual IR
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-43860.cpp'
+; TWO-NEXT: [004]           {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [003]     3     {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [005]           {Variable} 'Var_2' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'Var_2' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-43860.cpp'
+; TWO-NEXT: [004]           {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [003]     3     {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [005]           {Variable} 'Var_2' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'Var_2' -> 'int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
new file mode 100644
index 0000000000000..5997830520647
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
@@ -0,0 +1,118 @@
+; REQUIRES: x86-registered-target
+
+; Test case 6 - Full logical view
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; Print low level details.
+; The following command prints low level information that includes
+; offsets within the debug information, debug location operands,
+; linkage names, etc.
+
+; RUN: llvm-debuginfo-analyzer --attribute=all \
+; RUN:                         --output-sort=offset \
+; RUN:                         --print=all \
+; RUN:                         %p/Inputs/test-clang.ll 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [0x0000000000][000]            {File} '{{.*}}test-clang{{.*}}.ll' -> Textual IR
+; ONE-EMPTY:
+; ONE-NEXT: [0x0000000000][001]              {CompileUnit} 'test.cpp'
+; ONE-NEXT: [0x0000000000][002]                {Producer} 'clang version 20{{.*}}'
+; ONE-NEXT:                                    {Directory} '{{.*}}/general'
+; ONE-NEXT:                                    {File} 'test.cpp'
+; ONE-NEXT:                                    {Public} 'foo' [0x0000000000:0x0000000023]
+; ONE-NEXT: [0x0000000000][002]                {Range} Lines 2:2 [0x0000000000:0x0000000023]
+; ONE-NEXT: [0x0000000000][002]                {Range} Lines 3:3 [0x0000000024:0x000000002f]
+; ONE-NEXT: [0x0000000000][002]                {Range} Lines 5:6 [0x0000000030:0x000000003b]
+; ONE-NEXT: [0x0000000000][002]                {Range} Lines 8:9 [0x000000003c:0x000000004f]
+; ONE-EMPTY:
+; ONE-NEXT: [0x0000000004][002]   {Source} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000004][002]      2         {Function} extern not_inlined 'foo' -> [0x0000000020]'int'
+; ONE-NEXT: [0x0000000004][003]                  {Range} Lines 2:2 [0x0000000000:0x0000000023]
+; ONE-NEXT: [0x0000000004][003]                  {Range} Lines 3:3 [0x0000000024:0x000000002f]
+; ONE-NEXT: [0x0000000004][003]                  {Range} Lines 8:9 [0x000000003c:0x000000004f]
+; ONE-NEXT: [0x0000000004][003]                  {Linkage}  0x0 '_Z3fooPKijb'
+; ONE-NEXT: [0x0000000008][003]                  {Block}
+; ONE-NEXT: [0x0000000008][004]                    {Range} Lines 5:6 [0x0000000030:0x000000003b]
+; ONE-NEXT: [0x000000000c][004]      5             {Variable} 'CONSTANT' -> [0x0000000038]'const INTEGER'
+; ONE-NEXT: [0x000000000c][005]                      {Coverage} 100.00%
+; ONE-NEXT: [0x0000000000][006]                        {Location}
+; ONE-NEXT: [0x0000000000][007]                          {Entry} bregx 5 ptr %CONSTANT+0
+; ONE-NEXT: [0x0000000030][004]      5             {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000030][004]                    {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
+; ONE-NEXT: [0x0000000034][004]      6             {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000034][004]                    {Code} 'store i32 7, ptr %retval, align 4, !dbg !33'
+; ONE-NEXT: [0x0000000038][004]      6             {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000038][004]                    {Code} 'br label %return, !dbg !33'
+; ONE-NEXT: [0x0000000010][003]      2           {Parameter} 'ParamPtr' -> [0x0000000024]'INTPTR'
+; ONE-NEXT: [0x0000000010][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000000][004]                    {Location}
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [0x0000000014][003]      2           {Parameter} 'ParamUnsigned' -> [0x0000000030]'unsigned int'
+; ONE-NEXT: [0x0000000014][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000000][004]                    {Location}
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [0x0000000018][003]      2           {Parameter} 'ParamBool' -> [0x0000000034]'bool'
+; ONE-NEXT: [0x0000000018][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000000][004]                    {Location}
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 4 ptr %ParamBool.addr+0
+; ONE-NEXT: [0x000000001c][003]      4           {TypeAlias} 'INTEGER' -> [0x0000000020]'int'
+; ONE-NEXT: [0x0000000000][003]      2           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000000][003]                  {Code} '%retval = alloca i32, align 4'
+; ONE-NEXT: [0x0000000004][003]                  {Code} '%ParamPtr.addr = alloca ptr, align 8'
+; ONE-NEXT: [0x0000000008][003]                  {Code} '%ParamUnsigned.addr = alloca i32, align 4'
+; ONE-NEXT: [0x000000000c][003]                  {Code} '%ParamBool.addr = alloca i8, align 1'
+; ONE-NEXT: [0x0000000010][003]                  {Code} '%CONSTANT = alloca i32, align 4'
+; ONE-NEXT: [0x0000000014][003]                  {Code} 'store ptr %ParamPtr, ptr %ParamPtr.addr, align 8'
+; ONE-NEXT: [0x0000000018][003]                  {Code} 'store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4'
+; ONE-NEXT: [0x000000001c][003]                  {Code} '%storedv = zext i1 %ParamBool to i8'
+; ONE-NEXT: [0x0000000020][003]                  {Code} 'store i8 %storedv, ptr %ParamBool.addr, align 1'
+; ONE-NEXT: [0x000000003c][003]      8           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x000000003c][003]                  {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34'
+; ONE-NEXT: [0x0000000040][003]      8           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000040][003]                  {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35'
+; ONE-NEXT: [0x0000000044][003]      8           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000044][003]                  {Code} 'br label %return, !dbg !35'
+; ONE-NEXT: [0x0000000048][003]      9           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000048][003]                  {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36'
+; ONE-NEXT: [0x000000004c][003]      9           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x000000004c][003]                  {Code} 'ret i32 %2, !dbg !36'
+; ONE-NEXT: [0x0000000024][003]      3           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000028][003]      3           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x000000002c][003]      3           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x000000002c][003]                  {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
+; ONE-NEXT: [0x0000000020][002]                {BaseType} 'int'
+; ONE-NEXT: [0x0000000024][002]      1         {TypeAlias} 'INTPTR' -> [0x0000000028]'* const int'
+; ONE-NEXT: [0x0000000030][002]                {BaseType} 'unsigned int'
+; ONE-NEXT: [0x0000000034][002]                {BaseType} 'bool'
+; ONE-EMPTY:
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Element      Total    Printed
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Scopes           5          3
+; ONE-NEXT: Symbols          4          4
+; ONE-NEXT: Types            5          5
+; ONE-NEXT: Lines           36         30
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Total           50         42
+; ONE-EMPTY:
+; ONE-NEXT: Scope Sizes:
+; ONE-NEXT:         60 (100.00%) : [0x0000000000][001]              {CompileUnit} 'test.cpp'
+; ONE-NEXT:         28 ( 46.67%) : [0x0000000004][002]      2         {Function} extern not_inlined 'foo' -> [0x0000000020]'int'
+; ONE-NEXT:          8 ( 13.33%) : [0x0000000008][003]                  {Block}
+; ONE-EMPTY:
+; ONE-NEXT: Totals by lexical level:
+; ONE-NEXT: [001]:         60 (100.00%)
+; ONE-NEXT: [002]:         28 ( 46.67%)
+; ONE-NEXT: [003]:          8 ( 13.33%)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
new file mode 100644
index 0000000000000..710aaa88a3bae
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
@@ -0,0 +1,48 @@
+; REQUIRES: x86-registered-target
+
+; Test case 7 - Logical view for debug-records and debug-intrinsics format.
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; The following command prints the debug locations for both formats:
+; debug-records and debug-intrinsics format.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,location \
+; RUN:                         --output-sort=name \
+; RUN:                         --print=symbols \
+; RUN:                         %p/Inputs/test-clang.ll 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,location \
+; RUN:                         --output-sort=name \
+; RUN:                         --print=symbols \
+; RUN:                         %p/Inputs/test-clang-intrinsics.ll 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} '{{.*}}test-clang{{.*}}.ll'
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT: [004]                   {Location}
+; ONE-NEXT: [005]                     {Entry} bregx 4 ptr %ParamBool.addr+0
+; ONE-NEXT: [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT: [004]                   {Location}
+; ONE-NEXT: [005]                     {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: [004]                   {Location}
+; ONE-NEXT: [005]                     {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: [006]                       {Location}
+; ONE-NEXT: [007]                         {Entry} bregx 5 ptr %CONSTANT+0
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/hello-world-clang.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/hello-world-clang.ll
new file mode 100644
index 0000000000000..e1d918bae9c80
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/hello-world-clang.ll
@@ -0,0 +1,49 @@
+; ModuleID = 'hello-world.cpp'
+source_filename = "hello-world.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux"
+
+ at .str = private unnamed_addr constant [14 x i8] c"Hello, World\0A\00", align 1, !dbg !0
+
+; Function Attrs: mustprogress noinline norecurse optnone uwtable
+define dso_local noundef i32 @main() #0 !dbg !18 {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, ptr %retval, align 4
+  %call = call noundef i32 (ptr, ...) @_Z6printfPKcz(ptr noundef @.str), !dbg !22
+  ret i32 0, !dbg !23
+}
+
+declare noundef i32 @_Z6printfPKcz(ptr noundef, ...) #1
+
+attributes #0 = { mustprogress noinline norecurse optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!8}
+!llvm.module.flags = !{!10, !11, !12, !13, !14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(scope: null, file: !2, line: 5, type: !3, isLocal: true, isDefinition: true)
+!2 = !DIFile(filename: "hello-world.cpp", directory: "/data/projects/scripts/regression-suite/input/general")
+!3 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 112, elements: !6)
+!4 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !5)
+!5 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!6 = !{!7}
+!7 = !DISubrange(count: 14)
+!8 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !2, producer: "clang version 20.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !9, splitDebugInlining: false, nameTableKind: None)
+!9 = !{!0}
+!10 = !{i32 7, !"Dwarf Version", i32 5}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{i32 8, !"PIC Level", i32 2}
+!14 = !{i32 7, !"PIE Level", i32 2}
+!15 = !{i32 7, !"uwtable", i32 2}
+!16 = !{i32 7, !"frame-pointer", i32 2}
+!17 = !{!"clang version 20.0.0"}
+!18 = distinct !DISubprogram(name: "main", scope: !2, file: !2, line: 3, type: !19, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !8)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!21}
+!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!22 = !DILocation(line: 5, column: 3, scope: !18)
+!23 = !DILocation(line: 6, column: 3, scope: !18)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-43860-clang.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-43860-clang.ll
new file mode 100644
index 0000000000000..5c68979f49a00
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-43860-clang.ll
@@ -0,0 +1,92 @@
+; ModuleID = 'pr-43860.cpp'
+source_filename = "pr-43860.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux"
+
+; Function Attrs: mustprogress noinline optnone uwtable
+define dso_local noundef i32 @_Z4testii(i32 noundef %Param_1, i32 noundef %Param_2) #0 !dbg !10 {
+entry:
+  %Param.addr.i = alloca i32, align 4
+  %Var_1.i = alloca i32, align 4
+  %Var_2.i = alloca i32, align 4
+  %Param_1.addr = alloca i32, align 4
+  %Param_2.addr = alloca i32, align 4
+  %A = alloca i32, align 4
+  store i32 %Param_1, ptr %Param_1.addr, align 4
+    #dbg_declare(ptr %Param_1.addr, !15, !DIExpression(), !16)
+  store i32 %Param_2, ptr %Param_2.addr, align 4
+    #dbg_declare(ptr %Param_2.addr, !17, !DIExpression(), !18)
+    #dbg_declare(ptr %A, !19, !DIExpression(), !20)
+  %0 = load i32, ptr %Param_1.addr, align 4, !dbg !21
+  store i32 %0, ptr %A, align 4, !dbg !20
+  %1 = load i32, ptr %Param_2.addr, align 4, !dbg !22
+  store i32 %1, ptr %Param.addr.i, align 4
+    #dbg_declare(ptr %Param.addr.i, !23, !DIExpression(), !27)
+    #dbg_declare(ptr %Var_1.i, !29, !DIExpression(), !30)
+  %2 = load i32, ptr %Param.addr.i, align 4, !dbg !31
+  store i32 %2, ptr %Var_1.i, align 4, !dbg !30
+    #dbg_declare(ptr %Var_2.i, !32, !DIExpression(), !34)
+  %3 = load i32, ptr %Param.addr.i, align 4, !dbg !35
+  %4 = load i32, ptr %Var_1.i, align 4, !dbg !36
+  %add.i = add nsw i32 %3, %4, !dbg !37
+  store i32 %add.i, ptr %Var_2.i, align 4, !dbg !34
+  %5 = load i32, ptr %Var_2.i, align 4, !dbg !38
+  store i32 %5, ptr %Var_1.i, align 4, !dbg !39
+  %6 = load i32, ptr %Var_1.i, align 4, !dbg !40
+  %7 = load i32, ptr %A, align 4, !dbg !41
+  %add = add nsw i32 %7, %6, !dbg !41
+  store i32 %add, ptr %A, align 4, !dbg !41
+  %8 = load i32, ptr %A, align 4, !dbg !42
+  ret i32 %8, !dbg !43
+}
+
+attributes #0 = { mustprogress noinline optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "pr-43860.cpp", directory: "/data/projects/scripts/regression-suite/input/general")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{!"clang version 20.0.0"}
+!10 = distinct !DISubprogram(name: "test", linkageName: "_Z4testii", scope: !1, file: !1, line: 11, type: !11, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !13, !13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{}
+!15 = !DILocalVariable(name: "Param_1", arg: 1, scope: !10, file: !1, line: 11, type: !13)
+!16 = !DILocation(line: 11, column: 14, scope: !10)
+!17 = !DILocalVariable(name: "Param_2", arg: 2, scope: !10, file: !1, line: 11, type: !13)
+!18 = !DILocation(line: 11, column: 27, scope: !10)
+!19 = !DILocalVariable(name: "A", scope: !10, file: !1, line: 12, type: !13)
+!20 = !DILocation(line: 12, column: 7, scope: !10)
+!21 = !DILocation(line: 12, column: 11, scope: !10)
+!22 = !DILocation(line: 13, column: 23, scope: !10)
+!23 = !DILocalVariable(name: "Param", arg: 1, scope: !24, file: !1, line: 2, type: !13)
+!24 = distinct !DISubprogram(name: "InlineFunction", linkageName: "_Z14InlineFunctioni", scope: !1, file: !1, line: 2, type: !25, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!25 = !DISubroutineType(types: !26)
+!26 = !{!13, !13}
+!27 = !DILocation(line: 2, column: 36, scope: !24, inlinedAt: !28)
+!28 = distinct !DILocation(line: 13, column: 8, scope: !10)
+!29 = !DILocalVariable(name: "Var_1", scope: !24, file: !1, line: 3, type: !13)
+!30 = !DILocation(line: 3, column: 7, scope: !24, inlinedAt: !28)
+!31 = !DILocation(line: 3, column: 15, scope: !24, inlinedAt: !28)
+!32 = !DILocalVariable(name: "Var_2", scope: !33, file: !1, line: 5, type: !13)
+!33 = distinct !DILexicalBlock(scope: !24, file: !1, line: 4, column: 3)
+!34 = !DILocation(line: 5, column: 9, scope: !33, inlinedAt: !28)
+!35 = !DILocation(line: 5, column: 17, scope: !33, inlinedAt: !28)
+!36 = !DILocation(line: 5, column: 25, scope: !33, inlinedAt: !28)
+!37 = !DILocation(line: 5, column: 23, scope: !33, inlinedAt: !28)
+!38 = !DILocation(line: 6, column: 13, scope: !33, inlinedAt: !28)
+!39 = !DILocation(line: 6, column: 11, scope: !33, inlinedAt: !28)
+!40 = !DILocation(line: 8, column: 10, scope: !24, inlinedAt: !28)
+!41 = !DILocation(line: 13, column: 5, scope: !10)
+!42 = !DILocation(line: 14, column: 10, scope: !10)
+!43 = !DILocation(line: 14, column: 3, scope: !10)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-44884-clang.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-44884-clang.ll
new file mode 100644
index 0000000000000..3521346cd5c4c
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-44884-clang.ll
@@ -0,0 +1,98 @@
+; ModuleID = 'pr-44884.cpp'
+source_filename = "pr-44884.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux"
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z3barf(float noundef %Input) #0 !dbg !12 {
+entry:
+  %Input.addr = alloca float, align 4
+  store float %Input, ptr %Input.addr, align 4
+    #dbg_declare(ptr %Input.addr, !17, !DIExpression(), !18)
+  %0 = load float, ptr %Input.addr, align 4, !dbg !19
+  %conv = fptosi float %0 to i32, !dbg !19
+  ret i32 %conv, !dbg !20
+}
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z3fooc(i8 noundef signext %Param) #0 !dbg !21 {
+entry:
+  %Param.addr = alloca i8, align 1
+  %Value = alloca i32, align 4
+  %Added = alloca float, align 4
+  store i8 %Param, ptr %Param.addr, align 1
+    #dbg_declare(ptr %Param.addr, !26, !DIExpression(), !27)
+    #dbg_declare(ptr %Value, !28, !DIExpression(), !30)
+  %0 = load i8, ptr %Param.addr, align 1, !dbg !31
+  %conv = sext i8 %0 to i32, !dbg !31
+  store i32 %conv, ptr %Value, align 4, !dbg !30
+    #dbg_declare(ptr %Added, !32, !DIExpression(), !36)
+  %1 = load i32, ptr %Value, align 4, !dbg !37
+  %2 = load i8, ptr %Param.addr, align 1, !dbg !38
+  %conv1 = sext i8 %2 to i32, !dbg !38
+  %add = add nsw i32 %1, %conv1, !dbg !39
+  %conv2 = sitofp i32 %add to float, !dbg !37
+  store float %conv2, ptr %Added, align 4, !dbg !36
+  %3 = load float, ptr %Added, align 4, !dbg !40
+  %call = call noundef i32 @_Z3barf(float noundef %3), !dbg !41
+  store i32 %call, ptr %Value, align 4, !dbg !42
+  %4 = load i32, ptr %Value, align 4, !dbg !43
+  %5 = load i8, ptr %Param.addr, align 1, !dbg !44
+  %conv3 = sext i8 %5 to i32, !dbg !44
+  %add4 = add nsw i32 %4, %conv3, !dbg !45
+  ret i32 %add4, !dbg !46
+}
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!4, !5, !6, !7, !8, !9, !10}
+!llvm.ident = !{!11}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "pr-44884.cpp", directory: "/data/projects/scripts/regression-suite/input/general")
+!2 = !{!3}
+!3 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!4 = !{i32 7, !"Dwarf Version", i32 5}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 4}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"PIE Level", i32 2}
+!9 = !{i32 7, !"uwtable", i32 2}
+!10 = !{i32 7, !"frame-pointer", i32 2}
+!11 = !{!"clang version 20.0.0"}
+!12 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barf", scope: !1, file: !1, line: 1, type: !13, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !16)
+!13 = !DISubroutineType(types: !14)
+!14 = !{!3, !15}
+!15 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+!16 = !{}
+!17 = !DILocalVariable(name: "Input", arg: 1, scope: !12, file: !1, line: 1, type: !15)
+!18 = !DILocation(line: 1, column: 15, scope: !12)
+!19 = !DILocation(line: 1, column: 36, scope: !12)
+!20 = !DILocation(line: 1, column: 24, scope: !12)
+!21 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooc", scope: !1, file: !1, line: 3, type: !22, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !16)
+!22 = !DISubroutineType(types: !23)
+!23 = !{!24, !25}
+!24 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!25 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!26 = !DILocalVariable(name: "Param", arg: 1, scope: !21, file: !1, line: 3, type: !25)
+!27 = !DILocation(line: 3, column: 19, scope: !21)
+!28 = !DILocalVariable(name: "Value", scope: !21, file: !1, line: 5, type: !29)
+!29 = !DIDerivedType(tag: DW_TAG_typedef, name: "INT", scope: !21, file: !1, line: 4, baseType: !3)
+!30 = !DILocation(line: 5, column: 7, scope: !21)
+!31 = !DILocation(line: 5, column: 15, scope: !21)
+!32 = !DILocalVariable(name: "Added", scope: !33, file: !1, line: 9, type: !35)
+!33 = distinct !DILexicalBlock(scope: !34, file: !1, line: 8, column: 5)
+!34 = distinct !DILexicalBlock(scope: !21, file: !1, line: 6, column: 3)
+!35 = !DIDerivedType(tag: DW_TAG_typedef, name: "FLOAT", scope: !21, file: !1, line: 7, baseType: !15)
+!36 = !DILocation(line: 9, column: 13, scope: !33)
+!37 = !DILocation(line: 9, column: 21, scope: !33)
+!38 = !DILocation(line: 9, column: 29, scope: !33)
+!39 = !DILocation(line: 9, column: 27, scope: !33)
+!40 = !DILocation(line: 10, column: 19, scope: !33)
+!41 = !DILocation(line: 10, column: 15, scope: !33)
+!42 = !DILocation(line: 10, column: 13, scope: !33)
+!43 = !DILocation(line: 13, column: 10, scope: !21)
+!44 = !DILocation(line: 13, column: 18, scope: !21)
+!45 = !DILocation(line: 13, column: 16, scope: !21)
+!46 = !DILocation(line: 13, column: 3, scope: !21)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-46466-clang.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-46466-clang.ll
new file mode 100644
index 0000000000000..ab4002d52e146
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-46466-clang.ll
@@ -0,0 +1,44 @@
+; ModuleID = 'pr-46466.cpp'
+source_filename = "pr-46466.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux"
+
+%struct.Struct = type { i8 }
+
+ at S = dso_local global %struct.Struct zeroinitializer, align 1, !dbg !0
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z4testv() #0 !dbg !18 {
+entry:
+  ret i32 1, !dbg !22
+}
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!10, !11, !12, !13, !14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "S", scope: !2, file: !3, line: 8, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 20.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "pr-46466.cpp", directory: "/data/projects/scripts/regression-suite/input/general")
+!4 = !{!0}
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Struct", file: !3, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !6, identifier: "_ZTS6Struct")
+!6 = !{!7}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "U", scope: !5, file: !3, line: 5, baseType: !8, size: 8)
+!8 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "Union", scope: !5, file: !3, line: 2, size: 8, flags: DIFlagTypePassByValue, elements: !9, identifier: "_ZTSN6Struct5UnionE")
+!9 = !{}
+!10 = !{i32 7, !"Dwarf Version", i32 5}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{i32 8, !"PIC Level", i32 2}
+!14 = !{i32 7, !"PIE Level", i32 2}
+!15 = !{i32 7, !"uwtable", i32 2}
+!16 = !{i32 7, !"frame-pointer", i32 2}
+!17 = !{!"clang version 20.0.0"}
+!18 = distinct !DISubprogram(name: "test", linkageName: "_Z4testv", scope: !3, file: !3, line: 9, type: !19, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!21}
+!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!22 = !DILocation(line: 10, column: 3, scope: !18)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang-intrinsics.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang-intrinsics.ll
new file mode 100644
index 0000000000000..ae48abf25647c
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang-intrinsics.ll
@@ -0,0 +1,87 @@
+; ModuleID = 'test.cpp'
+source_filename = "test.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux"
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z3fooPKijb(ptr noundef %ParamPtr, i32 noundef %ParamUnsigned, i1 noundef zeroext %ParamBool) #0 !dbg !10 {
+entry:
+  %retval = alloca i32, align 4
+  %ParamPtr.addr = alloca ptr, align 8
+  %ParamUnsigned.addr = alloca i32, align 4
+  %ParamBool.addr = alloca i8, align 1
+  %CONSTANT = alloca i32, align 4
+  store ptr %ParamPtr, ptr %ParamPtr.addr, align 8
+  tail call void @llvm.dbg.declare(metadata ptr %ParamPtr.addr, metadata !20, metadata !DIExpression()), !dbg !21
+  store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4
+  tail call void @llvm.dbg.declare(metadata ptr %ParamUnsigned.addr, metadata !22, metadata !DIExpression()), !dbg !23
+  %storedv = zext i1 %ParamBool to i8
+  store i8 %storedv, ptr %ParamBool.addr, align 1
+  tail call void @llvm.dbg.declare(metadata ptr %ParamBool.addr, metadata !24, metadata !DIExpression()), !dbg !25
+  %0 = load i8, ptr %ParamBool.addr, align 1, !dbg !26
+  %loadedv = trunc i8 %0 to i1, !dbg !26
+  br i1 %loadedv, label %if.then, label %if.end, !dbg !26
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.dbg.declare(metadata ptr %CONSTANT, metadata !28, metadata !DIExpression()), !dbg !32
+  store i32 7, ptr %CONSTANT, align 4, !dbg !32
+  store i32 7, ptr %retval, align 4, !dbg !33
+  br label %return, !dbg !33
+
+if.end:                                           ; preds = %entry
+  %1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34
+  store i32 %1, ptr %retval, align 4, !dbg !35
+  br label %return, !dbg !35
+
+return:                                           ; preds = %if.end, %if.then
+  %2 = load i32, ptr %retval, align 4, !dbg !36
+  ret i32 %2, !dbg !36
+}
+
+; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.cpp", directory: "/data/projects/scripts/regression-suite/input/general")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{!"clang version 20.0.0"}
+!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooPKijb", scope: !1, file: !1, line: 2, type: !11, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !19)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !14, !17, !18}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "INTPTR", file: !1, line: 1, baseType: !15)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13)
+!17 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!18 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean)
+!19 = !{}
+!20 = !DILocalVariable(name: "ParamPtr", arg: 1, scope: !10, file: !1, line: 2, type: !14)
+!21 = !DILocation(line: 2, column: 16, scope: !10)
+!22 = !DILocalVariable(name: "ParamUnsigned", arg: 2, scope: !10, file: !1, line: 2, type: !17)
+!23 = !DILocation(line: 2, column: 35, scope: !10)
+!24 = !DILocalVariable(name: "ParamBool", arg: 3, scope: !10, file: !1, line: 2, type: !18)
+!25 = !DILocation(line: 2, column: 55, scope: !10)
+!26 = !DILocation(line: 3, column: 7, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !10, file: !1, line: 3, column: 7)
+!28 = !DILocalVariable(name: "CONSTANT", scope: !29, file: !1, line: 5, type: !30)
+!29 = distinct !DILexicalBlock(scope: !27, file: !1, line: 3, column: 18)
+!30 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !31)
+!31 = !DIDerivedType(tag: DW_TAG_typedef, name: "INTEGER", scope: !10, file: !1, line: 4, baseType: !13)
+!32 = !DILocation(line: 5, column: 19, scope: !29)
+!33 = !DILocation(line: 6, column: 5, scope: !29)
+!34 = !DILocation(line: 8, column: 10, scope: !10)
+!35 = !DILocation(line: 8, column: 3, scope: !10)
+!36 = !DILocation(line: 9, column: 1, scope: !10)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang.ll
new file mode 100644
index 0000000000000..610be460b9fa9
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang.ll
@@ -0,0 +1,83 @@
+; ModuleID = 'test.cpp'
+source_filename = "test.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux"
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z3fooPKijb(ptr noundef %ParamPtr, i32 noundef %ParamUnsigned, i1 noundef zeroext %ParamBool) #0 !dbg !10 {
+entry:
+  %retval = alloca i32, align 4
+  %ParamPtr.addr = alloca ptr, align 8
+  %ParamUnsigned.addr = alloca i32, align 4
+  %ParamBool.addr = alloca i8, align 1
+  %CONSTANT = alloca i32, align 4
+  store ptr %ParamPtr, ptr %ParamPtr.addr, align 8
+    #dbg_declare(ptr %ParamPtr.addr, !20, !DIExpression(), !21)
+  store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4
+    #dbg_declare(ptr %ParamUnsigned.addr, !22, !DIExpression(), !23)
+  %storedv = zext i1 %ParamBool to i8
+  store i8 %storedv, ptr %ParamBool.addr, align 1
+    #dbg_declare(ptr %ParamBool.addr, !24, !DIExpression(), !25)
+  %0 = load i8, ptr %ParamBool.addr, align 1, !dbg !26
+  %loadedv = trunc i8 %0 to i1, !dbg !26
+  br i1 %loadedv, label %if.then, label %if.end, !dbg !26
+
+if.then:                                          ; preds = %entry
+    #dbg_declare(ptr %CONSTANT, !28, !DIExpression(), !32)
+  store i32 7, ptr %CONSTANT, align 4, !dbg !32
+  store i32 7, ptr %retval, align 4, !dbg !33
+  br label %return, !dbg !33
+
+if.end:                                           ; preds = %entry
+  %1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34
+  store i32 %1, ptr %retval, align 4, !dbg !35
+  br label %return, !dbg !35
+
+return:                                           ; preds = %if.end, %if.then
+  %2 = load i32, ptr %retval, align 4, !dbg !36
+  ret i32 %2, !dbg !36
+}
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.cpp", directory: "/data/projects/scripts/regression-suite/input/general")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{!"clang version 20.0.0"}
+!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooPKijb", scope: !1, file: !1, line: 2, type: !11, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !19)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !14, !17, !18}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "INTPTR", file: !1, line: 1, baseType: !15)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13)
+!17 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!18 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean)
+!19 = !{}
+!20 = !DILocalVariable(name: "ParamPtr", arg: 1, scope: !10, file: !1, line: 2, type: !14)
+!21 = !DILocation(line: 2, column: 16, scope: !10)
+!22 = !DILocalVariable(name: "ParamUnsigned", arg: 2, scope: !10, file: !1, line: 2, type: !17)
+!23 = !DILocation(line: 2, column: 35, scope: !10)
+!24 = !DILocalVariable(name: "ParamBool", arg: 3, scope: !10, file: !1, line: 2, type: !18)
+!25 = !DILocation(line: 2, column: 55, scope: !10)
+!26 = !DILocation(line: 3, column: 7, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !10, file: !1, line: 3, column: 7)
+!28 = !DILocalVariable(name: "CONSTANT", scope: !29, file: !1, line: 5, type: !30)
+!29 = distinct !DILexicalBlock(scope: !27, file: !1, line: 3, column: 18)
+!30 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !31)
+!31 = !DIDerivedType(tag: DW_TAG_typedef, name: "INTEGER", scope: !10, file: !1, line: 4, baseType: !13)
+!32 = !DILocation(line: 5, column: 19, scope: !29)
+!33 = !DILocation(line: 6, column: 5, scope: !29)
+!34 = !DILocation(line: 8, column: 10, scope: !10)
+!35 = !DILocation(line: 8, column: 3, scope: !10)
+!36 = !DILocation(line: 9, column: 1, scope: !10)
diff --git a/llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt b/llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt
index 3e16d81abe35c..31b3157ec85e6 100644
--- a/llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt
+++ b/llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
   AllTargetsDisassemblers
   AllTargetsInfos
   BinaryFormat
+  Core
   DebugInfoCodeView
   DebugInfoLogicalView
   DebugInfoPDB
@@ -10,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
   MCDisassembler
   Object
   Support
+  TransformUtils
   )
 
 add_llvm_tool(llvm-debuginfo-analyzer
diff --git a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
index 42a4b72229483..c28f8c5aab83f 100644
--- a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
@@ -1,12 +1,14 @@
 set(LLVM_LINK_COMPONENTS
   ${LLVM_TARGETS_TO_BUILD}
   AsmPrinter
+  Core
   DebugInfoDWARF
   DebugInfoLogicalView
   MC
   MCDisassembler
   Object
   TargetParser
+  TransformUtils
   )
 
 add_llvm_unittest_with_input_files(DebugInfoLogicalViewTests
@@ -17,6 +19,7 @@ add_llvm_unittest_with_input_files(DebugInfoLogicalViewTests
   CompareElementsTest.cpp
   DWARFGeneratedTest.cpp
   DWARFReaderTest.cpp
+  IRReaderTest.cpp
   SelectElementsTest.cpp
   LocationRangesTest.cpp
   LogicalElementsTest.cpp
diff --git a/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
new file mode 100644
index 0000000000000..83828c2171d68
--- /dev/null
+++ b/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
@@ -0,0 +1,355 @@
+//===- llvm/unittest/DebugInfo/LogicalView/IRReaderTest.cpp ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/COM.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+extern const char *TestMainArgv0;
+
+namespace {
+
+const char *IrClang = "test-clang.ll";
+const char *BcClang = "test-clang.bc";
+const char *DwarfGcc = "test-dwarf-gcc.o";
+
+// Helper function to get the first compile unit.
+LVScopeCompileUnit *getFirstCompileUnit(LVScopeRoot *Root) {
+  EXPECT_NE(Root, nullptr);
+  const LVScopes *CompileUnits = Root->getScopes();
+  EXPECT_NE(CompileUnits, nullptr);
+  EXPECT_EQ(CompileUnits->size(), 1u);
+
+  LVScopes::const_iterator Iter = CompileUnits->begin();
+  EXPECT_NE(Iter, nullptr);
+  LVScopeCompileUnit *CompileUnit = static_cast<LVScopeCompileUnit *>(*Iter);
+  EXPECT_NE(CompileUnit, nullptr);
+  return CompileUnit;
+}
+
+// Helper function to create a reader.
+std::unique_ptr<LVReader> createReader(LVReaderHandler &ReaderHandler,
+                                       SmallString<128> &InputsDir,
+                                       StringRef Filename) {
+  SmallString<128> ObjectName(InputsDir);
+  llvm::sys::path::append(ObjectName, Filename);
+
+  Expected<std::unique_ptr<LVReader>> ReaderOrErr =
+      ReaderHandler.createReader(std::string(ObjectName));
+  EXPECT_THAT_EXPECTED(ReaderOrErr, Succeeded());
+  std::unique_ptr<LVReader> Reader = std::move(*ReaderOrErr);
+  EXPECT_NE(Reader, nullptr);
+  return Reader;
+}
+
+// Check the logical elements basic properties.
+void checkElementProperties(LVReader *Reader) {
+  LVScopeRoot *Root = Reader->getScopesRoot();
+  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
+
+  EXPECT_EQ(Root->getFileFormatName(), "Textual IR");
+  EXPECT_EQ(Root->getName(), IrClang);
+
+  EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
+  EXPECT_TRUE(CompileUnit->getProducer().starts_with("clang"));
+  EXPECT_EQ(CompileUnit->getName(), "test.cpp");
+
+  EXPECT_EQ(CompileUnit->lineCount(), 0u);
+  EXPECT_EQ(CompileUnit->scopeCount(), 1u);
+  EXPECT_EQ(CompileUnit->symbolCount(), 0u);
+  EXPECT_EQ(CompileUnit->typeCount(), 7u);
+  EXPECT_EQ(CompileUnit->rangeCount(), 4u);
+
+  const LVLocations *Ranges = CompileUnit->getRanges();
+  ASSERT_NE(Ranges, nullptr);
+  ASSERT_EQ(Ranges->size(), 4u);
+  LVLocations::const_iterator IterLocation = Ranges->begin();
+  LVLocation *Location = (*IterLocation);
+  EXPECT_STREQ(Location->getIntervalInfo().c_str(),
+               "{Range} Lines 2:2 [0x0000000000:0x0000000023]");
+
+  LVRange RangeList;
+  CompileUnit->getRanges(RangeList);
+
+  const LVRangeEntries &RangeEntries = RangeList.getEntries();
+  ASSERT_EQ(RangeEntries.size(), 4u);
+  LVRangeEntries::const_iterator IterRanges = RangeEntries.cbegin();
+  LVRangeEntry RangeEntry = *IterRanges;
+  EXPECT_EQ(RangeEntry.lower(), 0u);
+  EXPECT_EQ(RangeEntry.upper(), 0x23u);
+  EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
+  EXPECT_EQ(RangeEntry.scope()->getName(), "test.cpp");
+  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x00u);
+
+  ++IterRanges;
+  RangeEntry = *IterRanges;
+  EXPECT_EQ(RangeEntry.lower(), 0x3cu);
+  EXPECT_EQ(RangeEntry.upper(), 0x4fu);
+  EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
+  EXPECT_EQ(RangeEntry.scope()->getName(), "test.cpp");
+  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x00u);
+
+  const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
+  ASSERT_EQ(PublicNames.size(), 1u);
+  LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
+  LVScope *Function = (*IterNames).first;
+  EXPECT_EQ(Function->getName(), "foo");
+  EXPECT_EQ(Function->getLineNumber(), 2u);
+  LVNameInfo NameInfo = (*IterNames).second;
+  EXPECT_EQ(NameInfo.first, 0u);
+  EXPECT_EQ(NameInfo.second, 0x23u);
+
+  // Lines (debug and assembler) for 'foo'.
+  const LVLines *Lines = Function->getLines();
+  ASSERT_NE(Lines, nullptr);
+  ASSERT_EQ(Lines->size(), 0x18u);
+}
+
+// Check the logical elements selection.
+void checkElementSelection(LVReader *Reader) {
+  LVScopeRoot *Root = Reader->getScopesRoot();
+  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
+
+  // Get the matched elements.
+  LVElements MatchedElements = CompileUnit->getMatchedElements();
+  std::map<LVOffset, LVElement *> MapElements;
+  for (LVElement *Element : MatchedElements)
+    MapElements[Element->getOffset()] = Element;
+  ASSERT_EQ(MapElements.size(), 0x0eu);
+
+  LVElement *Element = MapElements[0x0000000004]; // 'foo'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("foo"), StringRef::npos);
+  EXPECT_EQ(Element->getIsScope(), 1);
+
+  Element = MapElements[0x000000000c]; // 'CONSTANT'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("CONSTANT"), StringRef::npos);
+  EXPECT_EQ(Element->getIsSymbol(), 1);
+
+  Element = MapElements[0x0000000024]; // 'INTPTR'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("INTPTR"), StringRef::npos);
+  EXPECT_EQ(Element->getIsType(), 1);
+
+  Element = MapElements[0x000000001c]; // 'INTEGER'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("INTEGER"), StringRef::npos);
+  EXPECT_EQ(Element->getIsType(), 1);
+
+  Element = MapElements[0x0000000040]; // 'store i32 %1, ptr %retval ...'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("store i32"), StringRef::npos);
+  EXPECT_EQ(Element->getIsLine(), 1);
+
+  // Get the parents for the matched elements.
+  LVScopes MatchedScopes = CompileUnit->getMatchedScopes();
+  std::set<LVOffset> SetScopes;
+  for (LVScope *Scope : MatchedScopes)
+    SetScopes.insert(Scope->getOffset());
+  std::set<LVOffset>::iterator Iter;
+  ASSERT_EQ(SetScopes.size(), 3u);
+
+  Iter = SetScopes.find(0x0000000000); // CompileUnit <- 'foo'
+  EXPECT_NE(Iter, SetScopes.end());
+  Iter = SetScopes.find(0x0000000004); // Function <- 'store i32 %1, ptr ...'
+  EXPECT_NE(Iter, SetScopes.end());
+  Iter = SetScopes.find(0x0000000008); // LexicalScope <- 'INTEGER'
+  EXPECT_NE(Iter, SetScopes.end());
+}
+
+// Check the logical elements comparison.
+void checkElementComparison(LVReader *Reference, LVReader *Target) {
+  LVCompare Compare(nulls());
+  Error Err = Compare.execute(Reference, Target);
+  ASSERT_THAT_ERROR(std::move(Err), Succeeded());
+
+  // Get comparison table.
+  LVPassTable PassTable = Compare.getPassTable();
+  ASSERT_EQ(PassTable.size(), 10u);
+
+  LVReader *Reader;
+  LVElement *Element;
+  LVComparePass Pass;
+
+  // Reference: Missing Variable 'CONSTANT'
+  std::tie(Reader, Element, Pass) = PassTable[1];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Reference);
+  EXPECT_EQ(Element->getLevel(), 4u);
+  EXPECT_EQ(Element->getLineNumber(), 5u);
+  EXPECT_EQ(Element->getName(), "CONSTANT");
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Reference: Missing TypeDefinition 'INTEGER'
+  std::tie(Reader, Element, Pass) = PassTable[2];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Reference);
+  EXPECT_EQ(Element->getLevel(), 3u);
+  EXPECT_EQ(Element->getLineNumber(), 4u);
+  EXPECT_EQ(Element->getName(), "INTEGER");
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Reference: Missing DebugLine
+  std::tie(Reader, Element, Pass) = PassTable[4];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Reference);
+  EXPECT_EQ(Element->getLevel(), 3u);
+  EXPECT_EQ(Element->getLineNumber(), 8u);
+  EXPECT_EQ(Element->getName(), "");
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Target: Added Variable 'CONSTANT'
+  std::tie(Reader, Element, Pass) = PassTable[7];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Target);
+  EXPECT_EQ(Element->getLevel(), 4u);
+  EXPECT_EQ(Element->getLineNumber(), 5u);
+  EXPECT_EQ(Element->getName(), "CONSTANT");
+  EXPECT_EQ(Pass, LVComparePass::Added);
+
+  // Target: Added TypeDefinition 'INTEGER'
+  std::tie(Reader, Element, Pass) = PassTable[8];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Target);
+  EXPECT_EQ(Element->getLevel(), 4u);
+  EXPECT_EQ(Element->getLineNumber(), 4u);
+  EXPECT_EQ(Element->getName(), "INTEGER");
+  EXPECT_EQ(Pass, LVComparePass::Added);
+}
+
+// Logical elements properties.
+void elementProperties(SmallString<128> &InputsDir) {
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setAttributeFormat();
+  ReaderOptions.setAttributeFilename();
+  ReaderOptions.setAttributeProducer();
+  ReaderOptions.setAttributePublics();
+  ReaderOptions.setAttributeRange();
+  ReaderOptions.setAttributeLocation();
+  ReaderOptions.setPrintAll();
+  ReaderOptions.resolveDependencies();
+
+  std::vector<std::string> Objects;
+  ScopedPrinter W(outs());
+  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
+
+  // Check logical elements properties.
+  std::unique_ptr<LVReader> Reader =
+      createReader(ReaderHandler, InputsDir, IrClang);
+  checkElementProperties(Reader.get());
+}
+
+// Logical elements selection.
+void elementSelection(SmallString<128> &InputsDir) {
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setPrintAll();
+
+  ReaderOptions.setSelectIgnoreCase();
+  ReaderOptions.setSelectUseRegex();
+
+  ReaderOptions.setReportList(); // Matched elements.
+  ReaderOptions.setReportView(); // Parents for matched elements.
+
+  // Add patterns.
+  ReaderOptions.Select.Generic.insert("foo");
+  ReaderOptions.Select.Generic.insert("store i32 %");
+  ReaderOptions.Select.Generic.insert("INT[a-z]*");
+  ReaderOptions.Select.Generic.insert("CONSTANT");
+
+  ReaderOptions.resolveDependencies();
+
+  std::vector<std::string> Objects;
+  ScopedPrinter W(outs());
+  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
+
+  // Check logical elements selection.
+  std::unique_ptr<LVReader> Reader =
+      createReader(ReaderHandler, InputsDir, BcClang);
+  checkElementSelection(Reader.get());
+}
+
+// Compare logical elements.
+void compareElements(SmallString<128> &InputsDir) {
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setPrintLines();
+  ReaderOptions.setPrintSymbols();
+  ReaderOptions.setPrintTypes();
+  ReaderOptions.setCompareLines();
+  ReaderOptions.setCompareSymbols();
+  ReaderOptions.setCompareTypes();
+
+  ReaderOptions.resolveDependencies();
+
+  std::vector<std::string> Objects;
+  ScopedPrinter W(outs());
+  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
+
+  // Check logical comparison.
+  std::unique_ptr<LVReader> Reference =
+      createReader(ReaderHandler, InputsDir, BcClang);
+  std::unique_ptr<LVReader> Target =
+      createReader(ReaderHandler, InputsDir, DwarfGcc);
+  checkElementComparison(Reference.get(), Target.get());
+}
+
+TEST(LogicalViewTest, IRReader) {
+  // Initialize targets and assembly printers/parsers.
+  llvm::InitializeAllTargetInfos();
+  llvm::InitializeAllTargetMCs();
+  InitializeAllDisassemblers();
+
+  llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
+  // This test requires a x86-registered-target.
+  Triple TT;
+  TT.setArch(Triple::x86_64);
+  TT.setVendor(Triple::UnknownVendor);
+  TT.setOS(Triple::UnknownOS);
+
+  std::string TargetLookupError;
+  if (!TargetRegistry::lookupTarget(std::string(TT.str()), TargetLookupError))
+    GTEST_SKIP();
+
+  SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0);
+
+  // Logical elements general properties and selection.
+  elementProperties(InputsDir);
+  elementSelection(InputsDir);
+
+  // Compare logical elements.
+  compareElements(InputsDir);
+}
+
+} // namespace
diff --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/README.md b/llvm/unittests/DebugInfo/LogicalView/Inputs/README.md
index ab194ffc1010c..e42c361fd980a 100644
--- a/llvm/unittests/DebugInfo/LogicalView/Inputs/README.md
+++ b/llvm/unittests/DebugInfo/LogicalView/Inputs/README.md
@@ -45,3 +45,14 @@ This file is a static library embedding the **test-codeview-msvc.o** object file
 It is generated by the "lib.exe" tool shipped with MSVC compiler.
 
 ```lib.exe /OUT:test-codeview-msvc.lib test-codeview-msvc.o```
+
+# IR Textual representation and bitcode files (Linux):
+
+## test-clang.ll
+
+```clang --target=x86_64-linux -S -w -emit-llvm -g test.cpp -o test-clang.ll```
+
+## test-clang.bc
+
+```clang --target=x86_64-linux -S -w -emit-llvm -g test.cpp -o test-clang.ll```
+```llvm-as test-clang.ll -o test-clang.bc```
diff --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.bc b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.bc
new file mode 100644
index 0000000000000000000000000000000000000000..841c6b0ddcf1396fbf6c32f1a590b8962fd51d11
GIT binary patch
literal 3260
zcma)8eQZ<L6~E8V at pHg_eu1#sV4G)>GI!$R#Yr3+JDWceFm0d)vMJp%VJESZ(BL?>
zlQ;oQ&#~zXt*H#nAMVB^yP%1#(;8a-U>lkoJ596Huz;#6qY-jSNCQnFYFWj!YTJ2E
z(e~%=)4k`O`*H5M=lsrj*JjV$sVzsS1R>NWVJZ*2^yl9k_~(@uw at g<yV7d~dks!1z
zKxn-{gMc6fR3cJw);cZRFQRnDb68CBY>8N*7QWWTQjG%Jx%IXfr7Jgx<u9z$*+w1y
zNlit=1};un&j~uF#h1%z``%IdFPP32YatV5+Zqz-k+%ej9P!a6g)JU`mQw8rO(S%g
zMo0>0ZSxAL_iQ7jWrv|T+n04Z)|GB=m at 2W^wu`A>R-mYHBt>Bw919Ak#TmE=ltXfa
zUIe<OrQ*rIp<ql&2CGa-Mi@#QOmO}#F3^RC!(7Nu3~PxYl#Qt7F#5JeHJ_HwrIj}{
z%DJ?3C9Rx_sP9<Sw+rf95#=(bLIxxr40HMvF(f9!ENth3UC{wCF>E1N^<r8*gV9S7
zb=Ix?BrPpi)psK58MktILA98cPNvoQ3FQn(bE$7xx6WW0oK1251Q*m2!(GunmK#Q^
zm~15_U13QyqRv{?H`2=Gv^1YqW+UncRuH9TYvtTPm^k5z*2;;K8C>6j2Q%DIg3z}_
z2fB!pFrMUwv^+bM<N^tP!O2Y2gv7&_h(Rr<mlNSjL_s+-p#n{Axs|LmhS0_Fh+M#y
z>!}z at WJMR`=rEc at Xg}DH_xHwEE%H(5Y}CSmrY9w)R8$YbS_rVj2|uTI at n#s#aME|3
z<ndW at 7+NF?_z8cC2-3tbLj-0;t28l475l}(wFQ9`F<>EvT|{VBbRXIxdptq*(L^{!
z at a?Q<iRI<2^&hgtFhvZki7oDWpCSS*u~{QI-4v_&NA_#U+pGs68kFV>i(1fWsi5(1
zfb91yh=3uTI!P(YniBES?fa&L_E!ViQ`@xB4cgcULYLvbAHkYxF{_+hP<qR;`cb<f
zmW$h1Vkk at mlYNpUB>R#gAG2h&#HP+psK7y9rlhzmx+Ra-PuuI`czr$`2V9*H6GINp
z4*>Jy17XfjbBcT!xso6k7 at 3ce-CZSDon$pNsk#GT)2Om;wU;?<x)wFf+KpFm^R=is
zhMV%M<pVC_L>E!VBbKORdBFHx#DJC<cv1pl2U+f at nCp{s0q}b=vg6?@`LIC#JwvWA
zc-wSZxtLZ0exRLqD`zyy$%tykE&3#3H%{A)$zppoXBe{^Msd?vZZ{nI?TG1P+%%q(
zeAvzTTeyHf8tNj#;A1%#N^y!CM`RC?>?<d^m>}<3WD7L80=J;Gs`&{Xv9~nJ`G|VH
zpj=!~J;2mn`60u&eb4!*DetWO?jkO3FieD#hngNIWV{8`$BHqcQQetP{Q`p^Qsy<P
zRkx`5RMe2qna1t)V32RK=0&?{6xdw+gLQCIZV>c=xYH7WWTf>jMXqGXdrtCereflj
zRlT_I%-n+N4k+MIn8u^^SE5^DIYZoT%;(HkCydiMxT87mxY8#kK&w75U<;@Cbc$SY
z$-XQASY`JZ**#kJjg$0I<XwgY_UnS^et}$cl24e5&sN+JlB&6dXI3<-C5>uQqXG{u
zYqomnUz at Jk>#yR*v8XZMat*u>mmLN at 9o(RwQ+)I}`G}D%6v+D)+5HrplEd&I#FCsl
zngpou77opVD<d(hv5*7P)q|(<mdTWACavQ0$%N8d+0Kv)ynkgN<Q`+!MEm7L(7_!|
zaVJ^WdwC2q$8+YfoMG0!2jG+ki%A at sO*Xe0RJ}2wIvgqYHgz)OBU<*TAbRAKJ?2G`
z_X?sVTDC9?m%U)&lgW^nQykuWHD>}GUbGwXU_;!Ph??`b8H_oG^C31wBNPN0P&;V*
zs6<g3&^hReNc`;Cn++*S+hMNK*<Md*E?i~m1dh$@#GaaS=PLK%DC7x-cD4KcEqhvn
z?SXE8DA*eCbOt=ZV0W)?XRyCJ<Z12p`TIkyogSYj;O;T%jcpyZb^2;gU7g<8p*QM1
zZ8{igudS`FuIi|3?{WJ&=>boG7eMQnUGQ~whiGkADC7_B*}WT>uKu=N?Y+l$_w)>`
zH9P%*-eaEj&@O&umEKcR+h*{(+v|*V?fQ<IHg}c2N~bfl)z;|swKYbaj;V1QJDzJ8
zbO*fjPu7lV at U-=J())eh-lrpj?OpD`(O~zm$GP85H+cp;J<k1&Yn}eVkh`tN;|;iv
zdv^MJyL}-~09A;s%m^i}5KjQ1fU6pz<iJ&pZHi%yU|b<oC at ex5O9=(ba+&h$l4!fR
zS~6R9opFp-=Q5QyB=`kGwIu&po}zRclBw3Yxs}_k(~~z^rylGry%;aDx9?0pn44+M
z&t-2c?KNJS`Qv!g3#ZOp|NZr6&-^Zb#y95To%%N9!JR<YuM21)zYxPM{v=?Uhof;e
zH?pLhN=uimeEI`CEf?eVdo_1m<mXOE2eL&zDabx|l8?vP2r;BBW~(p<k;cbri~oGi
za0N46jMk6k1TRD4Q_e3a=V|4ln{Stk|IXR8a(XSm+!L7WF at O><%986x*MMH~R|CL$
z4w6?6!psCw4LNrjH-XCNCWVj)D3Lc`jGE3vQp4+0Q8OgCL=J;-H;vG{KsO2-%<!y%
z9|XKF_Dv at a?UERvi*h=-BvMlv;QQX*-lIRQhSvE)_pvtc)&7Ic&gR4YzF>E!&(lG}
zNLz1jkJAm_bcO;&`s42=i;N9s?JpiY(ri8040{{*H6DKFQuKlO`2>zx5cMW<k^C{6
zu+7d~)jQ%_?B<L0VvA_29G+r3hEX+4wiKfbv5m4-;Kng6v_O}!9ZX7);$KHlzM+vK
zhRNXvw_-&)3Kvqyg<lr=Rz?2t(-dn!dh~^${rtAngxoo at 1<<r?PFP-{6uJ%1vj#k4
zXtdzERICn6r*$t%(A{!OI>T-#xDZOkepSt@@`XezkbY7;47qONNibzby~f6m2x}Sq
zw*^p?{lWHIh_Rw%sbIE=LY*VX%&(~~vpVD1CLvXRk=a-#{6L#;D7TiaTN at t7thA8n
zu}D5d at vT(9g$Ndi?q=u?x`^N^krPc)LL}YfmAty(z>)k%^jAo>gvxbPl0jaDKm+6z
zso1ueRYc!PevHtRZ1jhPs8M{%jSJ3-TvI7#T`gi?8gXY4T`?86MzmevWl_ThNd_1R
zFz*X<G0d_*u83|cokhq160;FrZyM_Mz8xe(**)v`HZ*M-pTo21?|*u%^JU3_bq(l^
zgJ)$DdkBZA=8u!MbAqx=&+G3iE!LVNv6pOb0DJXJOfIcz%|y!o6{616I-aAj_@|E1
zn^Y7wc8DEoLW~9&&o3EX<E05iho3Z5%O^Dl4mL<OA*^cc4fZo(fro3c^w9|Mu+Wjz
zwix=;ci90U53JY<;~VfX9xTN*>-lw1o1pUe=kd-Lp7Ok(XQ0$W<zLQ+po*dL`}p#7
zp6~PPpO&ZdJmuflsB&%Q=b*!8=z<P^;79%^fc~44|KCg-Ht3J)Yj*bgUiS44`gZno
O`})IAe;jMaq5lAjYAJF6

literal 0
HcmV?d00001

diff --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.ll b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.ll
new file mode 100644
index 0000000000000..a2277f5554232
--- /dev/null
+++ b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.ll
@@ -0,0 +1,83 @@
+; ModuleID = 'test.cpp'
+source_filename = "test.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux"
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z3fooPKijb(ptr noundef %ParamPtr, i32 noundef %ParamUnsigned, i1 noundef zeroext %ParamBool) #0 !dbg !10 {
+entry:
+  %retval = alloca i32, align 4
+  %ParamPtr.addr = alloca ptr, align 8
+  %ParamUnsigned.addr = alloca i32, align 4
+  %ParamBool.addr = alloca i8, align 1
+  %CONSTANT = alloca i32, align 4
+  store ptr %ParamPtr, ptr %ParamPtr.addr, align 8
+    #dbg_declare(ptr %ParamPtr.addr, !20, !DIExpression(), !21)
+  store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4
+    #dbg_declare(ptr %ParamUnsigned.addr, !22, !DIExpression(), !23)
+  %storedv = zext i1 %ParamBool to i8
+  store i8 %storedv, ptr %ParamBool.addr, align 1
+    #dbg_declare(ptr %ParamBool.addr, !24, !DIExpression(), !25)
+  %0 = load i8, ptr %ParamBool.addr, align 1, !dbg !26
+  %loadedv = trunc i8 %0 to i1, !dbg !26
+  br i1 %loadedv, label %if.then, label %if.end, !dbg !26
+
+if.then:                                          ; preds = %entry
+    #dbg_declare(ptr %CONSTANT, !28, !DIExpression(), !32)
+  store i32 7, ptr %CONSTANT, align 4, !dbg !32
+  store i32 7, ptr %retval, align 4, !dbg !33
+  br label %return, !dbg !33
+
+if.end:                                           ; preds = %entry
+  %1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34
+  store i32 %1, ptr %retval, align 4, !dbg !35
+  br label %return, !dbg !35
+
+return:                                           ; preds = %if.end, %if.then
+  %2 = load i32, ptr %retval, align 4, !dbg !36
+  ret i32 %2, !dbg !36
+}
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0git (https://github.com/llvm/llvm-project.git 16e45b8fac797c6d4ba161228b54665492204a9d)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.cpp", directory: "X:\\scripts\\regression-suite\\input\\general", checksumkind: CSK_MD5, checksum: "969bd5763e7769d696eb29bdc55331d7")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git 16e45b8fac797c6d4ba161228b54665492204a9d)"}
+!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooPKijb", scope: !1, file: !1, line: 2, type: !11, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !19)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !14, !17, !18}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "INTPTR", file: !1, line: 1, baseType: !15)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13)
+!17 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!18 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean)
+!19 = !{}
+!20 = !DILocalVariable(name: "ParamPtr", arg: 1, scope: !10, file: !1, line: 2, type: !14)
+!21 = !DILocation(line: 2, column: 16, scope: !10)
+!22 = !DILocalVariable(name: "ParamUnsigned", arg: 2, scope: !10, file: !1, line: 2, type: !17)
+!23 = !DILocation(line: 2, column: 35, scope: !10)
+!24 = !DILocalVariable(name: "ParamBool", arg: 3, scope: !10, file: !1, line: 2, type: !18)
+!25 = !DILocation(line: 2, column: 55, scope: !10)
+!26 = !DILocation(line: 3, column: 7, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !10, file: !1, line: 3, column: 7)
+!28 = !DILocalVariable(name: "CONSTANT", scope: !29, file: !1, line: 5, type: !30)
+!29 = distinct !DILexicalBlock(scope: !27, file: !1, line: 3, column: 18)
+!30 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !31)
+!31 = !DIDerivedType(tag: DW_TAG_typedef, name: "INTEGER", scope: !10, file: !1, line: 4, baseType: !13)
+!32 = !DILocation(line: 5, column: 19, scope: !29)
+!33 = !DILocation(line: 6, column: 5, scope: !29)
+!34 = !DILocation(line: 8, column: 10, scope: !10)
+!35 = !DILocation(line: 8, column: 3, scope: !10)
+!36 = !DILocation(line: 9, column: 1, scope: !10)

>From b5bf4fcc810ec92f526294f0e3aebc9379514adb Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Wed, 11 Jun 2025 08:49:51 +0100
Subject: [PATCH 02/13] [llvm-debuginfo-analyzer] Add support for LLVM IR
 format.

Add support for the LLVM IR format and be able to generate
logical views.

Both textual representation (.ll) and bitcode (.bc) format
are supported.

Note: This patch requires:

Add DebugSSAUpdater class to track debug value liveness
https://github.com/llvm/llvm-project/pull/135349

Note: Address reviewers comments.
---
 .../CommandGuide/llvm-debuginfo-analyzer.rst  |  28 ++
 .../DebugInfo/LogicalView/LVReaderHandler.h   |   7 +-
 .../LogicalView/Readers/LVIRReader.h          |  56 +--
 .../DebugInfo/LogicalView/LVReaderHandler.cpp |  14 +-
 .../LogicalView/Readers/LVDWARFReader.cpp     |  10 +-
 .../LogicalView/Readers/LVIRReader.cpp        | 322 ++++++++----------
 .../IR/01-ir-print-basic-details.test         |   2 +
 .../IR/01-ir-select-logical-elements.test     |  33 +-
 .../IR/06-ir-full-logical-view.test           |  66 ++--
 .../DebugInfo/LogicalView/IRReaderTest.cpp    |  38 ++-
 10 files changed, 302 insertions(+), 274 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index 3d1b971d31db6..a2df5c4da4fc9 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -2264,6 +2264,34 @@ layout and given the number of matches.
   -----------------------------
   Total           33         12
 
+The following prints all *symbols* and *types* that contain the exact **'INTPTR'**
+in their names or types, using a tab layout and given the number of matches.
+
+.. code-block:: none
+
+  llvm-debuginfo-analyzer --attribute=level
+                          --select=INTPTR
+                          --report=list
+                          --print=symbols,types,summary
+                          test-clang.ll
+
+  Logical View:
+  [000]           {File} 'test-clang.ll'
+
+  [001]           {CompileUnit} 'test.cpp'
+  [002]     1     {TypeAlias} 'INTPTR' -> '* const int'
+  [003]     2     {Parameter} 'ParamPtr' -> 'INTPTR'
+
+  -----------------------------
+  Element      Total    Printed
+  -----------------------------
+  Scopes           5          0
+  Symbols          4          1
+  Types            2          1
+  Lines           23          0
+  -----------------------------
+  Total           34          2
+
 COMPARISON MODE
 ^^^^^^^^^^^^^^^
 Given the previous example we found the above debug information issue
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
index fc2b89b2ef421..3336c9415927c 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
@@ -31,7 +31,7 @@ namespace logicalview {
 
 using LVReaders = std::vector<std::unique_ptr<LVReader>>;
 using ArgVector = std::vector<std::string>;
-using PdbOrObjOrIr =
+using InputHandle =
     PointerUnion<object::ObjectFile *, pdb::PDBFile *, object::IRObjectFile *,
                  MemoryBufferRef *, StringRef *>;
 
@@ -67,9 +67,8 @@ class LVReaderHandler {
   Error handleObject(LVReaders &Readers, StringRef Filename,
                      MemoryBufferRef Buffer);
 
-  Error createReader(StringRef Filename, LVReaders &Readers,
-                     PdbOrObjOrIr &Input, StringRef FileFormatName,
-                     StringRef ExePath = {});
+  Error createReader(StringRef Filename, LVReaders &Readers, InputHandle &Input,
+                     StringRef FileFormatName, StringRef ExePath = {});
 
 public:
   LVReaderHandler() = delete;
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
index 5c70ec9077791..3a7d5d91986d5 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
@@ -58,7 +58,9 @@ class LVIRReader final : public LVReader {
   // Whether to emit all linkage names, or just abstract subprograms.
   bool UseAllLinkageNames = true;
 
-  // Dependencies on external options (llc, etc).
+  // Looking at IR generated with the '-gdwarf -gsplit-dwarf=split' the only
+  // difference is setting the 'DICompileUnit::splitDebugFilename' to the
+  // name of the split filename: "xxx.dwo".
   bool includeMinimalInlineScopes() const;
   bool useAllLinkageNames() const { return UseAllLinkageNames; }
 
@@ -66,10 +68,7 @@ class LVIRReader final : public LVReader {
   void mapFortranLanguage(unsigned DWLang);
   bool moduleIsInFortran() const { return LanguageIsFortran; }
 
-  // Generate logical debug line before prologue.
-  bool GenerateLineBeforePrologue = true;
-
-  // We assume a constante increase between instructions.
+  // We assume a constant instruction-size increase between instructions.
   const unsigned OffsetIncrease = 4;
   void updateLineOffset() { CurrentOffset += OffsetIncrease; }
 
@@ -79,6 +78,7 @@ class LVIRReader final : public LVReader {
   std::unique_ptr<DbgValueRangeTable> DbgValueRanges;
 
   // Record the last assigned file index for each compile unit.
+  // This data structure is to aid mapping DIFiles onto a DWARF-like file table.
   using LVIndexFiles = std::map<LVScopeCompileUnit *, size_t>;
   LVIndexFiles IndexFiles;
 
@@ -99,13 +99,13 @@ class LVIRReader final : public LVReader {
     return FileIndex;
   }
 
-  // Collect the compile unit metadata files.
+  // Store a FileID number for each DIFile seen.
   using LVCompileUnitFiles = std::map<const DIFile *, size_t>;
   LVCompileUnitFiles CompileUnitFiles;
 
   size_t getOrCreateSourceID(const DIFile *File);
 
-  // Associate the logical elements to metadata objects.
+  // Associate the metadata objects to logical elements.
   using LVMDObjects = std::map<const MDNode *, LVElement *>;
   LVMDObjects MDObjects;
 
@@ -130,18 +130,23 @@ class LVIRReader final : public LVReader {
     return static_cast<LVType *>(getElementForSeenMD(MD));
   }
 
-  // Inlined concrete scopes with its associated inlined abstract scopes.
-  // When creating abstract scopes, there is no direct information to find
+  // Abstract scopes mapped to the associated inlined scopes.
+  // When creating inlined scopes, there is no direct information to find
   // the correct lexical scope.
-  using LVInlinedScopes = std::map<LVScope *, LVScope *>;
+  using LVScopeEntry = std::pair<LVScope *, const DILocation *>;
+  using LVInlinedScopes = std::map<LVScopeEntry, LVScope *>;
   LVInlinedScopes InlinedScopes;
 
-  void addInlinedScope(LVScope *ConcreteScope, LVScope *AbstractScope) {
-    if (InlinedScopes.find(ConcreteScope) == InlinedScopes.end())
-      InlinedScopes.emplace(ConcreteScope, AbstractScope);
+  void addInlinedScope(LVScope *AbstractScope, const DILocation *InlinedAt,
+                       LVScope *InlinedScope) {
+    auto Entry = LVScopeEntry(AbstractScope, InlinedAt);
+    if (InlinedScopes.find(Entry) == InlinedScopes.end())
+      InlinedScopes.emplace(Entry, InlinedScope);
   }
-  LVScope *getInlinedScope(LVScope *ConcreteScope) const {
-    LVInlinedScopes::const_iterator Iter = InlinedScopes.find(ConcreteScope);
+  LVScope *getInlinedScope(LVScope *AbstractScope,
+                           const DILocation *InlinedAt) const {
+    auto Entry = LVScopeEntry(AbstractScope, InlinedAt);
+    LVInlinedScopes::const_iterator Iter = InlinedScopes.find(Entry);
     return Iter != InlinedScopes.end() ? Iter->second : nullptr;
   }
 
@@ -163,9 +168,6 @@ class LVIRReader final : public LVReader {
 
   void processBasicBlocks(Function &F, const DISubprogram *SP);
 
-  void addGlobalName(StringRef Name, LVElement *Element,
-                     const DIScope *Context);
-
   void addAccess(LVElement *Element, DINode::DIFlags Flags);
 
   void addConstantValue(LVElement *Element, const DIExpression *DIExpr);
@@ -175,7 +177,7 @@ class LVIRReader final : public LVReader {
                         const DIType *Ty);
   void addConstantValue(LVElement *Element, const APInt &Value, bool Unsigned);
   void addConstantValue(LVElement *Element, uint64_t Value, const DIType *Ty);
-  void addConstantValue(LVElement *Element, bool Unsigned, uint64_t Value);
+  void addConstantValue(LVElement *Element, uint64_t Value, bool Unsigned);
 
   void addString(LVElement *Element, StringRef Str);
 
@@ -197,8 +199,6 @@ class LVIRReader final : public LVReader {
   bool applySubprogramDefinitionAttributes(LVScope *Function,
                                            const DISubprogram *SP,
                                            bool Minimal = false);
-  void applySubprogramAttributesToDefinition(LVScope *Function,
-                                             const DISubprogram *SP);
 
   void constructAggregate(LVScopeAggregate *Aggregate,
                           const DICompositeType *CTy);
@@ -210,7 +210,8 @@ class LVIRReader final : public LVReader {
                                 LVType *IndexType);
   void constructImportedEntity(LVElement *Element, const DIImportedEntity *IE);
 
-  void constructLine(LVScope *Scope, const DISubprogram *SP, Instruction &I);
+  void constructLine(LVScope *Scope, const DISubprogram *SP, Instruction &I,
+                     bool &GenerateLineBeforePrologue);
 
   LVSymbol *getOrCreateMember(LVScope *Aggregate, const DIDerivedType *DT);
   LVSymbol *getOrCreateStaticMember(LVScope *Aggregate,
@@ -220,14 +221,15 @@ class LVIRReader final : public LVReader {
   LVScope *getOrCreateScope(const DIScope *Context);
   void constructScope(LVElement *Element, const DIScope *Context);
 
-  LVScope *getOrCreateSubprogram(const DISubprogram *SP, bool Minimal = false);
+  LVScope *getOrCreateSubprogram(const DISubprogram *SP);
   LVScope *getOrCreateSubprogram(LVScope *Function, const DISubprogram *SP,
                                  bool Minimal = false);
   void constructSubprogramArguments(LVScope *Function,
                                     const DITypeRefArray Args);
 
-  LVScope *getOrCreateInlinedScope(LVScope *Parent, const DILocation *DL);
-  LVScope *getOrCreateAbstractScope(LVScope *OriginScope, const DILocation *DL);
+  LVScope *getOrCreateAbstractScope(LVScope *Parent, const DILocation *DL);
+  LVScope *getOrCreateInlinedScope(LVScope *AbstractScope,
+                                   const DILocation *DL);
 
   void constructSubrange(LVScopeArray *Array, const DISubrange *GSR,
                          LVType *IndexType);
@@ -245,8 +247,8 @@ class LVIRReader final : public LVReader {
   LVSymbol *getOrCreateVariable(const DIGlobalVariableExpression *GVE);
   LVSymbol *getOrCreateVariable(const DIVariable *Var,
                                 const DILocation *DL = nullptr);
-  LVSymbol *getOrCreateAbstractVariable(LVSymbol *OriginSymbol,
-                                        const DILocation *DL);
+  LVSymbol *getOrCreateInlinedVariable(LVSymbol *OriginSymbol,
+                                       const DILocation *DL);
 
   LVElement *constructElement(const DINode *DN);
 
diff --git a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
index a1721a3a8e624..d7350defc404c 100644
--- a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
@@ -41,7 +41,7 @@ Error LVReaderHandler::process() {
 }
 
 Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
-                                    PdbOrObjOrIr &Input,
+                                    InputHandle &Input,
                                     StringRef FileFormatName,
                                     StringRef ExePath) {
   auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> {
@@ -66,7 +66,7 @@ Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
       return std::make_unique<LVIRReader>(Filename, FileFormatName, Ir, W);
     }
     if (isa<MemoryBufferRef *>(Input)) {
-      // If the filename extension is '.ll' create a IR reader.
+      // If the filename extension is '.ll' create an IR reader.
       const StringRef IRFileExt = ".ll";
       MemoryBufferRef *MemBuf = cast<MemoryBufferRef *>(Input);
       if (llvm::sys::path::extension(Filename) == IRFileExt)
@@ -240,7 +240,7 @@ Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
     if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =
             ObjForArch.getAsObjectFile()) {
       MachOObjectFile &Obj = **MachOOrErr;
-      PdbOrObjOrIr Input = &Obj;
+      InputHandle Input = &Obj;
       if (Error Err =
               createReader(Filename, Readers, Input, Obj.getFileFormatName()))
         return Err;
@@ -260,7 +260,7 @@ Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
 
 Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
                                     Binary &Binary) {
-  if (PdbOrObjOrIr Input = dyn_cast<ObjectFile>(&Binary))
+  if (InputHandle Input = dyn_cast<ObjectFile>(&Binary))
     return createReader(Filename, Readers, Input,
                         cast<ObjectFile *>(Input)->getFileFormatName());
 
@@ -270,7 +270,7 @@ Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
   if (Archive *Arch = dyn_cast<Archive>(&Binary))
     return handleArchive(Readers, Filename, *Arch);
 
-  if (PdbOrObjOrIr Input = dyn_cast<IRObjectFile>(&Binary))
+  if (InputHandle Input = dyn_cast<IRObjectFile>(&Binary))
     return createReader(Filename, Readers, Input, "Bitcode IR");
 
   return createStringError(errc::not_supported,
@@ -287,7 +287,7 @@ Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
 
   std::unique_ptr<NativeSession> PdbSession;
   PdbSession.reset(static_cast<NativeSession *>(Session.release()));
-  PdbOrObjOrIr Input = &PdbSession->getPDBFile();
+  InputHandle Input = &PdbSession->getPDBFile();
   StringRef FileFormatName;
   size_t Pos = Buffer.find_first_of("\r\n");
   if (Pos)
@@ -297,7 +297,7 @@ Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
 
 Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
                                     MemoryBufferRef Buffer) {
-  if (PdbOrObjOrIr Input = dyn_cast<MemoryBufferRef>(&Buffer))
+  if (InputHandle Input = dyn_cast<MemoryBufferRef>(&Buffer))
     return createReader(Filename, Readers, Input, IRFileFormat);
 
   return createStringError(errc::not_supported,
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
index 2a1dd08b6bc58..772d821dcda81 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
@@ -528,16 +528,14 @@ void LVDWARFReader::createLineAndFileRecords(
     for (const DWARFDebugLine::FileNameEntry &Entry :
          Lines->Prologue.FileNames) {
       std::string Directory;
-      Lines->getDirectoryForEntry(Entry, Directory);
+      if (Lines->getDirectoryForEntry(Entry, Directory))
+        Directory = transformPath(Directory);
       if (Directory.empty())
         Directory = std::string(CompileUnit->getCompilationDirectory());
-      // Take just the filename component, as it may be contain the full
-      // path that would be added to the already existing path in Directory.
-      StringRef File =
-          llvm::sys::path::filename(dwarf::toStringRef(Entry.Name));
+      std::string File = transformPath(dwarf::toStringRef(Entry.Name));
       std::string String;
       raw_string_ostream(String) << Directory << "/" << File;
-      CompileUnit->addFilename(transformPath(String));
+      CompileUnit->addFilename(String);
     }
 
   // In DWARF5 the file indexes start at 0;
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index d8a9a18afce90..f74edacda97f4 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -34,18 +34,16 @@ using namespace llvm::logicalview;
 
 #define DEBUG_TYPE "IRReader"
 
-// Extra debug traces. Default is false
-#define DEBUG_ALL
-
-// These flavours of DINodes are not handled:
-//   DW_TAG_APPLE_property   = 19896
-//   DW_TAG_atomic_type      = 71
-//   DW_TAG_common_block     = 26
-//   DW_TAG_file_type        = 41
-//   DW_TAG_friend           = 42
-//   DW_TAG_generic_subrange = 69
-//   DW_TAG_immutable_type   = 75
-//   DW_TAG_module           = 30
+// These flavours of DINodes are not implemented but technically possible:
+//   DW_TAG_APPLE_property   = 0x4200
+//   DW_TAG_atomic_type      = 0x0047
+//   DW_TAG_common_block     = 0x001a
+//   DW_TAG_file_type        = 0x0029
+//   DW_TAG_friend           = 0x002a
+//   DW_TAG_generic_subrange = 0x0045
+//   DW_TAG_immutable_type   = 0x004b
+//   DW_TAG_module           = 0x001e
+//   DW_TAG_variant_part     = 0x0033
 
 // Create a logical element and setup the following information:
 // - Name, DWARF tag, line
@@ -84,29 +82,22 @@ void LVIRReader::mapFortranLanguage(unsigned DWLang) {
   }
 }
 
-// Looking at IR generated with the '-gdwarf -gsplit-dwarf=split' the only
-// difference is setting the 'DICompileUnit::splitDebugFilename' to the
-// name of the split filename: "xxx.dwo".
 bool LVIRReader::includeMinimalInlineScopes() const {
   return getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly;
 }
 
 // For the given 'DIFile' generate an index 1-based to indicate the
 // source file where the logical element is declared.
-// In DWARF v4, the files are 1-indexed.
-// In DWARF v5, the files are 0-indexed.
 // The IR reader expects the indexes as 1-indexed.
 // Each compile unit, keeps track of the last assigned index.
 size_t LVIRReader::getOrCreateSourceID(const DIFile *File) {
   if (!File)
     return 0;
 
-#ifdef DEBUG_ALL
   LLVM_DEBUG({
     dbgs() << "\n[getOrCreateSourceID] DIFile\n";
     File->dump();
   });
-#endif
 
   addMD(File, CompileUnit);
 
@@ -116,7 +107,7 @@ size_t LVIRReader::getOrCreateSourceID(const DIFile *File) {
   });
   size_t FileIndex = 0;
   LVCompileUnitFiles::iterator Iter = CompileUnitFiles.find(File);
-  if (Iter == CompileUnitFiles.cend()) {
+  if (Iter == CompileUnitFiles.end()) {
     FileIndex = getFileIndex(CompileUnit);
     std::string Directory(File->getDirectory());
     if (Directory.empty())
@@ -209,6 +200,8 @@ void LVIRReader::addConstantValue(LVElement *Element,
                                   const DIExpression *DIExpr) {
   std::optional<DIExpression::SignedOrUnsignedConstant> Constant =
       DIExpr->isConstant();
+  if (Constant == std::nullopt)
+    return;
   std::stringstream Stream;
   if (DIExpression::SignedOrUnsignedConstant::SignedConstant == Constant) {
     int64_t Value = DIExpr->getElement(1);
@@ -236,8 +229,8 @@ void LVIRReader::addConstantValue(LVElement *Element, uint64_t Val,
   addConstantValue(Element, DebugHandlerBase::isUnsignedDIType(Ty), Val);
 }
 
-void LVIRReader::addConstantValue(LVElement *Element, bool Unsigned,
-                                  uint64_t Val) {
+void LVIRReader::addConstantValue(LVElement *Element, uint64_t Val,
+                                  bool Unsigned) {
   addConstantValue(Element, llvm::APInt(64, Val, Unsigned), Unsigned);
 }
 
@@ -271,7 +264,9 @@ void LVIRReader::processScopes() {
   //   as the code the handles public names, expects them to have one.
   //   Use an arbitrary increment of 4.
   // - Resolve any line pattern match.
-  LVOffset Offset = 0;
+  // At this stage the compile unit and the root scopes they have the
+  // same offset, which is incorrect. Update the compile unit offset.
+  LVOffset Offset = 4;
   auto SetOffset = [&](LVElement *Element) {
     Element->setOffset(Offset);
     Offset += OffsetIncrease;
@@ -334,12 +329,10 @@ LVScope *LVIRReader::getParentScopeImpl(const DIScope *Context) {
   if (!Context)
     return CompileUnit;
 
-#ifdef DEBUG_ALL
   LLVM_DEBUG({
     dbgs() << "\n[getParentScopeImpl] DIScope\n";
     Context->dump();
   });
-#endif
 
   // Check for an already seen scope parent.
   if (LVScope *Parent = getScopeForSeenMD(Context))
@@ -352,12 +345,10 @@ LVScope *LVIRReader::getParentScopeImpl(const DIScope *Context) {
 // Get the logical parent for the given metadata node.
 LVScope *LVIRReader::getParentScope(const DILocation *DL) {
   assert(DL && "Invalid metadata node.");
-#ifdef DEBUG_ALL
   LLVM_DEBUG({
     dbgs() << "\n[getParentScope] DILocation\n";
     DL->dump();
   });
-#endif
 
   return getParentScopeImpl(cast<DIScope>(DL->getScope()));
 }
@@ -365,12 +356,10 @@ LVScope *LVIRReader::getParentScope(const DILocation *DL) {
 // Get the logical parent for the given metadata node.
 LVScope *LVIRReader::getParentScope(const DINode *DN) {
   assert(DN && "Invalid metadata node.");
-#ifdef DEBUG_ALL
   LLVM_DEBUG({
     dbgs() << "\n[getParentScope] DINode\n";
     DN->dump();
   });
-#endif
 
   return getParentScopeImpl(getMDScope(DN));
 }
@@ -380,12 +369,10 @@ LVScope *LVIRReader::traverseParentScope(const DIScope *Context) {
   if (!Context)
     return CompileUnit;
 
-#ifdef DEBUG_ALL
   LLVM_DEBUG({
     dbgs() << "\n[traverseParentScope] DIScope\n";
     Context->dump();
   });
-#endif
 
   // Check if the metadata is already seen.
   if (LVScope *Parent = getScopeForSeenMD(Context))
@@ -431,16 +418,6 @@ LVType *LVIRReader::getIndexType() {
   return NodeIndexType;
 }
 
-// addGlobalName - Add a new global name to the compile unit.
-void LVIRReader::addGlobalName(StringRef Name, LVElement *Element,
-                               const DIScope *Context) {
-  assert(Element && "Invalid logical element.");
-  LLVM_DEBUG({
-    dbgs() << "\n[addGlobalName] DIScope\n";
-    Context->dump();
-  });
-}
-
 // Add accessibility info if available.
 void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) {
   assert(Element && "Invalid logical element.");
@@ -474,12 +451,10 @@ void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) {
 //   DIMacroFile
 const DIFile *LVIRReader::getMDFile(const MDNode *MD) const {
   assert(MD && "Invalid metadata node.");
-#ifdef DEBUG_ALL
   LLVM_DEBUG({
     dbgs() << "\n[getMDFile] MDNode\n";
     MD->dump();
   });
-#endif
 
   if (auto *T = dyn_cast<DIScope>(MD))
     return T->getFile();
@@ -524,27 +499,10 @@ const DIFile *LVIRReader::getMDFile(const MDNode *MD) const {
 //   DIEnumerator
 StringRef LVIRReader::getMDName(const DINode *DN) const {
   assert(DN && "Invalid metadata node.");
-#ifdef DEBUG_ALL
   LLVM_DEBUG({
     dbgs() << "\n[getMDName] DINode\n";
     DN->dump();
   });
-#endif
-
-  if (auto *T = dyn_cast<DIType>(DN))
-    return T->getName();
-
-  if (auto *T = dyn_cast<DISubprogram>(DN))
-    return T->getName();
-
-  if (auto *T = dyn_cast<DINamespace>(DN))
-    return T->getName();
-
-  if (auto *T = dyn_cast<DICommonBlock>(DN))
-    return T->getName();
-
-  if (auto *T = dyn_cast<DIModule>(DN))
-    return T->getName();
 
   if (auto *T = dyn_cast<DIImportedEntity>(DN))
     return T->getName();
@@ -588,12 +546,10 @@ StringRef LVIRReader::getMDName(const DINode *DN) const {
 
 const DIScope *LVIRReader::getMDScope(const DINode *DN) const {
   assert(DN && "Invalid metadata node.");
-#ifdef DEBUG_ALL
   LLVM_DEBUG({
     dbgs() << "\n[getMDScope] DINode\n";
     DN->dump();
   });
-#endif
 
   if (dyn_cast<DIBasicType>(DN))
     return getCUNode();
@@ -718,6 +674,29 @@ bool LVIRReader::applySubprogramDefinitionAttributes(LVScope *Function,
       DeclArgs = SPDecl->getType()->getTypeArray();
       DefinitionArgs = SP->getType()->getTypeArray();
 
+      // The element zero in 'DefinitionArgs' and 'DeclArgs' arrays is
+      // the subprogram return type. A 'void' return does not have a
+      // type and it is represented by a 'nullptr' value.
+      // For the given test case and its IR:
+      //
+      // 1 struct Bar {
+      // 2  bool foo(int a);
+      // 3 };
+      // 4
+      // 5 bool Bar::foo(int a) {
+      // 6   return false;
+      // 7 }
+      //
+      // !10 = !DISubprogram(name: "foo", line: 5, type: !14,
+      //                     spFlags: DISPFlagDefinition)
+      // !13 = !DISubprogram(name: "foo", line: 2, type: !14, spFlags: 0)
+      // !14 = !DISubroutineType(types: !15)
+      // !15 = !{!16, !17, !18}
+      // !16 = !DIBasicType(name: "bool", ...)
+      //
+      // '!15' represents both 'DefinitionArgs' and 'DeclArgs' arrays.
+      // For cases where they have a different metadata node, use the
+      // type from the 'DefinitionArgs' array as the correct type.
       if (DeclArgs.size() && DefinitionArgs.size())
         if (DefinitionArgs[0] != nullptr && DeclArgs[0] != DefinitionArgs[0]) {
           LVElement *ElementType = getOrCreateType(DefinitionArgs[0]);
@@ -762,18 +741,6 @@ bool LVIRReader::applySubprogramDefinitionAttributes(LVScope *Function,
   return true;
 }
 
-void LVIRReader::applySubprogramAttributesToDefinition(LVScope *Function,
-                                                       const DISubprogram *SP) {
-  assert(Function && "Invalid logical element");
-  assert(SP && "Invalid metadata node.");
-  LLVM_DEBUG({
-    dbgs() << "\n[applySubprogramAttributesToDefinition] DISubprogram\n";
-    SP->dump();
-  });
-
-  applySubprogramAttributes(Function, SP, includeMinimalInlineScopes());
-}
-
 // DICompositeType
 void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate,
                                     const DICompositeType *CTy) {
@@ -789,8 +756,6 @@ void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate,
   Aggregate->setIsFinalized();
 
   dwarf::Tag Tag = Aggregate->getTag();
-  if (Tag == dwarf::DW_TAG_variant_part) {
-  }
 
   // Add template parameters to a class, structure or union types.
   if (Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type ||
@@ -798,7 +763,7 @@ void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate,
     addTemplateParams(Aggregate, CTy->getTemplateParams());
 
   // Add elements to aggregate type.
-  for (const auto Member : CTy->getElements()) {
+  for (const auto *Member : CTy->getElements()) {
     if (!Member)
       continue;
     LLVM_DEBUG({
@@ -934,12 +899,12 @@ void LVIRReader::constructImportedEntity(LVElement *Element,
   }
 }
 
-LVScope *LVIRReader::getOrCreateAbstractScope(LVScope *OriginScope,
-                                              const DILocation *DL) {
-  assert(OriginScope && "Invalid logical element");
+LVScope *LVIRReader::getOrCreateInlinedScope(LVScope *AbstractScope,
+                                             const DILocation *DL) {
+  assert(AbstractScope && "Invalid logical element");
   assert(DL && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateAbstractScope] DILocation\n";
+    dbgs() << "\n[getOrCreateInlinedScope] DILocation\n";
     DL->dump();
   });
 
@@ -947,114 +912,101 @@ LVScope *LVIRReader::getOrCreateAbstractScope(LVScope *OriginScope,
   DILocalScope *Context = DL->getScope();
   LLVM_DEBUG({
     dbgs() << "\nParent Scope:\n";
-    OriginScope->getParentScope()->dump();
+    AbstractScope->getParentScope()->dump();
     dbgs() << "\nOriginScope:\n";
-    OriginScope->dump();
+    AbstractScope->dump();
     dbgs() << "\nInlinedAt:\n";
     InlinedAt->dump();
     dbgs() << "\nContext:\n";
     Context->dump();
   });
 
-  dwarf::Tag Tag = OriginScope->getTag();
-  if (OriginScope->getIsFunction() || OriginScope->getIsInlinedFunction()) {
+  dwarf::Tag Tag = AbstractScope->getTag();
+  if (AbstractScope->getIsFunction() || AbstractScope->getIsInlinedFunction()) {
     Tag = dwarf::DW_TAG_inlined_subroutine;
-    OriginScope->setInlineCode(dwarf::DW_INL_inlined);
+    AbstractScope->setInlineCode(dwarf::DW_INL_inlined);
   }
-  LVScope *AbstractScope = static_cast<LVScope *>(createElement(Tag));
-  if (AbstractScope) {
-    addInlinedScope(OriginScope, AbstractScope);
-    AbstractScope->setTag(Tag);
-    AbstractScope->setIsFinalized();
-    AbstractScope->setName(OriginScope->getName());
-    AbstractScope->setType(OriginScope->getType());
-
-    AbstractScope->setCallLineNumber(InlinedAt->getLine());
-    AbstractScope->setCallFilenameIndex(
+  LVScope *InlinedScope = static_cast<LVScope *>(createElement(Tag));
+  if (InlinedScope) {
+    addInlinedScope(AbstractScope, InlinedAt, InlinedScope);
+    InlinedScope->setTag(Tag);
+    InlinedScope->setIsFinalized();
+    InlinedScope->setName(AbstractScope->getName());
+    InlinedScope->setType(AbstractScope->getType());
+
+    InlinedScope->setCallLineNumber(InlinedAt->getLine());
+    InlinedScope->setCallFilenameIndex(
         getOrCreateSourceID(InlinedAt->getFile()));
 
-    AbstractScope->setReference(OriginScope);
-    AbstractScope->setHasReferenceAbstract();
+    InlinedScope->setReference(AbstractScope);
+    InlinedScope->setHasReferenceAbstract();
 
     // Get or create the parent scope for the inlined subprogram.
-    LVScope *Parent = AbstractScope->getIsLexicalBlock()
-                          ? getInlinedScope(OriginScope->getParentScope())
-                          : getOrCreateScope(InlinedAt->getScope());
+    LVScope *Parent =
+        InlinedScope->getIsLexicalBlock()
+            ? getInlinedScope(AbstractScope->getParentScope(), InlinedAt)
+            : getOrCreateScope(InlinedAt->getScope());
     assert(Parent && "Parent scope is NULL.");
-    Parent->addElement(AbstractScope);
+    Parent->addElement(InlinedScope);
   }
 
-  return AbstractScope;
+  return InlinedScope;
 }
 
-LVScope *LVIRReader::getOrCreateInlinedScope(LVScope *Parent,
-                                             const DILocation *DL) {
+LVScope *LVIRReader::getOrCreateAbstractScope(LVScope *Parent,
+                                              const DILocation *DL) {
   assert(Parent && "Invalid logical element");
   assert(DL && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateInlinedScope] DILocation\n";
+    dbgs() << "\n[getOrCreateAbstractScope] DILocation\n";
     DL->dump();
     dbgs() << "Parent Logical Scope:\n";
     Parent->dump();
   });
 
-  // Get the 'origin' and 'abstract' debug locations.
   const DILocation *InlinedAt = DL->getInlinedAt();
   if (!InlinedAt)
     return nullptr;
 
   DILocalScope *Context = DL->getScope();
-  assert(Context && "Context is null.");
   if (!Context)
     return nullptr;
 
-  LLVM_DEBUG({
-    dbgs() << "\nInlinedAt:\n";
-    InlinedAt->dump();
-    dbgs() << "\nContext:\n";
-    Context->dump();
-  });
-
-  // Get the seed scope to be used to create the inlined scope.
-  LLVM_DEBUG({
-    LVScope *ParentScope = getOrCreateSubprogram(
-        static_cast<DISubprogram *>(InlinedAt->getScope()));
-    assert((Parent == ParentScope) && "Scopes don't match.");
-  });
-
   // Check if we have seen the scope.
-  LVScope *OriginScope = getScopeForSeenMD(Context);
-  if (!OriginScope) {
-    // Create the 'origin' scope.
+  LVScope *AbstractScope = getScopeForSeenMD(Context);
+  if (!AbstractScope) {
+    // Create the 'abstract' scope.
     if (isa<DISubprogram>(Context)) {
-      OriginScope = getOrCreateSubprogram(static_cast<DISubprogram *>(Context));
-      OriginScope->setInlineCode(dwarf::DW_INL_inlined);
+      AbstractScope =
+          getOrCreateSubprogram(static_cast<DISubprogram *>(Context));
+      AbstractScope->setInlineCode(dwarf::DW_INL_inlined);
     } else if (isa<DILexicalBlock>(Context)) {
-      OriginScope = getOrCreateScope(static_cast<DIScope *>(Context));
+      AbstractScope = getOrCreateScope(static_cast<DIScope *>(Context));
     }
     LLVM_DEBUG({
       dbgs() << "\nParent Scope:\n";
-      OriginScope->getParentScope()->dump();
-      dbgs() << "Inlined (Origin) Logical Scope:\n";
-      OriginScope->dump();
+      AbstractScope->getParentScope()->dump();
+      dbgs() << "Abstract Scope:\n";
+      AbstractScope->dump();
     });
 
-    // Create the 'abstract' scope.
-    LVScope *InlinedScope = getOrCreateAbstractScope(OriginScope, DL);
+    // Create the 'inlined' scope.
+    LVScope *InlinedScope = getOrCreateInlinedScope(AbstractScope, DL);
     assert(InlinedScope && "InlinedScope is null.");
     LLVM_DEBUG({
       dbgs() << "\nParent Scope:\n";
       InlinedScope->getParentScope()->dump();
-      dbgs() << "\nInlined (Abstract) Logical Scope:\n";
+      dbgs() << "\nInlined Scope:\n";
       InlinedScope->dump();
     });
   }
 
-  return OriginScope;
+  return AbstractScope;
 }
 
 void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
-                               Instruction &I) {
+                               Instruction &I,
+                               bool &GenerateLineBeforePrologue) {
   assert(Scope && "Invalid logical element");
   assert(SP && "Invalid metadata node.");
   LLVM_DEBUG({
@@ -1131,8 +1083,8 @@ void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
   if (const DebugLoc DbgLoc = I.getDebugLoc()) {
     const DILocation *DL = DbgLoc.get();
     Parent = getParentScope(DL);
-    if (DL->getInlinedAt())
-      Parent = getInlinedScope(Parent);
+    if (const DILocation *InlinedAt = DL->getInlinedAt())
+      Parent = getInlinedScope(Parent, InlinedAt);
 
     LLVM_DEBUG({
       dbgs() << "\n[constructLine] DILocation\n";
@@ -1298,8 +1250,7 @@ LVSymbol *LVIRReader::getOrCreateStaticMember(LVScope *Aggregate,
 }
 
 // DISubprogram
-LVScope *LVIRReader::getOrCreateSubprogram(const DISubprogram *SP,
-                                           bool Minimal) {
+LVScope *LVIRReader::getOrCreateSubprogram(const DISubprogram *SP) {
   assert(SP && "Invalid metadata node.");
   LLVM_DEBUG({
     dbgs() << "\n[getOrCreateSubprogram] DISubprogram\n";
@@ -1327,7 +1278,7 @@ LVScope *LVIRReader::getOrCreateSubprogram(const DISubprogram *SP,
     if (!Function->getParent())
       Parent->addElement(Function);
 
-    getOrCreateSubprogram(Function, SP, Minimal);
+    getOrCreateSubprogram(Function, SP, includeMinimalInlineScopes());
   }
 
   return Function;
@@ -1747,12 +1698,12 @@ LVIRReader::getOrCreateVariable(const DIGlobalVariableExpression *GVE) {
   return Symbol;
 }
 
-LVSymbol *LVIRReader::getOrCreateAbstractVariable(LVSymbol *OriginSymbol,
-                                                  const DILocation *DL) {
+LVSymbol *LVIRReader::getOrCreateInlinedVariable(LVSymbol *OriginSymbol,
+                                                 const DILocation *DL) {
   assert(OriginSymbol && "Invalid logical element");
   assert(DL && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateAbstractVariable] DIVariable\n";
+    dbgs() << "\n[getOrCreateInlinedVariable] DIVariable\n";
     DL->dump();
   });
 
@@ -1762,35 +1713,35 @@ LVSymbol *LVIRReader::getOrCreateAbstractVariable(LVSymbol *OriginSymbol,
   }
 
   dwarf::Tag Tag = OriginSymbol->getTag();
-  LVSymbol *AbstractSymbol = static_cast<LVSymbol *>(createElement(Tag));
-  if (AbstractSymbol) {
-    AbstractSymbol->setTag(Tag);
-    AbstractSymbol->setIsFinalized();
-    AbstractSymbol->setName(OriginSymbol->getName());
-    AbstractSymbol->setType(OriginSymbol->getType());
-
-    AbstractSymbol->setCallLineNumber(InlinedAt->getLine());
-    AbstractSymbol->setCallFilenameIndex(
+  LVSymbol *InlinedSymbol = static_cast<LVSymbol *>(createElement(Tag));
+  if (InlinedSymbol) {
+    InlinedSymbol->setTag(Tag);
+    InlinedSymbol->setIsFinalized();
+    InlinedSymbol->setName(OriginSymbol->getName());
+    InlinedSymbol->setType(OriginSymbol->getType());
+
+    InlinedSymbol->setCallLineNumber(InlinedAt->getLine());
+    InlinedSymbol->setCallFilenameIndex(
         getOrCreateSourceID(InlinedAt->getFile()));
 
     OriginSymbol->setInlineCode(dwarf::DW_INL_inlined);
-    AbstractSymbol->setReference(OriginSymbol);
-    AbstractSymbol->setHasReferenceAbstract();
+    InlinedSymbol->setReference(OriginSymbol);
+    InlinedSymbol->setHasReferenceAbstract();
 
     if (OriginSymbol->getIsParameter())
-      AbstractSymbol->setIsParameter();
+      InlinedSymbol->setIsParameter();
 
-    LVScope *OriginScope = OriginSymbol->getParentScope();
-    assert(OriginScope && "Invalid logical element");
-    LVScope *AbstractScope = getInlinedScope(OriginScope);
-    if (!AbstractScope)
-      AbstractScope = getOrCreateAbstractScope(OriginScope, DL);
+    LVScope *AbstractScope = OriginSymbol->getParentScope();
+    assert(AbstractScope && "Invalid logical element");
+    LVScope *InlinedScope = getInlinedScope(AbstractScope, InlinedAt);
+    if (!InlinedScope)
+      InlinedScope = getOrCreateInlinedScope(AbstractScope, DL);
 
-    assert(AbstractScope && "Parent scope is NULL.");
-    AbstractScope->addElement(AbstractSymbol);
+    assert(InlinedScope && "Parent scope is NULL.");
+    InlinedScope->addElement(InlinedSymbol);
   }
 
-  return AbstractSymbol;
+  return InlinedSymbol;
 }
 
 // DIGlobalVariable
@@ -1807,8 +1758,12 @@ LVSymbol *LVIRReader::getOrCreateVariable(const DIVariable *Var,
     }
   });
 
+  // Use the 'InlinedAt' information to identify a symbol that is being
+  // inlined. Its abstract representation is created just once.
+  const DILocation *InlinedAt = DL ? DL->getInlinedAt() : nullptr;
+
   LVSymbol *Symbol = getSymbolForSeenMD(Var);
-  if (Symbol && Symbol->getIsFinalized())
+  if (Symbol && Symbol->getIsFinalized() && !InlinedAt)
     return Symbol;
 
   if (!options().getPrintSymbols()) {
@@ -1823,7 +1778,7 @@ LVSymbol *LVIRReader::getOrCreateVariable(const DIVariable *Var,
 
   if (!Symbol)
     Symbol = static_cast<LVSymbol *>(constructElement(Var));
-  if (Symbol) {
+  if (Symbol && !Symbol->getIsFinalized()) {
     Symbol->setIsFinalized();
     LVScope *Parent = getParentScope(Var);
     Parent->addElement(Symbol);
@@ -1864,12 +1819,12 @@ LVSymbol *LVIRReader::getOrCreateVariable(const DIVariable *Var,
       if (MDTuple *TP = GV->getTemplateParams())
         addTemplateParams(Symbol, DINodeArray(TP));
     }
-
-    // Create the 'abstract' symbol.
-    if (DL)
-      getOrCreateAbstractVariable(Symbol, DL);
   }
 
+  // Create the 'inlined' symbol.
+  if (DL)
+    getOrCreateInlinedVariable(Symbol, DL);
+
   return Symbol;
 }
 
@@ -1911,7 +1866,7 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
   SmallVector<DebugVariableAggregate> SeenVars;
 
   // Handle dbg.values and dbg.declare.
-  auto HandleDbgVariable = [&](Instruction &I, auto *DbgVar) {
+  auto HandleDbgVariable = [&](auto *DbgVar) {
     LLVM_DEBUG({
       dbgs() << "\n[HandleDbgVariable]\n";
       DbgVar->dump();
@@ -1926,14 +1881,10 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
     // Skip undefined values.
     if (!DbgVar->isKillLocation())
       getOrCreateVariable(DbgVar->getVariable(), DbgVar->getDebugLoc().get());
-
-    if (const auto *DL =
-            cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg))) {
-      getOrCreateInlinedScope(Scope, DL);
-    }
   };
 
-  GenerateLineBeforePrologue = true;
+  // Generate logical debug line before prologue.
+  bool GenerateLineBeforePrologue = true;
   for (BasicBlock &BB : F) {
     printAllInstructions(&BB);
 
@@ -1941,10 +1892,14 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
       LLVM_DEBUG(dbgs() << "\nInstruction: '" << I << "'\n");
 
       for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
-        HandleDbgVariable(I, &DVR);
+        HandleDbgVariable(&DVR);
+
+      if (const auto *DL =
+              cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg)))
+        getOrCreateAbstractScope(Scope, DL);
 
       if (options().getPrintAnyLine())
-        constructLine(Scope, SP, I);
+        constructLine(Scope, SP, I, GenerateLineBeforePrologue);
 
       // Update code offset.
       updateLineOffset();
@@ -2251,7 +2206,9 @@ void LVIRReader::removeEmptyScopes() {
       // If the target scope has lines, move them to the scope parent.
       const LVLines *Lines = Scope->getLines();
       if (Lines) {
-        for (LVLine *Line : *Lines) {
+        LVLines Pack;
+        std::copy(Lines->begin(), Lines->end(), std::back_inserter(Pack));
+        for (LVLine *Line : Pack) {
           if (Scope->removeElement(Line)) {
             LLVM_DEBUG({ dbgs() << "Line: " << Line->getID() << "\n"; });
             Line->resetParent();
@@ -2263,13 +2220,14 @@ void LVIRReader::removeEmptyScopes() {
 
       if (Parent->removeElement(Scope)) {
         const LVScopes *Scopes = Scope->getScopes();
-        if (Scopes)
+        if (Scopes) {
           for (LVScope *Child : *Scopes) {
             LLVM_DEBUG({ dbgs() << "Child: " << Child->getID() << "\n"; });
             Child->resetParent();
             Parent->addElement(Child);
             Child->updateLevel(Parent, /*Moved=*/false);
           }
+        }
       }
     }
   };
@@ -2322,7 +2280,7 @@ void LVIRReader::checkScopes(LVScope *Scope) {
   };
 
   std::function<void(LVScope * Parent)> Traverse = [&](LVScope *Current) {
-    auto Check = [&](const auto &Set) {
+    auto Check = [&](const auto *Set) {
       if (Set)
         for (const auto &Entry : *Set)
           if (!Entry->getIsFinalized())
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test
index 064b0ef626417..51a807942c48e 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test
@@ -70,7 +70,9 @@
 ; ONE-NEXT: [003]     9           {Line}
 ; ONE-NEXT: [003]                 {Code} 'ret i32 %2, !dbg !36'
 ; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} '%0 = load i8, ptr %ParamBool.addr, align 1, !dbg !26'
 ; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} '%loadedv = trunc i8 %0 to i1, !dbg !26'
 ; ONE-NEXT: [003]     3           {Line}
 ; ONE-NEXT: [003]                 {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
 ; ONE-NEXT: [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test
index 48466d1bd5aa3..51bbb30c1d97e 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test
@@ -33,6 +33,7 @@
 ; ONE-NEXT: [003]           {Code} '%0 = load i8, ptr %ParamBool.addr, align 1, !dbg !26'
 ; ONE-NEXT: [003]           {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34'
 ; ONE-NEXT: [003]           {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36'
+; ONE-NEXT: [003]           {Code} '%loadedv = trunc i8 %0 to i1, !dbg !26'
 ; ONE-NEXT: [003]           {Code} '%storedv = zext i1 %ParamBool to i8'
 ; ONE-NEXT: [003]           {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
 ; ONE-NEXT: [003]           {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35'
@@ -48,9 +49,9 @@
 ; ONE-NEXT: Scopes           5          0
 ; ONE-NEXT: Symbols          4          0
 ; ONE-NEXT: Types            2          0
-; ONE-NEXT: Lines           22         11
+; ONE-NEXT: Lines           23         12
 ; ONE-NEXT: -----------------------------
-; ONE-NEXT: Total           33         11
+; ONE-NEXT: Total           34         12
 
 ; RUN: llvm-as %p/Inputs/test-clang.ll -o %t.test-clang.bc
 
@@ -120,3 +121,31 @@
 ; THREE-NEXT: Lines            0          0
 ; THREE-NEXT: -----------------------------
 ; THREE-NEXT: Total            9          1
+
+; Select logical elements using exact match.
+; The following prints all 'symbols' and 'types' that contain 'INTPTR' in
+; their names or types, using a tab layout and given the number of matches.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --select=INTPTR \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,instructions,summary \
+; RUN:                         %p/Inputs/test-clang.ll 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=FOUR %s
+
+; FOUR:      Logical View:
+; FOUR-NEXT: [000]           {File} 'test-clang.ll'
+; FOUR-EMPTY:
+; FOUR-NEXT: [001]           {CompileUnit} 'test.cpp'
+; FOUR-NEXT: [002]     1     {TypeAlias} 'INTPTR' -> '* const int'
+; FOUR-NEXT: [003]     2     {Parameter} 'ParamPtr' -> 'INTPTR'
+; FOUR-EMPTY:
+; FOUR-NEXT: -----------------------------
+; FOUR-NEXT: Element      Total    Printed
+; FOUR-NEXT: -----------------------------
+; FOUR-NEXT: Scopes           5          0
+; FOUR-NEXT: Symbols          4          1
+; FOUR-NEXT: Types            2          1
+; FOUR-NEXT: Lines           23          0
+; FOUR-NEXT: -----------------------------
+; FOUR-NEXT: Total           34          2
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
index 5997830520647..02acc02c91937 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
@@ -27,26 +27,26 @@
 ; ONE:      Logical View:
 ; ONE-NEXT: [0x0000000000][000]            {File} '{{.*}}test-clang{{.*}}.ll' -> Textual IR
 ; ONE-EMPTY:
-; ONE-NEXT: [0x0000000000][001]              {CompileUnit} 'test.cpp'
-; ONE-NEXT: [0x0000000000][002]                {Producer} 'clang version 20{{.*}}'
+; ONE-NEXT: [0x0000000004][001]              {CompileUnit} 'test.cpp'
+; ONE-NEXT: [0x0000000004][002]                {Producer} 'clang version 20{{.*}}'
 ; ONE-NEXT:                                    {Directory} '{{.*}}/general'
 ; ONE-NEXT:                                    {File} 'test.cpp'
 ; ONE-NEXT:                                    {Public} 'foo' [0x0000000000:0x0000000023]
-; ONE-NEXT: [0x0000000000][002]                {Range} Lines 2:2 [0x0000000000:0x0000000023]
-; ONE-NEXT: [0x0000000000][002]                {Range} Lines 3:3 [0x0000000024:0x000000002f]
-; ONE-NEXT: [0x0000000000][002]                {Range} Lines 5:6 [0x0000000030:0x000000003b]
-; ONE-NEXT: [0x0000000000][002]                {Range} Lines 8:9 [0x000000003c:0x000000004f]
+; ONE-NEXT: [0x0000000004][002]                {Range} Lines 2:2 [0x0000000000:0x0000000023]
+; ONE-NEXT: [0x0000000004][002]                {Range} Lines 3:3 [0x0000000024:0x000000002f]
+; ONE-NEXT: [0x0000000004][002]                {Range} Lines 5:6 [0x0000000030:0x000000003b]
+; ONE-NEXT: [0x0000000004][002]                {Range} Lines 8:9 [0x000000003c:0x000000004f]
 ; ONE-EMPTY:
-; ONE-NEXT: [0x0000000004][002]   {Source} '{{.*}}/general/test.cpp'
-; ONE-NEXT: [0x0000000004][002]      2         {Function} extern not_inlined 'foo' -> [0x0000000020]'int'
-; ONE-NEXT: [0x0000000004][003]                  {Range} Lines 2:2 [0x0000000000:0x0000000023]
-; ONE-NEXT: [0x0000000004][003]                  {Range} Lines 3:3 [0x0000000024:0x000000002f]
-; ONE-NEXT: [0x0000000004][003]                  {Range} Lines 8:9 [0x000000003c:0x000000004f]
-; ONE-NEXT: [0x0000000004][003]                  {Linkage}  0x0 '_Z3fooPKijb'
-; ONE-NEXT: [0x0000000008][003]                  {Block}
-; ONE-NEXT: [0x0000000008][004]                    {Range} Lines 5:6 [0x0000000030:0x000000003b]
-; ONE-NEXT: [0x000000000c][004]      5             {Variable} 'CONSTANT' -> [0x0000000038]'const INTEGER'
-; ONE-NEXT: [0x000000000c][005]                      {Coverage} 100.00%
+; ONE-NEXT: [0x0000000008][002]   {Source} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000008][002]      2         {Function} extern not_inlined 'foo' -> [0x0000000024]'int'
+; ONE-NEXT: [0x0000000008][003]                  {Range} Lines 2:2 [0x0000000000:0x0000000023]
+; ONE-NEXT: [0x0000000008][003]                  {Range} Lines 3:3 [0x0000000024:0x000000002f]
+; ONE-NEXT: [0x0000000008][003]                  {Range} Lines 8:9 [0x000000003c:0x000000004f]
+; ONE-NEXT: [0x0000000008][003]                  {Linkage}  0x0 '_Z3fooPKijb'
+; ONE-NEXT: [0x000000000c][003]                  {Block}
+; ONE-NEXT: [0x000000000c][004]                    {Range} Lines 5:6 [0x0000000030:0x000000003b]
+; ONE-NEXT: [0x0000000010][004]      5             {Variable} 'CONSTANT' -> [0x000000003c]'const INTEGER'
+; ONE-NEXT: [0x0000000010][005]                      {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][006]                        {Location}
 ; ONE-NEXT: [0x0000000000][007]                          {Entry} bregx 5 ptr %CONSTANT+0
 ; ONE-NEXT: [0x0000000030][004]      5             {Line} '{{.*}}/general/test.cpp'
@@ -55,19 +55,19 @@
 ; ONE-NEXT: [0x0000000034][004]                    {Code} 'store i32 7, ptr %retval, align 4, !dbg !33'
 ; ONE-NEXT: [0x0000000038][004]      6             {Line} '{{.*}}/general/test.cpp'
 ; ONE-NEXT: [0x0000000038][004]                    {Code} 'br label %return, !dbg !33'
-; ONE-NEXT: [0x0000000010][003]      2           {Parameter} 'ParamPtr' -> [0x0000000024]'INTPTR'
-; ONE-NEXT: [0x0000000010][004]                    {Coverage} 100.00%
-; ONE-NEXT: [0x0000000000][004]                    {Location}
-; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
-; ONE-NEXT: [0x0000000014][003]      2           {Parameter} 'ParamUnsigned' -> [0x0000000030]'unsigned int'
+; ONE-NEXT: [0x0000000014][003]      2           {Parameter} 'ParamPtr' -> [0x0000000028]'INTPTR'
 ; ONE-NEXT: [0x0000000014][004]                    {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][004]                    {Location}
 ; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
-; ONE-NEXT: [0x0000000018][003]      2           {Parameter} 'ParamBool' -> [0x0000000034]'bool'
+; ONE-NEXT: [0x0000000018][003]      2           {Parameter} 'ParamUnsigned' -> [0x0000000034]'unsigned int'
 ; ONE-NEXT: [0x0000000018][004]                    {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][004]                    {Location}
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [0x000000001c][003]      2           {Parameter} 'ParamBool' -> [0x0000000038]'bool'
+; ONE-NEXT: [0x000000001c][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000000][004]                    {Location}
 ; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 4 ptr %ParamBool.addr+0
-; ONE-NEXT: [0x000000001c][003]      4           {TypeAlias} 'INTEGER' -> [0x0000000020]'int'
+; ONE-NEXT: [0x0000000020][003]      4           {TypeAlias} 'INTEGER' -> [0x0000000024]'int'
 ; ONE-NEXT: [0x0000000000][003]      2           {Line} '{{.*}}/general/test.cpp'
 ; ONE-NEXT: [0x0000000000][003]                  {Code} '%retval = alloca i32, align 4'
 ; ONE-NEXT: [0x0000000004][003]                  {Code} '%ParamPtr.addr = alloca ptr, align 8'
@@ -89,13 +89,15 @@
 ; ONE-NEXT: [0x000000004c][003]      9           {Line} '{{.*}}/general/test.cpp'
 ; ONE-NEXT: [0x000000004c][003]                  {Code} 'ret i32 %2, !dbg !36'
 ; ONE-NEXT: [0x0000000024][003]      3           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000024][003]                  {Code} '%0 = load i8, ptr %ParamBool.addr, align 1, !dbg !26'
 ; ONE-NEXT: [0x0000000028][003]      3           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000028][003]                  {Code} '%loadedv = trunc i8 %0 to i1, !dbg !26'
 ; ONE-NEXT: [0x000000002c][003]      3           {Line} '{{.*}}/general/test.cpp'
 ; ONE-NEXT: [0x000000002c][003]                  {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
-; ONE-NEXT: [0x0000000020][002]                {BaseType} 'int'
-; ONE-NEXT: [0x0000000024][002]      1         {TypeAlias} 'INTPTR' -> [0x0000000028]'* const int'
-; ONE-NEXT: [0x0000000030][002]                {BaseType} 'unsigned int'
-; ONE-NEXT: [0x0000000034][002]                {BaseType} 'bool'
+; ONE-NEXT: [0x0000000024][002]                {BaseType} 'int'
+; ONE-NEXT: [0x0000000028][002]      1         {TypeAlias} 'INTPTR' -> [0x000000002c]'* const int'
+; ONE-NEXT: [0x0000000034][002]                {BaseType} 'unsigned int'
+; ONE-NEXT: [0x0000000038][002]                {BaseType} 'bool'
 ; ONE-EMPTY:
 ; ONE-NEXT: -----------------------------
 ; ONE-NEXT: Element      Total    Printed
@@ -103,14 +105,14 @@
 ; ONE-NEXT: Scopes           5          3
 ; ONE-NEXT: Symbols          4          4
 ; ONE-NEXT: Types            5          5
-; ONE-NEXT: Lines           36         30
+; ONE-NEXT: Lines           38         32
 ; ONE-NEXT: -----------------------------
-; ONE-NEXT: Total           50         42
+; ONE-NEXT: Total           52         44
 ; ONE-EMPTY:
 ; ONE-NEXT: Scope Sizes:
-; ONE-NEXT:         60 (100.00%) : [0x0000000000][001]              {CompileUnit} 'test.cpp'
-; ONE-NEXT:         28 ( 46.67%) : [0x0000000004][002]      2         {Function} extern not_inlined 'foo' -> [0x0000000020]'int'
-; ONE-NEXT:          8 ( 13.33%) : [0x0000000008][003]                  {Block}
+; ONE-NEXT:         60 (100.00%) : [0x0000000004][001]              {CompileUnit} 'test.cpp'
+; ONE-NEXT:         28 ( 46.67%) : [0x0000000008][002]      2         {Function} extern not_inlined 'foo' -> [0x0000000024]'int'
+; ONE-NEXT:          8 ( 13.33%) : [0x000000000c][003]                  {Block}
 ; ONE-EMPTY:
 ; ONE-NEXT: Totals by lexical level:
 ; ONE-NEXT: [001]:         60 (100.00%)
diff --git a/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
index 83828c2171d68..907a97c8ccc12 100644
--- a/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
@@ -99,7 +99,7 @@ void checkElementProperties(LVReader *Reader) {
   EXPECT_EQ(RangeEntry.upper(), 0x23u);
   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
   EXPECT_EQ(RangeEntry.scope()->getName(), "test.cpp");
-  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x00u);
+  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x04u);
 
   ++IterRanges;
   RangeEntry = *IterRanges;
@@ -107,7 +107,7 @@ void checkElementProperties(LVReader *Reader) {
   EXPECT_EQ(RangeEntry.upper(), 0x4fu);
   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
   EXPECT_EQ(RangeEntry.scope()->getName(), "test.cpp");
-  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x00u);
+  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x04u);
 
   const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
   ASSERT_EQ(PublicNames.size(), 1u);
@@ -122,7 +122,7 @@ void checkElementProperties(LVReader *Reader) {
   // Lines (debug and assembler) for 'foo'.
   const LVLines *Lines = Function->getLines();
   ASSERT_NE(Lines, nullptr);
-  ASSERT_EQ(Lines->size(), 0x18u);
+  ASSERT_EQ(Lines->size(), 0x1au);
 }
 
 // Check the logical elements selection.
@@ -135,24 +135,24 @@ void checkElementSelection(LVReader *Reader) {
   std::map<LVOffset, LVElement *> MapElements;
   for (LVElement *Element : MatchedElements)
     MapElements[Element->getOffset()] = Element;
-  ASSERT_EQ(MapElements.size(), 0x0eu);
+  ASSERT_EQ(MapElements.size(), 0x0du);
 
-  LVElement *Element = MapElements[0x0000000004]; // 'foo'
+  LVElement *Element = MapElements[0x0000000008]; // 'foo'
   ASSERT_NE(Element, nullptr);
   EXPECT_NE(Element->getName().find("foo"), StringRef::npos);
   EXPECT_EQ(Element->getIsScope(), 1);
 
-  Element = MapElements[0x000000000c]; // 'CONSTANT'
+  Element = MapElements[0x0000000010]; // 'CONSTANT'
   ASSERT_NE(Element, nullptr);
   EXPECT_NE(Element->getName().find("CONSTANT"), StringRef::npos);
   EXPECT_EQ(Element->getIsSymbol(), 1);
 
-  Element = MapElements[0x0000000024]; // 'INTPTR'
+  Element = MapElements[0x0000000028]; // 'INTPTR'
   ASSERT_NE(Element, nullptr);
   EXPECT_NE(Element->getName().find("INTPTR"), StringRef::npos);
   EXPECT_EQ(Element->getIsType(), 1);
 
-  Element = MapElements[0x000000001c]; // 'INTEGER'
+  Element = MapElements[0x0000000020]; // 'INTEGER'
   ASSERT_NE(Element, nullptr);
   EXPECT_NE(Element->getName().find("INTEGER"), StringRef::npos);
   EXPECT_EQ(Element->getIsType(), 1);
@@ -170,11 +170,11 @@ void checkElementSelection(LVReader *Reader) {
   std::set<LVOffset>::iterator Iter;
   ASSERT_EQ(SetScopes.size(), 3u);
 
-  Iter = SetScopes.find(0x0000000000); // CompileUnit <- 'foo'
+  Iter = SetScopes.find(0x0000000004); // CompileUnit <- 'foo'
   EXPECT_NE(Iter, SetScopes.end());
-  Iter = SetScopes.find(0x0000000004); // Function <- 'store i32 %1, ptr ...'
+  Iter = SetScopes.find(0x0000000008); // Function <- 'store i32 %1, ptr ...'
   EXPECT_NE(Iter, SetScopes.end());
-  Iter = SetScopes.find(0x0000000008); // LexicalScope <- 'INTEGER'
+  Iter = SetScopes.find(0x000000000c); // LexicalScope <- 'INTEGER'
   EXPECT_NE(Iter, SetScopes.end());
 }
 
@@ -186,7 +186,7 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
 
   // Get comparison table.
   LVPassTable PassTable = Compare.getPassTable();
-  ASSERT_EQ(PassTable.size(), 10u);
+  ASSERT_EQ(PassTable.size(), 9u);
 
   LVReader *Reader;
   LVElement *Element;
@@ -223,7 +223,7 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
   EXPECT_EQ(Pass, LVComparePass::Missing);
 
   // Target: Added Variable 'CONSTANT'
-  std::tie(Reader, Element, Pass) = PassTable[7];
+  std::tie(Reader, Element, Pass) = PassTable[6];
   ASSERT_NE(Reader, nullptr);
   ASSERT_NE(Element, nullptr);
   EXPECT_EQ(Reader, Target);
@@ -233,7 +233,7 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
   EXPECT_EQ(Pass, LVComparePass::Added);
 
   // Target: Added TypeDefinition 'INTEGER'
-  std::tie(Reader, Element, Pass) = PassTable[8];
+  std::tie(Reader, Element, Pass) = PassTable[7];
   ASSERT_NE(Reader, nullptr);
   ASSERT_NE(Element, nullptr);
   EXPECT_EQ(Reader, Target);
@@ -241,6 +241,16 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
   EXPECT_EQ(Element->getLineNumber(), 4u);
   EXPECT_EQ(Element->getName(), "INTEGER");
   EXPECT_EQ(Pass, LVComparePass::Added);
+
+  // Target: Added DebugLine
+  std::tie(Reader, Element, Pass) = PassTable[8];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Target);
+  EXPECT_EQ(Element->getLevel(), 4u);
+  EXPECT_EQ(Element->getLineNumber(), 8u);
+  EXPECT_EQ(Element->getName(), "");
+  EXPECT_EQ(Pass, LVComparePass::Added);
 }
 
 // Logical elements properties.

>From c236e1a2a0e599e08ca5bf7a5067acaa8880be0f Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Thu, 11 Sep 2025 21:20:41 +0100
Subject: [PATCH 03/13] [llvm-debuginfo-analyzer] Add support for LLVM IR
 format.

Fixed compilation issues after latest DebugSSAUpdater rebase.
---
 .../DebugInfo/LogicalView/Readers/LVIRReader.h   |  2 ++
 .../DebugInfo/LogicalView/Readers/LVIRReader.cpp | 16 +++++++++-------
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
index 3a7d5d91986d5..2a7e612f6f7b3 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
@@ -75,6 +75,8 @@ class LVIRReader final : public LVReader {
   // An anonymous type for index type.
   LVType *NodeIndexType = nullptr;
 
+  SSAValueNameMap ValueNameMap;
+  DenseMap<void*, uint64_t> InstrLineAddrMap;
   std::unique_ptr<DbgValueRangeTable> DbgValueRanges;
 
   // Record the last assigned file index for each compile unit.
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index f74edacda97f4..43c41f1661234 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -319,7 +319,7 @@ std::string LVIRReader::getRegisterName(LVSmall Opcode,
     //   dbgs() << "Printing Value: " << Operands[0] << " - "
     //          << DbgValueRanges->getVariableName(Operands[0]) << "\n";
     // });
-    return DbgValueRanges->getVariableName(Operands[0]);
+    return ValueNameMap.getName(Operands[0]);
   }
 
   llvm_unreachable("We shouldn't actually have any other reg types here!");
@@ -1074,8 +1074,6 @@ void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
       Line->setAddress(CurrentOffset);
       Line->setName(Text);
       Parent->addElement(Line);
-
-      DbgValueRanges->addLine(I.getIterator(), CurrentOffset);
     }
   };
 
@@ -1901,10 +1899,12 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
       if (options().getPrintAnyLine())
         constructLine(Scope, SP, I, GenerateLineBeforePrologue);
 
+      InstrLineAddrMap[I.getIterator().getNodePtr()] = CurrentOffset;
+
       // Update code offset.
       updateLineOffset();
     }
-    DbgValueRanges->addLine(BB.end(), CurrentOffset);
+    InstrLineAddrMap[BB.end().getNodePtr()] = CurrentOffset;
   }
   GenerateLineBeforePrologue = false;
 
@@ -1934,7 +1934,7 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
     });
 
     auto AddLocationOp = [&](Value *V, bool IsMem) {
-      uint64_t RegValue = DbgValueRanges->addVariableName(V, Size);
+      uint64_t RegValue = ValueNameMap.addValue(V);
       if (IsMem)
         Symbol->addLocationOperands(dwarf::DW_OP_bregx, {RegValue, 0});
       else
@@ -1970,8 +1970,10 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
       AddLocation(DV);
     } else {
       for (DbgRangeEntry Entry : DbgValueRanges->getVariableRanges(DVA)) {
-        LVOffset Start = DbgValueRanges->getLine(Entry.Start);
-        LVOffset End = DbgValueRanges->getLine(Entry.End);
+        // These line addresses should have already been inserted into the
+        // InstrLineAddrMap, so we assume they are present here.
+        LVOffset Start = InstrLineAddrMap.at(Entry.Start.getNodePtr());
+        LVOffset End = InstrLineAddrMap.at(Entry.End.getNodePtr());
         Symbol->addLocation(llvm::dwarf::DW_AT_location, Start, End,
                             /*SectionOffset=*/0, /*OffsetOnEntry=*/0);
         DbgValueDef DV = Entry.Value;

>From 34b7b3820470ae7bc391b399327be84c999e29ee Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Thu, 11 Sep 2025 21:57:21 +0100
Subject: [PATCH 04/13] [llvm-debuginfo-analyzer] IR Reader.

Updated test cases that failed due to an upstream fix related
to the high-pc value being now exclusive.

  https://github.com/llvm/llvm-project/pull/153318
---
 .../IR/02-ir-logical-lines.test               |  2 +-
 ...03-ir-incorrect-lexical-scope-typedef.test |  4 +--
 .../DebugInfo/LogicalView/IRReaderTest.cpp    | 32 +++++++++----------
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test
index f8470e5bf27ae..76272e3f677ea 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test
@@ -57,4 +57,4 @@
 ; ONE-NEXT: [003]                 {Code} 'addq	$0x10, %rsp'
 ; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
 ; ONE-NEXT: [003]                 {Code} 'retq'
-; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [002]     6         {Line}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
index 008d6b5e37b91..7d200e4f681ac 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
@@ -92,7 +92,6 @@
 ; ONE-NEXT: [005]     9               {Line}
 ; ONE-NEXT: [005]     9               {Line}
 ; ONE-NEXT: [005]    10               {Line}
-; ONE-NEXT: [005]    13               {Line}
 ; ONE-NEXT: [004]     7             {TypeAlias} 'FLOAT' -> 'float'
 ; ONE-NEXT: [003]     3           {Parameter} 'Param' -> 'char'
 ; ONE-NEXT: [003]     4           {TypeAlias} 'INT' -> 'int'
@@ -100,8 +99,9 @@
 ; ONE-NEXT: [003]     3           {Line}
 ; ONE-NEXT: [003]     5           {Line}
 ; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
 ; ONE-NEXT: [003]    14           {Line}
-; ONE-NEXT: [003]    14           {Line}
+; ONE-NEXT: [002]    14         {Line}
 
 ; Using the selection facilities, we can produce a simple tabular
 ; output showing just the logical types that are 'Typedef'.
diff --git a/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
index 907a97c8ccc12..c1b9b806a7cd1 100644
--- a/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
@@ -186,12 +186,22 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
 
   // Get comparison table.
   LVPassTable PassTable = Compare.getPassTable();
-  ASSERT_EQ(PassTable.size(), 9u);
+  ASSERT_EQ(PassTable.size(), 6u);
 
   LVReader *Reader;
   LVElement *Element;
   LVComparePass Pass;
 
+  // Reference: Missing DebugLine
+  std::tie(Reader, Element, Pass) = PassTable[0];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Reference);
+  EXPECT_EQ(Element->getLevel(), 3u);
+  EXPECT_EQ(Element->getLineNumber(), 0u);
+  EXPECT_EQ(Element->getName(), "");
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
   // Reference: Missing Variable 'CONSTANT'
   std::tie(Reader, Element, Pass) = PassTable[1];
   ASSERT_NE(Reader, nullptr);
@@ -212,18 +222,8 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
   EXPECT_EQ(Element->getName(), "INTEGER");
   EXPECT_EQ(Pass, LVComparePass::Missing);
 
-  // Reference: Missing DebugLine
-  std::tie(Reader, Element, Pass) = PassTable[4];
-  ASSERT_NE(Reader, nullptr);
-  ASSERT_NE(Element, nullptr);
-  EXPECT_EQ(Reader, Reference);
-  EXPECT_EQ(Element->getLevel(), 3u);
-  EXPECT_EQ(Element->getLineNumber(), 8u);
-  EXPECT_EQ(Element->getName(), "");
-  EXPECT_EQ(Pass, LVComparePass::Missing);
-
   // Target: Added Variable 'CONSTANT'
-  std::tie(Reader, Element, Pass) = PassTable[6];
+  std::tie(Reader, Element, Pass) = PassTable[3];
   ASSERT_NE(Reader, nullptr);
   ASSERT_NE(Element, nullptr);
   EXPECT_EQ(Reader, Target);
@@ -233,7 +233,7 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
   EXPECT_EQ(Pass, LVComparePass::Added);
 
   // Target: Added TypeDefinition 'INTEGER'
-  std::tie(Reader, Element, Pass) = PassTable[7];
+  std::tie(Reader, Element, Pass) = PassTable[4];
   ASSERT_NE(Reader, nullptr);
   ASSERT_NE(Element, nullptr);
   EXPECT_EQ(Reader, Target);
@@ -243,12 +243,12 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
   EXPECT_EQ(Pass, LVComparePass::Added);
 
   // Target: Added DebugLine
-  std::tie(Reader, Element, Pass) = PassTable[8];
+  std::tie(Reader, Element, Pass) = PassTable[5];
   ASSERT_NE(Reader, nullptr);
   ASSERT_NE(Element, nullptr);
   EXPECT_EQ(Reader, Target);
-  EXPECT_EQ(Element->getLevel(), 4u);
-  EXPECT_EQ(Element->getLineNumber(), 8u);
+  EXPECT_EQ(Element->getLevel(), 2u);
+  EXPECT_EQ(Element->getLineNumber(), 9u);
   EXPECT_EQ(Element->getName(), "");
   EXPECT_EQ(Pass, LVComparePass::Added);
 }

>From 0823b2bf1dda792befb8a88442ba1eb88d24aff6 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Thu, 11 Sep 2025 22:00:11 +0100
Subject: [PATCH 05/13] [llvm-debuginfo-analyzer] IR Reader.

Updated test cases that failed due to the DebugSSAUpdater rebase.
---
 .../IR/06-ir-full-logical-view.test                       | 8 ++++----
 .../llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test   | 8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
index 02acc02c91937..23e3312e1faa6 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
@@ -48,7 +48,7 @@
 ; ONE-NEXT: [0x0000000010][004]      5             {Variable} 'CONSTANT' -> [0x000000003c]'const INTEGER'
 ; ONE-NEXT: [0x0000000010][005]                      {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][006]                        {Location}
-; ONE-NEXT: [0x0000000000][007]                          {Entry} bregx 5 ptr %CONSTANT+0
+; ONE-NEXT: [0x0000000000][007]                          {Entry} bregx 3ptr %CONSTANT+0
 ; ONE-NEXT: [0x0000000030][004]      5             {Line} '{{.*}}/general/test.cpp'
 ; ONE-NEXT: [0x0000000030][004]                    {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
 ; ONE-NEXT: [0x0000000034][004]      6             {Line} '{{.*}}/general/test.cpp'
@@ -58,15 +58,15 @@
 ; ONE-NEXT: [0x0000000014][003]      2           {Parameter} 'ParamPtr' -> [0x0000000028]'INTPTR'
 ; ONE-NEXT: [0x0000000014][004]                    {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][004]                    {Location}
-; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0ptr %ParamPtr.addr+0
 ; ONE-NEXT: [0x0000000018][003]      2           {Parameter} 'ParamUnsigned' -> [0x0000000034]'unsigned int'
 ; ONE-NEXT: [0x0000000018][004]                    {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][004]                    {Location}
-; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 1ptr %ParamUnsigned.addr+0
 ; ONE-NEXT: [0x000000001c][003]      2           {Parameter} 'ParamBool' -> [0x0000000038]'bool'
 ; ONE-NEXT: [0x000000001c][004]                    {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][004]                    {Location}
-; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 4 ptr %ParamBool.addr+0
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 2ptr %ParamBool.addr+0
 ; ONE-NEXT: [0x0000000020][003]      4           {TypeAlias} 'INTEGER' -> [0x0000000024]'int'
 ; ONE-NEXT: [0x0000000000][003]      2           {Line} '{{.*}}/general/test.cpp'
 ; ONE-NEXT: [0x0000000000][003]                  {Code} '%retval = alloca i32, align 4'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
index 710aaa88a3bae..c4fc263e9b9d6 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
@@ -35,14 +35,14 @@
 ; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
 ; ONE-NEXT: [003]     2           {Parameter} 'ParamBool' -> 'bool'
 ; ONE-NEXT: [004]                   {Location}
-; ONE-NEXT: [005]                     {Entry} bregx 4 ptr %ParamBool.addr+0
+; ONE-NEXT: [005]                     {Entry} bregx 2ptr %ParamBool.addr+0
 ; ONE-NEXT: [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
 ; ONE-NEXT: [004]                   {Location}
-; ONE-NEXT: [005]                     {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [005]                     {Entry} bregx 0ptr %ParamPtr.addr+0
 ; ONE-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
 ; ONE-NEXT: [004]                   {Location}
-; ONE-NEXT: [005]                     {Entry} bregx 0 ptr %ParamPtr.addr ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [005]                     {Entry} bregx 1ptr %ParamUnsigned.addr+0
 ; ONE-NEXT: [003]                 {Block}
 ; ONE-NEXT: [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
 ; ONE-NEXT: [006]                       {Location}
-; ONE-NEXT: [007]                         {Entry} bregx 5 ptr %CONSTANT+0
+; ONE-NEXT: [007]                         {Entry} bregx 3ptr %CONSTANT+0

>From 554231c1f5a3f26b2e927d1053ddd760dd020f9c Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Fri, 12 Sep 2025 17:55:13 +0100
Subject: [PATCH 06/13] [llvm-debuginfo-analyzer] IR Reader.

Add a missing space between the offset and 'ptr' for a
better layout.

  [004] 9 {Variable} 'CONSTANT' -> 'const INTEGER'
  [006]     {Location}
  [007]       {Entry} bregx 3 ptr %CONSTANT+0
---
 llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp     | 5 +++--
 .../IR/06-ir-full-logical-view.test                       | 8 ++++----
 .../llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test   | 8 ++++----
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index 43c41f1661234..f96153646ad5c 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -317,9 +317,10 @@ std::string LVIRReader::getRegisterName(LVSmall Opcode,
     // Leaving it here, just for any specific needs.
     // LLVM_DEBUG({
     //   dbgs() << "Printing Value: " << Operands[0] << " - "
-    //          << DbgValueRanges->getVariableName(Operands[0]) << "\n";
+    //          << ValueNameMap.getName(Operands[0]) << "\n";
     // });
-    return ValueNameMap.getName(Operands[0]);
+    // Add an extra space for a better layout when printing locations.
+    return " " + ValueNameMap.getName(Operands[0]);
   }
 
   llvm_unreachable("We shouldn't actually have any other reg types here!");
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
index 23e3312e1faa6..c3abfefe5a7e3 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
@@ -48,7 +48,7 @@
 ; ONE-NEXT: [0x0000000010][004]      5             {Variable} 'CONSTANT' -> [0x000000003c]'const INTEGER'
 ; ONE-NEXT: [0x0000000010][005]                      {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][006]                        {Location}
-; ONE-NEXT: [0x0000000000][007]                          {Entry} bregx 3ptr %CONSTANT+0
+; ONE-NEXT: [0x0000000000][007]                          {Entry} bregx 3 ptr %CONSTANT+0
 ; ONE-NEXT: [0x0000000030][004]      5             {Line} '{{.*}}/general/test.cpp'
 ; ONE-NEXT: [0x0000000030][004]                    {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
 ; ONE-NEXT: [0x0000000034][004]      6             {Line} '{{.*}}/general/test.cpp'
@@ -58,15 +58,15 @@
 ; ONE-NEXT: [0x0000000014][003]      2           {Parameter} 'ParamPtr' -> [0x0000000028]'INTPTR'
 ; ONE-NEXT: [0x0000000014][004]                    {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][004]                    {Location}
-; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0ptr %ParamPtr.addr+0
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 0 ptr %ParamPtr.addr+0
 ; ONE-NEXT: [0x0000000018][003]      2           {Parameter} 'ParamUnsigned' -> [0x0000000034]'unsigned int'
 ; ONE-NEXT: [0x0000000018][004]                    {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][004]                    {Location}
-; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 1ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 1 ptr %ParamUnsigned.addr+0
 ; ONE-NEXT: [0x000000001c][003]      2           {Parameter} 'ParamBool' -> [0x0000000038]'bool'
 ; ONE-NEXT: [0x000000001c][004]                    {Coverage} 100.00%
 ; ONE-NEXT: [0x0000000000][004]                    {Location}
-; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 2ptr %ParamBool.addr+0
+; ONE-NEXT: [0x0000000000][005]                      {Entry} bregx 2 ptr %ParamBool.addr+0
 ; ONE-NEXT: [0x0000000020][003]      4           {TypeAlias} 'INTEGER' -> [0x0000000024]'int'
 ; ONE-NEXT: [0x0000000000][003]      2           {Line} '{{.*}}/general/test.cpp'
 ; ONE-NEXT: [0x0000000000][003]                  {Code} '%retval = alloca i32, align 4'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
index c4fc263e9b9d6..a3b08d5a6d01a 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test
@@ -35,14 +35,14 @@
 ; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
 ; ONE-NEXT: [003]     2           {Parameter} 'ParamBool' -> 'bool'
 ; ONE-NEXT: [004]                   {Location}
-; ONE-NEXT: [005]                     {Entry} bregx 2ptr %ParamBool.addr+0
+; ONE-NEXT: [005]                     {Entry} bregx 2 ptr %ParamBool.addr+0
 ; ONE-NEXT: [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
 ; ONE-NEXT: [004]                   {Location}
-; ONE-NEXT: [005]                     {Entry} bregx 0ptr %ParamPtr.addr+0
+; ONE-NEXT: [005]                     {Entry} bregx 0 ptr %ParamPtr.addr+0
 ; ONE-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
 ; ONE-NEXT: [004]                   {Location}
-; ONE-NEXT: [005]                     {Entry} bregx 1ptr %ParamUnsigned.addr+0
+; ONE-NEXT: [005]                     {Entry} bregx 1 ptr %ParamUnsigned.addr+0
 ; ONE-NEXT: [003]                 {Block}
 ; ONE-NEXT: [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
 ; ONE-NEXT: [006]                       {Location}
-; ONE-NEXT: [007]                         {Entry} bregx 3ptr %CONSTANT+0
+; ONE-NEXT: [007]                         {Entry} bregx 3 ptr %CONSTANT+0

>From 0ecca139b284b0ee8278d167f62a3b05e60cf1e4 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Tue, 16 Sep 2025 22:25:12 +0100
Subject: [PATCH 07/13] [llvm-debuginfo-analyzer] IR Reader.

Fix issue reported by Clang format.
---
 llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
index 2a7e612f6f7b3..8a6389cab0c98 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
@@ -76,7 +76,7 @@ class LVIRReader final : public LVReader {
   LVType *NodeIndexType = nullptr;
 
   SSAValueNameMap ValueNameMap;
-  DenseMap<void*, uint64_t> InstrLineAddrMap;
+  DenseMap<void *, uint64_t> InstrLineAddrMap;
   std::unique_ptr<DbgValueRangeTable> DbgValueRanges;
 
   // Record the last assigned file index for each compile unit.

>From 96f14a13f07e5fc4294b5399e8e9780e1c44e855 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Wed, 17 Sep 2025 10:47:42 +0100
Subject: [PATCH 08/13] [llvm-debuginfo-analyzer] IR Reader.

Fix issue with C++98 error:

  extra ';' outside of a function is incompatible with C++98
  [-Werror,-Wc++98-compat-extra-semi]
---
 llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index f96153646ad5c..4dd6a1f73ff04 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -439,7 +439,7 @@ void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) {
     Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
   else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPublic)
     Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
-};
+}
 
 // getFile()
 //   DIScope

>From acf05325c0a86d9163b6049ec3a4880b40da5d32 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Sat, 27 Sep 2025 21:01:44 +0100
Subject: [PATCH 09/13] [llvm-debuginfo-analyzer] IR Reader.

Changes required after rebase with upstream to include:

  Remove LVScope::Children container.
  https://github.com/llvm/llvm-project/pull/144750
---
 llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp     |  3 ++-
 .../lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp | 12 ++++++------
 .../IR/01-ir-compare-logical-elements.test           |  2 +-
 3 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
index de2c2bb502800..1c0d8fa5af64e 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
@@ -32,7 +32,8 @@ void printCollectedElements(LVScope *Root) {
           Entry->print(dbgs());
     };
 
-    Print(Parent->getChildren());
+    for (LVElement *Element : Parent->getChildren())
+      Element->print(dbgs());
     Print(Parent->getLines());
     Print(Parent->getRanges());
     if (const LVScopes *Scopes = Parent->getScopes())
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index 4dd6a1f73ff04..6c90a4832b4ec 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -2283,14 +2283,14 @@ void LVIRReader::checkScopes(LVScope *Scope) {
   };
 
   std::function<void(LVScope * Parent)> Traverse = [&](LVScope *Current) {
-    auto Check = [&](const auto *Set) {
-      if (Set)
-        for (const auto &Entry : *Set)
-          if (!Entry->getIsFinalized())
-            PrintElement(Entry);
+    auto Check = [&](auto *Entry) {
+      if (Entry)
+        if (!Entry->getIsFinalized())
+          PrintElement(Entry);
     };
 
-    Check(Current->getChildren());
+    for (LVElement *Element : Current->getChildren())
+      Check(Element);
 
     if (Current->getScopes())
       for (LVScope *Scope : *Current->getScopes())
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test
index 0c2741b1a0adb..4d28ab844b767 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test
@@ -35,8 +35,8 @@
 ; ONE-NEXT:  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
 ; ONE-NEXT:  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
 ; ONE-NEXT:  [003]                 {Block}
-; ONE-NEXT:  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
 ; ONE-NEXT: +[004]     4             {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT:  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
 ; ONE-NEXT:  [003]     2           {Parameter} 'ParamBool' -> 'bool'
 ; ONE-NEXT:  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
 ; ONE-NEXT:  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'

>From 04a7a955a33d744f6baafbc33a3b0bab090c2454 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Wed, 22 Oct 2025 10:23:29 +0100
Subject: [PATCH 10/13] [llvm-debuginfo-analyzer] IR Reader.

Changes required after rebase with upstream to include:

  [llvm][DebugInfo][NFC] Abstract DICompileUnit::SourceLanguage
  to allow alternate DWARF SourceLanguage encoding (#162255)

  https://github.com/llvm/llvm-project/pull/162255
---
 llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index 6c90a4832b4ec..8707d91df8ec6 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -2024,7 +2024,7 @@ Error LVIRReader::createScopes() {
     });
 
     // Record if the current source language is Fortran.
-    mapFortranLanguage(CU->getSourceLanguage());
+    mapFortranLanguage(CU->getSourceLanguage().getUnversionedName());
 
     CompileUnit = static_cast<LVScopeCompileUnit *>(constructElement(CU));
     CUNode = const_cast<DICompileUnit *>(CU);

>From e696ef5c20ecd4273b0c7ea00aa8e9f3bad9a5e8 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Mon, 3 Nov 2025 08:07:57 +0000
Subject: [PATCH 11/13] [llvm-debuginfo-analyzer] IR Reader.

Rust generates multiple #dbg_declare's.

  %self.dbg.spill = alloca [8 x i8], align 8
  store ptr %self, ptr %self.dbg.spill, align 8
    #dbg_declare(ptr %self.dbg.spill, !892, !DIExpression(), !894)
    #dbg_declare(ptr %self.dbg.spill, !895, !DIExpression(), !905)

Change the assertion for a warning and return, otherwise
the IR Reader will not be able to process Rust IR's.
---
 llvm/lib/Transforms/Utils/DebugSSAUpdater.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/llvm/lib/Transforms/Utils/DebugSSAUpdater.cpp b/llvm/lib/Transforms/Utils/DebugSSAUpdater.cpp
index cceabd891d72c..79dc1aa9bfd38 100644
--- a/llvm/lib/Transforms/Utils/DebugSSAUpdater.cpp
+++ b/llvm/lib/Transforms/Utils/DebugSSAUpdater.cpp
@@ -281,6 +281,15 @@ void DbgValueRangeTable::addVariable(Function *F, DebugVariableAggregate DVA) {
   // which case we need a complete SSA liveness analysis to determine live-in
   // values per-block, or a variable has a single #dbg_declare.
   if (DeclareRecordFound) {
+    // Rust generates multiple #dbg_declare's.
+    // %self.dbg.spill = alloca [8 x i8], align 8
+    // store ptr %self, ptr %self.dbg.spill, align 8
+    //   #dbg_declare(ptr %self.dbg.spill, !892, !DIExpression(), !894)
+    //   #dbg_declare(ptr %self.dbg.spill, !895, !DIExpression(), !905)
+    if (NumRecordsFound != 1) {
+      LLVM_DEBUG(dbgs() << "Multiple records for a #dbg_declare!\n");
+      return;
+    }
     // FIXME: This should be changed for fragments!
     LLVM_DEBUG(dbgs() << "Single location found for variable!\n");
     assert(NumRecordsFound == 1 &&

>From b3c383be68b4568b7653580400294ffb08084b09 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Mon, 3 Nov 2025 08:14:01 +0000
Subject: [PATCH 12/13] [llvm-debuginfo-analyzer] IR Reader.

Add the ability to print basic information about a logical
element. Mainly is used to print information while dealing
with IR.

It uses the current command line arguments to control what
to print. The information is printed in a single line. In
the minimum case it includes name and type.
---
 llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h  | 7 +++++++
 llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h | 7 +++++++
 llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp         | 5 +++++
 llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp        | 5 +++++
 4 files changed, 24 insertions(+)

diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index 34bace886a15f..793a66e40b02b 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -374,6 +374,13 @@ class LLVM_ABI LVElement : public LVObject {
   // Report the current element as missing or added during comparison.
   virtual void report(LVComparePass Pass) {}
 
+  // Print the basic and extra information. Used mainly to debug IR.
+  void printCommon(raw_ostream &OS, bool Full = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dumpCommon() const { printCommon(dbgs(), /*Full=*/true); }
+#endif
+
   static LVElementDispatch &getDispatch() { return Dispatch; }
 };
 
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
index 090af54cd1b85..6bf7f9d2105f8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
@@ -159,6 +159,13 @@ class LLVM_ABI LVLocation : public LVObject {
 
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
+
+  // Print the basic and extra information. Used mainly to debug IR.
+  void printCommon(raw_ostream &OS, bool Full = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dumpCommon() const { printCommon(dbgs(), /*Full=*/true); }
+#endif
 };
 
 class LLVM_ABI LVLocationSymbol final : public LVLocation {
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
index b61907c7bc3d3..a1882a1ba31ed 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -567,3 +567,8 @@ void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
                     /*UseQuotes=*/false, /*PrintRef=*/false);
   }
 }
+
+void LVElement::printCommon(raw_ostream &OS, bool Full) const {
+  LVElement::print(OS, Full);
+  printExtra(OS, Full);
+}
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
index 3c078d8ee74b8..cae1d37fa7e47 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
@@ -603,6 +603,11 @@ void LVLocation::setKind() {
     getParentSymbol()->setFillGaps();
 }
 
+void LVLocation::printCommon(raw_ostream &OS, bool Full) const {
+  print(OS, Full);
+  printExtra(OS, Full);
+}
+
 void LVLocationSymbol::updateKind() {
   // Update the location type for simple ones.
   if (Entries && Entries->size() == 1) {

>From 355e1d6fc35896155a0e44df3c1b30d8d3b7132f Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Fri, 13 Feb 2026 10:41:34 +0000
Subject: [PATCH 13/13] [llvm-debuginfo-analyzer] Add support for LLVM IR
 format.

- Addressed all the reviewers comments.
  * Added test case for multiple compile units.

- Reviewed the inlining functionality issues, found when
  processing IRs produced by the Russ compiler:
  * Incorrect inlined lexical scopes as Clang allocates them
    at the scope of the enclosing function.
  * An assertion produced when in the inlining chain one of
    the original scopes has not been created.

- Fix compilation errors after upstream change:
  Remove DITypeRefArray in favour of DITypeArray
  https://github.com/llvm/llvm-project/pull/177066
---
 .../CommandGuide/llvm-debuginfo-analyzer.rst  |  16 +-
 .../DebugInfo/LogicalView/Core/LVReader.h     |   3 +
 .../DebugInfo/LogicalView/Core/LVSupport.h    |   6 +-
 .../LogicalView/Readers/LVIRReader.h          |  84 +-
 .../DebugInfo/LogicalView/Core/LVElement.cpp  |   6 +-
 .../DebugInfo/LogicalView/Core/LVReader.cpp   |  10 +-
 .../DebugInfo/LogicalView/LVReaderHandler.cpp |  15 +-
 .../LogicalView/Readers/LVIRReader.cpp        | 904 ++++++++++++------
 ...03-ir-incorrect-lexical-scope-typedef.test |   4 +-
 .../IR/04-ir-missing-nested-enumerators.test  |   4 +-
 ...5-ir-incorrect-lexical-scope-variable.test |   2 +-
 .../IR/06-ir-full-logical-view.test           |   3 +-
 .../IR/08-ir-multiple-compile-units.test      | 165 ++++
 .../IR/Inputs/unit-1.ll                       |  58 ++
 .../IR/Inputs/unit-2.ll                       |  58 ++
 .../IR/Inputs/unit-3.ll                       |  58 ++
 .../llvm-debuginfo-analyzer/IR/Inputs/unit.ll |  34 +
 .../DebugInfo/LogicalView/IRReaderTest.cpp    |   4 +-
 .../DebugInfo/LogicalView/Inputs/README.md    |   3 +-
 19 files changed, 1064 insertions(+), 373 deletions(-)
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/08-ir-multiple-compile-units.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-1.ll
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-2.ll
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-3.ll
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit.ll

diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index a2df5c4da4fc9..67e307bb7fcc2 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -13,11 +13,11 @@ SYNOPSIS
 DESCRIPTION
 -----------
 :program:`llvm-debuginfo-analyzer` parses debug and text sections in
-binary object files and textual IR representations and prints their
-contents in a logical view, which is a human readable representation
+binary object files or LLVM IR textual / bitcode representation and prints
+their contents in a logical view, which is a human readable representation
 that closely matches the structure of the original user source code.
 Supported object file formats include ELF, Mach-O, WebAssembly, PDB,
-COFF, IR (textual representation and bitcode).
+COFF and IR (textual representation and bitcode).
 
 The **logical view** abstracts the complexity associated with the
 different low-level representations of the debugging information that
@@ -2132,8 +2132,8 @@ layout and given the number of matches.
   -----------------------------
   Total           71          8
 
-IR (Textual representation and bitcode) SUPPORT
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LLVM IR (textual / bitcode representation) SUPPORT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 The below example is used to show the IR output generated by
 :program:`llvm-debuginfo-analyzer`. We compiled the example for a
 IR 64-bit target with Clang (-O0 -g --target=x86_64-linux):
@@ -2225,7 +2225,7 @@ the element.
 SELECT LOGICAL ELEMENTS
 ^^^^^^^^^^^^^^^^^^^^^^^
 The following prints all *instructions*, *symbols* and *types* that
-contain **'block'** or **'.store'** in their names or types, using a tab
+contain **'LOAD'** or **'store'** in their names or types, using a tab
 layout and given the number of matches.
 
 .. code-block:: none
@@ -2390,8 +2390,8 @@ missing and added elements.
    [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
   -[003]     4           {TypeAlias} 'INTEGER' -> 'int'
 
-The same output but this time comparing the Clang bitcode with the
-binary object (DWARF) generated by GCC.
+The previous command yields the same output, but this time comparing
+the Clang bitcode with the binary object (DWARF) generated by GCC.
 
 LOGICAL ELEMENTS
 """"""""""""""""
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index 371bffb2ed163..774318cb3c53e 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -193,6 +193,9 @@ class LLVM_ABI LVReader {
   virtual Error printMatchedElements(bool UseMatchedElements);
   virtual void sortScopes() {}
 
+  void printCollectedElements(LVScope *Root);
+  bool checkIntegrityScopesTree(LVScope *Root);
+
 public:
   LVReader() = delete;
   LVReader(StringRef InputFilename, StringRef FileFormatName, ScopedPrinter &W,
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
index bd1b7238f6137..89b78042a615f 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -119,7 +119,7 @@ template <typename T> class LVProperties {
 #define KIND_3(ENUM, FIELD, F1, F2, F3)                                        \
   BOOL_BIT_3(Kinds, ENUM, FIELD, F1, F2, F3)
 
-const int DEC_WIDTH = 8;
+static constexpr int DEC_WIDTH = 8;
 inline FormattedNumber decValue(uint64_t N, unsigned Width = DEC_WIDTH) {
   return format_decimal(N, Width);
 }
@@ -129,10 +129,10 @@ inline std::string decString(uint64_t Value, size_t Width = DEC_WIDTH) {
   std::string String;
   raw_string_ostream Stream(String);
   Stream << decValue(Value, Width);
-  return Stream.str();
+  return String;
 }
 
-const int HEX_WIDTH = 12;
+static constexpr int HEX_WIDTH = 12;
 inline FormattedNumber hexValue(uint64_t N, unsigned Width = HEX_WIDTH,
                                 bool Upper = false) {
   return format_hex(N, Width, Upper);
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
index 8a6389cab0c98..e638444e6d87a 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
@@ -25,6 +25,7 @@ class DIScope;
 class DISubprogram;
 class DIVariable;
 class BasicBlock;
+class Module;
 
 namespace object {
 class IRObjectFile;
@@ -37,20 +38,23 @@ class LVLine;
 class LVScopeCompileUnit;
 class LVSymbol;
 class LVType;
+struct LVSourceLanguage;
 
 class LVIRReader final : public LVReader {
   object::IRObjectFile *BitCodeIR = nullptr;
   MemoryBufferRef *TextualIR = nullptr;
 
+  // Used by the metadata 'dump' functions, so the metadata nodes will be
+  // numbered canonically; otherwise, pointer addresses are substituted.
+  Module *TheModule = nullptr;
+
   // Symbols with locations for current compile unit.
   LVSymbols SymbolsWithLocations;
 
-  LVSectionIndex SectionIndex = 0;
-
   const DICompileUnit *CUNode = nullptr;
 
-  // The Dwarf Version (from the module flags).
-  unsigned DwarfVersion;
+  // The Dwarf version (from the module flags).
+  unsigned DwarfVersion = 0;
 
   // Location index for global variables.
   uint64_t PoolAddressIndex = 0;
@@ -64,17 +68,15 @@ class LVIRReader final : public LVReader {
   bool includeMinimalInlineScopes() const;
   bool useAllLinkageNames() const { return UseAllLinkageNames; }
 
-  bool LanguageIsFortran = false;
-  void mapFortranLanguage(unsigned DWLang);
-  bool moduleIsInFortran() const { return LanguageIsFortran; }
+  // Default lower bound for arrays.
+  int64_t DefaultLowerBound = 0;
+  int64_t getDefaultLowerBound() const { return DefaultLowerBound; }
+  void setDefaultLowerBound(LVSourceLanguage *SL);
 
   // We assume a constant instruction-size increase between instructions.
   const unsigned OffsetIncrease = 4;
   void updateLineOffset() { CurrentOffset += OffsetIncrease; }
 
-  // An anonymous type for index type.
-  LVType *NodeIndexType = nullptr;
-
   SSAValueNameMap ValueNameMap;
   DenseMap<void *, uint64_t> InstrLineAddrMap;
   std::unique_ptr<DbgValueRangeTable> DbgValueRanges;
@@ -105,6 +107,10 @@ class LVIRReader final : public LVReader {
   using LVCompileUnitFiles = std::map<const DIFile *, size_t>;
   LVCompileUnitFiles CompileUnitFiles;
 
+  // For the given 'DIFile', generate a 1-based index to indicate the
+  // source file where the logical element is declared.
+  // The IR reader expects the indexes to be 1-based.
+  // Each compile unit, keeps track of the last assigned index.
   size_t getOrCreateSourceID(const DIFile *File);
 
   // Associate the metadata objects to logical elements.
@@ -112,8 +118,7 @@ class LVIRReader final : public LVReader {
   LVMDObjects MDObjects;
 
   void addMD(const MDNode *MD, LVElement *Element) {
-    if (MDObjects.find(MD) == MDObjects.end())
-      MDObjects.emplace(MD, Element);
+    MDObjects.try_emplace(MD, Element);
   }
   LVElement *getElementForSeenMD(const MDNode *MD) const {
     LVMDObjects::const_iterator Iter = MDObjects.find(MD);
@@ -132,46 +137,37 @@ class LVIRReader final : public LVReader {
     return static_cast<LVType *>(getElementForSeenMD(MD));
   }
 
-  // Abstract scopes mapped to the associated inlined scopes.
-  // When creating inlined scopes, there is no direct information to find
-  // the correct lexical scope.
-  using LVScopeEntry = std::pair<LVScope *, const DILocation *>;
-  using LVInlinedScopes = std::map<LVScopeEntry, LVScope *>;
-  LVInlinedScopes InlinedScopes;
-
-  void addInlinedScope(LVScope *AbstractScope, const DILocation *InlinedAt,
-                       LVScope *InlinedScope) {
-    auto Entry = LVScopeEntry(AbstractScope, InlinedAt);
-    if (InlinedScopes.find(Entry) == InlinedScopes.end())
-      InlinedScopes.emplace(Entry, InlinedScope);
-  }
-  LVScope *getInlinedScope(LVScope *AbstractScope,
-                           const DILocation *InlinedAt) const {
-    auto Entry = LVScopeEntry(AbstractScope, InlinedAt);
-    LVInlinedScopes::const_iterator Iter = InlinedScopes.find(Entry);
-    return Iter != InlinedScopes.end() ? Iter->second : nullptr;
-  }
-
   const DIFile *getMDFile(const MDNode *MD) const;
   StringRef getMDName(const DINode *DN) const;
   const DIScope *getMDScope(const DINode *DN) const;
 
+  // An anonymous type for index type.
+  LVType *NodeIndexType = nullptr;
   LVType *getIndexType();
 
+  // Get current metadata DICompileUnit object.
   const DICompileUnit *getCUNode() const { return CUNode; }
 
+  // Get the parent scope for the given metadata object.
   LVScope *getParentScopeImpl(const DIScope *Context);
   LVScope *getParentScope(const DINode *DN);
   LVScope *getParentScope(const DILocation *DL);
+
+  // Traverse the scope hierarchy and create each node in the hierarchy.
   LVScope *traverseParentScope(const DIScope *Context);
 
+  // Create the location ranges for the given scope and in the case of
+  // functions, generate an entry in the public names set.
   void constructRange(LVScope *Scope, LVAddress LowPC, LVAddress HighPC);
   void constructRange(LVScope *Scope);
 
-  void processBasicBlocks(Function &F, const DISubprogram *SP);
+  // Generate debug logical lines for the given function.
+  void processBasicBlocks(Function &F);
 
+  // Add accessibility information if available.
   void addAccess(LVElement *Element, DINode::DIFlags Flags);
 
+  // Add a constant value to a logical element.
   void addConstantValue(LVElement *Element, const DIExpression *DIExpr);
   void addConstantValue(LVElement *Element, const ConstantInt *CI,
                         const DIType *Ty);
@@ -181,8 +177,7 @@ class LVIRReader final : public LVReader {
   void addConstantValue(LVElement *Element, uint64_t Value, const DIType *Ty);
   void addConstantValue(LVElement *Element, uint64_t Value, bool Unsigned);
 
-  void addString(LVElement *Element, StringRef Str);
-
+  // Add template parameters to logical element.
   void addTemplateParams(LVElement *Element, const DINodeArray TParams);
 
   // Add location information to specified logical element.
@@ -192,7 +187,7 @@ class LVIRReader final : public LVReader {
   void addSourceLine(LVElement *Element, const DILabel *L);
   void addSourceLine(LVElement *Element, const DILocalVariable *LV);
   void addSourceLine(LVElement *Element, const DILocation *DL);
-  void addSourceLine(LVElement *Element, const DIObjCProperty *Ty);
+  void addSourceLine(LVElement *Element, const DIObjCProperty *OP);
   void addSourceLine(LVElement *Element, const DISubprogram *SP);
   void addSourceLine(LVElement *Element, const DIType *Ty);
 
@@ -226,14 +221,12 @@ class LVIRReader final : public LVReader {
   LVScope *getOrCreateSubprogram(const DISubprogram *SP);
   LVScope *getOrCreateSubprogram(LVScope *Function, const DISubprogram *SP,
                                  bool Minimal = false);
-  void constructSubprogramArguments(LVScope *Function,
-                                    const DITypeRefArray Args);
+  void constructSubprogramArguments(LVScope *Function, const DITypeArray Args);
 
-  LVScope *getOrCreateAbstractScope(LVScope *Parent, const DILocation *DL);
-  LVScope *getOrCreateInlinedScope(LVScope *AbstractScope,
-                                   const DILocation *DL);
+  LVScope *getOrCreateAbstractScope(const DILocation *DL);
+  LVScope *getOrCreateInlinedScope(const DILocation *DL);
 
-  void constructSubrange(LVScopeArray *Array, const DISubrange *GSR,
+  void constructSubrange(LVScopeArray *Array, const DISubrange *SR,
                          LVType *IndexType);
 
   void constructTemplateTypeParameter(LVElement *Element,
@@ -254,11 +247,16 @@ class LVIRReader final : public LVReader {
 
   LVElement *constructElement(const DINode *DN);
 
+  // After the scopes have been created, remove empty ones.
   void removeEmptyScopes();
+
+  // Adjust the inlined lexical scopes to their correct scope.
+  void resolveInlinedLexicalScopes();
+
   void processLocationGaps();
   void processScopes();
 
-  // These functions are only for development.
+  // Check if the scopes have been properly constructed (finalized).
   void checkScopes(LVScope *Scope);
 
 protected:
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
index a1882a1ba31ed..e74036217bb2d 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -557,12 +557,12 @@ void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
   if (options().getPrintFormatting() && options().getAttributeLinkage()) {
     // Include the section index only if '--attribute=offset', as the
     // index can be different depending on the specific reader.
-    std::string Section;
+    std::string Text;
     if (options().getAttributeOffset()) {
       LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
-      Section = (Twine(" 0x" + Twine::utohexstr(SectionIndex) + " ")).str();
+      Text = Twine(" 0x" + Twine::utohexstr(SectionIndex) + " ").str();
     }
-    std::string Text = (Twine(Section + "'" + getLinkageName() + "'")).str();
+    Text += Twine("'" + getLinkageName() + "'").str();
     printAttributes(OS, Full, "{Linkage} ", Parent, Text,
                     /*UseQuotes=*/false, /*PrintRef=*/false);
   }
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
index 1c0d8fa5af64e..89ce475a8b998 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
@@ -22,14 +22,14 @@ using namespace llvm::logicalview;
 
 #define DEBUG_TYPE "Reader"
 
-// Traverse all the logical elements and print its basic information.
-void printCollectedElements(LVScope *Root) {
+// Traverse all the logical elements and print their basic information.
+void LVReader::printCollectedElements(LVScope *Root) {
   std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) {
     // Print the elements.
     auto Print = [&](const auto &Set) {
       if (Set)
         for (const auto &Entry : *Set)
-          Entry->print(dbgs());
+          Entry->printCommon(dbgs());
     };
 
     for (LVElement *Element : Parent->getChildren())
@@ -50,7 +50,7 @@ void printCollectedElements(LVScope *Root) {
 // Detect elements that are inserted more than once at different scopes,
 // causing a crash on the reader destruction, as the element is already
 // deleted from other scope. Helper for CodeView reader.
-bool checkIntegrityScopesTree(LVScope *Root) {
+bool LVReader::checkIntegrityScopesTree(LVScope *Root) {
   using LVDuplicateEntry = std::tuple<LVElement *, LVScope *, LVScope *>;
   using LVDuplicate = std::vector<LVDuplicateEntry>;
   LVDuplicate Duplicate;
@@ -176,7 +176,7 @@ std::error_code LVSplitContext::open(std::string ContextName,
   return std::error_code();
 }
 
-static LVReader *CurrentReader = nullptr;
+LVReader *CurrentReader = nullptr;
 LVReader &LVReader::getInstance() {
   if (CurrentReader)
     return *CurrentReader;
diff --git a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
index d7350defc404c..ecb92a61b040c 100644
--- a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
@@ -27,7 +27,7 @@ using namespace llvm::logicalview;
 
 #define DEBUG_TYPE "ReaderHandler"
 
-static const StringRef IRFileFormat = "Textual IR";
+static constexpr StringRef IRFileFormatName = "LLVM IR";
 
 Error LVReaderHandler::process() {
   if (Error Err = createReaders())
@@ -61,16 +61,15 @@ Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
       return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, Pdb,
                                                 W, ExePath);
     }
-    if (isa<IRObjectFile *>(Input)) {
-      IRObjectFile *Ir = cast<IRObjectFile *>(Input);
+    if (IRObjectFile *Ir = dyn_cast<IRObjectFile *>(Input)) {
       return std::make_unique<LVIRReader>(Filename, FileFormatName, Ir, W);
     }
-    if (isa<MemoryBufferRef *>(Input)) {
+    if (MemoryBufferRef *MemBuf = dyn_cast<MemoryBufferRef *>(Input)) {
       // If the filename extension is '.ll' create an IR reader.
       const StringRef IRFileExt = ".ll";
-      MemoryBufferRef *MemBuf = cast<MemoryBufferRef *>(Input);
       if (llvm::sys::path::extension(Filename) == IRFileExt)
-        return std::make_unique<LVIRReader>(Filename, IRFileFormat, MemBuf, W);
+        return std::make_unique<LVIRReader>(Filename, IRFileFormatName, MemBuf,
+                                            W);
     }
     return nullptr;
   };
@@ -209,7 +208,7 @@ Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,
   LLVMContext Context;
   Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer, &Context);
   if (errorToErrorCode(BinOrErr.takeError())) {
-    // Assume it is textual representation (IR or C/C++ source code).
+    // Assume it is LLVM IR textual representation.
     return handleObject(Readers, Filename, Buffer);
   }
   return handleObject(Readers, Filename, *BinOrErr.get());
@@ -298,7 +297,7 @@ Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
 Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
                                     MemoryBufferRef Buffer) {
   if (InputHandle Input = dyn_cast<MemoryBufferRef>(&Buffer))
-    return createReader(Filename, Readers, Input, IRFileFormat);
+    return createReader(Filename, Readers, Input, IRFileFormatName);
 
   return createStringError(errc::not_supported,
                            "Binary object format in '%s' is not supported.",
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index 8707d91df8ec6..0d638a640b59a 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 //
 // This implements the LVIRReader class.
-// It supports LLVM text IR and bitcode format.
+// It supports LLVM textual and bitcode IR format.
 //
 //===----------------------------------------------------------------------===//
 
@@ -34,7 +34,121 @@ using namespace llvm::logicalview;
 
 #define DEBUG_TYPE "IRReader"
 
-// These flavours of DINodes are not implemented but technically possible:
+namespace {
+
+// Abstract scopes mapped to the associated inlined scopes.
+// When creating inlined scopes, there is no direct information to find
+// the correct lexical scope.
+using LVScopeEntry = std::pair<const DILocalScope *, const DILocation *>;
+using LVInlinedScopes = std::map<LVScopeEntry, LVScope *>;
+LVInlinedScopes InlinedScopes;
+
+void addInlinedScope(const DILocalScope *OriginContext,
+                     const DILocation *InlinedAt, LVScope *InlinedScope) {
+  auto Entry = LVScopeEntry(OriginContext, InlinedAt);
+  InlinedScopes.try_emplace(Entry, InlinedScope);
+}
+LVScope *getInlinedScope(const DILocalScope *OriginContext,
+                         const DILocation *InlinedAt) {
+  auto Entry = LVScopeEntry(OriginContext, InlinedAt);
+  LVInlinedScopes::const_iterator Iter = InlinedScopes.find(Entry);
+  return Iter != InlinedScopes.end() ? Iter->second : nullptr;
+}
+
+// Used to find the correct location for the inlined lexical blocks that
+// are allocated at their enclosing function level.
+// Keep a link between the inlined scope and its associated origin scope.
+using LVInlinedToOrigin = std::map<LVScope *, LVScope *>;
+LVInlinedToOrigin InlinedToOrigin;
+
+// Keep a list of inlined scopes created from the same origin scope.
+// The original scope can be inlined multiple times.
+using LVList = llvm::SmallVector<LVScope *, 2>;
+using LVInlinedList = std::map<LVScope *, LVList>;
+LVInlinedList InlinedList;
+
+void addInlinedInfo(LVScope *Origin, LVScope *Inlined) {
+  // Add the link between the inlined and the origin scopes.
+  InlinedToOrigin.try_emplace(Inlined, Origin);
+
+  // For the given origin scope, add the inlined scope to its inlined list.
+  auto It = InlinedList.find(Origin);
+  if (It == InlinedList.end()) {
+    LVList List;
+    List.push_back(Inlined);
+    InlinedList.try_emplace(Origin, std::move(List));
+  } else {
+    LVList &List = It->second;
+    List.push_back(Inlined);
+  }
+}
+
+LVList &getInlinedList(LVScope *Origin) {
+  static LVList List;
+  auto It = InlinedList.find(Origin);
+  return (It == InlinedList.end()) ? List : It->second;
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+void dumpInlinedInfo(const char *Text, bool Full = false) {
+  // Use 17 as the field length; it corresponds to '{InlinedFunction}'
+  const unsigned LEN = 17;
+
+  auto PrintEntry = [&](auto Text, LVScope *Scope) {
+    std::stringstream SS;
+    SS << Text << hexSquareString(Scope->getID())
+       << hexSquareString(Scope->getParentScope()->getID()) << " "
+       << std::setw(LEN) << std::left << formattedKind(Scope->kind());
+    dbgs() << SS.str();
+  };
+  auto PrintExtra = [&](auto Text, LVScope *Scope) {
+    dbgs() << Text;
+    Scope->dumpCommon();
+  };
+
+  // For each origin scope prints its associated inlined scopes.
+  dbgs() << "\nOrigin -> Inlined list: " << Text << "\n\n";
+  for (auto &Entry : InlinedList) {
+    LVScope *OriginScope = Entry.first;
+    LVList &List = Entry.second;
+    PrintEntry("", OriginScope);
+    dbgs() << "\n";
+    unsigned Count = 0;
+    for (auto &Scope : List) {
+      dbgs() << decString(++Count, /*Width=*/2);
+      PrintEntry(" ", Scope);
+      dbgs() << "\n";
+    }
+  }
+
+  dbgs() << "\nOrigin -> Inlined: " << Text << "\n\n";
+  for (auto &Entry : InlinedToOrigin) {
+    LVScope *InlinedScope = Entry.first;
+    LVScope *OriginScope = Entry.second;
+    PrintEntry("", InlinedScope);
+    dbgs() << " -> ";
+    PrintEntry("", OriginScope);
+    dbgs() << "\n";
+  }
+
+  if (Full) {
+    dbgs() << "\n";
+    for (auto &Entry : InlinedToOrigin) {
+      LVScope *InlinedScope = Entry.first;
+      LVScope *OriginScope = Entry.second;
+      PrintExtra("OriginParent:  ", OriginScope->getParentScope());
+      PrintExtra("Origin:        ", OriginScope);
+      PrintExtra("InlinedParent: ", InlinedScope->getParentScope());
+      PrintExtra("Inlined:       ", InlinedScope);
+      dbgs() << "\n";
+    }
+  }
+}
+#endif
+
+} // namespace
+
+// These flavours of 'DINode's are not implemented but technically possible:
 //   DW_TAG_APPLE_property   = 0x4200
 //   DW_TAG_atomic_type      = 0x0047
 //   DW_TAG_common_block     = 0x001a
@@ -55,60 +169,49 @@ LVElement *LVIRReader::constructElement(const DINode *DN) {
     Element->setTag(Tag);
     addMD(DN, Element);
 
-    StringRef Name = getMDName(DN);
-    if (!Name.empty())
+    if (StringRef Name = getMDName(DN); !Name.empty())
       Element->setName(Name);
 
     // Record any file information.
     if (const DIFile *File = getMDFile(DN))
       getOrCreateSourceID(File);
   }
-
   return Element;
 }
 
-void LVIRReader::mapFortranLanguage(unsigned DWLang) {
-  switch (DWLang) {
-  case dwarf::DW_LANG_Fortran77:
-  case dwarf::DW_LANG_Fortran90:
-  case dwarf::DW_LANG_Fortran95:
-  case dwarf::DW_LANG_Fortran03:
-  case dwarf::DW_LANG_Fortran08:
-  case dwarf::DW_LANG_Fortran18:
-    LanguageIsFortran = true;
-    break;
-  default:
-    LanguageIsFortran = false;
-  }
+void LVIRReader::setDefaultLowerBound(LVSourceLanguage *SL) {
+  assert(SL && "Invalid language ID.");
+  StringRef LanguageName = SL->getName();
+
+  // Fortran uses 1 as the default lowerbound; other languages use 0.
+  DefaultLowerBound = LanguageName.contains("fortran") ? 1 : 0;
+
+  LLVM_DEBUG({ dbgs() << "Language Name: " << LanguageName << "\n"; });
 }
 
 bool LVIRReader::includeMinimalInlineScopes() const {
   return getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly;
 }
 
-// For the given 'DIFile' generate an index 1-based to indicate the
-// source file where the logical element is declared.
-// The IR reader expects the indexes as 1-indexed.
-// Each compile unit, keeps track of the last assigned index.
 size_t LVIRReader::getOrCreateSourceID(const DIFile *File) {
   if (!File)
     return 0;
 
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateSourceID] DIFile\n";
-    File->dump();
+    dbgs() << "\n[getOrCreateSourceID]\n";
+    dbgs() << "File: ";
+    File->dump(TheModule);
   });
-
   addMD(File, CompileUnit);
 
   LLVM_DEBUG({
     dbgs() << "Directory: '" << File->getDirectory() << "'\n";
     dbgs() << "Filename:  '" << File->getFilename() << "'\n";
   });
-  size_t FileIndex = 0;
-  LVCompileUnitFiles::iterator Iter = CompileUnitFiles.find(File);
-  if (Iter == CompileUnitFiles.end()) {
-    FileIndex = getFileIndex(CompileUnit);
+
+  size_t FileIndex = getFileIndex(CompileUnit);
+  auto [Iter, Inserted] = CompileUnitFiles.try_emplace(File, ++FileIndex);
+  if (Inserted) {
     std::string Directory(File->getDirectory());
     if (Directory.empty())
       Directory = std::string(CompileUnit->getCompilationDirectory());
@@ -117,7 +220,6 @@ size_t LVIRReader::getOrCreateSourceID(const DIFile *File) {
     raw_string_ostream Out(FullName);
     Out << Directory << "/" << llvm::sys::path::filename(File->getFilename());
     CompileUnit->addFilename(transformPath(FullName));
-    CompileUnitFiles.emplace(File, ++FileIndex);
     updateFileIndex(CompileUnit, FileIndex);
   } else {
     FileIndex = Iter->second;
@@ -133,7 +235,7 @@ void LVIRReader::addSourceLine(LVElement *Element, unsigned Line,
     return;
 
   // After the scopes are created, the generic reader traverses the 'Children'
-  // and perform additional setting tasks (resolve types names, references,
+  // and performs additional setting tasks (resolve types names, references,
   // etc.). One of those tasks is select the correct string pool index based on
   // the commmand line options: --attribute=filename or --attribute=pathname.
   // As the 'Children' do not include logical lines, do that selection now,
@@ -147,7 +249,7 @@ void LVIRReader::addSourceLine(LVElement *Element, unsigned Line,
 
   LLVM_DEBUG({
     dbgs() << "\n[addSourceLine]\n";
-    File->dump();
+    File->dump(TheModule);
     dbgs() << "FileIndex: " << Element->getFilenameIndex() << ", ";
     dbgs() << "ID:   " << Element->getID() << ", ";
     dbgs() << "Kind: " << Element->kind() << ", ";
@@ -181,9 +283,9 @@ void LVIRReader::addSourceLine(LVElement *Element, const DILocation *DL) {
   addSourceLine(Element, DL->getLine(), DL->getFile());
 }
 
-void LVIRReader::addSourceLine(LVElement *Element, const DIObjCProperty *Ty) {
-  assert(Ty);
-  addSourceLine(Element, Ty->getLine(), Ty->getFile());
+void LVIRReader::addSourceLine(LVElement *Element, const DIObjCProperty *OP) {
+  assert(OP);
+  addSourceLine(Element, OP->getLine(), OP->getFile());
 }
 
 void LVIRReader::addSourceLine(LVElement *Element, const DISubprogram *SP) {
@@ -203,20 +305,15 @@ void LVIRReader::addConstantValue(LVElement *Element,
   if (Constant == std::nullopt)
     return;
   std::stringstream Stream;
+  uint64_t Value = DIExpr->getElement(1);
   if (DIExpression::SignedOrUnsignedConstant::SignedConstant == Constant) {
-    int64_t Value = DIExpr->getElement(1);
-    if (Value < 0) {
+    if (int64_t SignedValue = static_cast<int64_t>(Value); SignedValue < 0) {
       Stream << "-";
-      Value = std::abs(Value);
+      Value = static_cast<uint64_t>(-SignedValue);
     }
-    Stream << hexString(Value, 2);
-    Element->setValue(Stream.str());
-  } else if (DIExpression::SignedOrUnsignedConstant::UnsignedConstant ==
-             Constant) {
-    uint64_t Value = DIExpr->getElement(1);
-    Stream << hexString(Value, 2);
-    Element->setValue(Stream.str());
   }
+  Stream << hexString(Value, 2);
+  Element->setValue(Stream.str());
 }
 
 void LVIRReader::addConstantValue(LVElement *Element, const ConstantInt *CI,
@@ -248,10 +345,6 @@ void LVIRReader::addConstantValue(LVElement *Element, const APInt &Value,
   Element->setValue(StringValue.str());
 }
 
-void LVIRReader::addString(LVElement *Element, StringRef String) {
-  Element->setValue(String);
-}
-
 void LVIRReader::processLocationGaps() {
   if (options().getAttributeAnyLocation())
     for (LVSymbol *Symbol : SymbolsWithLocations)
@@ -266,7 +359,7 @@ void LVIRReader::processScopes() {
   // - Resolve any line pattern match.
   // At this stage the compile unit and the root scopes they have the
   // same offset, which is incorrect. Update the compile unit offset.
-  LVOffset Offset = 4;
+  LVOffset Offset = OffsetIncrease;
   auto SetOffset = [&](LVElement *Element) {
     Element->setOffset(Offset);
     Offset += OffsetIncrease;
@@ -281,7 +374,7 @@ void LVIRReader::processScopes() {
       for (LVScope *Scope : *Scopes)
         TraverseScope(Scope);
 
-    // Set an arbitrary 'Offset' for symbols and types.
+    // Set an arbitrary, but strictly-increasing 'Offset' for symbols and types.
     if (const LVSymbols *Symbols = Current->getSymbols())
       for (LVSymbol *Symbol : *Symbols)
         SetOffset(Symbol);
@@ -331,8 +424,9 @@ LVScope *LVIRReader::getParentScopeImpl(const DIScope *Context) {
     return CompileUnit;
 
   LLVM_DEBUG({
-    dbgs() << "\n[getParentScopeImpl] DIScope\n";
-    Context->dump();
+    dbgs() << "\n[getParentScopeImpl]\n";
+    dbgs() << "Context: ";
+    Context->dump(TheModule);
   });
 
   // Check for an already seen scope parent.
@@ -347,8 +441,9 @@ LVScope *LVIRReader::getParentScopeImpl(const DIScope *Context) {
 LVScope *LVIRReader::getParentScope(const DILocation *DL) {
   assert(DL && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getParentScope] DILocation\n";
-    DL->dump();
+    dbgs() << "\n[getParentScope]\n";
+    dbgs() << "DL: ";
+    DL->dump(TheModule);
   });
 
   return getParentScopeImpl(cast<DIScope>(DL->getScope()));
@@ -358,21 +453,22 @@ LVScope *LVIRReader::getParentScope(const DILocation *DL) {
 LVScope *LVIRReader::getParentScope(const DINode *DN) {
   assert(DN && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getParentScope] DINode\n";
-    DN->dump();
+    dbgs() << "\n[getParentScope]\n";
+    dbgs() << "DN: ";
+    DN->dump(TheModule);
   });
 
   return getParentScopeImpl(getMDScope(DN));
 }
 
-// Traverse the scope hierarchy and create each node in the hierarchy.
 LVScope *LVIRReader::traverseParentScope(const DIScope *Context) {
   if (!Context)
     return CompileUnit;
 
   LLVM_DEBUG({
-    dbgs() << "\n[traverseParentScope] DIScope\n";
-    Context->dump();
+    dbgs() << "\n[traverseParentScope]\n";
+    dbgs() << "Context: \n";
+    Context->dump(TheModule);
   });
 
   // Check if the metadata is already seen.
@@ -419,26 +515,36 @@ LVType *LVIRReader::getIndexType() {
   return NodeIndexType;
 }
 
-// Add accessibility info if available.
 void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) {
   assert(Element && "Invalid logical element.");
-  LLVM_DEBUG({ dbgs() << "\n[addAccess] DIFlags " << Flags << "\n"; });
+  LLVM_DEBUG({
+    dbgs() << "\n[addAccess]\n";
+    dbgs() << "Flags: " << Flags << "\n";
+  });
 
-  if ((Flags & DINode::FlagAccessibility) == DINode::FlagZero) {
+  const unsigned Accessibility = (Flags & DINode::FlagAccessibility);
+  switch (Accessibility) {
+  case DINode::FlagProtected:
+    Element->setAccessibilityCode(dwarf::DW_ACCESS_protected);
+    return;
+  case DINode::FlagPrivate:
+    Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
+    return;
+  case DINode::FlagPublic:
+    Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
+    return;
+  case DINode::FlagZero:
+    // If no explicit access control, provide the default for the parent.
     LVScope *Parent = Element->getParentScope();
-    if (Parent->getIsClass())
+    if (Parent->getIsClass()) {
       Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
-    else if (Parent->getIsStructure() || Parent->getIsUnion())
+      return;
+    }
+    if (Parent->getIsStructure() || Parent->getIsUnion()) {
       Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
-    return;
+      return;
+    }
   }
-
-  if ((Flags & DINode::FlagAccessibility) == DINode::FlagProtected)
-    Element->setAccessibilityCode(dwarf::DW_ACCESS_protected);
-  else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPrivate)
-    Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
-  else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPublic)
-    Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
 }
 
 // getFile()
@@ -453,8 +559,9 @@ void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) {
 const DIFile *LVIRReader::getMDFile(const MDNode *MD) const {
   assert(MD && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getMDFile] MDNode\n";
-    MD->dump();
+    dbgs() << "\n[getMDFile]\n";
+    dbgs() << "MD: ";
+    MD->dump(TheModule);
   });
 
   if (auto *T = dyn_cast<DIScope>(MD))
@@ -484,7 +591,7 @@ const DIFile *LVIRReader::getMDFile(const MDNode *MD) const {
   return nullptr;
 }
 
-// getName()
+// getMDName()
 //   DIScope
 //   DIType
 //   DISubprogram
@@ -501,8 +608,9 @@ const DIFile *LVIRReader::getMDFile(const MDNode *MD) const {
 StringRef LVIRReader::getMDName(const DINode *DN) const {
   assert(DN && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getMDName] DINode\n";
-    DN->dump();
+    dbgs() << "\n[getMDName]\n";
+    dbgs() << "DN: ";
+    DN->dump(TheModule);
   });
 
   if (auto *T = dyn_cast<DIImportedEntity>(DN))
@@ -520,7 +628,7 @@ StringRef LVIRReader::getMDName(const DINode *DN) const {
   if (auto *T = dyn_cast<DIEnumerator>(DN))
     return T->getName();
 
-  if (/*auto *T = */ dyn_cast<DISubrange>(DN))
+  if (isa<DISubrange>(DN))
     return StringRef();
 
   if (auto *T = dyn_cast<DIVariable>(DN))
@@ -548,8 +656,9 @@ StringRef LVIRReader::getMDName(const DINode *DN) const {
 const DIScope *LVIRReader::getMDScope(const DINode *DN) const {
   assert(DN && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getMDScope] DINode\n";
-    DN->dump();
+    dbgs() << "\n[getMDScope]\n";
+    dbgs() << "DN: ";
+    DN->dump(TheModule);
   });
 
   if (dyn_cast<DIBasicType>(DN))
@@ -586,10 +695,11 @@ void LVIRReader::addTemplateParams(LVElement *Element,
   assert(Element && "Invalid logical element");
   // assert(TParams && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[addTemplateParams] DINodeArray\n";
-    // TParams->dump();
-    for (const auto *Entry : TParams)
-      Entry->dump();
+    dbgs() << "\n[addTemplateParams]\n";
+    for (const auto *Entry : TParams) {
+      dbgs() << "Entry: ";
+      Entry->dump(TheModule);
+    }
   });
 
   // Add template parameters.
@@ -608,8 +718,9 @@ void LVIRReader::applySubprogramAttributes(LVScope *Function,
   assert(Function && "Invalid logical element");
   assert(SP && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[applySubprogramAttributes] DISubprogram\n";
-    SP->dump();
+    dbgs() << "\n[applySubprogramAttributes]\n";
+    dbgs() << "SP: ";
+    SP->dump(TheModule);
   });
 
   // If -fdebug-info-for-profiling is enabled, need to emit the subprogram
@@ -627,7 +738,7 @@ void LVIRReader::applySubprogramAttributes(LVScope *Function,
   if (SkipSPAttributes)
     return;
 
-  DITypeRefArray Args;
+  DITypeArray Args;
   if (const DISubroutineType *SPTy = SP->getType())
     Args = SPTy->getTypeArray();
 
@@ -663,15 +774,16 @@ bool LVIRReader::applySubprogramDefinitionAttributes(LVScope *Function,
   assert(Function && "Invalid logical element");
   assert(SP && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[applySubprogramDefinitionAttributes] DISubprogram\n";
-    SP->dump();
+    dbgs() << "\n[applySubprogramDefinitionAttributes]\n";
+    dbgs() << "SP: ";
+    SP->dump(TheModule);
   });
 
   LVScope *Reference = nullptr;
   StringRef DeclLinkageName;
   if (const DISubprogram *SPDecl = SP->getDeclaration()) {
     if (!Minimal) {
-      DITypeRefArray DeclArgs, DefinitionArgs;
+      DITypeArray DeclArgs, DefinitionArgs;
       DeclArgs = SPDecl->getType()->getTypeArray();
       DefinitionArgs = SP->getType()->getTypeArray();
 
@@ -724,18 +836,15 @@ bool LVIRReader::applySubprogramDefinitionAttributes(LVScope *Function,
 
   // Add the linkage name if we have one and it isn't in the Decl.
   StringRef LinkageName = SP->getLinkageName();
-  assert(((LinkageName.empty() || DeclLinkageName.empty()) ||
-          LinkageName == DeclLinkageName) &&
-         "decl has a linkage name and it is different");
-  if (DeclLinkageName.empty() && (useAllLinkageNames()))
-    // Always emit it for abstract subprograms.
+  // Always emit it for abstract subprograms.
+  if (DeclLinkageName != LinkageName && (useAllLinkageNames()))
     Function->setLinkageName(LinkageName);
 
   if (!Reference)
     return false;
 
-  // Refer to the function declaration where all the other attributes will be
-  // found.
+  // Refer to the function declaration where all the other attributes
+  // will be found.
   Function->setReference(Reference);
   Function->setHasReferenceSpecification();
 
@@ -748,8 +857,9 @@ void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate,
   assert(Aggregate && "Invalid logical element");
   assert(CTy && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructAggregate] DICompositeType\n";
-    CTy->dump();
+    dbgs() << "\n[constructAggregate]\n";
+    dbgs() << "CTy: ";
+    CTy->dump(TheModule);
   });
 
   if (Aggregate->getIsFinalized())
@@ -768,8 +878,8 @@ void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate,
     if (!Member)
       continue;
     LLVM_DEBUG({
-      dbgs() << "\nAggregate Element\n";
-      Member->dump();
+      dbgs() << "\nMember: ";
+      Member->dump(TheModule);
     });
     if (const auto *SP = dyn_cast<DISubprogram>(Member))
       getOrCreateSubprogram(SP);
@@ -793,8 +903,9 @@ void LVIRReader::constructArray(LVScopeArray *Array,
   assert(Array && "Invalid logical element");
   assert(CTy && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructArray] DICompositeType\n";
-    CTy->dump();
+    dbgs() << "\n[constructArray]\n";
+    dbgs() << "CTy: ";
+    CTy->dump(TheModule);
   });
 
   if (Array->getIsFinalized())
@@ -825,8 +936,9 @@ void LVIRReader::constructEnum(LVScopeEnumeration *Enumeration,
   assert(Enumeration && "Invalid logical element");
   assert(CTy && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructEnum] DICompositeType\n";
-    CTy->dump();
+    dbgs() << "\n[constructEnum]\n";
+    dbgs() << "CTy: ";
+    CTy->dump(TheModule);
   });
 
   if (Enumeration->getIsFinalized())
@@ -861,8 +973,9 @@ void LVIRReader::constructGenericSubrange(LVScopeArray *Array,
   assert(Array && "Invalid logical element");
   assert(GSR && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructGenericSubrange] DIGenericSubrange\n";
-    GSR->dump();
+    dbgs() << "\n[constructGenericSubrange]\n";
+    dbgs() << "GSR: ";
+    GSR->dump(TheModule);
   });
 
   LLVM_DEBUG({ dbgs() << "\nNot implemented\n"; });
@@ -874,8 +987,9 @@ void LVIRReader::constructImportedEntity(LVElement *Element,
   assert(Element && "Invalid logical element");
   assert(IE && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructImportedEntity] DIImportedEntity\n";
-    IE->dump();
+    dbgs() << "\n[constructImportedEntity]\n";
+    dbgs() << "IE: ";
+    IE->dump(TheModule);
   });
 
   if (LVElement *Import = constructElement(IE)) {
@@ -900,109 +1014,118 @@ void LVIRReader::constructImportedEntity(LVElement *Element,
   }
 }
 
-LVScope *LVIRReader::getOrCreateInlinedScope(LVScope *AbstractScope,
-                                             const DILocation *DL) {
-  assert(AbstractScope && "Invalid logical element");
+// Traverse the 'inlinedAt' chain and create their associated inlined scopes.
+LVScope *LVIRReader::getOrCreateInlinedScope(const DILocation *DL) {
   assert(DL && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateInlinedScope] DILocation\n";
-    DL->dump();
+    dbgs() << "\n[getOrCreateInlinedScope]\n";
+    dbgs() << "DL: ";
+    DL->dump(TheModule);
   });
 
+  const DILocalScope *OriginContext = DL->getScope();
+  LLVM_DEBUG({
+    dbgs() << "OriginContext: ";
+    OriginContext->dump(TheModule);
+  });
+
+  auto CreateScope = [&](const DILocalScope *Context) -> LVScope * {
+    LVScope *Scope = nullptr;
+    if (const auto *SP = dyn_cast<DISubprogram>(Context))
+      Scope = getOrCreateSubprogram(SP);
+    else
+      Scope = getOrCreateScope(Context);
+    LLVM_DEBUG({
+      dbgs() << "Scope: ";
+      Scope->dumpCommon();
+    });
+
+    return Scope;
+  };
+
   const DILocation *InlinedAt = DL->getInlinedAt();
-  DILocalScope *Context = DL->getScope();
+  if (!InlinedAt)
+    return CreateScope(OriginContext);
+
   LLVM_DEBUG({
-    dbgs() << "\nParent Scope:\n";
-    AbstractScope->getParentScope()->dump();
-    dbgs() << "\nOriginScope:\n";
-    AbstractScope->dump();
-    dbgs() << "\nInlinedAt:\n";
-    InlinedAt->dump();
-    dbgs() << "\nContext:\n";
-    Context->dump();
+    dbgs() << "InlinedAt: ";
+    InlinedAt->dump(TheModule);
   });
 
-  dwarf::Tag Tag = AbstractScope->getTag();
-  if (AbstractScope->getIsFunction() || AbstractScope->getIsInlinedFunction()) {
+  // Check if the inlined scope is already created.
+  if (LVScope *InlinedScope = getInlinedScope(OriginContext, InlinedAt))
+    return InlinedScope;
+
+  // Get or create the original context, which will be the seed for the
+  // inlined scope that we intend to create.
+  LVScope *OriginScope = CreateScope(OriginContext);
+
+  dwarf::Tag Tag = OriginScope->getTag();
+  if (OriginScope->getIsFunction() || OriginScope->getIsInlinedFunction()) {
     Tag = dwarf::DW_TAG_inlined_subroutine;
-    AbstractScope->setInlineCode(dwarf::DW_INL_inlined);
+    OriginScope->setInlineCode(dwarf::DW_INL_inlined);
   }
   LVScope *InlinedScope = static_cast<LVScope *>(createElement(Tag));
   if (InlinedScope) {
-    addInlinedScope(AbstractScope, InlinedAt, InlinedScope);
+    addInlinedScope(OriginContext, InlinedAt, InlinedScope);
     InlinedScope->setTag(Tag);
     InlinedScope->setIsFinalized();
-    InlinedScope->setName(AbstractScope->getName());
-    InlinedScope->setType(AbstractScope->getType());
+    InlinedScope->setName(OriginScope->getName());
+    InlinedScope->setType(OriginScope->getType());
 
     InlinedScope->setCallLineNumber(InlinedAt->getLine());
     InlinedScope->setCallFilenameIndex(
         getOrCreateSourceID(InlinedAt->getFile()));
 
-    InlinedScope->setReference(AbstractScope);
+    InlinedScope->setReference(OriginScope);
     InlinedScope->setHasReferenceAbstract();
 
-    // Get or create the parent scope for the inlined subprogram.
-    LVScope *Parent =
-        InlinedScope->getIsLexicalBlock()
-            ? getInlinedScope(AbstractScope->getParentScope(), InlinedAt)
-            : getOrCreateScope(InlinedAt->getScope());
-    assert(Parent && "Parent scope is NULL.");
-    Parent->addElement(InlinedScope);
-  }
-
-  return InlinedScope;
-}
-
-LVScope *LVIRReader::getOrCreateAbstractScope(LVScope *Parent,
-                                              const DILocation *DL) {
-  assert(Parent && "Invalid logical element");
-  assert(DL && "Invalid metadata node.");
-  LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateAbstractScope] DILocation\n";
-    DL->dump();
-    dbgs() << "Parent Logical Scope:\n";
-    Parent->dump();
-  });
-
-  const DILocation *InlinedAt = DL->getInlinedAt();
-  if (!InlinedAt)
-    return nullptr;
+    // Record the link between the origin and the inlined scope, to be
+    // used to get the correct parent scope for logical lexical scopes.
+    LLVM_DEBUG({
+      dbgs() << "Linking\n";
+      OriginScope->dumpCommon();
+      InlinedScope->dumpCommon();
+    });
+    addInlinedInfo(OriginScope, InlinedScope);
 
-  DILocalScope *Context = DL->getScope();
-  if (!Context)
-    return nullptr;
+    DILocalScope *AbstractContext = InlinedAt->getScope();
+    LLVM_DEBUG({
+      dbgs() << "AbstractContext: ";
+      AbstractContext->dump(TheModule);
+    });
 
-  // Check if we have seen the scope.
-  LVScope *AbstractScope = getScopeForSeenMD(Context);
-  if (!AbstractScope) {
-    // Create the 'abstract' scope.
-    if (isa<DISubprogram>(Context)) {
-      AbstractScope =
-          getOrCreateSubprogram(static_cast<DISubprogram *>(Context));
-      AbstractScope->setInlineCode(dwarf::DW_INL_inlined);
-    } else if (isa<DILexicalBlock>(Context)) {
-      AbstractScope = getOrCreateScope(static_cast<DIScope *>(Context));
-    }
+    LVScope *AbstractScope = getOrCreateInlinedScope(InlinedAt);
+    assert(AbstractScope && "Logical scope is NULL.");
     LLVM_DEBUG({
-      dbgs() << "\nParent Scope:\n";
-      AbstractScope->getParentScope()->dump();
-      dbgs() << "Abstract Scope:\n";
-      AbstractScope->dump();
+      dbgs() << "AbstractScope: ";
+      AbstractScope->dumpCommon();
     });
 
-    // Create the 'inlined' scope.
-    LVScope *InlinedScope = getOrCreateInlinedScope(AbstractScope, DL);
-    assert(InlinedScope && "InlinedScope is null.");
+    // Add the created inlined scope.
+    AbstractScope->addElement(InlinedScope);
+
     LLVM_DEBUG({
-      dbgs() << "\nParent Scope:\n";
-      InlinedScope->getParentScope()->dump();
-      dbgs() << "\nInlined Scope:\n";
-      InlinedScope->dump();
+      dbgs() << "InlinedScope:  ";
+      InlinedScope->dumpCommon();
     });
   }
 
-  return AbstractScope;
+  return InlinedScope;
+}
+
+LVScope *LVIRReader::getOrCreateAbstractScope(const DILocation *DL) {
+  assert(DL && "Invalid metadata node.");
+  LLVM_DEBUG({
+    dbgs() << "\n[getOrCreateAbstractScope]\n";
+    dbgs() << "DL: ";
+    DL->dump(TheModule);
+  });
+
+  // Create the 'inlined' scope.
+  LVScope *InlinedScope = getOrCreateInlinedScope(DL);
+  assert(InlinedScope && "InlinedScope is null.");
+  return InlinedScope;
 }
 
 void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
@@ -1011,15 +1134,21 @@ void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
   assert(Scope && "Invalid logical element");
   assert(SP && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructLine] Instruction\n";
+    dbgs() << "\n[constructLine]\n";
+    dbgs() << "Instruction: ";
     I.dump();
-    dbgs() << "Logical Scope:\n";
-    Scope->dump();
+    dbgs() << "Logical Scope: ";
+    Scope->dumpCommon();
   });
 
   auto AddDebugLine = [&](LVScope *Parent, unsigned ID) -> LVLine * {
     assert(Parent && "Invalid logical element");
     assert(ID == Metadata::DILocationKind && "Invalid Metadata Object");
+    LLVM_DEBUG({
+      dbgs() << "\n[AddDebugLine]\n";
+      dbgs() << "Parent: ";
+      Parent->dumpCommon();
+    });
 
     LVLine *Line = createLineDebug();
     if (Line) {
@@ -1030,9 +1159,12 @@ void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
 
       // FIXME: How to get discrimination flags:
       // IsStmt, BasicBlock, EndSequence, EpilogueBegin, PrologueEnd.
+      //
+      // Explore the 'Key Instructions' information added to the metadata:
+      //   !DILocation(line: ..., scope: ..., atomGroup: ..., atomRank: ...)
 
       // Add mapping for this debug line.
-      CompileUnit->addMapping(Line, SectionIndex);
+      CompileUnit->addMapping(Line, /*SectionIndex=*/0);
 
       // Replicate the DWARF reader functionality of adding a linkage
       // name to a function with ranges (logical lines), regardless if
@@ -1081,13 +1213,16 @@ void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP,
   LVScope *Parent = Scope;
   if (const DebugLoc DbgLoc = I.getDebugLoc()) {
     const DILocation *DL = DbgLoc.get();
-    Parent = getParentScope(DL);
-    if (const DILocation *InlinedAt = DL->getInlinedAt())
-      Parent = getInlinedScope(Parent, InlinedAt);
+    LLVM_DEBUG({
+      dbgs() << "DL: ";
+      DL->dump(TheModule);
+    });
 
+    Parent = getOrCreateAbstractScope(DL);
+    assert(Parent && "Invalid logical element");
     LLVM_DEBUG({
-      dbgs() << "\n[constructLine] DILocation\n";
-      DL->dump();
+      dbgs() << "Parent: ";
+      Parent->dumpCommon();
     });
 
     if (options().getPrintLines() && DL->getLine()) {
@@ -1117,8 +1252,9 @@ LVSymbol *LVIRReader::getOrCreateMember(LVScope *Aggregate,
   assert(Aggregate && "Invalid logical element");
   assert(DT && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateMember] DIDerivedType\n";
-    DT->dump();
+    dbgs() << "\n[getOrCreateMember]\n";
+    dbgs() << "DT: ";
+    DT->dump(TheModule);
   });
 
   LVSymbol *Member = getSymbolForSeenMD(DT);
@@ -1198,22 +1334,23 @@ void LVIRReader::constructScope(LVElement *Element, const DIScope *Context) {
   assert(Element && "Invalid logical element");
   assert(Context && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructScope] DIScope\n";
-    Context->dump();
+    dbgs() << "\n[constructScope]\n";
+    dbgs() << "Context: ";
+    Context->dump(TheModule);
   });
 
-  if (Context && isa<DICompositeType>(Context)) {
-    const DICompositeType *CTy = cast<DICompositeType>(Context);
+  if (const DICompositeType *CTy =
+          dyn_cast_if_present<DICompositeType>(Context)) {
     constructType(static_cast<LVScope *>(Element), CTy);
-  } else if (Context && isa<DIDerivedType>(Context)) {
-    const DIDerivedType *DT = cast<DIDerivedType>(Context);
+  } else if (const DIDerivedType *DT =
+                 dyn_cast_if_present<DIDerivedType>(Context)) {
     constructType(Element, DT);
-  } else if (Context && isa<DISubprogram>(Context)) {
-    const DISubprogram *SP = cast<DISubprogram>(Context);
+  } else if (const DISubprogram *SP =
+                 dyn_cast_if_present<DISubprogram>(Context)) {
     getOrCreateSubprogram(static_cast<LVScope *>(Element), SP);
-  } else if (Context && isa<DINamespace>(Context)) {
+  } else if (dyn_cast_if_present<DINamespace>(Context)) {
     Element->setIsFinalized();
-  } else if (Context && isa<DILexicalBlock>(Context)) {
+  } else if (dyn_cast_if_present<DILexicalBlock>(Context)) {
     Element->setIsFinalized();
   }
 }
@@ -1223,8 +1360,9 @@ LVSymbol *LVIRReader::getOrCreateStaticMember(LVScope *Aggregate,
   assert(Aggregate && "Invalid logical element");
   assert(DT && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateStaticMember] DIDerivedType\n";
-    DT->dump();
+    dbgs() << "\n[getOrCreateStaticMember]\n";
+    dbgs() << "DT: ";
+    DT->dump(TheModule);
   });
 
   LVSymbol *Member = getSymbolForSeenMD(DT);
@@ -1252,8 +1390,9 @@ LVSymbol *LVIRReader::getOrCreateStaticMember(LVScope *Aggregate,
 LVScope *LVIRReader::getOrCreateSubprogram(const DISubprogram *SP) {
   assert(SP && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateSubprogram] DISubprogram\n";
-    SP->dump();
+    dbgs() << "\n[getOrCreateSubprogram]\n";
+    dbgs() << "SP: ";
+    SP->dump(TheModule);
   });
 
   LVScope *Function = getScopeForSeenMD(SP);
@@ -1290,8 +1429,9 @@ LVScope *LVIRReader::getOrCreateSubprogram(LVScope *Function,
   assert(Function && "Invalid logical element");
   assert(SP && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateSubprogram] DISubprogram\n";
-    SP->dump();
+    dbgs() << "\n[getOrCreateSubprogram]\n";
+    dbgs() << "SP: ";
+    SP->dump(TheModule);
   });
 
   if (Function->getIsFinalized())
@@ -1327,13 +1467,15 @@ LVScope *LVIRReader::getOrCreateSubprogram(LVScope *Function,
 }
 
 void LVIRReader::constructSubprogramArguments(LVScope *Function,
-                                              const DITypeRefArray Args) {
+                                              const DITypeArray Args) {
   assert(Function && "Invalid logical element");
   LLVM_DEBUG({
-    dbgs() << "\n[constructSubprogramArguments] DITypeRefArray\n";
+    dbgs() << "\n[constructSubprogramArguments]\n";
     for (unsigned i = 1, N = Args.size(); i < N; ++i) {
-      if (const DIType *Ty = Args[i])
-        Ty->dump();
+      if (const DIType *Ty = Args[i]) {
+        dbgs() << "Ty: ";
+        Ty->dump(TheModule);
+      }
     }
   });
 
@@ -1361,20 +1503,21 @@ void LVIRReader::constructSubprogramArguments(LVScope *Function,
 }
 
 // DISubrange
-void LVIRReader::constructSubrange(LVScopeArray *Array, const DISubrange *GSR,
+void LVIRReader::constructSubrange(LVScopeArray *Array, const DISubrange *SR,
                                    LVType *IndexType) {
   assert(Array && "Invalid logical element");
-  assert(GSR && "Invalid metadata node.");
+  assert(SR && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructSubrange] DISubrange\n";
-    GSR->dump();
+    dbgs() << "\n[constructSubrange]\n";
+    dbgs() << "SR: ";
+    SR->dump(TheModule);
   });
 
   // The DISubrange can be shared between different arrays, when they are
   // the same. We need to create independent logical elements for each one,
   // as they are going to be added to different arrays.
   if (LVTypeSubrange *Subrange =
-          static_cast<LVTypeSubrange *>(constructElement(GSR))) {
+          static_cast<LVTypeSubrange *>(constructElement(SR))) {
     Subrange->setIsFinalized();
     Array->addElement(Subrange);
     Subrange->setType(IndexType);
@@ -1384,13 +1527,13 @@ void LVIRReader::constructSubrange(LVScopeArray *Array, const DISubrange *GSR,
     // Otherwise, if it has an upperboud, use (upperbound - lowerbound + 1),
     // where lowerbound is from the LowerBound field of the Subrange,
     // or the language default lowerbound if that field is unspecified.
-    if (auto *CI = dyn_cast_if_present<ConstantInt *>(GSR->getCount()))
+    if (auto *CI = dyn_cast_if_present<ConstantInt *>(SR->getCount()))
       Count = CI->getSExtValue();
     else if (auto *UI =
-                 dyn_cast_if_present<ConstantInt *>(GSR->getUpperBound())) {
+                 dyn_cast_if_present<ConstantInt *>(SR->getUpperBound())) {
       // Fortran uses 1 as the default lowerbound; other languages use 0.
-      int64_t Lowerbound = (moduleIsInFortran()) ? 1 : 0;
-      auto *LI = dyn_cast_if_present<ConstantInt *>(GSR->getLowerBound());
+      int64_t Lowerbound = getDefaultLowerBound();
+      auto *LI = dyn_cast_if_present<ConstantInt *>(SR->getLowerBound());
       Lowerbound = (LI) ? LI->getSExtValue() : Lowerbound;
       Count = UI->getSExtValue() - Lowerbound + 1;
     }
@@ -1407,8 +1550,9 @@ void LVIRReader::constructTemplateTypeParameter(
   assert(Element && "Invalid logical element");
   assert(TTP && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructTemplateTypeParameter] DITemplateTypeParameter\n";
-    TTP->dump();
+    dbgs() << "\n[constructTemplateTypeParameter]\n";
+    dbgs() << "TTP: ";
+    TTP->dump(TheModule);
   });
 
   // The DITemplateTypeParameter can be shared between different subprogram
@@ -1439,8 +1583,9 @@ void LVIRReader::constructTemplateValueParameter(
   assert(Element && "Invalid logical element");
   assert(TVP && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructTemplateValueParameter] DITemplateValueParameter\n";
-    TVP->dump();
+    dbgs() << "\n[constructTemplateValueParameter]\n";
+    dbgs() << "TVP: ";
+    TVP->dump(TheModule);
   });
 
   // The DITemplateValueParameter can be shared between different subprogram
@@ -1490,8 +1635,9 @@ void LVIRReader::constructType(LVScope *Scope, const DICompositeType *CTy) {
   assert(Scope && "Invalid logical element");
   assert(CTy && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructType] DICompositeType\n";
-    CTy->dump();
+    dbgs() << "\n[constructType]\n";
+    dbgs() << "CTy: ";
+    CTy->dump(TheModule);
   });
 
   dwarf::Tag Tag = Scope->getTag();
@@ -1545,8 +1691,9 @@ void LVIRReader::constructType(LVElement *Element, const DIDerivedType *DT) {
   assert(Element && "Invalid logical element");
   assert(DT && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructType] DIDerivedType\n";
-    DT->dump();
+    dbgs() << "\n[constructType]\n";
+    dbgs() << "DT: ";
+    DT->dump(TheModule);
   });
 
   // For DW_TAG_member, the flag is set during the construction of the
@@ -1578,8 +1725,9 @@ void LVIRReader::constructType(LVScope *Function,
   assert(Function && "Invalid logical element");
   assert(SPTy && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[constructType] DISubroutineType\n";
-    SPTy->dump();
+    dbgs() << "\n[constructType]\n";
+    dbgs() << "SPTy: ";
+    SPTy->dump(TheModule);
   });
 
   if (Function->getIsFinalized())
@@ -1588,7 +1736,7 @@ void LVIRReader::constructType(LVScope *Function,
 
   // For DISubprogram, the DISubroutineType contains the types for:
   //   return type, param 1 type, ..., param n type
-  DITypeRefArray Args = SPTy->getTypeArray();
+  DITypeArray Args = SPTy->getTypeArray();
   if (Args.size()) {
     LVElement *ElementType = getOrCreateType(Args[0]);
     Function->setType(ElementType);
@@ -1600,8 +1748,9 @@ void LVIRReader::constructType(LVScope *Function,
 // DINamespace
 LVScope *LVIRReader::getOrCreateNamespace(const DINamespace *NS) {
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateNamespace] DINamespace\n";
-    NS->dump();
+    dbgs() << "\n[getOrCreateNamespace]\n";
+    dbgs() << "NS: ";
+    NS->dump(TheModule);
   });
 
   LVScope *Scope = getOrCreateScope(NS);
@@ -1615,9 +1764,11 @@ LVScope *LVIRReader::getOrCreateNamespace(const DINamespace *NS) {
 }
 
 LVScope *LVIRReader::getOrCreateScope(const DIScope *Context) {
+  assert(Context && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateScope] DIScope\n";
-    Context->dump();
+    dbgs() << "\n[getOrCreateScope]\n";
+    dbgs() << "Context: ";
+    Context->dump(TheModule);
   });
 
   // Check if the scope is already created.
@@ -1643,8 +1794,9 @@ LVElement *LVIRReader::getOrCreateType(const DIType *Ty, LVScope *Scope) {
     return nullptr;
 
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateType] DIType\n";
-    Ty->dump();
+    dbgs() << "\n[getOrCreateType]\n";
+    dbgs() << "Ty :";
+    Ty->dump(TheModule);
   });
 
   // Check if the element is already created.
@@ -1658,7 +1810,7 @@ LVElement *LVIRReader::getOrCreateType(const DIType *Ty, LVScope *Scope) {
     LVScope *Parent = Scope ? Scope : getParentScope(Ty);
     Parent->addElement(Element);
 
-    if (/*const DIBasicType *BT =*/dyn_cast<DIBasicType>(Ty)) {
+    if (isa<DIBasicType>(Ty)) {
       Element->setIsFinalized();
     } else if (const DIDerivedType *DT = dyn_cast<DIDerivedType>(Ty)) {
       constructType(Element, DT);
@@ -1677,8 +1829,9 @@ LVSymbol *
 LVIRReader::getOrCreateVariable(const DIGlobalVariableExpression *GVE) {
   assert(GVE && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateVariable] DIGlobalVariableExpression\n";
-    GVE->dump();
+    dbgs() << "\n[getOrCreateVariable]\n";
+    dbgs() << "GVE: ";
+    GVE->dump(TheModule);
   });
 
   const DIGlobalVariable *DIGV = GVE->getVariable();
@@ -1702,8 +1855,9 @@ LVSymbol *LVIRReader::getOrCreateInlinedVariable(LVSymbol *OriginSymbol,
   assert(OriginSymbol && "Invalid logical element");
   assert(DL && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateInlinedVariable] DIVariable\n";
-    DL->dump();
+    dbgs() << "\n[getOrCreateInlinedVariable]\n";
+    dbgs() << "DL: ";
+    DL->dump(TheModule);
   });
 
   const DILocation *InlinedAt = DL->getInlinedAt();
@@ -1730,13 +1884,11 @@ LVSymbol *LVIRReader::getOrCreateInlinedVariable(LVSymbol *OriginSymbol,
     if (OriginSymbol->getIsParameter())
       InlinedSymbol->setIsParameter();
 
-    LVScope *AbstractScope = OriginSymbol->getParentScope();
-    assert(AbstractScope && "Invalid logical element");
-    LVScope *InlinedScope = getInlinedScope(AbstractScope, InlinedAt);
-    if (!InlinedScope)
-      InlinedScope = getOrCreateInlinedScope(AbstractScope, DL);
+    // Get or create the local scope associated with the location.
+    LVScope *InlinedScope = getOrCreateInlinedScope(DL);
+    assert(InlinedScope && "Invalid logical element");
 
-    assert(InlinedScope && "Parent scope is NULL.");
+    // Add the created inlined scope.
     InlinedScope->addElement(InlinedSymbol);
   }
 
@@ -1749,11 +1901,12 @@ LVSymbol *LVIRReader::getOrCreateVariable(const DIVariable *Var,
                                           const DILocation *DL) {
   assert(Var && "Invalid metadata node.");
   LLVM_DEBUG({
-    dbgs() << "\n[getOrCreateVariable] DIVariable\n";
-    Var->dump();
+    dbgs() << "\n[getOrCreateVariable]\n";
+    dbgs() << "Var: ";
+    Var->dump(TheModule);
     if (DL) {
-      dbgs() << "DILocation\n";
-      DL->dump();
+      dbgs() << "DL: ";
+      DL->dump(TheModule);
     }
   });
 
@@ -1829,29 +1982,44 @@ LVSymbol *LVIRReader::getOrCreateVariable(const DIVariable *Var,
 
 #ifdef LLVM_DEBUG
 void LVIRReader::printAllInstructions(BasicBlock *BB) {
+  const Function *F = BB->getParent();
+  if (!F)
+    return;
+  const DISubprogram *SP = cast<DISubprogram>(F->getSubprogram());
   LLVM_DEBUG({
-    dbgs() << "\nBegin all instructions:\n";
+    dbgs() << "\nBegin all instructions: '" << SP->getName() << "'\n";
     for (Instruction &I : *BB) {
-      dbgs() << "Instruction: '" << I << "'\n";
-      for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
-        DVR.getVariable()->dump();
+      dbgs() << "I: '" << I << "'\n";
+      for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
+        dbgs() << "  Var: ";
+        DVR.getVariable()->dump(TheModule);
+      }
+      if (const auto *DL =
+              cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg))) {
+        dbgs() << "  DL: ";
+        DL->dump(TheModule);
+      }
     }
-    dbgs() << "End all instructions:\n\n";
+    dbgs() << "End all instructions: '" << SP->getName() << "'\n\n";
   });
 }
 #endif
 
-void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
-  assert(SP && "Invalid metadata node.");
+void LVIRReader::processBasicBlocks(Function &F) {
+  const DISubprogram *SP = cast_or_null<DISubprogram>(F.getSubprogram());
+  if (!SP)
+    return;
+
   LLVM_DEBUG({
-    dbgs() << "\n[processBasicBlocks] DISubprogram\n";
-    SP->dump();
+    dbgs() << "\n[processBasicBlocks]\n";
+    dbgs() << "SP: ";
+    SP->dump(TheModule);
   });
 
   // Check if we need to add a dwarf::DW_TAG_unspecified_parameters.
   bool AddUnspecifiedParameters = false;
   if (const DISubroutineType *SPTy = SP->getType()) {
-    DITypeRefArray Args = SPTy->getTypeArray();
+    DITypeArray Args = SPTy->getTypeArray();
     unsigned N = Args.size();
     if (N > 1) {
       const DIType *Ty = Args[N - 1];
@@ -1868,6 +2036,7 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
   auto HandleDbgVariable = [&](auto *DbgVar) {
     LLVM_DEBUG({
       dbgs() << "\n[HandleDbgVariable]\n";
+      dbgs() << "DbgVar: ";
       DbgVar->dump();
     });
 
@@ -1890,13 +2059,18 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
     for (Instruction &I : BB) {
       LLVM_DEBUG(dbgs() << "\nInstruction: '" << I << "'\n");
 
+      if (const auto *DL =
+              cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg))) {
+        LLVM_DEBUG({
+          dbgs() << "  Location: ";
+          DL->dump(TheModule);
+        });
+        getOrCreateAbstractScope(DL);
+      }
+
       for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
         HandleDbgVariable(&DVR);
 
-      if (const auto *DL =
-              cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg)))
-        getOrCreateAbstractScope(Scope, DL);
-
       if (options().getPrintAnyLine())
         constructLine(Scope, SP, I, GenerateLineBeforePrologue);
 
@@ -1917,8 +2091,8 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
     }
   }
 
-  LLVM_DEBUG({ dbgs() << "Traverse seen debug variables\n"; });
-  for (auto DVA : SeenVars) {
+  LLVM_DEBUG({ dbgs() << "\nTraverse seen debug variables\n"; });
+  for (const DebugVariableAggregate &DVA : SeenVars) {
     LLVM_DEBUG({ DbgValueRanges->printValues(DVA, dbgs()); });
     DILocalVariable *LV = const_cast<DILocalVariable *>(DVA.getVariable());
     LVSymbol *Symbol = getSymbolForSeenMD(LV);
@@ -1929,8 +2103,8 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
     DIType *Ty = LV->getType();
     uint64_t Size = Ty ? Ty->getSizeInBits() / CHAR_BIT : 1;
     LLVM_DEBUG({
-      LV->dump();
-      Ty->dump();
+      LV->dump(TheModule);
+      Ty->dump(TheModule);
       dbgs() << "Type size: " << Size << "\n";
     });
 
@@ -1970,7 +2144,8 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
       assert(DV.IsMemory && "Single location should be memory!");
       AddLocation(DV);
     } else {
-      for (DbgRangeEntry Entry : DbgValueRanges->getVariableRanges(DVA)) {
+      for (const DbgRangeEntry &Entry :
+           DbgValueRanges->getVariableRanges(DVA)) {
         // These line addresses should have already been inserted into the
         // InstrLineAddrMap, so we assume they are present here.
         LVOffset Start = InstrLineAddrMap.at(Entry.Start.getNodePtr());
@@ -2006,26 +2181,24 @@ Error LVIRReader::createScopes() {
       BitCodeIR ? BitCodeIR->getMemoryBufferRef() : *TextualIR, Err, Context);
   if (!M)
     return createStringError(errc::invalid_argument,
-                             "Could not create IR information: %s",
+                             "Could not create IR module for: %s",
                              getFilename().str().c_str());
 
-  if (!M->getNamedMetadata("llvm.dbg.cu")) {
+  TheModule = M.get();
+  if (!TheModule->getNamedMetadata("llvm.dbg.cu")) {
     LLVM_DEBUG(dbgs() << "Skipping module without debug info\n");
     return Error::success();
   }
 
-  DwarfVersion = M->getDwarfVersion();
+  DwarfVersion = TheModule->getDwarfVersion();
 
   LLVM_DEBUG({ dbgs() << "\nProcess CompileUnits\n"; });
-  for (const DICompileUnit *CU : M->debug_compile_units()) {
+  for (const DICompileUnit *CU : TheModule->debug_compile_units()) {
     LLVM_DEBUG({
-      dbgs() << "\nDICompileUnit:\n";
-      CU->dump();
+      dbgs() << "\nCU: ";
+      CU->dump(TheModule);
     });
 
-    // Record if the current source language is Fortran.
-    mapFortranLanguage(CU->getSourceLanguage().getUnversionedName());
-
     CompileUnit = static_cast<LVScopeCompileUnit *>(constructElement(CU));
     CUNode = const_cast<DICompileUnit *>(CU);
 
@@ -2036,6 +2209,18 @@ Error LVIRReader::createScopes() {
 
     Root->addElement(CompileUnit);
 
+    uint16_t LanguageName = CU->getSourceLanguage().getUnversionedName();
+    LVSourceLanguage SL =
+        TheModule->getCodeViewFlag()
+            ? LVSourceLanguage(
+                  static_cast<llvm::codeview::SourceLanguage>(LanguageName))
+            : LVSourceLanguage(
+                  static_cast<llvm::dwarf::SourceLanguage>(LanguageName));
+    setDefaultLowerBound(&SL);
+
+    if (options().getAttributeLanguage())
+      CompileUnit->setSourceLanguage(SL);
+
     if (options().getAttributeProducer())
       CompileUnit->setProducer(CU->getProducer());
 
@@ -2072,21 +2257,23 @@ Error LVIRReader::createScopes() {
     dbgs() << "\nFunctions\n";
     for (Function &F : M->getFunctionList())
       if (const auto *SP = cast_or_null<DISubprogram>(F.getSubprogram()))
-        SP->dump();
+        SP->dump(TheModule);
   });
 
   for (Function &F : M->getFunctionList())
-    if (const auto *SP = cast_or_null<DISubprogram>(F.getSubprogram()))
-      processBasicBlocks(F, SP);
+    processBasicBlocks(F);
 
   // Perform extra tasks on the created scopes.
+  resolveInlinedLexicalScopes();
   removeEmptyScopes();
+
   processLocationGaps();
   processScopes();
 
   if (options().getInternalIntegrity())
     checkScopes(CompileUnit);
 
+  TheModule = nullptr;
   return Error::success();
 }
 
@@ -2109,12 +2296,12 @@ void LVIRReader::constructRange(LVScope *Scope, LVAddress LowPC,
         Scope->getIsFunction() && !Scope->getIsInlinedFunction())
       CompileUnit->addPublicName(Scope, LowPC, HighPC);
   }
-  addSectionRange(SectionIndex, Scope, LowPC, HighPC);
+  addSectionRange(/*SectionIndex=*/0, Scope, LowPC, HighPC);
 
   // Replicate DWARF reader funtionality of processing DW_AT_ranges for
   // the compilation unit.
   CompileUnit->addObject(LowPC, HighPC);
-  addSectionRange(SectionIndex, CompileUnit, LowPC, HighPC);
+  addSectionRange(/*SectionIndex=*/0, CompileUnit, LowPC, HighPC);
 }
 
 // Create the location ranges for the given scope and in the case of
@@ -2182,8 +2369,7 @@ void LVIRReader::constructRange(LVScope *Scope) {
 // The '--internal=id' is turned on just for debugging traces. Then
 // it is turned to its previous state.
 void LVIRReader::removeEmptyScopes() {
-  // Preserve current setting for '--internal=id'.
-  bool InternalID = options().getInternalID();
+  LLVM_DEBUG({ dbgs() << "\n[removeEmptyScopes]\n"; });
 
   SmallVector<LVScope *> EmptyScopes;
 
@@ -2252,17 +2438,147 @@ void LVIRReader::removeEmptyScopes() {
     }
   };
 
+  // Preserve current setting for '--internal=id'.
+  bool InternalID = options().getInternalID();
+  options().setInternalID();
+
+  LLVM_DEBUG({
+    dbgs() << "\nBefore - RemoveEmptyScopes\n";
+    printCollectedElements(Root);
+  });
+
   TraverseScope(CompileUnit);
   DeleteEmptyScopes();
 
+  LLVM_DEBUG({
+    dbgs() << "\nAfter - RemoveEmptyScopes\n";
+    printCollectedElements(Root);
+  });
+
   // Restore setting for '--internal=id'.
-  if (InternalID)
-    options().setInternalID();
+  if (!InternalID)
+    options().resetInternalID();
+}
+
+// The IR generated by Clang, allocates the inlined lexical scopes
+// at the enclosing function level. Move them to the correct scope.
+void LVIRReader::resolveInlinedLexicalScopes() {
+  LLVM_DEBUG({ dbgs() << "\n[resolveInlinedLexicalScopes]\n"; });
+  LLVM_DEBUG({ dumpInlinedInfo("Before", /*Full=*/false); });
+
+  std::function<void(LVScope * Scope)> TraverseChildren = [&](LVScope *Parent) {
+    LLVM_DEBUG({
+      dbgs() << "\nParent Scope: ";
+      Parent->dumpCommon();
+    });
+
+    // Get associated inlined scopes for the parent scope.
+    LVList &ParentInlinedList = getInlinedList(Parent);
+
+    // Check if the inlined scope parent is in the ParentInlinedList.
+    auto CheckInlinedScope = [&](LVList &ScopeInlinedList) -> bool {
+      bool Matched = true;
+      for (auto &InlinedScope : ScopeInlinedList) {
+        LLVM_DEBUG({
+          dbgs() << "Inlined Scope:  ";
+          InlinedScope->dumpCommon();
+        });
+        LVScope *ParentScope = InlinedScope->getParentScope();
+        for (auto &ParentInlinedScope : ParentInlinedList) {
+          if (ParentInlinedScope != ParentScope) {
+            // If the parent for the inlined scope is not the Parent Inlined
+            // list, it means the lexical scope is incorrect.
+            // Stop the traversal as the other inlined scopes will have the
+            // same problem as they were created from the same original scope.
+            LLVM_DEBUG({
+              dbgs() << "\nIncorrect parent scope\n";
+              dbgs() << "ParentInlinedScope: ";
+              ParentInlinedScope->dumpCommon();
+              dbgs() << "ParentScope: ";
+              ParentScope->dumpCommon();
+              dbgs() << "\n";
+            });
+            Matched = false;
+            break;
+          }
+        }
+        if (!Matched)
+          break;
+      }
+      return Matched;
+    };
+
+    // Adjust the inlined scopes based on the ParentInlinedList.
+    auto AdjustInlinedScope = [&](LVList &ScopeInlinedList) {
+      assert(ScopeInlinedList.size() == ParentInlinedList.size() &&
+             "Scope list do not have same number of items.");
+
+      LLVM_DEBUG({ dbgs() << "Begin scope adjustment\n"; });
+      LVScope *CurrentParent = nullptr;
+      LVScope *TargetParent = nullptr;
+      LVScope *InlinedScope = nullptr;
+      auto ItInlined = ScopeInlinedList.begin();
+      auto ItParent = ParentInlinedList.begin();
+      while (ItInlined != ScopeInlinedList.end()) {
+        TargetParent = *ItParent;
+        InlinedScope = *ItInlined;
+        CurrentParent = InlinedScope->getParentScope();
+
+        LLVM_DEBUG({
+          dbgs() << "Target Parent:  ";
+          TargetParent->dumpCommon();
+          dbgs() << "Current Parent: ";
+          CurrentParent->dumpCommon();
+          dbgs() << "Inlined:        ";
+          InlinedScope->dumpCommon();
+        });
+
+        // Correct lexical scope.
+        if (CurrentParent->removeElement(InlinedScope)) {
+          TargetParent->addElement(InlinedScope);
+          InlinedScope->updateLevel(TargetParent, /*Moved=*/false);
+        }
+        ++ItInlined;
+        ++ItParent;
+      }
+      LLVM_DEBUG({ dbgs() << "End scope adjustment\n"; });
+    };
+
+    // Traverse the scope children.
+    if (const LVScopes *Children = Parent->getScopes())
+      for (LVScope *Scope : *Children) {
+        LLVM_DEBUG({
+          dbgs() << "\nOrigin Scope: ";
+          Scope->dumpCommon();
+        });
+
+        // Get associated inlined scopes for the scope.
+        LVList &ScopeInlinedList = getInlinedList(Scope);
+        if (!CheckInlinedScope(ScopeInlinedList)) {
+          // AdjustInlinedScope to the correct lexical scope.
+          AdjustInlinedScope(ScopeInlinedList);
+        }
+        TraverseChildren(Scope);
+      }
+  };
+
+  // Traverse the origin scopes and for each function scope, analyze their
+  // associated inlined scopes to see if they have to be move to their
+  // correct lexical scope.
+  for (auto &Entry : InlinedList) {
+    LVScope *OriginScope = Entry.first;
+    if (OriginScope->getIsFunction())
+      TraverseChildren(OriginScope);
+  }
+
+  LLVM_DEBUG({ dumpInlinedInfo("After", /*Full=*/false); });
 }
 
-// During the IR Reader development, traverse all the logical elements
-// to check if they have been properly constructed (finalized).
+// During the IR-to-logical-view construction, traverse all the logical
+// elements to check if they have been properly constructed (finalized).
 void LVIRReader::checkScopes(LVScope *Scope) {
+  LLVM_DEBUG({ dbgs() << "\n[checkScopes]\n"; });
+
   auto PrintElement = [](LVElement *Element) {
     LLVM_DEBUG({
       dwarf::Tag Tag = Element->getTag();
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
index 7d200e4f681ac..174994af9eb50 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test
@@ -38,7 +38,7 @@
 ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
 
 ; ONE:      Logical View:
-; ONE-NEXT: [000]           {File} 'pr-44884-clang.ll' -> Textual IR
+; ONE-NEXT: [000]           {File} 'pr-44884-clang.ll' -> LLVM IR
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 20{{.*}}'
@@ -124,7 +124,7 @@
 ; TWO-NEXT: [003]     4     {TypeAlias} 'INT' -> 'int'
 ; TWO-EMPTY:
 ; TWO-NEXT: Logical View:
-; TWO-NEXT: [000]           {File} 'pr-44884-clang.ll' -> Textual IR
+; TWO-NEXT: [000]           {File} 'pr-44884-clang.ll' -> LLVM IR
 ; TWO-EMPTY:
 ; TWO-NEXT: [001]           {CompileUnit} 'pr-44884.cpp'
 ; TWO-NEXT: [003]     7     {TypeAlias} 'FLOAT' -> 'float'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test
index 811065437b02f..ff1b1545a2e16 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test
@@ -70,7 +70,7 @@
 ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
 
 ; TWO:      Logical View:
-; TWO-NEXT: [000]           {File} 'pr-46466-clang.ll' -> Textual IR
+; TWO-NEXT: [000]           {File} 'pr-46466-clang.ll' -> LLVM IR
 ; TWO-EMPTY:
 ; TWO-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
 ; TWO-EMPTY:
@@ -112,7 +112,7 @@
 ; THREE-NEXT: Total            4          0
 ; THREE-EMPTY:
 ; THREE-NEXT: Logical View:
-; THREE-NEXT: [000]           {File} 'pr-46466-clang.ll' -> Textual IR
+; THREE-NEXT: [000]           {File} 'pr-46466-clang.ll' -> LLVM IR
 ; THREE-EMPTY:
 ; THREE-NEXT: [001]           {CompileUnit} 'pr-46466.cpp'
 ; THREE-EMPTY:
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test
index cd7150d4608a9..4dee9959ecbe7 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test
@@ -95,7 +95,7 @@
 ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
 
 ; TWO:      Logical View:
-; TWO-NEXT: [000]           {File} 'pr-43860-clang.ll' -> Textual IR
+; TWO-NEXT: [000]           {File} 'pr-43860-clang.ll' -> LLVM IR
 ; TWO-EMPTY:
 ; TWO-NEXT: [001]           {CompileUnit} 'pr-43860.cpp'
 ; TWO-NEXT: [004]           {Variable} 'Var_1' -> 'int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
index c3abfefe5a7e3..3f6db431a676c 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test
@@ -25,10 +25,11 @@
 ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
 
 ; ONE:      Logical View:
-; ONE-NEXT: [0x0000000000][000]            {File} '{{.*}}test-clang{{.*}}.ll' -> Textual IR
+; ONE-NEXT: [0x0000000000][000]            {File} '{{.*}}test-clang{{.*}}.ll' -> LLVM IR
 ; ONE-EMPTY:
 ; ONE-NEXT: [0x0000000004][001]              {CompileUnit} 'test.cpp'
 ; ONE-NEXT: [0x0000000004][002]                {Producer} 'clang version 20{{.*}}'
+; ONE-NEXT: [0x0000000004][002]                {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT:                                    {Directory} '{{.*}}/general'
 ; ONE-NEXT:                                    {File} 'test.cpp'
 ; ONE-NEXT:                                    {Public} 'foo' [0x0000000000:0x0000000023]
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/08-ir-multiple-compile-units.test b/llvm/test/tools/llvm-debuginfo-analyzer/IR/08-ir-multiple-compile-units.test
new file mode 100644
index 0000000000000..62a980a9ce606
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/08-ir-multiple-compile-units.test
@@ -0,0 +1,165 @@
+; REQUIRES: x86-registered-target
+
+; Test case 8 - Multiple compile units.
+
+; Using the following input files:
+
+; unit-1.cpp
+; 1 int Var_1 = 1;
+; 2 int foo_1(int P1) {
+; 3   int V1 = P1;
+; 4   return V1 + Var_1;
+; 5 }
+; 6
+; 7 void f1() {
+; 8   foo_1(111);
+; 9 }
+
+; unit-2.cpp
+; 1 int Var_2 = 1;
+; 2 int foo_2(int P2) {
+; 3   int V2 = P2;
+; 4   return V2 + Var_2;
+; 5 }
+; 6
+; 7 void f2() {
+; 8   foo_2(222);
+; 9 }
+
+; unit-3.cpp
+; 1 int Var_3 = 1;
+; 2 int foo_3(int P3) {
+; 3   int V3 = P3;
+; 4   return V3 + Var_3;
+; 5 }
+; 6
+; 7 void f3() {
+; 8   foo_3(333);
+; 9 }
+
+; unit.cpp
+; 1 void f1();
+; 2 void f2();
+; 3 void f3();
+; 4
+; 5 void foo() {
+; 6   f1();
+; 7   f2();
+; 8   f3();
+; 9 }
+
+; Generate a combined IR (bitcode) and print its basic details.
+; The following command prints basic details for all the logical-- elements
+; sorted by the debug information internal offset; it includes its lexical
+; level and debug info format.
+
+; Generate individual bitcode files
+; RUN: llvm-as %p/Inputs/unit-1.ll -o %t.unit-1.bc
+; RUN: llvm-as %p/Inputs/unit-2.ll -o %t.unit-2.bc
+; RUN: llvm-as %p/Inputs/unit-3.ll -o %t.unit-3.bc
+; RUN: llvm-as %p/Inputs/unit.ll   -o %t.unit.bc
+
+; Combine the individual bitcode files
+; RUN: llvm-link %t.unit-1.bc %t.unit-2.bc %t.unit-3.bc %t.unit.bc -o %t.unit-combined.bc
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=offset \
+; RUN:                         --print=scopes,symbols,types,lines,instructions \
+; RUN:                         %t.unit-combined.bc 2>&1 > %t.unit-combined.view
+
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s < %t.unit-combined.view
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} '{{.*}}unit-combined.bc' -> Bitcode IR
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'unit-1.cpp'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo_1' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'P1' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'V1' -> 'int'
+; ONE-NEXT: [003]     2           {Line}
+; ONE-NEXT: [003]                 {Code} '%P1.addr = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} '%V1 = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} 'store i32 %P1, ptr %P1.addr, align 4'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} '%0 = load i32, ptr %P1.addr, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'store i32 %0, ptr %V1, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%1 = load i32, ptr %V1, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%2 = load i32, ptr @Var_1, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%add = add nsw i32 %1, %2, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret i32 %add, !dbg !{{.*}}'
+; ONE-NEXT: [002]     7         {Function} extern not_inlined 'f1' -> 'void'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} '%call = call noundef i32 @_Z5foo_1i(i32 noundef 111), !dbg !{{.*}}'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret void, !dbg !{{.*}}'
+; ONE-NEXT: [002]     1         {Variable} extern 'Var_1' -> 'int'
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'unit-2.cpp'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo_2' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'P2' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'V2' -> 'int'
+; ONE-NEXT: [003]     2           {Line}
+; ONE-NEXT: [003]                 {Code} '%P2.addr = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} '%V2 = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} 'store i32 %P2, ptr %P2.addr, align 4'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} '%0 = load i32, ptr %P2.addr, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'store i32 %0, ptr %V2, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%1 = load i32, ptr %V2, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%2 = load i32, ptr @Var_2, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%add = add nsw i32 %1, %2, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret i32 %add, !dbg !{{.*}}'
+; ONE-NEXT: [002]     7         {Function} extern not_inlined 'f2' -> 'void'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} '%call = call noundef i32 @_Z5foo_2i(i32 noundef 222), !dbg !{{.*}}'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret void, !dbg !{{.*}}'
+; ONE-NEXT: [002]     1         {Variable} extern 'Var_2' -> 'int'
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'unit-3.cpp'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo_3' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'P3' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'V3' -> 'int'
+; ONE-NEXT: [003]     2           {Line}
+; ONE-NEXT: [003]                 {Code} '%P3.addr = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} '%V3 = alloca i32, align 4'
+; ONE-NEXT: [003]                 {Code} 'store i32 %P3, ptr %P3.addr, align 4'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} '%0 = load i32, ptr %P3.addr, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'store i32 %0, ptr %V3, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%1 = load i32, ptr %V3, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%2 = load i32, ptr @Var_3, align 4, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} '%add = add nsw i32 %1, %2, !dbg !{{.*}}'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret i32 %add, !dbg !{{.*}}'
+; ONE-NEXT: [002]     7         {Function} extern not_inlined 'f3' -> 'void'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} '%call = call noundef i32 @_Z5foo_3i(i32 noundef 333), !dbg !{{.*}}'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret void, !dbg !{{.*}}'
+; ONE-NEXT: [002]     1         {Variable} extern 'Var_3' -> 'int'
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'unit.cpp'
+; ONE-NEXT: [002]     5         {Function} extern not_inlined 'foo' -> 'void'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [003]                 {Code} 'call void @_Z2f1v(), !dbg !{{.*}}'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'call void @_Z2f2v(), !dbg !{{.*}}'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} 'call void @_Z2f3v(), !dbg !{{.*}}'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} 'ret void, !dbg !{{.*}}'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-1.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-1.ll
new file mode 100644
index 0000000000000..5dfdb03711691
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-1.ll
@@ -0,0 +1,58 @@
+source_filename = "unit-1.cpp"
+target triple = "x86_64-unknown-linux"
+
+ at Var_1 = dso_local global i32 1, align 4, !dbg !0
+
+define dso_local noundef i32 @_Z5foo_1i(i32 noundef %P1) !dbg !14 {
+entry:
+  %P1.addr = alloca i32, align 4
+  %V1 = alloca i32, align 4
+  store i32 %P1, ptr %P1.addr, align 4
+    #dbg_declare(ptr %P1.addr, !18, !DIExpression(), !19)
+    #dbg_declare(ptr %V1, !20, !DIExpression(), !21)
+  %0 = load i32, ptr %P1.addr, align 4, !dbg !22
+  store i32 %0, ptr %V1, align 4, !dbg !21
+  %1 = load i32, ptr %V1, align 4, !dbg !23
+  %2 = load i32, ptr @Var_1, align 4, !dbg !24
+  %add = add nsw i32 %1, %2, !dbg !25
+  ret i32 %add, !dbg !26
+}
+
+define dso_local void @_Z2f1v() !dbg !27 {
+entry:
+  %call = call noundef i32 @_Z5foo_1i(i32 noundef 111), !dbg !30
+  ret void, !dbg !31
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!6, !7, !8}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "Var_1", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 23.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "unit-1.cpp", directory: "", checksumkind: CSK_MD5, checksum: "13624fbfa5a73fa5a878920cde9f37b6")
+!4 = !{!0}
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!6 = !{i32 7, !"Dwarf Version", i32 5}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{!"clang version 23.0.0"}
+!14 = distinct !DISubprogram(name: "foo_1", linkageName: "_Z5foo_1i", scope: !3, file: !3, line: 2, type: !15, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !17)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!5, !5}
+!17 = !{}
+!18 = !DILocalVariable(name: "P1", arg: 1, scope: !14, file: !3, line: 2, type: !5)
+!19 = !DILocation(line: 2, column: 15, scope: !14)
+!20 = !DILocalVariable(name: "V1", scope: !14, file: !3, line: 3, type: !5)
+!21 = !DILocation(line: 3, column: 7, scope: !14)
+!22 = !DILocation(line: 3, column: 12, scope: !14)
+!23 = !DILocation(line: 4, column: 10, scope: !14)
+!24 = !DILocation(line: 4, column: 15, scope: !14)
+!25 = !DILocation(line: 4, column: 13, scope: !14)
+!26 = !DILocation(line: 4, column: 3, scope: !14)
+!27 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !3, file: !3, line: 7, type: !28, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!28 = !DISubroutineType(types: !29)
+!29 = !{null}
+!30 = !DILocation(line: 8, column: 3, scope: !27)
+!31 = !DILocation(line: 9, column: 1, scope: !27)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-2.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-2.ll
new file mode 100644
index 0000000000000..c4a6e4840f099
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-2.ll
@@ -0,0 +1,58 @@
+source_filename = "unit-2.cpp"
+target triple = "x86_64-unknown-linux"
+
+ at Var_2 = dso_local global i32 1, align 4, !dbg !0
+
+define dso_local noundef i32 @_Z5foo_2i(i32 noundef %P2) !dbg !14 {
+entry:
+  %P2.addr = alloca i32, align 4
+  %V2 = alloca i32, align 4
+  store i32 %P2, ptr %P2.addr, align 4
+    #dbg_declare(ptr %P2.addr, !18, !DIExpression(), !19)
+    #dbg_declare(ptr %V2, !20, !DIExpression(), !21)
+  %0 = load i32, ptr %P2.addr, align 4, !dbg !22
+  store i32 %0, ptr %V2, align 4, !dbg !21
+  %1 = load i32, ptr %V2, align 4, !dbg !23
+  %2 = load i32, ptr @Var_2, align 4, !dbg !24
+  %add = add nsw i32 %1, %2, !dbg !25
+  ret i32 %add, !dbg !26
+}
+
+define dso_local void @_Z2f2v() !dbg !27 {
+entry:
+  %call = call noundef i32 @_Z5foo_2i(i32 noundef 222), !dbg !30
+  ret void, !dbg !31
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!6, !7, !8}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "Var_2", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 23.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "unit-2.cpp", directory: "", checksumkind: CSK_MD5, checksum: "dd97ef1e977b3c5b03e5686f919327a5")
+!4 = !{!0}
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!6 = !{i32 7, !"Dwarf Version", i32 5}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{!"clang version 23.0.0"}
+!14 = distinct !DISubprogram(name: "foo_2", linkageName: "_Z5foo_2i", scope: !3, file: !3, line: 2, type: !15, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !17)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!5, !5}
+!17 = !{}
+!18 = !DILocalVariable(name: "P2", arg: 1, scope: !14, file: !3, line: 2, type: !5)
+!19 = !DILocation(line: 2, column: 15, scope: !14)
+!20 = !DILocalVariable(name: "V2", scope: !14, file: !3, line: 3, type: !5)
+!21 = !DILocation(line: 3, column: 7, scope: !14)
+!22 = !DILocation(line: 3, column: 12, scope: !14)
+!23 = !DILocation(line: 4, column: 10, scope: !14)
+!24 = !DILocation(line: 4, column: 15, scope: !14)
+!25 = !DILocation(line: 4, column: 13, scope: !14)
+!26 = !DILocation(line: 4, column: 3, scope: !14)
+!27 = distinct !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !3, file: !3, line: 7, type: !28, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!28 = !DISubroutineType(types: !29)
+!29 = !{null}
+!30 = !DILocation(line: 8, column: 3, scope: !27)
+!31 = !DILocation(line: 9, column: 1, scope: !27)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-3.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-3.ll
new file mode 100644
index 0000000000000..9e98281270e9c
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit-3.ll
@@ -0,0 +1,58 @@
+source_filename = "unit-3.cpp"
+target triple = "x86_64-unknown-linux"
+
+ at Var_3 = dso_local global i32 1, align 4, !dbg !0
+
+define dso_local noundef i32 @_Z5foo_3i(i32 noundef %P3) !dbg !14 {
+entry:
+  %P3.addr = alloca i32, align 4
+  %V3 = alloca i32, align 4
+  store i32 %P3, ptr %P3.addr, align 4
+    #dbg_declare(ptr %P3.addr, !18, !DIExpression(), !19)
+    #dbg_declare(ptr %V3, !20, !DIExpression(), !21)
+  %0 = load i32, ptr %P3.addr, align 4, !dbg !22
+  store i32 %0, ptr %V3, align 4, !dbg !21
+  %1 = load i32, ptr %V3, align 4, !dbg !23
+  %2 = load i32, ptr @Var_3, align 4, !dbg !24
+  %add = add nsw i32 %1, %2, !dbg !25
+  ret i32 %add, !dbg !26
+}
+
+define dso_local void @_Z2f3v() !dbg !27 {
+entry:
+  %call = call noundef i32 @_Z5foo_3i(i32 noundef 333), !dbg !30
+  ret void, !dbg !31
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!6, !7, !8}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "Var_3", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 23.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "unit-3.cpp", directory: "", checksumkind: CSK_MD5, checksum: "fcd53200d3096d44f8a8308b6ed33c23")
+!4 = !{!0}
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!6 = !{i32 7, !"Dwarf Version", i32 5}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{!"clang version 23.0.0"}
+!14 = distinct !DISubprogram(name: "foo_3", linkageName: "_Z5foo_3i", scope: !3, file: !3, line: 2, type: !15, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !17)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!5, !5}
+!17 = !{}
+!18 = !DILocalVariable(name: "P3", arg: 1, scope: !14, file: !3, line: 2, type: !5)
+!19 = !DILocation(line: 2, column: 15, scope: !14)
+!20 = !DILocalVariable(name: "V3", scope: !14, file: !3, line: 3, type: !5)
+!21 = !DILocation(line: 3, column: 7, scope: !14)
+!22 = !DILocation(line: 3, column: 12, scope: !14)
+!23 = !DILocation(line: 4, column: 10, scope: !14)
+!24 = !DILocation(line: 4, column: 15, scope: !14)
+!25 = !DILocation(line: 4, column: 13, scope: !14)
+!26 = !DILocation(line: 4, column: 3, scope: !14)
+!27 = distinct !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !3, file: !3, line: 7, type: !28, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!28 = !DISubroutineType(types: !29)
+!29 = !{null}
+!30 = !DILocation(line: 8, column: 3, scope: !27)
+!31 = !DILocation(line: 9, column: 1, scope: !27)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit.ll b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit.ll
new file mode 100644
index 0000000000000..75802a14abb9a
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/unit.ll
@@ -0,0 +1,34 @@
+source_filename = "unit.cpp"
+target triple = "x86_64-unknown-linux"
+
+define dso_local void @_Z3foov() !dbg !10 {
+entry:
+  call void @_Z2f1v(), !dbg !13
+  call void @_Z2f2v(), !dbg !14
+  call void @_Z2f3v(), !dbg !15
+  ret void, !dbg !16
+}
+
+declare void @_Z2f1v()
+
+declare void @_Z2f2v()
+
+declare void @_Z2f3v()
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 23.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "unit.cpp", directory: "", checksumkind: CSK_MD5, checksum: "d340f597b69d89b7c542f22ce3d36231")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!9 = !{!"clang version 23.0.0"}
+!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 5, type: !11, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !DILocation(line: 6, column: 3, scope: !10)
+!14 = !DILocation(line: 7, column: 3, scope: !10)
+!15 = !DILocation(line: 8, column: 3, scope: !10)
+!16 = !DILocation(line: 9, column: 1, scope: !10)
diff --git a/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
index c1b9b806a7cd1..6dd4973627e91 100644
--- a/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp
@@ -67,7 +67,7 @@ void checkElementProperties(LVReader *Reader) {
   LVScopeRoot *Root = Reader->getScopesRoot();
   LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
 
-  EXPECT_EQ(Root->getFileFormatName(), "Textual IR");
+  EXPECT_EQ(Root->getFileFormatName(), "LLVM IR");
   EXPECT_EQ(Root->getName(), IrClang);
 
   EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
@@ -349,7 +349,7 @@ TEST(LogicalViewTest, IRReader) {
   TT.setOS(Triple::UnknownOS);
 
   std::string TargetLookupError;
-  if (!TargetRegistry::lookupTarget(std::string(TT.str()), TargetLookupError))
+  if (!TargetRegistry::lookupTarget(TT, TargetLookupError))
     GTEST_SKIP();
 
   SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0);
diff --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/README.md b/llvm/unittests/DebugInfo/LogicalView/Inputs/README.md
index e42c361fd980a..e3d1d27ebb77a 100644
--- a/llvm/unittests/DebugInfo/LogicalView/Inputs/README.md
+++ b/llvm/unittests/DebugInfo/LogicalView/Inputs/README.md
@@ -46,7 +46,7 @@ It is generated by the "lib.exe" tool shipped with MSVC compiler.
 
 ```lib.exe /OUT:test-codeview-msvc.lib test-codeview-msvc.o```
 
-# IR Textual representation and bitcode files (Linux):
+# IR textual representation (.ll) and bitcode (.bc) files (x86_64-unknown-linux):
 
 ## test-clang.ll
 
@@ -55,4 +55,5 @@ It is generated by the "lib.exe" tool shipped with MSVC compiler.
 ## test-clang.bc
 
 ```clang --target=x86_64-linux -S -w -emit-llvm -g test.cpp -o test-clang.ll```
+
 ```llvm-as test-clang.ll -o test-clang.bc```



More information about the llvm-commits mailing list