[llvm] e98a4c5 - [llvm-debuginfo-analyzer] (07/09) - Compare elements

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 24 00:29:45 PDT 2022


Author: Carlos Alberto Enciso
Date: 2022-10-24T08:27:06+01:00
New Revision: e98a4c5acb378bdaae5f7aeb747bd27146f45191

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

LOG: [llvm-debuginfo-analyzer] (07/09) - Compare elements

llvm-debuginfo-analyzer is a command line tool that processes debug
info contained in a binary file and produces a debug information
format agnostic “Logical View”, which is a high-level semantic
representation of the debug info, independent of the low-level
format.

The code has been divided into the following patches:

1) Interval tree
2) Driver and documentation
3) Logical elements
4) Locations and ranges
5) Select elements
6) Warning and internal options
7) Compare elements
8) ELF Reader
9) CodeView Reader

Full details:
https://discourse.llvm.org/t/llvm-dev-rfc-llvm-dva-debug-information-visual-analyzer/62570

This patch:

Compare elements
- Support for logical elements comparison. See '--compare' options.
  LVCompare

Reviewed By: psamolysov, probinson

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

Added: 
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVCompare.h
    llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp
    llvm/unittests/DebugInfo/LogicalView/CompareElementsTest.cpp

Modified: 
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
    llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
    llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
    llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVCompare.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVCompare.h
