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

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 7 06:35:43 PDT 2025


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

>From d8333fde3e861163a27f37302a732028e94c6584 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Mon, 7 Apr 2025 12:07:21 +0100
Subject: [PATCH 1/2] [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/134055
---
 .../CommandGuide/llvm-debuginfo-analyzer.rst  |  169 +-
 .../DebugInfo/LogicalView/Core/LVReader.h     |   26 +-
 .../DebugInfo/LogicalView/Core/LVSupport.h    |   13 +
 .../DebugInfo/LogicalView/LVReaderHandler.h   |   12 +-
 .../LogicalView/Readers/LVBinaryReader.h      |   12 +-
 .../LogicalView/Readers/LVDWARFReader.h       |   10 -
 .../LogicalView/Readers/LVIRReader.h          |  300 +++
 llvm/lib/DebugInfo/LogicalView/CMakeLists.txt |    2 +
 .../DebugInfo/LogicalView/Core/LVElement.cpp  |   12 +-
 .../DebugInfo/LogicalView/Core/LVReader.cpp   |  271 ++
 .../DebugInfo/LogicalView/LVReaderHandler.cpp |   45 +-
 .../LogicalView/Readers/LVBinaryReader.cpp    |   24 -
 .../LogicalView/Readers/LVDWARFReader.cpp     |  224 +-
 .../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 +
 35 files changed, 5025 insertions(+), 283 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 60fa024db5e99..c5d3293c02f57 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
@@ -2124,6 +2125,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
@@ -2197,6 +2330,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/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index 9ce26398e48df..c848ea44f63a7 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -56,7 +56,7 @@ class LVSplitContext final {
 
 /// The logical reader owns of all the logical elements created during
 /// the debug information parsing. For its creation it uses a specific
-///  bump allocator for each type of logical element.
+/// bump allocator for each type of logical element.
 class LVReader {
   LVBinaryType BinaryType;
 
@@ -121,7 +121,24 @@ class LVReader {
 
 #undef LV_OBJECT_ALLOCATOR
 
+  // Scopes with ranges for current compile unit. It is used to find a line
+  // giving its exact or closest address. To support comdat functions, all
+  // addresses for the same section are recorded in the same map.
+  using LVSectionRanges = std::map<LVSectionIndex, std::unique_ptr<LVRange>>;
+  LVSectionRanges SectionRanges;
+
 protected:
+  // Current elements during the processing of a DIE/MDNode.
+  LVElement *CurrentElement = nullptr;
+  LVScope *CurrentScope = nullptr;
+  LVSymbol *CurrentSymbol = nullptr;
+  LVType *CurrentType = nullptr;
+  LVLine *CurrentLine = nullptr;
+  LVOffset CurrentOffset = 0;
+
+  // Address ranges collected for current DIE/MDNode/AST Node.
+  std::vector<LVAddressRange> CurrentRanges;
+
   LVScopeRoot *Root = nullptr;
   std::string InputFilename;
   std::string FileFormatName;
@@ -132,11 +149,18 @@ class LVReader {
   // Only for ELF format. The CodeView is handled in a different way.
   LVSectionIndex DotTextSectionIndex = UndefinedSectionIndex;
 
+  void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope);
+  void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope,
+                       LVAddress LowerAddress, LVAddress UpperAddress);
+  LVRange *getSectionRanges(LVSectionIndex SectionIndex);
+
   // Record Compilation Unit entry.
   void addCompileUnitOffset(LVOffset Offset, LVScopeCompileUnit *CompileUnit) {
     CompileUnits.emplace(Offset, CompileUnit);
   }
 
+  LVElement *createElement(dwarf::Tag Tag);
+
   // Create the Scope Root.
   virtual Error createScopes() {
     Root = createScopeRoot();
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
index 8269344fe6efe..28f6dbcf4e2ae 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -99,6 +99,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 bf30501d00c1f..cbc5b031b8e65 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/MemoryBuffer.h"
@@ -29,7 +30,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,
@@ -60,9 +63,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 9cda64e33ddf7..bd897a9944bf7 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 {
@@ -93,12 +94,6 @@ class LVBinaryReader : public LVReader {
       SectionAddresses.emplace(Section.getAddress(), Section);
   }
 
-  // Scopes with ranges for current compile unit. It is used to find a line
-  // giving its exact or closest address. To support comdat functions, all
-  // addresses for the same section are recorded in the same map.
-  using LVSectionRanges = std::map<LVSectionIndex, std::unique_ptr<LVRange>>;
-  LVSectionRanges SectionRanges;
-
   // Image base and virtual address for Executable file.
   uint64_t ImageBaseAddress = 0;
   uint64_t VirtualAddress = 0;
@@ -179,11 +174,6 @@ class LVBinaryReader : public LVReader {
   Expected<std::pair<LVSectionIndex, object::SectionRef>>
   getSection(LVScope *Scope, LVAddress Address, LVSectionIndex SectionIndex);
 
-  void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope);
-  void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope,
-                       LVAddress LowerAddress, LVAddress UpperAddress);
-  LVRange *getSectionRanges(LVSectionIndex SectionIndex);
-
   void includeInlineeLines(LVSectionIndex SectionIndex, LVScope *Function);
 
   Error createInstructions();
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
index fdc97249d8e5a..3fb099924b5f2 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
@@ -39,12 +39,6 @@ class LVDWARFReader final : public LVBinaryReader {
   LVAddress CUBaseAddress = 0;
   LVAddress CUHighAddress = 0;
 
-  // Current elements during the processing of a DIE.
-  LVElement *CurrentElement = nullptr;
-  LVScope *CurrentScope = nullptr;
-  LVSymbol *CurrentSymbol = nullptr;
-  LVType *CurrentType = nullptr;
-  LVOffset CurrentOffset = 0;
   LVOffset CurrentEndOffset = 0;
 
   // In DWARF v4, the files are 1-indexed.
@@ -52,9 +46,6 @@ class LVDWARFReader final : public LVBinaryReader {
   // The DWARF reader expects the indexes as 1-indexed.
   bool IncrementFileIndex = false;
 
-  // Address ranges collected for current DIE.
-  std::vector<LVAddressRange> CurrentRanges;
-
   // Symbols with locations for current compile unit.
   LVSymbols SymbolsWithLocations;
 
@@ -82,7 +73,6 @@ class LVDWARFReader final : public LVBinaryReader {
 
   void mapRangeAddress(const object::ObjectFile &Obj) override;
 
-  LVElement *createElement(dwarf::Tag Tag);
   void traverseDieAndChildren(DWARFDie &DIE, LVScope *Parent,
                               DWARFDie &SkeletonDie);
   // Process the attributes for the given DIE.
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 f5adab723927a..06401f6d88eca 100644
--- a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
@@ -25,6 +25,7 @@ add_lv_impl_folder(Readers
   Readers/LVCodeViewReader.cpp
   Readers/LVCodeViewVisitor.cpp
   Readers/LVDWARFReader.cpp
+  Readers/LVIRReader.cpp
   )
 
 list(APPEND LIBLV_ADDITIONAL_HEADER_DIRS
@@ -40,6 +41,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 c3f1d6843957f..bb1e5dcfc67ab 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;
@@ -195,6 +222,250 @@ StringRef LVReader::getFilename(LVObject *Object, size_t Index) const {
   return CompileUnit ? CompileUnit->getFilename(Index) : StringRef();
 }
 
+void LVReader::addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope) {
+  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
+  ScopesWithRanges->addEntry(Scope);
+}
+
+void LVReader::addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope,
+                               LVAddress LowerAddress, LVAddress UpperAddress) {
+  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
+  ScopesWithRanges->addEntry(Scope, LowerAddress, UpperAddress);
+}
+
+LVRange *LVReader::getSectionRanges(LVSectionIndex SectionIndex) {
+  // Check if we already have a mapping for this section index.
+  LVSectionRanges::iterator IterSection = SectionRanges.find(SectionIndex);
+  if (IterSection == SectionRanges.end())
+    IterSection =
+        SectionRanges.emplace(SectionIndex, std::make_unique<LVRange>()).first;
+  LVRange *Range = IterSection->second.get();
+  assert(Range && "Range is null.");
+  return Range;
+}
+
+LVElement *LVReader::createElement(dwarf::Tag Tag) {
+  CurrentScope = nullptr;
+  CurrentSymbol = nullptr;
+  CurrentType = nullptr;
+  CurrentRanges.clear();
+
+  LLVM_DEBUG(
+      { dbgs() << "\n[createElement] " << dwarf::TagString(Tag) << "\n"; });
+
+  if (!options().getPrintSymbols()) {
+    switch (Tag) {
+    // As the command line options did not specify a request to print
+    // logical symbols (--print=symbols or --print=all or --print=elements),
+    // skip its creation.
+    case dwarf::DW_TAG_formal_parameter:
+    case dwarf::DW_TAG_unspecified_parameters:
+    case dwarf::DW_TAG_member:
+    case dwarf::DW_TAG_variable:
+    case dwarf::DW_TAG_inheritance:
+    case dwarf::DW_TAG_constant:
+    case dwarf::DW_TAG_call_site_parameter:
+    case dwarf::DW_TAG_GNU_call_site_parameter:
+      return nullptr;
+    default:
+      break;
+    }
+  }
+
+  switch (Tag) {
+  // Types.
+  case dwarf::DW_TAG_base_type:
+    CurrentType = createType();
+    CurrentType->setIsBase();
+    if (options().getAttributeBase())
+      CurrentType->setIncludeInPrint();
+    return CurrentType;
+  case dwarf::DW_TAG_const_type:
+    CurrentType = createType();
+    CurrentType->setIsConst();
+    CurrentType->setName("const");
+    return CurrentType;
+  case dwarf::DW_TAG_enumerator:
+    CurrentType = createTypeEnumerator();
+    return CurrentType;
+  case dwarf::DW_TAG_imported_declaration:
+    CurrentType = createTypeImport();
+    CurrentType->setIsImportDeclaration();
+    return CurrentType;
+  case dwarf::DW_TAG_imported_module:
+    CurrentType = createTypeImport();
+    CurrentType->setIsImportModule();
+    return CurrentType;
+  case dwarf::DW_TAG_pointer_type:
+    CurrentType = createType();
+    CurrentType->setIsPointer();
+    CurrentType->setName("*");
+    return CurrentType;
+  case dwarf::DW_TAG_ptr_to_member_type:
+    CurrentType = createType();
+    CurrentType->setIsPointerMember();
+    CurrentType->setName("*");
+    return CurrentType;
+  case dwarf::DW_TAG_reference_type:
+    CurrentType = createType();
+    CurrentType->setIsReference();
+    CurrentType->setName("&");
+    return CurrentType;
+  case dwarf::DW_TAG_restrict_type:
+    CurrentType = createType();
+    CurrentType->setIsRestrict();
+    CurrentType->setName("restrict");
+    return CurrentType;
+  case dwarf::DW_TAG_rvalue_reference_type:
+    CurrentType = createType();
+    CurrentType->setIsRvalueReference();
+    CurrentType->setName("&&");
+    return CurrentType;
+  case dwarf::DW_TAG_subrange_type:
+    CurrentType = createTypeSubrange();
+    return CurrentType;
+  case dwarf::DW_TAG_template_value_parameter:
+    CurrentType = createTypeParam();
+    CurrentType->setIsTemplateValueParam();
+    return CurrentType;
+  case dwarf::DW_TAG_template_type_parameter:
+    CurrentType = createTypeParam();
+    CurrentType->setIsTemplateTypeParam();
+    return CurrentType;
+  case dwarf::DW_TAG_GNU_template_template_param:
+    CurrentType = createTypeParam();
+    CurrentType->setIsTemplateTemplateParam();
+    return CurrentType;
+  case dwarf::DW_TAG_typedef:
+    CurrentType = createTypeDefinition();
+    return CurrentType;
+  case dwarf::DW_TAG_unspecified_type:
+    CurrentType = createType();
+    CurrentType->setIsUnspecified();
+    return CurrentType;
+  case dwarf::DW_TAG_volatile_type:
+    CurrentType = createType();
+    CurrentType->setIsVolatile();
+    CurrentType->setName("volatile");
+    return CurrentType;
+
+  // Symbols.
+  case dwarf::DW_TAG_formal_parameter:
+    CurrentSymbol = createSymbol();
+    CurrentSymbol->setIsParameter();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_unspecified_parameters:
+    CurrentSymbol = createSymbol();
+    CurrentSymbol->setIsUnspecified();
+    CurrentSymbol->setName("...");
+    return CurrentSymbol;
+  case dwarf::DW_TAG_member:
+    CurrentSymbol = createSymbol();
+    CurrentSymbol->setIsMember();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_variable:
+    CurrentSymbol = createSymbol();
+    CurrentSymbol->setIsVariable();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_inheritance:
+    CurrentSymbol = createSymbol();
+    CurrentSymbol->setIsInheritance();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_call_site_parameter:
+  case dwarf::DW_TAG_GNU_call_site_parameter:
+    CurrentSymbol = createSymbol();
+    CurrentSymbol->setIsCallSiteParameter();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_constant:
+    CurrentSymbol = createSymbol();
+    CurrentSymbol->setIsConstant();
+    return CurrentSymbol;
+
+  // Scopes.
+  case dwarf::DW_TAG_catch_block:
+    CurrentScope = createScope();
+    CurrentScope->setIsCatchBlock();
+    return CurrentScope;
+  case dwarf::DW_TAG_lexical_block:
+    CurrentScope = createScope();
+    CurrentScope->setIsLexicalBlock();
+    return CurrentScope;
+  case dwarf::DW_TAG_try_block:
+    CurrentScope = createScope();
+    CurrentScope->setIsTryBlock();
+    return CurrentScope;
+  case dwarf::DW_TAG_compile_unit:
+  case dwarf::DW_TAG_skeleton_unit:
+    CurrentScope = createScopeCompileUnit();
+    CompileUnit = static_cast<LVScopeCompileUnit *>(CurrentScope);
+    return CurrentScope;
+  case dwarf::DW_TAG_inlined_subroutine:
+    CurrentScope = createScopeFunctionInlined();
+    return CurrentScope;
+  case dwarf::DW_TAG_namespace:
+    CurrentScope = createScopeNamespace();
+    return CurrentScope;
+  case dwarf::DW_TAG_template_alias:
+    CurrentScope = createScopeAlias();
+    return CurrentScope;
+  case dwarf::DW_TAG_array_type:
+    CurrentScope = createScopeArray();
+    return CurrentScope;
+  case dwarf::DW_TAG_call_site:
+  case dwarf::DW_TAG_GNU_call_site:
+    CurrentScope = createScopeFunction();
+    CurrentScope->setIsCallSite();
+    return CurrentScope;
+  case dwarf::DW_TAG_entry_point:
+    CurrentScope = createScopeFunction();
+    CurrentScope->setIsEntryPoint();
+    return CurrentScope;
+  case dwarf::DW_TAG_subprogram:
+    CurrentScope = createScopeFunction();
+    CurrentScope->setIsSubprogram();
+    return CurrentScope;
+  case dwarf::DW_TAG_subroutine_type:
+    CurrentScope = createScopeFunctionType();
+    return CurrentScope;
+  case dwarf::DW_TAG_label:
+    CurrentScope = createScopeFunction();
+    CurrentScope->setIsLabel();
+    return CurrentScope;
+  case dwarf::DW_TAG_class_type:
+    CurrentScope = createScopeAggregate();
+    CurrentScope->setIsClass();
+    return CurrentScope;
+  case dwarf::DW_TAG_structure_type:
+    CurrentScope = createScopeAggregate();
+    CurrentScope->setIsStructure();
+    return CurrentScope;
+  case dwarf::DW_TAG_union_type:
+    CurrentScope = createScopeAggregate();
+    CurrentScope->setIsUnion();
+    return CurrentScope;
+  case dwarf::DW_TAG_enumeration_type:
+    CurrentScope = createScopeEnumeration();
+    return CurrentScope;
+  case dwarf::DW_TAG_GNU_formal_parameter_pack:
+    CurrentScope = createScopeFormalPack();
+    return CurrentScope;
+  case dwarf::DW_TAG_GNU_template_parameter_pack:
+    CurrentScope = createScopeTemplatePack();
+    return CurrentScope;
+  default:
+    // Collect TAGs not implemented.
+    if (options().getInternalTag() && Tag)
+      CompileUnit->addDebugTag(Tag, CurrentOffset);
+    break;
+  }
+
+  LLVM_DEBUG({
+    dbgs() << "DWARF Tag not implemented: " << dwarf::TagString(Tag) << "\n";
+  });
+
+  return nullptr;
+}
+
 // The Reader is the module that creates the logical view using the debug
 // information contained in the binary file specified in the command line.
 // This is the main entry point for the Reader and performs the following
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/LVBinaryReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
index ad14baa0c9269..9b86bdfe88f1f 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
@@ -367,30 +367,6 @@ LVBinaryReader::getSection(LVScope *Scope, LVAddress Address,
   return std::make_pair(Iter->first, Iter->second);
 }
 
-void LVBinaryReader::addSectionRange(LVSectionIndex SectionIndex,
-                                     LVScope *Scope) {
-  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
-  ScopesWithRanges->addEntry(Scope);
-}
-
-void LVBinaryReader::addSectionRange(LVSectionIndex SectionIndex,
-                                     LVScope *Scope, LVAddress LowerAddress,
-                                     LVAddress UpperAddress) {
-  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
-  ScopesWithRanges->addEntry(Scope, LowerAddress, UpperAddress);
-}
-
-LVRange *LVBinaryReader::getSectionRanges(LVSectionIndex SectionIndex) {
-  // Check if we already have a mapping for this section index.
-  LVSectionRanges::iterator IterSection = SectionRanges.find(SectionIndex);
-  if (IterSection == SectionRanges.end())
-    IterSection =
-        SectionRanges.emplace(SectionIndex, std::make_unique<LVRange>()).first;
-  LVRange *Range = IterSection->second.get();
-  assert(Range && "Range is null.");
-  return Range;
-}
-
 Error LVBinaryReader::createInstructions(LVScope *Scope,
                                          LVSectionIndex SectionIndex,
                                          const LVNameInfo &NameInfo) {
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
index 42da957233667..bb1e87ae9b67c 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
@@ -28,220 +28,6 @@ using namespace llvm::logicalview;
 
 #define DEBUG_TYPE "DWARFReader"
 
-LVElement *LVDWARFReader::createElement(dwarf::Tag Tag) {
-  CurrentScope = nullptr;
-  CurrentSymbol = nullptr;
-  CurrentType = nullptr;
-  CurrentRanges.clear();
-
-  if (!options().getPrintSymbols()) {
-    switch (Tag) {
-    // As the command line options did not specify a request to print
-    // logical symbols (--print=symbols or --print=all or --print=elements),
-    // skip its creation.
-    case dwarf::DW_TAG_formal_parameter:
-    case dwarf::DW_TAG_unspecified_parameters:
-    case dwarf::DW_TAG_member:
-    case dwarf::DW_TAG_variable:
-    case dwarf::DW_TAG_inheritance:
-    case dwarf::DW_TAG_constant:
-    case dwarf::DW_TAG_call_site_parameter:
-    case dwarf::DW_TAG_GNU_call_site_parameter:
-      return nullptr;
-    default:
-      break;
-    }
-  }
-
-  switch (Tag) {
-  // Types.
-  case dwarf::DW_TAG_base_type:
-    CurrentType = createType();
-    CurrentType->setIsBase();
-    if (options().getAttributeBase())
-      CurrentType->setIncludeInPrint();
-    return CurrentType;
-  case dwarf::DW_TAG_const_type:
-    CurrentType = createType();
-    CurrentType->setIsConst();
-    CurrentType->setName("const");
-    return CurrentType;
-  case dwarf::DW_TAG_enumerator:
-    CurrentType = createTypeEnumerator();
-    return CurrentType;
-  case dwarf::DW_TAG_imported_declaration:
-    CurrentType = createTypeImport();
-    CurrentType->setIsImportDeclaration();
-    return CurrentType;
-  case dwarf::DW_TAG_imported_module:
-    CurrentType = createTypeImport();
-    CurrentType->setIsImportModule();
-    return CurrentType;
-  case dwarf::DW_TAG_pointer_type:
-    CurrentType = createType();
-    CurrentType->setIsPointer();
-    CurrentType->setName("*");
-    return CurrentType;
-  case dwarf::DW_TAG_ptr_to_member_type:
-    CurrentType = createType();
-    CurrentType->setIsPointerMember();
-    CurrentType->setName("*");
-    return CurrentType;
-  case dwarf::DW_TAG_reference_type:
-    CurrentType = createType();
-    CurrentType->setIsReference();
-    CurrentType->setName("&");
-    return CurrentType;
-  case dwarf::DW_TAG_restrict_type:
-    CurrentType = createType();
-    CurrentType->setIsRestrict();
-    CurrentType->setName("restrict");
-    return CurrentType;
-  case dwarf::DW_TAG_rvalue_reference_type:
-    CurrentType = createType();
-    CurrentType->setIsRvalueReference();
-    CurrentType->setName("&&");
-    return CurrentType;
-  case dwarf::DW_TAG_subrange_type:
-    CurrentType = createTypeSubrange();
-    return CurrentType;
-  case dwarf::DW_TAG_template_value_parameter:
-    CurrentType = createTypeParam();
-    CurrentType->setIsTemplateValueParam();
-    return CurrentType;
-  case dwarf::DW_TAG_template_type_parameter:
-    CurrentType = createTypeParam();
-    CurrentType->setIsTemplateTypeParam();
-    return CurrentType;
-  case dwarf::DW_TAG_GNU_template_template_param:
-    CurrentType = createTypeParam();
-    CurrentType->setIsTemplateTemplateParam();
-    return CurrentType;
-  case dwarf::DW_TAG_typedef:
-    CurrentType = createTypeDefinition();
-    return CurrentType;
-  case dwarf::DW_TAG_unspecified_type:
-    CurrentType = createType();
-    CurrentType->setIsUnspecified();
-    return CurrentType;
-  case dwarf::DW_TAG_volatile_type:
-    CurrentType = createType();
-    CurrentType->setIsVolatile();
-    CurrentType->setName("volatile");
-    return CurrentType;
-
-  // Symbols.
-  case dwarf::DW_TAG_formal_parameter:
-    CurrentSymbol = createSymbol();
-    CurrentSymbol->setIsParameter();
-    return CurrentSymbol;
-  case dwarf::DW_TAG_unspecified_parameters:
-    CurrentSymbol = createSymbol();
-    CurrentSymbol->setIsUnspecified();
-    CurrentSymbol->setName("...");
-    return CurrentSymbol;
-  case dwarf::DW_TAG_member:
-    CurrentSymbol = createSymbol();
-    CurrentSymbol->setIsMember();
-    return CurrentSymbol;
-  case dwarf::DW_TAG_variable:
-    CurrentSymbol = createSymbol();
-    CurrentSymbol->setIsVariable();
-    return CurrentSymbol;
-  case dwarf::DW_TAG_inheritance:
-    CurrentSymbol = createSymbol();
-    CurrentSymbol->setIsInheritance();
-    return CurrentSymbol;
-  case dwarf::DW_TAG_call_site_parameter:
-  case dwarf::DW_TAG_GNU_call_site_parameter:
-    CurrentSymbol = createSymbol();
-    CurrentSymbol->setIsCallSiteParameter();
-    return CurrentSymbol;
-  case dwarf::DW_TAG_constant:
-    CurrentSymbol = createSymbol();
-    CurrentSymbol->setIsConstant();
-    return CurrentSymbol;
-
-  // Scopes.
-  case dwarf::DW_TAG_catch_block:
-    CurrentScope = createScope();
-    CurrentScope->setIsCatchBlock();
-    return CurrentScope;
-  case dwarf::DW_TAG_lexical_block:
-    CurrentScope = createScope();
-    CurrentScope->setIsLexicalBlock();
-    return CurrentScope;
-  case dwarf::DW_TAG_try_block:
-    CurrentScope = createScope();
-    CurrentScope->setIsTryBlock();
-    return CurrentScope;
-  case dwarf::DW_TAG_compile_unit:
-  case dwarf::DW_TAG_skeleton_unit:
-    CurrentScope = createScopeCompileUnit();
-    CompileUnit = static_cast<LVScopeCompileUnit *>(CurrentScope);
-    return CurrentScope;
-  case dwarf::DW_TAG_inlined_subroutine:
-    CurrentScope = createScopeFunctionInlined();
-    return CurrentScope;
-  case dwarf::DW_TAG_namespace:
-    CurrentScope = createScopeNamespace();
-    return CurrentScope;
-  case dwarf::DW_TAG_template_alias:
-    CurrentScope = createScopeAlias();
-    return CurrentScope;
-  case dwarf::DW_TAG_array_type:
-    CurrentScope = createScopeArray();
-    return CurrentScope;
-  case dwarf::DW_TAG_call_site:
-  case dwarf::DW_TAG_GNU_call_site:
-    CurrentScope = createScopeFunction();
-    CurrentScope->setIsCallSite();
-    return CurrentScope;
-  case dwarf::DW_TAG_entry_point:
-    CurrentScope = createScopeFunction();
-    CurrentScope->setIsEntryPoint();
-    return CurrentScope;
-  case dwarf::DW_TAG_subprogram:
-    CurrentScope = createScopeFunction();
-    CurrentScope->setIsSubprogram();
-    return CurrentScope;
-  case dwarf::DW_TAG_subroutine_type:
-    CurrentScope = createScopeFunctionType();
-    return CurrentScope;
-  case dwarf::DW_TAG_label:
-    CurrentScope = createScopeFunction();
-    CurrentScope->setIsLabel();
-    return CurrentScope;
-  case dwarf::DW_TAG_class_type:
-    CurrentScope = createScopeAggregate();
-    CurrentScope->setIsClass();
-    return CurrentScope;
-  case dwarf::DW_TAG_structure_type:
-    CurrentScope = createScopeAggregate();
-    CurrentScope->setIsStructure();
-    return CurrentScope;
-  case dwarf::DW_TAG_union_type:
-    CurrentScope = createScopeAggregate();
-    CurrentScope->setIsUnion();
-    return CurrentScope;
-  case dwarf::DW_TAG_enumeration_type:
-    CurrentScope = createScopeEnumeration();
-    return CurrentScope;
-  case dwarf::DW_TAG_GNU_formal_parameter_pack:
-    CurrentScope = createScopeFormalPack();
-    return CurrentScope;
-  case dwarf::DW_TAG_GNU_template_parameter_pack:
-    CurrentScope = createScopeTemplatePack();
-    return CurrentScope;
-  default:
-    // Collect TAGs not implemented.
-    if (options().getInternalTag() && Tag)
-      CompileUnit->addDebugTag(Tag, CurrentOffset);
-    break;
-  }
-  return nullptr;
-}
-
 void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
                                         LVOffset *OffsetPtr,
                                         const AttributeSpec &AttrSpec) {
@@ -728,14 +514,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..dbb284bff2e67
--- /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 undef 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) {
+    DbgValueRanges->printValues(DVA, dbgs());
+    DILocalVariable *LV = const_cast<DILocalVariable *>(DVA.getVariable());
+    LVSymbol *Symbol = getSymbolForSeenMD(LV);
+    // Undef 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 9119cf6fb602c419c2a64b307a0fa115f76efe96 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Mon, 7 Apr 2025 14:30:48 +0100
Subject: [PATCH 2/2] [llvm-debuginfo-analyzer] Add support for LLVM IR format.

Fix code formatter issues:
- 'undef' deprecator.
- clang-format issue.
---
 llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h | 6 +++---
 llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp     | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
index cbc5b031b8e65..c743e517e371b 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
@@ -30,9 +30,9 @@ namespace logicalview {
 
 using LVReaders = std::vector<std::unique_ptr<LVReader>>;
 using ArgVector = std::vector<std::string>;
-using PdbOrObjOrIr = PointerUnion<object::ObjectFile *, pdb::PDBFile *,
-                                  object::IRObjectFile *, MemoryBufferRef *,
-                                  StringRef *>;
+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,
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index dbb284bff2e67..2ecce08544c66 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -1923,7 +1923,7 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
       SeenVars.push_back(DVA);
     }
 
-    // Skip undef values.
+    // Skip Undefined values.
     if (!DbgVar->isKillLocation())
       getOrCreateVariable(DbgVar->getVariable(), DbgVar->getDebugLoc().get());
 
@@ -1966,7 +1966,7 @@ void LVIRReader::processBasicBlocks(Function &F, const DISubprogram *SP) {
     DbgValueRanges->printValues(DVA, dbgs());
     DILocalVariable *LV = const_cast<DILocalVariable *>(DVA.getVariable());
     LVSymbol *Symbol = getSymbolForSeenMD(LV);
-    // Undef only value, ignore.
+    // Undefined only value, ignore.
     if (!Symbol)
       continue;
 



More information about the llvm-commits mailing list