new file mode 100644
index 0000000000000..4019ea6f17448
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVCompare.h
@@ -0,0 +1,89 @@
+//===-- LVCompare.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 LVCompare class, which is used to describe a logical
+// view comparison.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVCOMPARE_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVCOMPARE_H
+
+#include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
+
+namespace llvm {
+namespace logicalview {
+
+class LVReader;
+
+// Record the elements missing or added and their compare pass.
+using LVPassEntry = std::tuple<LVReader *, LVElement *, LVComparePass>;
+using LVPassTable = std::vector<LVPassEntry>;
+
+class LVCompare final {
+  raw_ostream &OS;
+  LVScopes ScopeStack;
+
+  // As the comparison is performed twice (by exchanging the reference
+  // and target readers) the element missing/added status does specify
+  // the comparison pass.
+  // By recording each missing/added elements along with its pass, it
+  // allows checking which elements were missing/added during each pass.
+  LVPassTable PassTable;
+
+  // Reader used on the LHS of the comparison.
+  // In the 'Missing' pass, it points to the reference reader.
+  // In the 'Added' pass it points to the target reader.
+  LVReader *Reader = nullptr;
+
+  bool FirstMissing = true;
+  bool PrintLines = false;
+  bool PrintScopes = false;
+  bool PrintSymbols = false;
+  bool PrintTypes = false;
+
+  static void setInstance(LVCompare *Compare);
+
+  void printCurrentStack();
+  void printSummary() const;
+
+public:
+  LVCompare() = delete;
+  LVCompare(raw_ostream &OS);
+  LVCompare(const LVCompare &) = delete;
+  LVCompare &operator=(const LVCompare &) = delete;
+  ~LVCompare() = default;
+
+  static LVCompare &getInstance();
+
+  // Scopes stack used during the missing/added reporting.
+  void push(LVScope *Scope) { ScopeStack.push_back(Scope); }
+  void pop() { ScopeStack.pop_back(); }
+
+  // Perform comparison between the 'Reference' and 'Target' scopes tree.
+  Error execute(LVReader *ReferenceReader, LVReader *TargetReader);
+
+  void addPassEntry(LVReader *Reader, LVElement *Element, LVComparePass Pass) {
+    PassTable.emplace_back(Reader, Element, Pass);
+  }
+  const LVPassTable &getPassTable() const & { return PassTable; }
+
+  void printItem(LVElement *Element, LVComparePass Pass);
+  void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const { print(dbgs()); }
+#endif
+};
+
+inline LVCompare &getComparator() { return LVCompare::getInstance(); }
+
+} // end namespace logicalview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVCOMPARE_H

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index bde8f670ac7c0..2603c4542e8dc 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -336,6 +336,14 @@ class LVElement : public LVObject {
   virtual void resolveReferences() {}
   void resolveParents();
 
+  bool referenceMatch(const LVElement *Element) const;
+
+  // Returns true if current element is logically equal to the given 'Element'.
+  bool equals(const LVElement *Element) const;
+
+  // Report the current element as missing or added during comparison.
+  virtual void report(LVComparePass Pass) {}
+
   static LVElementDispatch &getDispatch() { return Dispatch; }
 };
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
index c925b414b6f8c..c335c34e372b9 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
@@ -42,6 +42,9 @@ class LVLine : public LVElement {
   LVProperties<LVLineKind> Kinds;
   static LVLineDispatch Dispatch;
 
+  // Find the current line in the given 'Targets'.
+  LVLine *findIn(const LVLines *Targets) const;
+
 public:
   LVLine() : LVElement(LVSubclassID::LV_LINE) {
     setIsLine();
@@ -83,6 +86,22 @@ class LVLine : public LVElement {
 
   static LVLineDispatch &getDispatch() { return Dispatch; }
 
+  // Iterate through the 'References' set and check that all its elements
+  // are present in the 'Targets' set. For a missing element, mark its
+  // parents as missing.
+  static void markMissingParents(const LVLines *References,
+                                 const LVLines *Targets);
+
+  // Returns true if current line is logically equal to the given 'Line'.
+  virtual bool equals(const LVLine *Line) const;
+
+  // Returns true if the given 'References' are logically equal to the
+  // given 'Targets'.
+  static bool equals(const LVLines *References, const LVLines *Targets);
+
+  // Report the current line as missing or added during comparison.
+  void report(LVComparePass Pass) override;
+
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override {}
 
@@ -114,6 +133,9 @@ class LVLineDebug final : public LVLine {
     setIsDiscriminator();
   }
 
+  // Returns true if current line is logically equal to the given 'Line'.
+  bool equals(const LVLine *Line) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -130,6 +152,9 @@ class LVLineAssembler final : public LVLine {
     return std::string(8, ' ');
   };
 
+  // Returns true if current line is logically equal to the given 'Line'.
+  bool equals(const LVLine *Line) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
index e08111828a5c5..bc368d9eaa794 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
@@ -101,6 +101,7 @@ using LVOffsets = SmallVector<LVOffset, 8>;
 const LVAddress MaxAddress = std::numeric_limits<uint64_t>::max();
 
 enum class LVBinaryType { NONE, ELF, COFF };
+enum class LVComparePass { Missing, Added };
 
 // Validate functions.
 using LVValidLocation = bool (LVLocation::*)();
@@ -319,6 +320,9 @@ class LVObject {
                        LVObject *Parent, StringRef Value,
                        bool UseQuotes = false, bool PrintRef = false) const;
 
+  // Mark branch as missing (current element and parents).
+  void markBranchAsMissing();
+
   // Prints the common information for an object (name, type, etc).
   virtual void print(raw_ostream &OS, bool Full = true) const;
   // Prints additional information for an object, depending on its kind

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index c5d71867282dc..06bb983debb57 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -61,6 +61,12 @@ class LVReader {
   using LVCompileUnits = std::map<LVOffset, LVScopeCompileUnit *>;
   LVCompileUnits CompileUnits;
 
+  // Added elements to be used during elements comparison.
+  LVLines Lines;
+  LVScopes Scopes;
+  LVSymbols Symbols;
+  LVTypes Types;
+
   // Create split folder.
   Error createSplitFolder();
   bool OutputSplit = false;
@@ -140,6 +146,29 @@ class LVReader {
   // Access to split context.
   LVSplitContext &getSplitContext() { return SplitContext; }
 
+  // In the case of element comparison, register that added element.
+  void notifyAddedElement(LVLine *Line) {
+    if (!options().getCompareContext() && options().getCompareLines())
+      Lines.push_back(Line);
+  }
+  void notifyAddedElement(LVScope *Scope) {
+    if (!options().getCompareContext() && options().getCompareScopes())
+      Scopes.push_back(Scope);
+  }
+  void notifyAddedElement(LVSymbol *Symbol) {
+    if (!options().getCompareContext() && options().getCompareSymbols())
+      Symbols.push_back(Symbol);
+  }
+  void notifyAddedElement(LVType *Type) {
+    if (!options().getCompareContext() && options().getCompareTypes())
+      Types.push_back(Type);
+  }
+
+  const LVLines &getLines() const { return Lines; }
+  const LVScopes &getScopes() const { return Scopes; }
+  const LVSymbols &getSymbols() const { return Symbols; }
+  const LVTypes &getTypes() const { return Types; }
+
   // Conditions to print an object.
   bool doPrintLine(const LVLine *Line) const {
     return patterns().printElement(Line);

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index a3268d260cf7f..01a560479aa39 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -101,6 +101,9 @@ class LVScope : public LVElement {
   // only-globals, only-locals, a-pattern.
   bool resolvePrinting() const;
 
+  // Find the current scope in the given 'Targets'.
+  LVScope *findIn(const LVScopes *Targets) const;
+
   // Traverse the scope parent tree, executing the given callback function
   // on each scope.
   void traverseParents(LVScopeGetFunction GetFunction,
@@ -249,6 +252,10 @@ class LVScope : public LVElement {
   // DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension.
   virtual LVScope *getReference() const { return nullptr; }
 
+  LVScope *getCompileUnitParent() const override {
+    return LVElement::getCompileUnitParent();
+  }
+
   // Follow a chain of references given by DW_AT_abstract_origin and/or
   // DW_AT_specification and update the scope name.
   StringRef resolveReferencesChain();
@@ -268,6 +275,35 @@ class LVScope : public LVElement {
 
   void resolveElements();
 
+  // Iterate through the 'References' set and check that all its elements
+  // are present in the 'Targets' set. For a missing element, mark its
+  // parents as missing.
+  static void markMissingParents(const LVScopes *References,
+                                 const LVScopes *Targets,
+                                 bool TraverseChildren);
+
+  // Checks if the current scope is contained within the target scope.
+  // Depending on the result, the callback may be performed.
+  virtual void markMissingParents(const LVScope *Target, bool TraverseChildren);
+
+  // Returns true if the current scope and the given 'Scope' have the
+  // same number of children.
+  virtual bool equalNumberOfChildren(const LVScope *Scope) const;
+
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  virtual bool equals(const LVScope *Scope) const;
+
+  // Returns true if the given 'References' are logically equal to the
+  // given 'Targets'.
+  static bool equals(const LVScopes *References, const LVScopes *Targets);
+
+  // For the given 'Scopes' returns a scope that is logically equal
+  // to the current scope; otherwise 'nullptr'.
+  virtual LVScope *findEqualScope(const LVScopes *Scopes) const;
+
+  // Report the current scope as missing or added during comparison.
+  void report(LVComparePass Pass) override;
+
   static LVScopeDispatch &getDispatch() { return Dispatch; }
 
   void print(raw_ostream &OS, bool Full = true) const override;
@@ -308,6 +344,13 @@ class LVScopeAggregate final : public LVScope {
     EncodedArgsIndex = getStringPool().getIndex(EncodedArgs);
   }
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
+  // For the given 'Scopes' returns a scope that is logically equal
+  // to the current scope; otherwise 'nullptr'.
+  LVScope *findEqualScope(const LVScopes *Scopes) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -322,6 +365,9 @@ class LVScopeAlias final : public LVScope {
   LVScopeAlias &operator=(const LVScopeAlias &) = delete;
   ~LVScopeAlias() = default;
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -335,6 +381,9 @@ class LVScopeArray final : public LVScope {
 
   void resolveExtra() override;
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -510,7 +559,7 @@ class LVScopeCompileUnit final : public LVScope {
 
   // A new element has been added to the scopes tree. Take the following steps:
   // Increase the added element counters, for printing summary.
-  // Notify the Reader if element comparison.
+  // During comparison notify the Reader of the new element.
   void addedElement(LVLine *Line);
   void addedElement(LVScope *Scope);
   void addedElement(LVSymbol *Symbol);
@@ -518,6 +567,9 @@ class LVScopeCompileUnit final : public LVScope {
 
   void addSize(LVScope *Scope, LVOffset Lower, LVOffset Upper);
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
   void printWarnings(raw_ostream &OS, bool Full = true) const override;
@@ -532,6 +584,9 @@ class LVScopeEnumeration final : public LVScope {
   LVScopeEnumeration &operator=(const LVScopeEnumeration &) = delete;
   ~LVScopeEnumeration() = default;
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -544,6 +599,9 @@ class LVScopeFormalPack final : public LVScope {
   LVScopeFormalPack &operator=(const LVScopeFormalPack &) = delete;
   ~LVScopeFormalPack() = default;
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -589,6 +647,13 @@ class LVScopeFunction : public LVScope {
   void resolveExtra() override;
   void resolveReferences() override;
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
+  // For the given 'Scopes' returns a scope that is logically equal
+  // to the current scope; otherwise 'nullptr'.
+  LVScope *findEqualScope(const LVScopes *Scopes) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -625,6 +690,13 @@ class LVScopeFunctionInlined final : public LVScopeFunction {
 
   void resolveExtra() override;
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
+  // For the given 'Scopes' returns a scope that is logically equal
+  // to the current scope; otherwise 'nullptr'.
+  LVScope *findEqualScope(const LVScopes *Scopes) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -659,6 +731,13 @@ class LVScopeNamespace final : public LVScope {
     setReference(static_cast<LVScope *>(Element));
   }
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
+  // For the given 'Scopes' returns a scope that is logically equal
+  // to the current scope; otherwise 'nullptr'.
+  LVScope *findEqualScope(const LVScopes *Scopes) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -682,6 +761,9 @@ class LVScopeRoot final : public LVScope {
   // Process the collected location, ranges and calculate coverage.
   void processRangeInformation();
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
   Error doPrintMatches(bool Split, raw_ostream &OS,
@@ -697,6 +779,9 @@ class LVScopeTemplatePack final : public LVScope {
   LVScopeTemplatePack &operator=(const LVScopeTemplatePack &) = delete;
   ~LVScopeTemplatePack() = default;
 
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
index 15ac6fc4a4dcc..b9628e3127849 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
@@ -63,6 +63,9 @@ class LVSymbol final : public LVElement {
   LVAutoLocations::iterator addLocationGap(LVAutoLocations::iterator Pos,
                                            LVAddress LowPC, LVAddress HighPC);
 
+  // Find the current symbol in the given 'Targets'.
+  LVSymbol *findIn(const LVSymbols *Targets) const;
+
 public:
   LVSymbol() : LVElement(LVSubclassID::LV_SYMBOL) {
     setIsSymbol();
@@ -157,6 +160,27 @@ class LVSymbol final : public LVElement {
 
   static LVSymbolDispatch &getDispatch() { return Dispatch; }
 
+  static bool parametersMatch(const LVSymbols *References,
+                              const LVSymbols *Targets);
+
+  static void getParameters(const LVSymbols *Symbols, LVSymbols *Parameters);
+
+  // Iterate through the 'References' set and check that all its elements
+  // are present in the 'Targets' set. For a missing element, mark its
+  // parents as missing.
+  static void markMissingParents(const LVSymbols *References,
+                                 const LVSymbols *Targets);
+
+  // Returns true if current type is logically equal to the given 'Symbol'.
+  bool equals(const LVSymbol *Symbol) const;
+
+  // Returns true if the given 'References' are logically equal to the
+  // given 'Targets'.
+  static bool equals(const LVSymbols *References, const LVSymbols *Targets);
+
+  // Report the current symbol as missing or added during comparison.
+  void report(LVComparePass Pass) override;
+
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
index a56202c3bcace..4d377ce2ff878 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
@@ -56,6 +56,9 @@ class LVType : public LVElement {
   LVProperties<Property> Properties;
   static LVTypeDispatch Dispatch;
 
+  // Find the current type in the given 'Targets'.
+  LVType *findIn(const LVTypes *Targets) const;
+
 public:
   LVType() : LVElement(LVSubclassID::LV_TYPE) { setIsType(); }
   LVType(const LVType &) = delete;
@@ -111,6 +114,28 @@ class LVType : public LVElement {
 
   static LVTypeDispatch &getDispatch() { return Dispatch; }
 
+  static bool parametersMatch(const LVTypes *References,
+                              const LVTypes *Targets);
+
+  static void getParameters(const LVTypes *Types, LVTypes *TypesParam,
+                            LVScopes *ScopesParam);
+
+  // Iterate through the 'References' set and check that all its elements
+  // are present in the 'Targets' set. For a missing element, mark its
+  // parents as missing.
+  static void markMissingParents(const LVTypes *References,
+                                 const LVTypes *Targets);
+
+  // Returns true if current type is logically equal to the given 'Type'.
+  virtual bool equals(const LVType *Type) const;
+
+  // Returns true if the given 'References' are logically equal to the
+  // given 'Targets'.
+  static bool equals(const LVTypes *References, const LVTypes *Targets);
+
+  // Report the current type as missing or added during comparison.
+  void report(LVComparePass Pass) override;
+
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 
@@ -136,6 +161,9 @@ class LVTypeDefinition final : public LVType {
 
   void resolveExtra() override;
 
+  // Returns true if current type is logically equal to the given 'Type'.
+  bool equals(const LVType *Type) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -162,6 +190,9 @@ class LVTypeEnumerator final : public LVType {
   }
   size_t getValueIndex() const override { return ValueIndex; }
 
+  // Returns true if current type is logically equal to the given 'Type'.
+  bool equals(const LVType *Type) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -173,6 +204,9 @@ class LVTypeImport final : public LVType {
   LVTypeImport &operator=(const LVTypeImport &) = delete;
   ~LVTypeImport() = default;
 
+  // Returns true if current type is logically equal to the given 'Type'.
+  bool equals(const LVType *Type) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -199,6 +233,9 @@ class LVTypeParam final : public LVType {
   // Encode the specific template argument.
   void encodeTemplateArgument(std::string &Name) const override;
 
+  // Returns true if current type is logically equal to the given 'Type'.
+  bool equals(const LVType *Type) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
@@ -241,6 +278,9 @@ class LVTypeSubrange final : public LVType {
 
   void resolveExtra() override;
 
+  // Returns true if current type is logically equal to the given 'Type'.
+  bool equals(const LVType *Type) const override;
+
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 

diff  --git a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
index d4cc4546b4bb0..b6f9fb832c382 100644
--- a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
@@ -4,6 +4,7 @@ macro(add_lv_impl_folder group)
 endmacro()
 
 add_lv_impl_folder(Core
+  Core/LVCompare.cpp
   Core/LVElement.cpp
   Core/LVLine.cpp
   Core/LVLocation.cpp

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp
new file mode 100644
index 0000000000000..65baf52ffb44f
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp
@@ -0,0 +1,428 @@
+//===-- LVCompare.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 LVCompare class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include <tuple>
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Compare"
+
+namespace {
+
+enum class LVCompareItem { Scope, Symbol, Type, Line, Total };
+enum class LVCompareIndex { Header, Expected, Missing, Added };
+using LVCompareEntry = std::tuple<const char *, unsigned, unsigned, unsigned>;
+using LVCompareInfo = std::map<LVCompareItem, LVCompareEntry>;
+LVCompareInfo Results = {
+    {LVCompareItem::Line, LVCompareEntry("Lines", 0, 0, 0)},
+    {LVCompareItem::Scope, LVCompareEntry("Scopes", 0, 0, 0)},
+    {LVCompareItem::Symbol, LVCompareEntry("Symbols", 0, 0, 0)},
+    {LVCompareItem::Type, LVCompareEntry("Types", 0, 0, 0)},
+    {LVCompareItem::Total, LVCompareEntry("Total", 0, 0, 0)}};
+static LVCompareInfo::iterator IterTotal = Results.end();
+
+constexpr unsigned getHeader() {
+  return static_cast<unsigned>(LVCompareIndex::Header);
+}
+constexpr unsigned getExpected() {
+  return static_cast<unsigned>(LVCompareIndex::Expected);
+}
+constexpr unsigned getMissing() {
+  return static_cast<unsigned>(LVCompareIndex::Missing);
+}
+constexpr unsigned getAdded() {
+  return static_cast<unsigned>(LVCompareIndex::Added);
+}
+
+LVCompare *CurrentComparator = nullptr;
+
+void zeroResults() {
+  // In case the same reader instance is used.
+  for (LVCompareInfo::reference Entry : Results) {
+    std::get<getExpected()>(Entry.second) = 0;
+    std::get<getMissing()>(Entry.second) = 0;
+    std::get<getAdded()>(Entry.second) = 0;
+  }
+  IterTotal = Results.find(LVCompareItem::Total);
+  assert(IterTotal != Results.end());
+}
+
+LVCompareInfo::iterator getResultsEntry(LVElement *Element) {
+  LVCompareItem Kind;
+  if (Element->getIsLine())
+    Kind = LVCompareItem::Line;
+  else if (Element->getIsScope())
+    Kind = LVCompareItem::Scope;
+  else if (Element->getIsSymbol())
+    Kind = LVCompareItem::Symbol;
+  else
+    Kind = LVCompareItem::Type;
+
+  // Used to update the expected, missing or added entry for the given kind.
+  LVCompareInfo::iterator Iter = Results.find(Kind);
+  assert(Iter != Results.end());
+  return Iter;
+}
+
+void updateExpected(LVElement *Element) {
+  LVCompareInfo::iterator Iter = getResultsEntry(Element);
+  // Update total for expected.
+  ++std::get<getExpected()>(IterTotal->second);
+  // Update total for specific element kind.
+  ++std::get<getExpected()>(Iter->second);
+}
+
+void updateMissingOrAdded(LVElement *Element, LVComparePass Pass) {
+  LVCompareInfo::iterator Iter = getResultsEntry(Element);
+  if (Pass == LVComparePass::Missing) {
+    ++std::get<getMissing()>(IterTotal->second);
+    ++std::get<getMissing()>(Iter->second);
+  } else {
+    ++std::get<getAdded()>(IterTotal->second);
+    ++std::get<getAdded()>(Iter->second);
+  }
+}
+
+} // namespace
+
+LVCompare &LVCompare::getInstance() {
+  static LVCompare DefaultComparator(outs());
+  return CurrentComparator ? *CurrentComparator : DefaultComparator;
+}
+
+void LVCompare::setInstance(LVCompare *Comparator) {
+  CurrentComparator = Comparator;
+}
+
+LVCompare::LVCompare(raw_ostream &OS) : OS(OS) {
+  PrintLines = options().getPrintLines();
+  PrintSymbols = options().getPrintSymbols();
+  PrintTypes = options().getPrintTypes();
+  PrintScopes =
+      options().getPrintScopes() || PrintLines || PrintSymbols || PrintTypes;
+}
+
+Error LVCompare::execute(LVReader *ReferenceReader, LVReader *TargetReader) {
+  setInstance(this);
+  // In the case of added elements, the 'Reference' reader will be modified;
+  // those elements will be added to it. Update the current reader instance.
+  LVReader::setInstance(ReferenceReader);
+
+  auto PrintHeader = [this](LVScopeRoot *LHS, LVScopeRoot *RHS) {
+    LLVM_DEBUG({
+      dbgs() << "[Reference] " << LHS->getName() << "\n"
+             << "[Target] " << RHS->getName() << "\n";
+    });
+    OS << "\nReference: " << formattedName(LHS->getName()) << "\n"
+       << "Target:    " << formattedName(RHS->getName()) << "\n";
+  };
+
+  // We traverse the given scopes tree ('Reference' and 'Target') twice.
+  // The first time we look for missing items from the 'Reference' and the
+  // second time we look for items added to the 'Target'.
+  // The comparison test includes the name, lexical level, type, source
+  // location, etc.
+  LVScopeRoot *ReferenceRoot = ReferenceReader->getScopesRoot();
+  LVScopeRoot *TargetRoot = TargetReader->getScopesRoot();
+  ReferenceRoot->setIsInCompare();
+  TargetRoot->setIsInCompare();
+
+  // Reset possible previous results.
+  zeroResults();
+
+  if (options().getCompareContext()) {
+    // Perform a logical view comparison as a whole unit. We start at the
+    // root reference; at each scope an equal test is applied to its children.
+    // If a 
diff erence is found, the current path is marked as missing.
+    auto CompareViews = [this](LVScopeRoot *LHS, LVScopeRoot *RHS) -> Error {
+      LHS->markMissingParents(RHS, /*TraverseChildren=*/true);
+      if (LHS->getIsMissingLink() && options().getReportAnyView()) {
+        // As we are printing a missing tree, enable formatting.
+        options().setPrintFormatting();
+        OS << "\nMissing Tree:\n";
+        if (Error Err = LHS->doPrint(/*Split=*/false, /*Match=*/false,
+                                     /*Print=*/true, OS))
+          return Err;
+        options().resetPrintFormatting();
+      }
+
+      return Error::success();
+    };
+
+    // If the user has requested printing details for the comparison, we
+    // disable the indentation and the added/missing tags ('+'/'-'), as the
+    // details are just a list of elements.
+    options().resetPrintFormatting();
+
+    PrintHeader(ReferenceRoot, TargetRoot);
+    Reader = ReferenceReader;
+    if (Error Err = CompareViews(ReferenceRoot, TargetRoot))
+      return Err;
+    FirstMissing = true;
+    ReferenceRoot->report(LVComparePass::Missing);
+
+    PrintHeader(TargetRoot, ReferenceRoot);
+    Reader = TargetReader;
+    if (Error Err = CompareViews(TargetRoot, ReferenceRoot))
+      return Err;
+    FirstMissing = true;
+    TargetRoot->report(LVComparePass::Added);
+
+    options().setPrintFormatting();
+
+    // Display a summary with the elements missing and/or added.
+    printSummary();
+  } else {
+    // Perform logical elements comparison. An equal test is apply to each
+    // element. If a 
diff erence is found, the reference element is marked as
+    // 'missing'.
+    // The final comparison result will show the 'Reference' scopes tree,
+    // having both missing and added elements.
+    using LVScopeLink = std::map<LVScope *, LVScope *>;
+    LVScopeLink ScopeLinks;
+    auto CompareReaders = [&](LVReader *LHS, LVReader *RHS, LVElements &Set,
+                              LVComparePass Pass) -> Error {
+      auto FindMatch = [&](auto &References, auto &Targets,
+                           const char *Category) -> Error {
+        LVElements Elements;
+        for (LVElement *Reference : References) {
+          // Report elements that can be printed; ignore logical elements that
+          // have qualifiers.
+          if (Reference->getIncludeInPrint()) {
+            if (Pass == LVComparePass::Missing)
+              updateExpected(Reference);
+            Reference->setIsInCompare();
+            LVElement *CurrentTarget = nullptr;
+            if (std::any_of(Targets.begin(), Targets.end(),
+                            [&](auto Target) -> bool {
+                              CurrentTarget = Target;
+                              return Reference->equals(Target);
+                            })) {
+              if (Pass == LVComparePass::Missing && Reference->getIsScope()) {
+                // If the elements being compared are scopes and are a match,
+                // they are recorded, to be used when creating the augmented
+                // tree, as insertion points for the "added" items.
+                ScopeLinks.emplace(static_cast<LVScope *>(CurrentTarget),
+                                   static_cast<LVScope *>(Reference));
+              }
+            } else {
+              // Element is missing or added.
+              Pass == LVComparePass::Missing ? Reference->setIsMissing()
+                                             : Reference->setIsAdded();
+              Elements.push_back(Reference);
+              updateMissingOrAdded(Reference, Pass);
+              // Record missing/added element.
+              addPassEntry(Reader, Reference, Pass);
+            }
+          }
+        }
+        if (Pass == LVComparePass::Added)
+          // Record all the current missing elements for this category.
+          Set.insert(Set.end(), Elements.begin(), Elements.end());
+        if (options().getReportList()) {
+          if (Elements.size()) {
+            OS << "\n(" << Elements.size() << ") "
+               << (Pass == LVComparePass::Missing ? "Missing" : "Added") << " "
+               << Category << ":\n";
+            for (const LVElement *Element : Elements) {
+              if (Error Err = Element->doPrint(/*Split=*/false, /*Match=*/false,
+                                               /*Print=*/true, OS))
+                return Err;
+            }
+          }
+        }
+
+        return Error::success();
+      };
+
+      // First compare the scopes, so they will be inserted at the front of
+      // the missing elements list. When they are moved, their children are
+      // moved as well and no additional work is required.
+      if (options().getCompareScopes())
+        if (Error Err = FindMatch(LHS->getScopes(), RHS->getScopes(), "Scopes"))
+          return Err;
+      if (options().getCompareSymbols())
+        if (Error Err =
+                FindMatch(LHS->getSymbols(), RHS->getSymbols(), "Symbols"))
+          return Err;
+      if (options().getCompareTypes())
+        if (Error Err = FindMatch(LHS->getTypes(), RHS->getTypes(), "Types"))
+          return Err;
+      if (options().getCompareLines())
+        if (Error Err = FindMatch(LHS->getLines(), RHS->getLines(), "Lines"))
+          return Err;
+
+      return Error::success();
+    };
+
+    // If the user has requested printing details for the comparison, we
+    // disable the indentation and the added/missing tags ('+'/'-'), as the
+    // details are just a list of elements.
+    options().resetPrintFormatting();
+
+    PrintHeader(ReferenceRoot, TargetRoot);
+    // Include the root in the expected count.
+    updateExpected(ReferenceRoot);
+
+    LVElements ElementsToAdd;
+    Reader = ReferenceReader;
+    if (Error Err = CompareReaders(ReferenceReader, TargetReader, ElementsToAdd,
+                                   LVComparePass::Missing))
+      return Err;
+    Reader = TargetReader;
+    if (Error Err = CompareReaders(TargetReader, ReferenceReader, ElementsToAdd,
+                                   LVComparePass::Added))
+      return Err;
+
+    LLVM_DEBUG({
+      dbgs() << "\nReference/Target Scope links:\n";
+      for (LVScopeLink::const_reference Entry : ScopeLinks)
+        dbgs() << "Source: " << hexSquareString(Entry.first->getOffset()) << " "
+               << "Destination: " << hexSquareString(Entry.second->getOffset())
+               << "\n";
+      dbgs() << "\n";
+    });
+
+    // Add the 'missing' elements from the 'Target' into the 'Reference'.
+    // First insert the missing scopes, as they include any missing children.
+    LVScope *Parent = nullptr;
+    for (LVElement *Element : ElementsToAdd) {
+      LLVM_DEBUG({
+        dbgs() << "Element to Insert: " << hexSquareString(Element->getOffset())
+               << ", Parent: "
+               << hexSquareString(Element->getParentScope()->getOffset())
+               << "\n";
+      });
+      // Skip already inserted elements. They were inserted, if their parents
+      // were missing. When inserting them, all the children are moved.
+      if (Element->getHasMoved())
+        continue;
+
+      // We need to find an insertion point in the reference scopes tree.
+      Parent = Element->getParentScope();
+      if (ScopeLinks.find(Parent) != ScopeLinks.end()) {
+        LVScope *InsertionPoint = ScopeLinks[Parent];
+        LLVM_DEBUG({
+          dbgs() << "Inserted at: "
+                 << hexSquareString(InsertionPoint->getOffset()) << "\n";
+        });
+        if (Parent->removeElement(Element)) {
+          // Be sure we have a current compile unit.
+          getReader().setCompileUnit(InsertionPoint->getCompileUnitParent());
+          InsertionPoint->addElement(Element);
+          Element->updateLevel(InsertionPoint, /*Moved=*/true);
+        }
+      }
+    }
+
+    options().setPrintFormatting();
+
+    // Display the augmented reference scopes tree.
+    if (options().getReportAnyView())
+      if (Error Err = ReferenceReader->doPrint())
+        return Err;
+
+    LLVM_DEBUG({
+      dbgs() << "\nModified Reference Reader";
+      if (Error Err = ReferenceReader->doPrint())
+        return Err;
+      dbgs() << "\nModified Target Reader";
+      if (Error Err = TargetReader->doPrint())
+        return Err;
+    });
+
+    // Display a summary with the elements missing and/or added.
+    printSummary();
+  }
+
+  return Error::success();
+}
+
+void LVCompare::printCurrentStack() {
+  for (const LVScope *Scope : ScopeStack) {
+    Scope->printAttributes(OS);
+    OS << Scope->lineNumberAsString(/*ShowZero=*/true) << " " << Scope->kind()
+       << " " << formattedName(Scope->getName()) << "\n";
+  }
+}
+
+void LVCompare::printItem(LVElement *Element, LVComparePass Pass) {
+  // Record expected, missing, added.
+  updateExpected(Element);
+  updateMissingOrAdded(Element, Pass);
+
+  // Record missing/added element.
+  if (Element->getIsMissing())
+    addPassEntry(Reader, Element, Pass);
+
+  if ((!PrintLines && Element->getIsLine()) ||
+      (!PrintScopes && Element->getIsScope()) ||
+      (!PrintSymbols && Element->getIsSymbol()) ||
+      (!PrintTypes && Element->getIsType()))
+    return;
+
+  if (Element->getIsMissing()) {
+    if (FirstMissing) {
+      OS << "\n";
+      FirstMissing = false;
+    }
+
+    StringRef Kind = Element->kind();
+    StringRef Name =
+        Element->getIsLine() ? Element->getPathname() : Element->getName();
+    StringRef Status = (Pass == LVComparePass::Missing) ? "Missing" : "Added";
+    OS << Status << " " << Kind << " '" << Name << "'";
+    if (Element->getLineNumber() > 0)
+      OS << " at line " << Element->getLineNumber();
+    OS << "\n";
+
+    if (options().getReportList()) {
+      printCurrentStack();
+      Element->printAttributes(OS);
+      OS << Element->lineNumberAsString(/*ShowZero=*/true) << " " << Kind << " "
+         << Name << "\n";
+    }
+  }
+}
+
+void LVCompare::printSummary() const {
+  if (!options().getPrintSummary())
+    return;
+  std::string Separator = std::string(40, '-');
+  auto PrintSeparator = [&]() { OS << Separator << "\n"; };
+  auto PrintHeadingRow = [&](const char *T, const char *U, const char *V,
+                             const char *W) {
+    OS << format("%-9s%9s  %9s  %9s\n", T, U, V, W);
+  };
+  auto PrintDataRow = [&](const char *T, unsigned U, unsigned V, unsigned W) {
+    OS << format("%-9s%9d  %9d  %9d\n", T, U, V, W);
+  };
+
+  OS << "\n";
+  PrintSeparator();
+  PrintHeadingRow("Element", "Expected", "Missing", "Added");
+  PrintSeparator();
+  for (LVCompareInfo::reference Entry : Results) {
+    if (Entry.first == LVCompareItem::Total)
+      PrintSeparator();
+    PrintDataRow(std::get<getHeader()>(Entry.second),
+                 std::get<getExpected()>(Entry.second),
+                 std::get<getMissing()>(Entry.second),
+                 std::get<getAdded()>(Entry.second));
+  }
+}
+
+void LVCompare::print(raw_ostream &OS) const { OS << "LVCompare\n"; }

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
index 262150a947afc..79046287595e5 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -431,6 +431,55 @@ void LVElement::resolveQualifiedName() {
   });
 }
 
+bool LVElement::referenceMatch(const LVElement *Element) const {
+  return (getHasReference() && Element->getHasReference()) ||
+         (!getHasReference() && !Element->getHasReference());
+}
+
+bool LVElement::equals(const LVElement *Element) const {
+  // The minimum factors that must be the same for an equality are:
+  // line number, level, name, qualified name and filename.
+  LLVM_DEBUG({
+    dbgs() << "\n[Element::equals]\n";
+    if (options().getAttributeOffset()) {
+      dbgs() << "Reference: " << hexSquareString(getOffset()) << "\n";
+      dbgs() << "Target   : " << hexSquareString(Element->getOffset()) << "\n";
+    }
+    dbgs() << "Reference: "
+           << "Kind = " << formattedKind(kind()) << ", "
+           << "Name = " << formattedName(getName()) << ", "
+           << "Qualified = " << formattedName(getQualifiedName()) << "\n"
+           << "Target   : "
+           << "Kind = " << formattedKind(Element->kind()) << ", "
+           << "Name = " << formattedName(Element->getName()) << ", "
+           << "Qualified = " << formattedName(Element->getQualifiedName())
+           << "\n"
+           << "Reference: "
+           << "NameIndex = " << getNameIndex() << ", "
+           << "QualifiedNameIndex = " << getQualifiedNameIndex() << ", "
+           << "FilenameIndex = " << getFilenameIndex() << "\n"
+           << "Target   : "
+           << "NameIndex = " << Element->getNameIndex() << ", "
+           << "QualifiedNameIndex = " << Element->getQualifiedNameIndex()
+           << ", "
+           << "FilenameIndex = " << Element->getFilenameIndex() << "\n";
+  });
+  if ((getLineNumber() != Element->getLineNumber()) ||
+      (getLevel() != Element->getLevel()))
+    return false;
+
+  if ((getQualifiedNameIndex() != Element->getQualifiedNameIndex()) ||
+      (getNameIndex() != Element->getNameIndex()) ||
+      (getFilenameIndex() != Element->getFilenameIndex()))
+    return false;
+
+  if (!getType() && !Element->getType())
+    return true;
+  if (getType() && Element->getType())
+    return getType()->equals(Element->getType());
+  return false;
+}
+
 // Print the FileName Index.
 void LVElement::printFileIndex(raw_ostream &OS, bool Full) const {
   if (options().getPrintFormatting() && options().getAttributeAnySource() &&

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
index ace1cefcbbc3d..c3810d282abc0 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 
 using namespace llvm;
@@ -65,6 +66,77 @@ std::string LVLine::noLineAsString(bool ShowZero) const {
                                                     : ("    -   ");
 }
 
+void LVLine::markMissingParents(const LVLines *References,
+                                const LVLines *Targets) {
+  if (!(References && Targets))
+    return;
+
+  LLVM_DEBUG({
+    dbgs() << "\n[LVLine::markMissingParents]\n";
+    for (const LVLine *Reference : *References)
+      dbgs() << "References: "
+             << "Kind = " << formattedKind(Reference->kind()) << ", "
+             << "Line = " << Reference->getLineNumber() << "\n";
+    for (const LVLine *Target : *Targets)
+      dbgs() << "Targets   : "
+             << "Kind = " << formattedKind(Target->kind()) << ", "
+             << "Line = " << Target->getLineNumber() << "\n";
+  });
+
+  for (LVLine *Reference : *References) {
+    LLVM_DEBUG({
+      dbgs() << "Search Reference: Line = " << Reference->getLineNumber()
+             << "\n";
+    });
+    if (!Reference->findIn(Targets))
+      Reference->markBranchAsMissing();
+  }
+}
+
+LVLine *LVLine::findIn(const LVLines *Targets) const {
+  if (!Targets)
+    return nullptr;
+
+  LLVM_DEBUG({
+    dbgs() << "\n[LVLine::findIn]\n"
+           << "Reference: "
+           << "Level = " << getLevel() << ", "
+           << "Kind = " << formattedKind(kind()) << ", "
+           << "Line = " << getLineNumber() << "\n";
+    for (const LVLine *Target : *Targets)
+      dbgs() << "Target   : "
+             << "Level = " << Target->getLevel() << ", "
+             << "Kind = " << formattedKind(Target->kind()) << ", "
+             << "Line = " << Target->getLineNumber() << "\n";
+  });
+
+  for (LVLine *Line : *Targets)
+    if (equals(Line))
+      return Line;
+
+  return nullptr;
+}
+
+bool LVLine::equals(const LVLine *Line) const {
+  return LVElement::equals(Line);
+}
+
+bool LVLine::equals(const LVLines *References, const LVLines *Targets) {
+  if (!References && !Targets)
+    return true;
+  if (References && Targets && References->size() == Targets->size()) {
+    for (const LVLine *Reference : *References)
+      if (!Reference->findIn(Targets))
+        return false;
+    return true;
+  }
+  return false;
+}
+
+void LVLine::report(LVComparePass Pass) {
+  getComparator().printItem(this, Pass);
+}
+
 void LVLine::print(raw_ostream &OS, bool Full) const {
   if (getReader().doPrintLine(this)) {
     getReaderCompileUnit()->incrementPrintedLines();
@@ -118,6 +190,12 @@ std::string LVLineDebug::statesInfo(bool Formatted) const {
   return String;
 }
 
+bool LVLineDebug::equals(const LVLine *Line) const {
+  if (!LVLine::equals(Line))
+    return false;
+  return getFilenameIndex() == Line->getFilenameIndex();
+}
+
 void LVLineDebug::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind());
 
@@ -133,6 +211,10 @@ void LVLineDebug::printExtra(raw_ostream &OS, bool Full) const {
 //===----------------------------------------------------------------------===//
 // Assembler line extracted from the ELF .text section.
 //===----------------------------------------------------------------------===//
+bool LVLineAssembler::equals(const LVLine *Line) const {
+  return LVLine::equals(Line);
+}
+
 void LVLineAssembler::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind());
   OS << " " << formattedName(getName());

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp
index e312ad46ba480..75acbf3225e08 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp
@@ -95,6 +95,18 @@ void LVObject::setParent(LVSymbol *Symbol) {
   setLevel(Symbol->getLevel() + 1);
 }
 
+void LVObject::markBranchAsMissing() {
+  // Mark the current object as 'missing'; then traverse the parents chain
+  // marking them as 'special missing' to indicate a missing branch. They
+  // can not be marked as missing, because will generate incorrect reports.
+  LVObject *Parent = this;
+  Parent->setIsMissing();
+  while (Parent) {
+    Parent->setIsMissingLink();
+    Parent = Parent->getParent();
+  }
+}
+
 Error LVObject::doPrint(bool Split, bool Match, bool Print, raw_ostream &OS,
                         bool Full) const {
   print(OS, Full);
@@ -129,6 +141,9 @@ void LVObject::printAttributes(raw_ostream &OS, bool Full) const {
   if (options().getInternalID())
     OS << hexSquareString(getID());
 #endif
+  if (options().getCompareExecute() &&
+      (options().getAttributeAdded() || options().getAttributeMissing()))
+    OS << (getIsAdded() ? '+' : getIsMissing() ? '-' : ' ');
   if (options().getAttributeOffset())
     OS << hexSquareString(getOffset());
   if (options().getAttributeLevel()) {

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
index 5d7401393a8fc..88f66cf2093be 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
@@ -276,7 +276,8 @@ Error LVReader::doPrint() {
 }
 
 Error LVReader::printScopes() {
-  if (bool DoPrint = options().getPrintExecute()) {
+  if (bool DoPrint =
+          (options().getPrintExecute() || options().getComparePrint())) {
     if (Error Err = createSplitFolder())
       return Err;
 

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index 56d5740afbd43..fc021c15e7d86 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVRange.h"
@@ -827,6 +828,172 @@ LVScope *LVScope::outermostParent(LVAddress Address) {
   return Parent;
 }
 
+LVScope *LVScope::findIn(const LVScopes *Targets) const {
+  if (!Targets)
+    return nullptr;
+
+  // In the case of overloaded functions, sometimes the DWARF used to
+  // describe them, does not give suficient information. Try to find a
+  // perfect match or mark them as possible conflicts.
+  LVScopes Candidates;
+  for (LVScope *Target : *Targets)
+    if (LVScope::equals(Target))
+      Candidates.push_back(Target);
+
+  LLVM_DEBUG({
+    if (!Candidates.empty()) {
+      dbgs() << "\n[LVScope::findIn]\n"
+             << "Reference: "
+             << "Offset = " << hexSquareString(getOffset()) << ", "
+             << "Level = " << getLevel() << ", "
+             << "Kind = " << formattedKind(kind()) << ", "
+             << "Name = " << formattedName(getName()) << "\n";
+      for (const LVScope *Candidate : Candidates)
+        dbgs() << "Candidate: "
+               << "Offset = " << hexSquareString(Candidate->getOffset()) << ", "
+               << "Level = " << Candidate->getLevel() << ", "
+               << "Kind = " << formattedKind(Candidate->kind()) << ", "
+               << "Name = " << formattedName(Candidate->getName()) << "\n";
+    }
+  });
+
+  if (!Candidates.empty())
+    return (Candidates.size() == 1)
+               ? (equals(Candidates[0]) ? Candidates[0] : nullptr)
+               : findEqualScope(&Candidates);
+
+  return nullptr;
+}
+
+bool LVScope::equalNumberOfChildren(const LVScope *Scope) const {
+  // Same number of children. Take into account which elements are requested
+  // to be included in the comparison.
+  return !(
+      (options().getCompareScopes() && scopeCount() != Scope->scopeCount()) ||
+      (options().getCompareSymbols() &&
+       symbolCount() != Scope->symbolCount()) ||
+      (options().getCompareTypes() && typeCount() != Scope->typeCount()) ||
+      (options().getCompareLines() && lineCount() != Scope->lineCount()));
+}
+
+void LVScope::markMissingParents(const LVScope *Target, bool TraverseChildren) {
+  auto SetCompareState = [&](auto *Container) {
+    if (Container)
+      for (auto *Entry : *Container)
+        Entry->setIsInCompare();
+  };
+  SetCompareState(Types);
+  SetCompareState(Symbols);
+  SetCompareState(Lines);
+  SetCompareState(Scopes);
+
+  // At this point, we are ready to start comparing the current scope, once
+  // the compare bits have been set.
+  if (options().getCompareTypes() && getTypes() && Target->getTypes())
+    LVType::markMissingParents(getTypes(), Target->getTypes());
+  if (options().getCompareSymbols() && getSymbols() && Target->getSymbols())
+    LVSymbol::markMissingParents(getSymbols(), Target->getSymbols());
+  if (options().getCompareLines() && getLines() && Target->getLines())
+    LVLine::markMissingParents(getLines(), Target->getLines());
+  if (getScopes() && Target->getScopes())
+    LVScope::markMissingParents(getScopes(), Target->getScopes(),
+                                TraverseChildren);
+}
+
+void LVScope::markMissingParents(const LVScopes *References,
+                                 const LVScopes *Targets,
+                                 bool TraverseChildren) {
+  if (!(References && Targets))
+    return;
+
+  LLVM_DEBUG({
+    dbgs() << "\n[LVScope::markMissingParents]\n";
+    for (const LVScope *Reference : *References)
+      dbgs() << "References: "
+             << "Offset = " << hexSquareString(Reference->getOffset()) << ", "
+             << "Level = " << Reference->getLevel() << ", "
+             << "Kind = " << formattedKind(Reference->kind()) << ", "
+             << "Name = " << formattedName(Reference->getName()) << "\n";
+    for (const LVScope *Target : *Targets)
+      dbgs() << "Targets   : "
+             << "Offset = " << hexSquareString(Target->getOffset()) << ", "
+             << "Level = " << Target->getLevel() << ", "
+             << "Kind = " << formattedKind(Target->kind()) << ", "
+             << "Name = " << formattedName(Target->getName()) << "\n";
+  });
+
+  for (LVScope *Reference : *References) {
+    // Don't process 'Block' scopes, as we can't identify them.
+    if (Reference->getIsBlock() || Reference->getIsGeneratedName())
+      continue;
+
+    LLVM_DEBUG({
+      dbgs() << "\nSearch Reference: "
+             << "Offset = " << hexSquareString(Reference->getOffset()) << " "
+             << "Name = " << formattedName(Reference->getName()) << "\n";
+    });
+    LVScope *Target = Reference->findIn(Targets);
+    if (Target) {
+      LLVM_DEBUG({
+        dbgs() << "\nFound Target: "
+               << "Offset = " << hexSquareString(Target->getOffset()) << " "
+               << "Name = " << formattedName(Target->getName()) << "\n";
+      });
+      if (TraverseChildren)
+        Reference->markMissingParents(Target, TraverseChildren);
+    } else {
+      LLVM_DEBUG({
+        dbgs() << "Missing Reference: "
+               << "Offset = " << hexSquareString(Reference->getOffset()) << " "
+               << "Name = " << formattedName(Reference->getName()) << "\n";
+      });
+      Reference->markBranchAsMissing();
+    }
+  }
+}
+
+bool LVScope::equals(const LVScope *Scope) const {
+  if (!LVElement::equals(Scope))
+    return false;
+  // For lexical scopes, check if their parents are the same.
+  if (getIsLexicalBlock() && Scope->getIsLexicalBlock())
+    return getParentScope()->equals(Scope->getParentScope());
+  return true;
+}
+
+LVScope *LVScope::findEqualScope(const LVScopes *Scopes) const {
+  assert(Scopes && "Scopes must not be nullptr");
+  for (LVScope *Scope : *Scopes)
+    if (equals(Scope))
+      return Scope;
+  return nullptr;
+}
+
+bool LVScope::equals(const LVScopes *References, const LVScopes *Targets) {
+  if (!References && !Targets)
+    return true;
+  if (References && Targets && References->size() == Targets->size()) {
+    for (const LVScope *Reference : *References)
+      if (!Reference->findIn(Targets))
+        return false;
+    return true;
+  }
+  return false;
+}
+
+void LVScope::report(LVComparePass Pass) {
+  getComparator().printItem(this, Pass);
+  getComparator().push(this);
+  if (Children)
+    for (LVElement *Element : *Children)
+      Element->report(Pass);
+
+  if (Lines)
+    for (LVLine *Line : *Lines)
+      Line->report(Pass);
+  getComparator().pop();
+}
+
 void LVScope::printActiveRanges(raw_ostream &OS, bool Full) const {
   if (options().getPrintFormatting() && options().getAttributeRange() &&
       Ranges) {
@@ -871,6 +1038,33 @@ void LVScope::printExtra(raw_ostream &OS, bool Full) const {
 //===----------------------------------------------------------------------===//
 // DWARF Union/Structure/Class.
 //===----------------------------------------------------------------------===//
+bool LVScopeAggregate::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+
+  if (!equalNumberOfChildren(Scope))
+    return false;
+
+  // Check if the parameters match in the case of templates.
+  if (!LVType::parametersMatch(getTypes(), Scope->getTypes()))
+    return false;
+
+  if (!isNamed() && !Scope->isNamed())
+    // In the case of unnamed union/structure/class compare the file name.
+    if (getFilenameIndex() != Scope->getFilenameIndex())
+      return false;
+
+  return true;
+}
+
+LVScope *LVScopeAggregate::findEqualScope(const LVScopes *Scopes) const {
+  assert(Scopes && "Scopes must not be nullptr");
+  for (LVScope *Scope : *Scopes)
+    if (equals(Scope))
+      return Scope;
+  return nullptr;
+}
+
 void LVScopeAggregate::printExtra(raw_ostream &OS, bool Full) const {
   LVScope::printExtra(OS, Full);
   if (Full) {
@@ -885,6 +1079,12 @@ void LVScopeAggregate::printExtra(raw_ostream &OS, bool Full) const {
 //===----------------------------------------------------------------------===//
 // DWARF Template alias.
 //===----------------------------------------------------------------------===//
+bool LVScopeAlias::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+  return equalNumberOfChildren(Scope);
+}
+
 void LVScopeAlias::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << formattedName(getName()) << " -> "
      << typeOffsetAsString()
@@ -965,6 +1165,21 @@ void LVScopeArray::resolveExtra() {
   setName(ArrayInfo.str());
 }
 
+bool LVScopeArray::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+
+  if (!equalNumberOfChildren(Scope))
+    return false;
+
+  // Despite the arrays are encoded, to reflect the dimensions, we have to
+  // check the subranges, in order to determine if they are the same.
+  if (!LVType::equals(getTypes(), Scope->getTypes()))
+    return false;
+
+  return true;
+}
+
 void LVScopeArray::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << typeOffsetAsString()
      << formattedName(getName()) << "\n";
@@ -1057,6 +1272,13 @@ StringRef LVScopeCompileUnit::getFilename(size_t Index) const {
   return getStringPool().getString(Filenames[Index - 1]);
 }
 
+bool LVScopeCompileUnit::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+
+  return getNameIndex() == Scope->getNameIndex();
+}
+
 void LVScopeCompileUnit::incrementPrintedLines() {
   options().getSelectExecute() ? ++Found.Lines : ++Printed.Lines;
 }
@@ -1090,10 +1312,23 @@ void LVScopeCompileUnit::increment(LVType *Type) {
 
 // A new element has been added to the scopes tree. Take the following steps:
 // Increase the added element counters, for printing summary.
-void LVScopeCompileUnit::addedElement(LVLine *Line) { increment(Line); }
-void LVScopeCompileUnit::addedElement(LVScope *Scope) { increment(Scope); }
-void LVScopeCompileUnit::addedElement(LVSymbol *Symbol) { increment(Symbol); }
-void LVScopeCompileUnit::addedElement(LVType *Type) { increment(Type); }
+// During comparison notify the Reader of the new element.
+void LVScopeCompileUnit::addedElement(LVLine *Line) {
+  increment(Line);
+  getReader().notifyAddedElement(Line);
+}
+void LVScopeCompileUnit::addedElement(LVScope *Scope) {
+  increment(Scope);
+  getReader().notifyAddedElement(Scope);
+}
+void LVScopeCompileUnit::addedElement(LVSymbol *Symbol) {
+  increment(Symbol);
+  getReader().notifyAddedElement(Symbol);
+}
+void LVScopeCompileUnit::addedElement(LVType *Type) {
+  increment(Type);
+  getReader().notifyAddedElement(Type);
+}
 
 // Record unsuported DWARF tags.
 void LVScopeCompileUnit::addDebugTag(dwarf::Tag Target, LVOffset Offset) {
@@ -1458,6 +1693,12 @@ void LVScopeCompileUnit::printExtra(raw_ostream &OS, bool Full) const {
 //===----------------------------------------------------------------------===//
 // DWARF enumeration (DW_TAG_enumeration_type).
 //===----------------------------------------------------------------------===//
+bool LVScopeEnumeration::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+  return equalNumberOfChildren(Scope);
+}
+
 void LVScopeEnumeration::printExtra(raw_ostream &OS, bool Full) const {
   // Print the full type name.
   OS << formattedKind(kind()) << " " << (getIsEnumClass() ? "class " : "")
@@ -1471,6 +1712,12 @@ void LVScopeEnumeration::printExtra(raw_ostream &OS, bool Full) const {
 //===----------------------------------------------------------------------===//
 // DWARF formal parameter pack (DW_TAG_GNU_formal_parameter_pack).
 //===----------------------------------------------------------------------===//
+bool LVScopeFormalPack::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+  return equalNumberOfChildren(Scope);
+}
+
 void LVScopeFormalPack::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
 }
@@ -1528,6 +1775,51 @@ void LVScopeFunction::resolveExtra() {
     resolveTemplate();
 }
 
+bool LVScopeFunction::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+
+  // When comparing logical elements, ignore any 
diff erence in the children.
+  if (options().getCompareContext() && !equalNumberOfChildren(Scope))
+    return false;
+
+  // Check if the linkage name matches.
+  if (getLinkageNameIndex() != Scope->getLinkageNameIndex())
+    return false;
+
+  // Check if the parameters match in the case of templates.
+  if (!LVType::parametersMatch(getTypes(), Scope->getTypes()))
+    return false;
+
+  // Check if the arguments match.
+  if (!LVSymbol::parametersMatch(getSymbols(), Scope->getSymbols()))
+    return false;
+
+  // Check if the lines match.
+  if (options().getCompareLines() &&
+      !LVLine::equals(getLines(), Scope->getLines()))
+    return false;
+
+  // Check if any reference is the same.
+  if (!referenceMatch(Scope))
+    return false;
+
+  if (getReference() && !getReference()->equals(Scope->getReference()))
+    return false;
+
+  return true;
+}
+
+LVScope *LVScopeFunction::findEqualScope(const LVScopes *Scopes) const {
+  assert(Scopes && "Scopes must not be nullptr");
+  // Go through candidates and try to find a best match.
+  for (LVScope *Scope : *Scopes)
+    // Match arguments, children, lines, references.
+    if (equals(Scope))
+      return Scope;
+  return nullptr;
+}
+
 void LVScopeFunction::printExtra(raw_ostream &OS, bool Full) const {
   LVScope *Reference = getReference();
 
@@ -1570,6 +1862,27 @@ void LVScopeFunctionInlined::resolveExtra() {
     resolveTemplate();
 }
 
+bool LVScopeFunctionInlined::equals(const LVScope *Scope) const {
+  if (!LVScopeFunction::equals(Scope))
+    return false;
+
+  // Check if any reference is the same.
+  if (getHasDiscriminator() && Scope->getHasDiscriminator())
+    if (getDiscriminator() != Scope->getDiscriminator())
+      return false;
+
+  // Check the call site information.
+  if (getCallFilenameIndex() != Scope->getCallFilenameIndex() ||
+      getCallLineNumber() != Scope->getCallLineNumber())
+    return false;
+
+  return true;
+}
+
+LVScope *LVScopeFunctionInlined::findEqualScope(const LVScopes *Scopes) const {
+  return LVScopeFunction::findEqualScope(Scopes);
+}
+
 void LVScopeFunctionInlined::printExtra(raw_ostream &OS, bool Full) const {
   LVScopeFunction::printExtra(OS, Full);
 }
@@ -1612,6 +1925,32 @@ void LVScopeFunctionType::resolveExtra() {
 //===----------------------------------------------------------------------===//
 // DWARF namespace (DW_TAG_namespace).
 //===----------------------------------------------------------------------===//
+bool LVScopeNamespace::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+
+  if (!equalNumberOfChildren(Scope))
+    return false;
+
+  // Check if any reference is the same.
+  if (!referenceMatch(Scope))
+    return false;
+
+  if (getReference() && !getReference()->equals(Scope->getReference()))
+    return false;
+
+  return true;
+}
+
+LVScope *LVScopeNamespace::findEqualScope(const LVScopes *Scopes) const {
+  assert(Scopes && "Scopes must not be nullptr");
+  // Go through candidates and try to find a best match.
+  for (LVScope *Scope : *Scopes)
+    if (equals(Scope))
+      return Scope;
+  return nullptr;
+}
+
 void LVScopeNamespace::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
 
@@ -1640,6 +1979,10 @@ void LVScopeRoot::processRangeInformation() {
     }
 }
 
+bool LVScopeRoot::equals(const LVScope *Scope) const {
+  return LVScope::equals(Scope);
+}
+
 void LVScopeRoot::print(raw_ostream &OS, bool Full) const {
   OS << "\nLogical View:\n";
   LVScope::print(OS, Full);
@@ -1695,6 +2038,12 @@ Error LVScopeRoot::doPrintMatches(bool Split, raw_ostream &OS,
 //===----------------------------------------------------------------------===//
 // DWARF template parameter pack (DW_TAG_GNU_template_parameter_pack).
 //===----------------------------------------------------------------------===//
+bool LVScopeTemplatePack::equals(const LVScope *Scope) const {
+  if (!LVScope::equals(Scope))
+    return false;
+  return equalNumberOfChildren(Scope);
+}
+
 void LVScopeTemplatePack::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
 }

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
index a467b3dd79463..82633fbc6b2e8 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
@@ -279,6 +280,110 @@ StringRef LVSymbol::resolveReferencesChain() {
   return getName();
 }
 
+void LVSymbol::markMissingParents(const LVSymbols *References,
+                                  const LVSymbols *Targets) {
+  if (!(References && Targets))
+    return;
+
+  LLVM_DEBUG({
+    dbgs() << "\n[LVSymbol::markMissingParents]\n";
+    for (const LVSymbol *Reference : *References)
+      dbgs() << "References: "
+             << "Kind = " << formattedKind(Reference->kind()) << ", "
+             << "Name = " << formattedName(Reference->getName()) << "\n";
+    for (const LVSymbol *Target : *Targets)
+      dbgs() << "Targets   : "
+             << "Kind = " << formattedKind(Target->kind()) << ", "
+             << "Name = " << formattedName(Target->getName()) << "\n";
+  });
+
+  for (LVSymbol *Reference : *References) {
+    LLVM_DEBUG({
+      dbgs() << "Search Reference: Name = "
+             << formattedName(Reference->getName()) << "\n";
+    });
+    if (!Reference->findIn(Targets))
+      Reference->markBranchAsMissing();
+  }
+}
+
+LVSymbol *LVSymbol::findIn(const LVSymbols *Targets) const {
+  if (!Targets)
+    return nullptr;
+
+  LLVM_DEBUG({
+    dbgs() << "\n[LVSymbol::findIn]\n"
+           << "Reference: "
+           << "Level = " << getLevel() << ", "
+           << "Kind = " << formattedKind(kind()) << ", "
+           << "Name = " << formattedName(getName()) << "\n";
+    for (const LVSymbol *Target : *Targets)
+      dbgs() << "Target   : "
+             << "Level = " << Target->getLevel() << ", "
+             << "Kind = " << formattedKind(Target->kind()) << ", "
+             << "Name = " << formattedName(Target->getName()) << "\n";
+  });
+
+  for (LVSymbol *Target : *Targets)
+    if (equals(Target))
+      return Target;
+
+  return nullptr;
+}
+
+// Check for a match on the arguments of a function.
+bool LVSymbol::parametersMatch(const LVSymbols *References,
+                               const LVSymbols *Targets) {
+  if (!References && !Targets)
+    return true;
+  if (References && Targets) {
+    LVSymbols ReferenceParams;
+    getParameters(References, &ReferenceParams);
+    LVSymbols TargetParams;
+    getParameters(Targets, &TargetParams);
+    return LVSymbol::equals(&ReferenceParams, &TargetParams);
+  }
+  return false;
+}
+
+// Return the symbols which are parameters.
+void LVSymbol::getParameters(const LVSymbols *Symbols, LVSymbols *Parameters) {
+  if (Symbols)
+    for (LVSymbol *Symbol : *Symbols)
+      if (Symbol->getIsParameter())
+        Parameters->push_back(Symbol);
+}
+
+bool LVSymbol::equals(const LVSymbol *Symbol) const {
+  if (!LVElement::equals(Symbol))
+    return false;
+
+  // Check if any reference is the same.
+  if (!referenceMatch(Symbol))
+    return false;
+
+  if (getReference() && !getReference()->equals(Symbol->getReference()))
+    return false;
+
+  return true;
+}
+
+bool LVSymbol::equals(const LVSymbols *References, const LVSymbols *Targets) {
+  if (!References && !Targets)
+    return true;
+  if (References && Targets && References->size() == Targets->size()) {
+    for (const LVSymbol *Reference : *References)
+      if (!Reference->findIn(Targets))
+        return false;
+    return true;
+  }
+  return false;
+}
+
+void LVSymbol::report(LVComparePass Pass) {
+  getComparator().printItem(this, Pass);
+}
+
 void LVSymbol::printLocations(raw_ostream &OS, bool Full) const {
   if (Locations)
     for (const LVLocation *Location : *Locations)

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
index 18b5d76ce8ecb..3d32c34ee02a3 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
 
@@ -169,6 +170,124 @@ StringRef LVType::resolveReferencesChain() {
   return getName();
 }
 
+void LVType::markMissingParents(const LVTypes *References,
+                                const LVTypes *Targets) {
+  if (!(References && Targets))
+    return;
+
+  LLVM_DEBUG({
+    dbgs() << "\n[LVType::markMissingParents]\n";
+    for (const LVType *Reference : *References)
+      dbgs() << "References: "
+             << "Kind = " << formattedKind(Reference->kind()) << ", "
+             << "Name = " << formattedName(Reference->getName()) << "\n";
+    for (const LVType *Target : *Targets)
+      dbgs() << "Targets   : "
+             << "Kind = " << formattedKind(Target->kind()) << ", "
+             << "Name = " << formattedName(Target->getName()) << "\n";
+  });
+
+  for (LVType *Reference : *References) {
+    LLVM_DEBUG({
+      dbgs() << "Search Reference: Name = "
+             << formattedName(Reference->getName()) << "\n";
+    });
+    if (!Reference->findIn(Targets))
+      Reference->markBranchAsMissing();
+  }
+}
+
+LVType *LVType::findIn(const LVTypes *Targets) const {
+  if (!Targets)
+    return nullptr;
+
+  LLVM_DEBUG({
+    dbgs() << "\n[LVType::findIn]\n"
+           << "Reference: "
+           << "Level = " << getLevel() << ", "
+           << "Kind = " << formattedKind(kind()) << ", "
+           << "Name = " << formattedName(getName()) << "\n";
+    for (const LVType *Target : *Targets)
+      dbgs() << "Target   : "
+             << "Level = " << Target->getLevel() << ", "
+             << "Kind = " << formattedKind(Target->kind()) << ", "
+             << "Name = " << formattedName(Target->getName()) << "\n";
+  });
+
+  for (LVType *Target : *Targets)
+    if (equals(Target))
+      return Target;
+
+  return nullptr;
+}
+
+// Check for a match on the arguments of a function.
+bool LVType::parametersMatch(const LVTypes *References,
+                             const LVTypes *Targets) {
+  if (!References && !Targets)
+    return true;
+  if (References && Targets) {
+    LVTypes ReferenceTypes;
+    LVScopes ReferenceScopes;
+    getParameters(References, &ReferenceTypes, &ReferenceScopes);
+    LVTypes TargetTypes;
+    LVScopes TargetScopes;
+    getParameters(Targets, &TargetTypes, &TargetScopes);
+    if (!LVType::equals(&ReferenceTypes, &TargetTypes) ||
+        !LVScope::equals(&ReferenceScopes, &TargetScopes))
+      return false;
+    return true;
+  }
+  return false;
+}
+
+// Return the types which are parameters.
+void LVType::getParameters(const LVTypes *Types, LVTypes *TypesParam,
+                           LVScopes *ScopesParam) {
+  if (!Types)
+    return;
+
+  // During a compare task, the template parameters are expanded to
+  // point to their real types, to avoid compare conflicts.
+  for (LVType *Type : *Types) {
+    if (!Type->getIsTemplateParam())
+      continue;
+    if (options().getAttributeArgument()) {
+      LVScope *Scope = nullptr;
+      if (Type->getIsKindType())
+        Type = Type->getTypeAsType();
+      else {
+        if (Type->getIsKindScope()) {
+          Scope = Type->getTypeAsScope();
+          Type = nullptr;
+        }
+      }
+      Type ? TypesParam->push_back(Type) : ScopesParam->push_back(Scope);
+    } else
+      TypesParam->push_back(Type);
+  }
+}
+
+bool LVType::equals(const LVType *Type) const {
+  return LVElement::equals(Type);
+}
+
+bool LVType::equals(const LVTypes *References, const LVTypes *Targets) {
+  if (!References && !Targets)
+    return true;
+  if (References && Targets && References->size() == Targets->size()) {
+    for (const LVType *Reference : *References)
+      if (!Reference->findIn(Targets))
+        return false;
+    return true;
+  }
+  return false;
+}
+
+void LVType::report(LVComparePass Pass) {
+  getComparator().printItem(this, Pass);
+}
+
 void LVType::print(raw_ostream &OS, bool Full) const {
   if (getIncludeInPrint() &&
       (getIsReference() || getReader().doPrintType(this))) {
@@ -229,6 +348,10 @@ void LVTypeDefinition::resolveExtra() {
     Aggregate->setName(getName());
 }
 
+bool LVTypeDefinition::equals(const LVType *Type) const {
+  return LVType::equals(Type);
+}
+
 void LVTypeDefinition::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << formattedName(getName()) << " -> "
      << typeOffsetAsString()
@@ -238,6 +361,10 @@ void LVTypeDefinition::printExtra(raw_ostream &OS, bool Full) const {
 //===----------------------------------------------------------------------===//
 // DWARF enumerator (DW_TAG_enumerator).
 //===----------------------------------------------------------------------===//
+bool LVTypeEnumerator::equals(const LVType *Type) const {
+  return LVType::equals(Type);
+}
+
 void LVTypeEnumerator::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " '" << getName()
      << "' = " << formattedName(getValue()) << "\n";
@@ -246,6 +373,10 @@ void LVTypeEnumerator::printExtra(raw_ostream &OS, bool Full) const {
 //===----------------------------------------------------------------------===//
 // DWARF import (DW_TAG_imported_module / DW_TAG_imported_declaration).
 //===----------------------------------------------------------------------===//
+bool LVTypeImport::equals(const LVType *Type) const {
+  return LVType::equals(Type);
+}
+
 void LVTypeImport::printExtra(raw_ostream &OS, bool Full) const {
   std::string Attributes =
       formatAttributes(virtualityString(), accessibilityString());
@@ -316,6 +447,21 @@ void LVTypeParam::encodeTemplateArgument(std::string &Name) const {
     Name.append(getValue());
 }
 
+bool LVTypeParam::equals(const LVType *Type) const {
+  if (!LVType::equals(Type))
+    return false;
+
+  // Checks the kind of template argument.
+  if (getIsTemplateTypeParam() && Type->getIsTemplateTypeParam())
+    return getType()->equals(Type->getType());
+
+  if ((getIsTemplateValueParam() && Type->getIsTemplateValueParam()) ||
+      (getIsTemplateTemplateParam() && Type->getIsTemplateTemplateParam()))
+    return getValueIndex() == Type->getValueIndex();
+
+  return false;
+}
+
 void LVTypeParam::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << formattedName(getName()) << " -> "
      << typeOffsetAsString();
@@ -365,6 +511,13 @@ void LVTypeSubrange::resolveExtra() {
   setName(String);
 }
 
+bool LVTypeSubrange::equals(const LVType *Type) const {
+  if (!LVType::equals(Type))
+    return false;
+
+  return getTypeName() == Type->getTypeName() && getName() == Type->getName();
+}
+
 void LVTypeSubrange::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " -> " << typeOffsetAsString()
      << formattedName(getTypeName()) << " " << formattedName(getName()) << "\n";

diff  --git a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
index 8512fd1a868d8..4a51f017164c5 100644
--- a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest(DebugInfoLogicalViewTests
   CommandLineOptionsTest.cpp
+  CompareElementsTest.cpp
   SelectElementsTest.cpp
   LocationRangesTest.cpp
   LogicalElementsTest.cpp

diff  --git a/llvm/unittests/DebugInfo/LogicalView/CompareElementsTest.cpp b/llvm/unittests/DebugInfo/LogicalView/CompareElementsTest.cpp
new file mode 100644
index 0000000000000..fa274ef03aa8c
--- /dev/null
+++ b/llvm/unittests/DebugInfo/LogicalView/CompareElementsTest.cpp
@@ -0,0 +1,450 @@
+//===- llvm/unittest/DebugInfo/LogicalView/CompareElementsTest.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/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+namespace {
+
+//===----------------------------------------------------------------------===//
+// Basic Reader functionality.
+class ReaderTestCompare : public LVReader {
+public:
+  // Types.
+  LVType *IntegerType = nullptr;
+  LVType *UnsignedType = nullptr;
+  LVType *GlobalType = nullptr;
+  LVType *LocalType = nullptr;
+  LVType *NestedType = nullptr;
+  LVTypeDefinition *TypeDefinitionOne = nullptr;
+  LVTypeDefinition *TypeDefinitionTwo = nullptr;
+  LVTypeEnumerator *EnumeratorOne = nullptr;
+  LVTypeEnumerator *EnumeratorTwo = nullptr;
+
+  // Scopes.
+  LVScope *NestedScope = nullptr;
+  LVScope *InnerScope = nullptr;
+  LVScopeAggregate *Aggregate = nullptr;
+  LVScopeEnumeration *Enumeration = nullptr;
+  LVScopeFunction *FunctionOne = nullptr;
+  LVScopeFunction *FunctionTwo = nullptr;
+  LVScopeNamespace *Namespace = nullptr;
+
+  // Symbols.
+  LVSymbol *GlobalVariable = nullptr;
+  LVSymbol *LocalVariable = nullptr;
+  LVSymbol *ClassMember = nullptr;
+  LVSymbol *NestedVariable = nullptr;
+  LVSymbol *ParameterOne = nullptr;
+  LVSymbol *ParameterTwo = nullptr;
+
+  // Lines.
+  LVLine *LineOne = nullptr;
+  LVLine *LineTwo = nullptr;
+  LVLine *LineThree = nullptr;
+
+protected:
+  void add(LVScope *Parent, LVElement *Element);
+  template <typename T, typename F> T *create(F Function) {
+    // 'Function' will update a specific kind of the logical element to
+    // have the ability of kind selection.
+    T *Element = new (std::nothrow) T();
+    EXPECT_NE(Element, nullptr);
+    (Element->*Function)();
+    return Element;
+  }
+  void set(LVElement *Element, StringRef Name, LVOffset Offset,
+           uint32_t LineNumber = 0, LVElement *Type = nullptr);
+
+public:
+  ReaderTestCompare(ScopedPrinter &W) : LVReader("", "", W) {
+    setInstance(this);
+  }
+
+  Error createScopes() { return LVReader::createScopes(); }
+  Error printScopes() { return LVReader::printScopes(); }
+
+  void createElements();
+  void addElements(bool IsReference, bool IsTarget);
+  void initElements();
+};
+
+// Helper function to add a logical element to a given scope.
+void ReaderTestCompare::add(LVScope *Parent, LVElement *Child) {
+  Parent->addElement(Child);
+  EXPECT_EQ(Child->getParent(), Parent);
+  EXPECT_EQ(Child->getLevel(), Parent->getLevel() + 1);
+}
+
+// Helper function to set the initial values for a given logical element.
+void ReaderTestCompare::set(LVElement *Element, StringRef Name, LVOffset Offset,
+                            uint32_t LineNumber, LVElement *Type) {
+  Element->setName(Name);
+  Element->setOffset(Offset);
+  Element->setLineNumber(LineNumber);
+  Element->setType(Type);
+}
+
+//===----------------------------------------------------------------------===//
+// Create the logical elements.
+void ReaderTestCompare::createElements() {
+  // Create scope root.
+  Error Err = createScopes();
+  ASSERT_THAT_ERROR(std::move(Err), Succeeded());
+  Root = getScopesRoot();
+  EXPECT_NE(Root, nullptr);
+
+  // Create the logical types.
+  IntegerType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
+  UnsignedType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
+  GlobalType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
+  LocalType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
+  NestedType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
+  EnumeratorOne =
+      create<LVTypeEnumerator, LVTypeSetFunction>(&LVType::setIsEnumerator);
+  EnumeratorTwo =
+      create<LVTypeEnumerator, LVTypeSetFunction>(&LVType::setIsEnumerator);
+  TypeDefinitionOne =
+      create<LVTypeDefinition, LVTypeSetFunction>(&LVType::setIsTypedef);
+  TypeDefinitionTwo =
+      create<LVTypeDefinition, LVTypeSetFunction>(&LVType::setIsTypedef);
+
+  // Create the logical scopes.
+  NestedScope =
+      create<LVScope, LVScopeSetFunction>(&LVScope::setIsLexicalBlock);
+  InnerScope = create<LVScope, LVScopeSetFunction>(&LVScope::setIsLexicalBlock);
+  Aggregate =
+      create<LVScopeAggregate, LVScopeSetFunction>(&LVScope::setIsAggregate);
+  CompileUnit = create<LVScopeCompileUnit, LVScopeSetFunction>(
+      &LVScope::setIsCompileUnit);
+  Enumeration = create<LVScopeEnumeration, LVScopeSetFunction>(
+      &LVScope::setIsEnumeration);
+  FunctionOne =
+      create<LVScopeFunction, LVScopeSetFunction>(&LVScope::setIsFunction);
+  FunctionTwo =
+      create<LVScopeFunction, LVScopeSetFunction>(&LVScope::setIsFunction);
+  Namespace =
+      create<LVScopeNamespace, LVScopeSetFunction>(&LVScope::setIsNamespace);
+
+  // Create the logical symbols.
+  GlobalVariable =
+      create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable);
+  LocalVariable =
+      create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable);
+  ClassMember = create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsMember);
+  NestedVariable =
+      create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable);
+  ParameterOne =
+      create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsParameter);
+  ParameterTwo =
+      create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsParameter);
+
+  // Create the logical lines.
+  LineOne = create<LVLine, LVLineSetFunction>(&LVLine::setIsLineDebug);
+  LineTwo = create<LVLine, LVLineSetFunction>(&LVLine::setIsLineDebug);
+  LineThree = create<LVLine, LVLineSetFunction>(&LVLine::setIsLineDebug);
+}
+
+// Reference Reader:              Target Reader:
+// ----------------------         ----------------------
+// Root                           Root
+//   CompileUnit                    CompileUnit
+//     IntegerType                    IntegerType
+//     UnsignedType                   UnsignedType
+//     FunctionOne                    FunctionOne
+//       ParameterOne                   ParameterOne
+//       LocalVariable                  ---
+//       LocalType                      LocalType
+//       LineOne                        LineOne
+//       NestedScope                    NestedScope
+//         NestedVariable                 NestedVariable
+//         NestedType                     NestedType
+//         LineTwo                        ---
+//         InnerScope                     InnerScope
+//           ---                            LineThree
+//     ---                            FunctionTwo
+//     ---                              ParameterTwo
+//     GlobalVariable                 GlobalVariable
+//     GlobalType                     GlobalType
+//     Namespace                      Namespace
+//       Aggregate                      Aggregate
+//         ClassMember                    ClassMember
+//       Enumeration                    Enumeration
+//         EnumeratorOne                  EnumeratorOne
+//         EnumeratorTwo                  EnumeratorTwo
+//       TypeDefinitionOne              ---
+//       ---                            TypeDefinitionTwo
+
+// Create the logical view adding the created logical elements.
+void ReaderTestCompare::addElements(bool IsReference, bool IsTarget) {
+  Root->setName(IsReference ? "Reference-Reader" : "Target-Reader");
+
+  auto Insert = [&](bool Insert, auto *Parent, auto *Child) {
+    if (Insert)
+      add(Parent, Child);
+  };
+
+  setCompileUnit(CompileUnit);
+  add(Root, CompileUnit);
+
+  // Add elements to CompileUnit.
+  Insert(true, CompileUnit, IntegerType);
+  Insert(true, CompileUnit, UnsignedType);
+  Insert(true, CompileUnit, FunctionOne);
+  Insert(IsTarget, CompileUnit, FunctionTwo);
+  Insert(true, CompileUnit, GlobalVariable);
+  Insert(true, CompileUnit, GlobalType);
+  Insert(true, CompileUnit, Namespace);
+
+  // Add elements to Namespace.
+  Insert(true, Namespace, Aggregate);
+  Insert(true, Namespace, Enumeration);
+  Insert(IsReference, Namespace, TypeDefinitionOne);
+  Insert(IsTarget, Namespace, TypeDefinitionTwo);
+
+  // Add elements to FunctionOne.
+  Insert(true, FunctionOne, ParameterOne);
+  Insert(IsReference, FunctionOne, LocalVariable);
+  Insert(true, FunctionOne, LocalType);
+  Insert(true, FunctionOne, LineOne);
+  Insert(true, FunctionOne, NestedScope);
+
+  // Add elements to FunctionTwo.
+  Insert(IsTarget, FunctionTwo, ParameterTwo);
+
+  // Add elements to NestedScope.
+  Insert(true, NestedScope, NestedVariable);
+  Insert(true, NestedScope, NestedType);
+  Insert(IsReference, NestedScope, LineTwo);
+  Insert(true, NestedScope, InnerScope);
+
+  // Add elements to Enumeration.
+  Insert(true, Enumeration, EnumeratorOne);
+  Insert(true, Enumeration, EnumeratorTwo);
+
+  // Add elements to Aggregate.
+  Insert(true, Aggregate, ClassMember);
+
+  Insert(IsTarget, InnerScope, LineThree);
+}
+
+// Set initial values to logical elements.
+void ReaderTestCompare::initElements() {
+  setFilename("LogicalElements.obj");
+
+  Root->setFileFormatName("FileFormat");
+
+  // Types.
+  set(IntegerType, "int", 0x1000);
+  set(UnsignedType, "unsigned", 0x1010);
+  set(GlobalType, "GlobalType", 0x1020, 1020);
+  set(LocalType, "LocalType", 0x1030, 1030);
+  set(NestedType, "NestedType", 0x1040, 1040);
+
+  set(TypeDefinitionOne, "INTEGER", 0x1050, 1050, IntegerType);
+  set(TypeDefinitionTwo, "INT", 0x1060, 1060, TypeDefinitionOne);
+
+  set(EnumeratorOne, "One", 0x1070, 1070);
+  EnumeratorOne->setValue("Blue");
+
+  set(EnumeratorTwo, "Two", 0x1080, 1080);
+  EnumeratorTwo->setValue("Red");
+
+  // Scopes.
+  set(Aggregate, "Class", 0x2000, 2000);
+  set(Enumeration, "Colors", 0x2010, 2010);
+  set(FunctionOne, "FunctionOne", 0x2020, 2020, GlobalType);
+  set(FunctionTwo, "FunctionTwo", 0x2030, 2030, GlobalType);
+  set(Namespace, "Namespace", 0x2040, 2040);
+  set(NestedScope, "", 0x2050, 2050);
+  set(InnerScope, "", 0x2060, 2060);
+  set(CompileUnit, "test.cpp", 0x2070, 2070);
+
+  // Symbols.
+  set(GlobalVariable, "GlobalVariable", 0x3000, 3000);
+  set(LocalVariable, "LocalVariable", 0x3010, 3010, UnsignedType);
+  set(ClassMember, "ClassMember", 0x3020, 3020, IntegerType);
+  set(ParameterOne, "ParameterOne", 0x3030, 3030, UnsignedType);
+  set(ParameterTwo, "ParameterTwo", 0x3040, 3040, UnsignedType);
+  set(NestedVariable, "NestedVariable", 0x3050, 3050);
+
+  // Lines.
+  set(LineOne, "", 0x4000, 4000);
+  set(LineTwo, "", 0x4010, 4010);
+  set(LineThree, "", 0x4020, 4020);
+}
+
+// Compare the logical views.
+void compareReadersViews(ReaderTestCompare *ReferenceReader,
+                         ReaderTestCompare *TargetReader) {
+  LVCompare Compare(nulls());
+  Error Err = Compare.execute(ReferenceReader, TargetReader);
+  ASSERT_THAT_ERROR(std::move(Err), Succeeded());
+
+  // Get comparison table.
+  LVPassTable PassTable = Compare.getPassTable();
+  ASSERT_EQ(PassTable.size(), 5u);
+
+  LVReader *Reader;
+  LVElement *Element;
+  LVComparePass Pass;
+
+  // Reference: Missing 'FunctionOne'
+  std::tie(Reader, Element, Pass) = PassTable[0];
+  EXPECT_EQ(Reader, ReferenceReader);
+  EXPECT_EQ(Element, ReferenceReader->FunctionOne);
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Reference: Missing 'TypeDefinitionOne'
+  std::tie(Reader, Element, Pass) = PassTable[1];
+  EXPECT_EQ(Reader, ReferenceReader);
+  EXPECT_EQ(Element, ReferenceReader->TypeDefinitionOne);
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Target: Added 'FunctionOne'
+  std::tie(Reader, Element, Pass) = PassTable[2];
+  EXPECT_EQ(Reader, TargetReader);
+  EXPECT_EQ(Element, TargetReader->FunctionOne);
+  EXPECT_EQ(Pass, LVComparePass::Added);
+
+  // Target: Added 'FunctionTwo'
+  std::tie(Reader, Element, Pass) = PassTable[3];
+  EXPECT_EQ(Reader, TargetReader);
+  EXPECT_EQ(Element, TargetReader->FunctionTwo);
+  EXPECT_EQ(Pass, LVComparePass::Added);
+
+  // Target: Added 'TypeDefinitionTwo'
+  std::tie(Reader, Element, Pass) = PassTable[4];
+  EXPECT_EQ(Reader, TargetReader);
+  EXPECT_EQ(Element, TargetReader->TypeDefinitionTwo);
+  EXPECT_EQ(Pass, LVComparePass::Added);
+}
+
+// Compare the logical elements.
+void compareReadersElements(ReaderTestCompare *ReferenceReader,
+                            ReaderTestCompare *TargetReader) {
+  LVCompare Compare(nulls());
+  Error Err = Compare.execute(ReferenceReader, TargetReader);
+  ASSERT_THAT_ERROR(std::move(Err), Succeeded());
+
+  // Get comparison table.
+  LVPassTable PassTable = Compare.getPassTable();
+  ASSERT_EQ(PassTable.size(), 7u);
+
+  LVReader *Reader;
+  LVElement *Element;
+  LVComparePass Pass;
+
+  // Reference: Missing 'LocalVariable'
+  std::tie(Reader, Element, Pass) = PassTable[0];
+  EXPECT_EQ(Reader, ReferenceReader);
+  EXPECT_EQ(Element, ReferenceReader->LocalVariable);
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Reference: Missing 'TypeDefinitionOne'
+  std::tie(Reader, Element, Pass) = PassTable[1];
+  EXPECT_EQ(Reader, ReferenceReader);
+  EXPECT_EQ(Element, ReferenceReader->TypeDefinitionOne);
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Reference: Missing 'LineTwo'
+  std::tie(Reader, Element, Pass) = PassTable[2];
+  EXPECT_EQ(Reader, ReferenceReader);
+  EXPECT_EQ(Element, ReferenceReader->LineTwo);
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Target: Added 'FunctionTwo'
+  std::tie(Reader, Element, Pass) = PassTable[3];
+  EXPECT_EQ(Reader, TargetReader);
+  EXPECT_EQ(Element, TargetReader->FunctionTwo);
+  EXPECT_EQ(Pass, LVComparePass::Added);
+
+  // Target: Added 'ParameterTwo'
+  std::tie(Reader, Element, Pass) = PassTable[4];
+  EXPECT_EQ(Reader, TargetReader);
+  EXPECT_EQ(Element, TargetReader->ParameterTwo);
+  EXPECT_EQ(Pass, LVComparePass::Added);
+
+  // Target: Added 'TypeDefinitionTwo'
+  std::tie(Reader, Element, Pass) = PassTable[5];
+  EXPECT_EQ(Reader, TargetReader);
+  EXPECT_EQ(Element, TargetReader->TypeDefinitionTwo);
+  EXPECT_EQ(Pass, LVComparePass::Added);
+
+  // Target: Added 'LineThree'
+  std::tie(Reader, Element, Pass) = PassTable[6];
+  EXPECT_EQ(Reader, TargetReader);
+  EXPECT_EQ(Element, TargetReader->LineThree);
+  EXPECT_EQ(Pass, LVComparePass::Added);
+}
+
+TEST(LogicalViewTest, CompareElements) {
+  ScopedPrinter W(outs());
+
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setCompareLines();
+  ReaderOptions.setCompareScopes();
+  ReaderOptions.setCompareSymbols();
+  ReaderOptions.setCompareTypes();
+
+  // The next set-ups are very similar. The only 
diff erence is the
+  // comparison type, which must be set before the readers are created.
+  //   Views: setCompareContext()
+  //   Elements: resetCompareContext()
+  {
+    // Compare the logical views as whole unit (--compare-context).
+    ReaderOptions.setCompareContext();
+    ReaderOptions.resolveDependencies();
+    options().setOptions(&ReaderOptions);
+
+    ReaderTestCompare ReferenceReader(W);
+    ReferenceReader.createElements();
+    ReferenceReader.addElements(/*IsReference=*/true, /*IsTarget=*/false);
+    ReferenceReader.initElements();
+
+    ReaderTestCompare TargetReader(W);
+    TargetReader.createElements();
+    TargetReader.addElements(/*IsReference=*/false, /*IsTarget=*/true);
+    TargetReader.initElements();
+
+    compareReadersViews(&ReferenceReader, &TargetReader);
+  }
+  {
+    // Compare the logical elements.
+    ReaderOptions.resetCompareContext();
+    ReaderOptions.resolveDependencies();
+    options().setOptions(&ReaderOptions);
+
+    ReaderTestCompare ReferenceReader(W);
+    ReferenceReader.createElements();
+    ReferenceReader.addElements(/*IsReference=*/true, /*IsTarget=*/false);
+    ReferenceReader.initElements();
+
+    ReaderTestCompare TargetReader(W);
+    TargetReader.createElements();
+    TargetReader.addElements(/*IsReference=*/false, /*IsTarget=*/true);
+    TargetReader.initElements();
+
+    compareReadersElements(&ReferenceReader, &TargetReader);
+  }
+}
+
+} // namespace


        


More information about the llvm-commits mailing list