[llvm] 0332a8e - [llvm-debuginfo-analyzer] (05/09) - Select elements

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 20 21:55:48 PDT 2022


Author: Carlos Alberto Enciso
Date: 2022-10-21T05:55:09+01:00
New Revision: 0332a8e7d6da29be945d16cc8c392ed7902397f5

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

LOG: [llvm-debuginfo-analyzer] (05/09) - Select 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:

Select elements
- Support for logical elements selection:
  LVPatterns

Reviewed By: psamolysov, probinson

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

Added: 
    llvm/unittests/DebugInfo/LogicalView/SelectElementsTest.cpp

Modified: 
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.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/Core/LVElement.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVOptions.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/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index 6bd06da942899..7bac7a31f5a41 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -17,7 +17,9 @@
 #include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVStringPool.h"
 #include "llvm/Support/Casting.h"
+#include <map>
 #include <set>
+#include <vector>
 
 namespace llvm {
 namespace logicalview {
@@ -60,6 +62,8 @@ enum class LVSubclassID : unsigned char {
 
 enum class LVElementKind { Discarded, Global, Optimized, LastEntry };
 using LVElementKindSet = std::set<LVElementKind>;
+using LVElementDispatch = std::map<LVElementKind, LVElementGetFunction>;
+using LVElementRequest = std::vector<LVElementGetFunction>;
 
 class LVElement : public LVObject {
   enum class Property {
@@ -98,6 +102,7 @@ class LVElement : public LVObject {
   };
   // Typed bitvector with properties for this element.
   LVProperties<Property> Properties;
+  static LVElementDispatch Dispatch;
 
   /// RTTI.
   const LVSubclassID SubclassID;
@@ -330,6 +335,9 @@ class LVElement : public LVObject {
   virtual void resolveName();
   virtual void resolveReferences() {}
   void resolveParents();
+
+public:
+  static LVElementDispatch &getDispatch() { return Dispatch; }
 };
 
 } // end namespace logicalview

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
index 98ec61549fe3d..c925b414b6f8c 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
@@ -33,11 +33,14 @@ enum class LVLineKind {
   LastEntry
 };
 using LVLineKindSet = std::set<LVLineKind>;
+using LVLineDispatch = std::map<LVLineKind, LVLineGetFunction>;
+using LVLineRequest = std::vector<LVLineGetFunction>;
 
 // Class to represent a logical line.
 class LVLine : public LVElement {
   // Typed bitvector with kinds for this line.
   LVProperties<LVLineKind> Kinds;
+  static LVLineDispatch Dispatch;
 
 public:
   LVLine() : LVElement(LVSubclassID::LV_LINE) {
@@ -78,6 +81,8 @@ class LVLine : public LVElement {
     return lineAsString(getLineNumber(), getDiscriminator(), ShowZero);
   }
 
+  static LVLineDispatch &getDispatch() { return Dispatch; }
+
   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/LVOptions.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h
index 88b027166d054..ba8e773e6f8a8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h
@@ -16,10 +16,10 @@
 
 #include "llvm/ADT/StringSet.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
-#include "llvm/DebugInfo/LogicalView/Core/LVOptions.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/Regex.h"
 #include <set>
 #include <string>
 
@@ -445,6 +445,201 @@ class LVOptions {
 inline LVOptions &options() { return (*LVOptions::getOptions()); }
 inline void setOptions(LVOptions *Options) { LVOptions::setOptions(Options); }
 
+class LVPatterns final {
+  // Pattern Mode.
+  enum class LVMatchMode {
+    None = 0, // No given pattern.
+    Match,    // Perfect match.
+    NoCase,   // Ignore case.
+    Regex     // Regular expression.
+  };
+
+  // Keep the search pattern information.
+  struct LVMatch {
+    std::string Pattern;                  // Normal pattern.
+    std::shared_ptr<Regex> RE;            // Regular Expression Pattern.
+    LVMatchMode Mode = LVMatchMode::None; // Match mode.
+  };
+
+  using LVMatchInfo = std::vector<LVMatch>;
+  LVMatchInfo GenericMatchInfo;
+  using LVMatchOffsets = std::vector<uint64_t>;
+  LVMatchOffsets OffsetMatchInfo;
+
+  // Element selection.
+  LVElementDispatch ElementDispatch;
+  LVLineDispatch LineDispatch;
+  LVScopeDispatch ScopeDispatch;
+  LVSymbolDispatch SymbolDispatch;
+  LVTypeDispatch TypeDispatch;
+
+  // Element selection request.
+  LVElementRequest ElementRequest;
+  LVLineRequest LineRequest;
+  LVScopeRequest ScopeRequest;
+  LVSymbolRequest SymbolRequest;
+  LVTypeRequest TypeRequest;
+
+  // Check an element printing Request.
+  template <typename T, typename U>
+  bool checkElementRequest(const T *Element, const U &Requests) const {
+    assert(Element && "Element must not be nullptr");
+    for (const auto &Request : Requests)
+      if ((Element->*Request)())
+        return true;
+    // Check generic element requests.
+    for (const LVElementGetFunction &Request : ElementRequest)
+      if ((Element->*Request)())
+        return true;
+    return false;
+  }
+
+  // Add an element printing request based on its kind.
+  template <typename T, typename U, typename V>
+  void addRequest(const T &Selection, const U &Dispatch, V &Request) const {
+    for (const auto &Entry : Selection) {
+      // Find target function to fullfit request.
+      typename U::const_iterator Iter = Dispatch.find(Entry);
+      if (Iter != Dispatch.end())
+        Request.push_back(Iter->second);
+    }
+  }
+
+  void addElement(LVElement *Element);
+
+  template <typename T, typename U>
+  void resolveGenericPatternMatch(T *Element, const U &Requests) {
+    assert(Element && "Element must not be nullptr");
+    auto CheckPattern = [=]() -> bool {
+      return Element->isNamed() &&
+             (matchGenericPattern(Element->getName()) ||
+              matchGenericPattern(Element->getTypeName()));
+    };
+    auto CheckOffset = [=]() -> bool {
+      return matchOffsetPattern(Element->getOffset());
+    };
+    if ((options().getSelectGenericPattern() && CheckPattern()) ||
+        (options().getSelectOffsetPattern() && CheckOffset()) ||
+        ((Requests.size() || ElementRequest.size()) &&
+         checkElementRequest(Element, Requests)))
+      addElement(Element);
+  }
+
+  template <typename U>
+  void resolveGenericPatternMatch(LVLine *Line, const U &Requests) {
+    assert(Line && "Line must not be nullptr");
+    auto CheckPattern = [=]() -> bool {
+      return matchGenericPattern(Line->lineNumberAsStringStripped()) ||
+             matchGenericPattern(Line->getName()) ||
+             matchGenericPattern(Line->getPathname());
+    };
+    auto CheckOffset = [=]() -> bool {
+      return matchOffsetPattern(Line->getAddress());
+    };
+    if ((options().getSelectGenericPattern() && CheckPattern()) ||
+        (options().getSelectOffsetPattern() && CheckOffset()) ||
+        (Requests.size() && checkElementRequest(Line, Requests)))
+      addElement(Line);
+  }
+
+  Error createMatchEntry(LVMatchInfo &Filters, StringRef Pattern,
+                         bool IgnoreCase, bool UseRegex);
+
+public:
+  static LVPatterns *getPatterns();
+
+  LVPatterns() {
+    ElementDispatch = LVElement::getDispatch();
+    LineDispatch = LVLine::getDispatch();
+    ScopeDispatch = LVScope::getDispatch();
+    SymbolDispatch = LVSymbol::getDispatch();
+    TypeDispatch = LVType::getDispatch();
+  }
+  LVPatterns(const LVPatterns &) = delete;
+  LVPatterns &operator=(const LVPatterns &) = delete;
+  ~LVPatterns() = default;
+
+  // Clear any existing patterns.
+  void clear() {
+    GenericMatchInfo.clear();
+    OffsetMatchInfo.clear();
+    ElementRequest.clear();
+    LineRequest.clear();
+    ScopeRequest.clear();
+    SymbolRequest.clear();
+    TypeRequest.clear();
+
+    options().resetSelectGenericKind();
+    options().resetSelectGenericPattern();
+    options().resetSelectOffsetPattern();
+  }
+
+  void addRequest(LVElementKindSet &Selection) {
+    addRequest(Selection, ElementDispatch, ElementRequest);
+  }
+  void addRequest(LVLineKindSet &Selection) {
+    addRequest(Selection, LineDispatch, LineRequest);
+  }
+  void addRequest(LVScopeKindSet &Selection) {
+    addRequest(Selection, ScopeDispatch, ScopeRequest);
+  }
+  void addRequest(LVSymbolKindSet &Selection) {
+    addRequest(Selection, SymbolDispatch, SymbolRequest);
+  }
+  void addRequest(LVTypeKindSelection &Selection) {
+    addRequest(Selection, TypeDispatch, TypeRequest);
+  }
+
+  void updateReportOptions();
+
+  bool matchPattern(StringRef Input, const LVMatchInfo &MatchInfo);
+  // Match a pattern (--select='pattern').
+  bool matchGenericPattern(StringRef Input) {
+    return matchPattern(Input, GenericMatchInfo);
+  }
+  bool matchOffsetPattern(LVOffset Offset) {
+    return std::find(OffsetMatchInfo.begin(), OffsetMatchInfo.end(), Offset) !=
+           OffsetMatchInfo.end();
+  }
+
+  void resolvePatternMatch(LVLine *Line) {
+    resolveGenericPatternMatch(Line, LineRequest);
+  }
+
+  void resolvePatternMatch(LVScope *Scope) {
+    resolveGenericPatternMatch(Scope, ScopeRequest);
+  }
+
+  void resolvePatternMatch(LVSymbol *Symbol) {
+    resolveGenericPatternMatch(Symbol, SymbolRequest);
+  }
+
+  void resolvePatternMatch(LVType *Type) {
+    resolveGenericPatternMatch(Type, TypeRequest);
+  }
+
+  void addPatterns(StringSet<> &Patterns, LVMatchInfo &Filters);
+
+  // Add generic and offset patterns info.
+  void addGenericPatterns(StringSet<> &Patterns);
+  void addOffsetPatterns(const LVOffsetSet &Patterns);
+
+  // Conditions to print an object.
+  bool printElement(const LVLine *Line) const;
+  bool printObject(const LVLocation *Location) const;
+  bool printElement(const LVScope *Scope) const;
+  bool printElement(const LVSymbol *Symbol) const;
+  bool printElement(const LVType *Type) const;
+
+  void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const { print(dbgs()); }
+#endif
+};
+
+inline LVPatterns &patterns() { return *LVPatterns::getPatterns(); }
+
 } // namespace logicalview
 } // namespace llvm
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index e464a44ba1c1d..1a1ee19f31900 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -141,11 +141,21 @@ class LVReader {
   LVSplitContext &getSplitContext() { return SplitContext; }
 
   // Conditions to print an object.
-  bool doPrintLine(const LVLine *Line) const { return true; }
-  bool doPrintLocation(const LVLocation *Location) const { return true; }
-  bool doPrintScope(const LVScope *Scope) const { return true; }
-  bool doPrintSymbol(const LVSymbol *Symbol) const { return true; }
-  bool doPrintType(const LVType *Type) const { return true; }
+  bool doPrintLine(const LVLine *Line) const {
+    return patterns().printElement(Line);
+  }
+  bool doPrintLocation(const LVLocation *Location) const {
+    return patterns().printObject(Location);
+  }
+  bool doPrintScope(const LVScope *Scope) const {
+    return patterns().printElement(Scope);
+  }
+  bool doPrintSymbol(const LVSymbol *Symbol) const {
+    return patterns().printElement(Symbol);
+  }
+  bool doPrintType(const LVType *Type) const {
+    return patterns().printElement(Type);
+  }
 
   static LVReader &getInstance();
   static void setInstance(LVReader *Reader);

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index 22b1694715390..860ed3c2e5012 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -53,6 +53,8 @@ enum class LVScopeKind {
   LastEntry
 };
 using LVScopeKindSet = std::set<LVScopeKind>;
+using LVScopeDispatch = std::map<LVScopeKind, LVScopeGetFunction>;
+using LVScopeRequest = std::vector<LVScopeGetFunction>;
 
 using LVOffsetElementMap = std::map<LVOffset, LVElement *>;
 
@@ -78,6 +80,7 @@ class LVScope : public LVElement {
   // Typed bitvector with kinds and properties for this scope.
   LVProperties<LVScopeKind> Kinds;
   LVProperties<Property> Properties;
+  static LVScopeDispatch Dispatch;
 
   // Coverage factor in units (bytes).
   unsigned CoverageFactor = 0;
@@ -118,8 +121,8 @@ class LVScope : public LVElement {
   void printEncodedArgs(raw_ostream &OS, bool Full) const;
 
   void printActiveRanges(raw_ostream &OS, bool Full = true) const;
-  virtual void printSizes(raw_ostream &OS) const {};
-  virtual void printSummary(raw_ostream &OS) const {};
+  virtual void printSizes(raw_ostream &OS) const {}
+  virtual void printSummary(raw_ostream &OS) const {}
 
   // Encoded template arguments.
   virtual StringRef getEncodedArgs() const { return StringRef(); }
@@ -259,6 +262,8 @@ class LVScope : public LVElement {
 
   void resolveElements();
 
+  static LVScopeDispatch &getDispatch() { return Dispatch; }
+
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
   virtual void printMatchedElements(raw_ostream &OS, bool UseMatchedElements) {}
@@ -385,6 +390,10 @@ class LVScopeCompileUnit final : public LVScope {
   LVScopeCompileUnit &operator=(const LVScopeCompileUnit &) = delete;
   ~LVScopeCompileUnit() = default;
 
+  LVScope *getCompileUnitParent() const override {
+    return static_cast<LVScope *>(const_cast<LVScopeCompileUnit *>(this));
+  }
+
   // Get the line located at the given address.
   LVLine *lineLowerBound(LVAddress Address) const;
   LVLine *lineUpperBound(LVAddress Address) const;
@@ -412,6 +421,14 @@ class LVScopeCompileUnit final : public LVScope {
   void processRangeLocationCoverage(
       LVValidLocation ValidLocation = &LVLocation::validateRanges);
 
+  // Add matched element.
+  void addMatched(LVElement *Element) { MatchedElements.push_back(Element); }
+  void addMatched(LVScope *Scope) { MatchedScopes.push_back(Scope); }
+  void propagatePatternMatch();
+
+  const LVElements &getMatchedElements() const { return MatchedElements; }
+  const LVScopes &getMatchedScopes() const { return MatchedScopes; }
+
   void printLocalNames(raw_ostream &OS, bool Full = true) const;
   void printSummary(raw_ostream &OS, const LVCounter &Counter,
                     const char *Header) const;

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
index 320bde953127d..15ac6fc4a4dcc 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
@@ -30,6 +30,8 @@ enum class LVSymbolKind {
   LastEntry
 };
 using LVSymbolKindSet = std::set<LVSymbolKind>;
+using LVSymbolDispatch = std::map<LVSymbolKind, LVSymbolGetFunction>;
+using LVSymbolRequest = std::vector<LVSymbolGetFunction>;
 
 class LVSymbol final : public LVElement {
   enum class Property { HasLocation, FillGaps, LastEntry };
@@ -37,6 +39,7 @@ class LVSymbol final : public LVElement {
   // Typed bitvector with kinds and properties for this symbol.
   LVProperties<LVSymbolKind> Kinds;
   LVProperties<Property> Properties;
+  static LVSymbolDispatch Dispatch;
 
   // CodeView symbol Linkage name.
   size_t LinkageNameIndex = 0;
@@ -152,6 +155,8 @@ class LVSymbol final : public LVElement {
   void resolveName() override;
   void resolveReferences() override;
 
+  static LVSymbolDispatch &getDispatch() { return Dispatch; }
+
   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 eae8942c3c312..a56202c3bcace 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
@@ -44,6 +44,8 @@ enum class LVTypeKind {
   LastEntry
 };
 using LVTypeKindSelection = std::set<LVTypeKind>;
+using LVTypeDispatch = std::map<LVTypeKind, LVTypeGetFunction>;
+using LVTypeRequest = std::vector<LVTypeGetFunction>;
 
 // Class to represent a DWARF Type.
 class LVType : public LVElement {
@@ -52,6 +54,7 @@ class LVType : public LVElement {
   // Typed bitvector with kinds and properties for this type.
   LVProperties<LVTypeKind> Kinds;
   LVProperties<Property> Properties;
+  static LVTypeDispatch Dispatch;
 
 public:
   LVType() : LVElement(LVSubclassID::LV_TYPE) { setIsType(); }
@@ -106,6 +109,8 @@ class LVType : public LVElement {
   void resolveName() override;
   void resolveReferences() override;
 
+  static LVTypeDispatch &getDispatch() { return Dispatch; }
+
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
index 8d7c09f6a2dc3..262150a947afc 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -21,6 +21,11 @@ using namespace llvm::logicalview;
 
 #define DEBUG_TYPE "Element"
 
+LVElementDispatch LVElement::Dispatch = {
+    {LVElementKind::Discarded, &LVElement::getIsDiscarded},
+    {LVElementKind::Global, &LVElement::getIsGlobalReference},
+    {LVElementKind::Optimized, &LVElement::getIsOptimized}};
+
 LVType *LVElement::getTypeAsType() const {
   return ElementType && ElementType->getIsType()
              ? static_cast<LVType *>(ElementType)

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
index 9d94f6d33b92d..cc36e6d28c0ba 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
@@ -45,6 +45,18 @@ const char *LVLine::kind() const {
   return Kind;
 }
 
+LVLineDispatch LVLine::Dispatch = {
+    {LVLineKind::IsBasicBlock, &LVLine::getIsBasicBlock},
+    {LVLineKind::IsDiscriminator, &LVLine::getIsDiscriminator},
+    {LVLineKind::IsEndSequence, &LVLine::getIsEndSequence},
+    {LVLineKind::IsLineDebug, &LVLine::getIsLineDebug},
+    {LVLineKind::IsLineAssembler, &LVLine::getIsLineAssembler},
+    {LVLineKind::IsNewStatement, &LVLine::getIsNewStatement},
+    {LVLineKind::IsEpilogueBegin, &LVLine::getIsEpilogueBegin},
+    {LVLineKind::IsPrologueEnd, &LVLine::getIsPrologueEnd},
+    {LVLineKind::IsAlwaysStepInto, &LVLine::getIsAlwaysStepInto},
+    {LVLineKind::IsNeverStepInto, &LVLine::getIsNeverStepInto}};
+
 // String used as padding for printing elements with no line number.
 std::string LVLine::noLineAsString(bool ShowZero) const {
   return (ShowZero || options().getAttributeZero()) ? ("    0   ")

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp
index 1afc24403837b..2bcc8a6b4c35b 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp
@@ -11,6 +11,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/Support/Errc.h"
 
 using namespace llvm;
 using namespace llvm::logicalview;
@@ -394,3 +396,181 @@ void LVOptions::print(raw_ostream &OS) const {
      << "Tag:       " << Options.getInternalTag() << "\n"
      << "\n";
 }
+
+//===----------------------------------------------------------------------===//
+// Logical element selection using patterns.
+//===----------------------------------------------------------------------===//
+LVPatterns *LVPatterns::getPatterns() {
+  static LVPatterns Patterns;
+  return &Patterns;
+}
+
+Error LVPatterns::createMatchEntry(LVMatchInfo &Filters, StringRef Pattern,
+                                   bool IgnoreCase, bool UseRegex) {
+  LVMatch Match;
+  // Process pattern as regular expression.
+  if (UseRegex) {
+    Match.Pattern = std::string(Pattern);
+    if (Pattern.size()) {
+      Match.RE = std::make_shared<Regex>(Pattern, IgnoreCase ? Regex::IgnoreCase
+                                                             : Regex::NoFlags);
+      std::string Error;
+      if (!Match.RE->isValid(Error))
+        return createStringError(errc::invalid_argument,
+                                 "Error in regular expression: %s",
+                                 Error.c_str());
+
+      Match.Mode = LVMatchMode::Regex;
+      Filters.push_back(Match);
+      return Error::success();
+    }
+  }
+
+  // Process pattern as an exact string match, depending on the case.
+  Match.Pattern = std::string(Pattern);
+  if (Match.Pattern.size()) {
+    Match.Mode = IgnoreCase ? LVMatchMode::NoCase : LVMatchMode::Match;
+    Filters.push_back(Match);
+  }
+
+  return Error::success();
+}
+
+void LVPatterns::addGenericPatterns(StringSet<> &Patterns) {
+  addPatterns(Patterns, GenericMatchInfo);
+  if (GenericMatchInfo.size()) {
+    options().setSelectGenericPattern();
+    options().setSelectExecute();
+  }
+}
+
+void LVPatterns::addOffsetPatterns(const LVOffsetSet &Patterns) {
+  for (const LVOffset &Entry : Patterns)
+    OffsetMatchInfo.push_back(Entry);
+  if (OffsetMatchInfo.size()) {
+    options().setSelectOffsetPattern();
+    options().setSelectExecute();
+  }
+}
+
+void LVPatterns::addPatterns(StringSet<> &Patterns, LVMatchInfo &Filters) {
+  bool IgnoreCase = options().getSelectIgnoreCase();
+  bool UseRegex = options().getSelectUseRegex();
+  for (const StringSet<>::value_type &Entry : Patterns) {
+    StringRef Pattern = Entry.first();
+    if (Error Err = createMatchEntry(Filters, Pattern, IgnoreCase, UseRegex))
+      consumeError(std::move(Err));
+  }
+
+  LLVM_DEBUG({
+    dbgs() << "\nPattern Information:\n";
+    for (LVMatch &Match : Filters)
+      dbgs() << "Mode: "
+             << (Match.Mode == LVMatchMode::Match ? "Match" : "Regex")
+             << " Pattern: '" << Match.Pattern << "'\n";
+  });
+}
+
+void LVPatterns::addElement(LVElement *Element) {
+  // Mark any element that matches a given pattern.
+  Element->setIsMatched();
+  options().setSelectExecute();
+  if (options().getReportList())
+    getReaderCompileUnit()->addMatched(Element);
+  if (options().getReportAnyView()) {
+    getReaderCompileUnit()->addMatched(Element->getIsScope()
+                                           ? static_cast<LVScope *>(Element)
+                                           : Element->getParentScope());
+    // Mark element as matched.
+    if (!Element->getIsScope())
+      Element->setHasPattern();
+  }
+}
+
+void LVPatterns::updateReportOptions() {
+  if (ElementRequest.size() || LineRequest.size() || ScopeRequest.size() ||
+      SymbolRequest.size() || TypeRequest.size()) {
+    options().setSelectGenericKind();
+    options().setSelectExecute();
+  }
+
+  // If we have selected requests and there are no specified report options,
+  // assume the 'details' option.
+  if (options().getSelectExecute() && !options().getReportExecute()) {
+    options().setReportExecute();
+    options().setReportList();
+  }
+}
+
+// Match a general pattern.
+bool LVPatterns::matchPattern(StringRef Input, const LVMatchInfo &MatchInfo) {
+  bool Matched = false;
+  // Traverse all match specifications.
+  for (const LVMatch &Match : MatchInfo) {
+    switch (Match.Mode) {
+    case LVMatchMode::Match:
+      Matched = Input.equals(Match.Pattern);
+      break;
+    case LVMatchMode::NoCase:
+      Matched = Input.equals_insensitive(Match.Pattern);
+      break;
+    case LVMatchMode::Regex:
+      Matched = Match.RE->match(Input);
+      break;
+    default:
+      break;
+    }
+    // Return if we have a match.
+    if (Matched)
+      return true;
+  }
+  return Matched;
+}
+
+bool LVPatterns::printElement(const LVLine *Line) const {
+  return (options().getPrintLines() && Line->getIsLineDebug()) ||
+         (options().getPrintInstructions() && Line->getIsLineAssembler());
+}
+
+bool LVPatterns::printObject(const LVLocation *Location) const {
+  if (options().getAttributeAll())
+    return true;
+  bool DoPrint = options().getAttributeAnyLocation();
+  // Consider the case of filler locations.
+  if (DoPrint && Location && Location->getIsGapEntry())
+    DoPrint = options().getAttributeGaps();
+  return DoPrint;
+}
+
+bool LVPatterns::printElement(const LVScope *Scope) const {
+  // A scope will be printed depending on the following rules:
+  // - Request to print scopes.
+  // - Request to print any of its children.
+  // - If the scope is Root or CompileUnit:
+  //     Request to print summary, sizes or warnings.
+  return options().getPrintScopes() ||
+         (options().getPrintSymbols() && Scope->getHasSymbols()) ||
+         (options().getPrintAnyLine() && Scope->getHasLines()) ||
+         (options().getPrintTypes() && Scope->getHasTypes()) ||
+         ((options().getPrintSizesSummary() || options().getPrintWarnings()) &&
+          (Scope->getIsRoot() || Scope->getIsCompileUnit()));
+}
+
+bool LVPatterns::printElement(const LVSymbol *Symbol) const {
+  // Print compiler generated symbols only if command line option.
+  if (Symbol->getIsArtificial())
+    return options().getAttributeGenerated() && options().getPrintSymbols();
+  return options().getPrintSymbols();
+}
+
+bool LVPatterns::printElement(const LVType *Type) const {
+  // Print array subranges only if print types is requested.
+  if (Type->getIsSubrange())
+    return options().getAttributeSubrange() && options().getPrintTypes();
+  return options().getPrintTypes();
+}
+
+void LVPatterns::print(raw_ostream &OS) const {
+  OS << "LVPatterns\n";
+  LLVM_DEBUG(dbgs() << "Print Patterns\n");
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
index 2154ace04e053..52098239598cd 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
@@ -129,6 +129,22 @@ Error LVReader::doLoad() {
   // Set current Reader instance.
   setInstance(this);
 
+  // Before any scopes creation, process any pattern specified by the
+  // --select and --select-offsets options.
+  patterns().addGenericPatterns(options().Select.Generic);
+  patterns().addOffsetPatterns(options().Select.Offsets);
+
+  // Add any specific element printing requests based on the element kind.
+  patterns().addRequest(options().Select.Elements);
+  patterns().addRequest(options().Select.Lines);
+  patterns().addRequest(options().Select.Scopes);
+  patterns().addRequest(options().Select.Symbols);
+  patterns().addRequest(options().Select.Types);
+
+  // Once we have processed the requests for any particular kind of elements,
+  // we need to update the report options, in order to have a default value.
+  patterns().updateReportOptions();
+
   // Delegate the scope tree creation to the specific reader.
   if (Error Err = createScopes())
     return Err;
@@ -150,6 +166,24 @@ Error LVReader::doPrint() {
   // Set current Reader instance.
   setInstance(this);
 
+  // Check for any '--report' request.
+  if (options().getReportExecute()) {
+    // Requested details.
+    if (options().getReportList())
+      if (Error Err = printMatchedElements(/*UseMatchedElements=*/true))
+        return Err;
+    // Requested only children.
+    if (options().getReportChildren() && !options().getReportParents())
+      if (Error Err = printMatchedElements(/*UseMatchedElements=*/false))
+        return Err;
+    // Requested (parents) or (parents and children).
+    if (options().getReportParents() || options().getReportView())
+      if (Error Err = printScopes())
+        return Err;
+
+    return Error::success();
+  }
+
   return printScopes();
 }
 
@@ -159,7 +193,9 @@ Error LVReader::printScopes() {
       return Err;
 
     // Start printing from the root.
-    bool DoMatch = false;
+    bool DoMatch = options().getSelectGenericPattern() ||
+                   options().getSelectGenericKind() ||
+                   options().getSelectOffsetPattern();
     return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS);
   }
 

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index 7a90d1f1ed80c..0228be7664111 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -87,6 +87,30 @@ const char *LVScope::kind() const {
   return Kind;
 }
 
+LVScopeDispatch LVScope::Dispatch = {
+    {LVScopeKind::IsAggregate, &LVScope::getIsAggregate},
+    {LVScopeKind::IsArray, &LVScope::getIsArray},
+    {LVScopeKind::IsBlock, &LVScope::getIsBlock},
+    {LVScopeKind::IsCallSite, &LVScope::getIsCallSite},
+    {LVScopeKind::IsCatchBlock, &LVScope::getIsCatchBlock},
+    {LVScopeKind::IsClass, &LVScope::getIsClass},
+    {LVScopeKind::IsCompileUnit, &LVScope::getIsCompileUnit},
+    {LVScopeKind::IsEntryPoint, &LVScope::getIsEntryPoint},
+    {LVScopeKind::IsEnumeration, &LVScope::getIsEnumeration},
+    {LVScopeKind::IsFunction, &LVScope::getIsFunction},
+    {LVScopeKind::IsFunctionType, &LVScope::getIsFunctionType},
+    {LVScopeKind::IsInlinedFunction, &LVScope::getIsInlinedFunction},
+    {LVScopeKind::IsLabel, &LVScope::getIsLabel},
+    {LVScopeKind::IsLexicalBlock, &LVScope::getIsLexicalBlock},
+    {LVScopeKind::IsNamespace, &LVScope::getIsNamespace},
+    {LVScopeKind::IsRoot, &LVScope::getIsRoot},
+    {LVScopeKind::IsStructure, &LVScope::getIsStructure},
+    {LVScopeKind::IsTemplate, &LVScope::getIsTemplate},
+    {LVScopeKind::IsTemplateAlias, &LVScope::getIsTemplateAlias},
+    {LVScopeKind::IsTemplatePack, &LVScope::getIsTemplatePack},
+    {LVScopeKind::IsTryBlock, &LVScope::getIsTryBlock},
+    {LVScopeKind::IsUnion, &LVScope::getIsUnion}};
+
 void LVScope::addToChildren(LVElement *Element) {
   if (!Children)
     Children = new LVElements();
@@ -395,6 +419,9 @@ void LVScope::resolveName() {
   }
 
   LVElement::resolveName();
+
+  // Resolve any given pattern.
+  patterns().resolvePatternMatch(this);
 }
 
 void LVScope::resolveReferences() {
@@ -432,6 +459,8 @@ void LVScope::resolveElements() {
     LVScopeCompileUnit *CompileUnit = static_cast<LVScopeCompileUnit *>(Scope);
     getReader().setCompileUnit(CompileUnit);
     CompileUnit->resolve();
+    // Propagate any matching information into the scopes tree.
+    CompileUnit->propagatePatternMatch();
   }
 }
 
@@ -530,6 +559,13 @@ void LVScope::encodeTemplateArguments(std::string &Name,
 }
 
 bool LVScope::resolvePrinting() const {
+  // In selection mode, always print the root scope regardless of the
+  // number of matched elements. If no matches, the root by itself will
+  // indicate no matches.
+  if (options().getSelectExecute()) {
+    return getIsRoot() || getIsCompileUnit() || getHasPattern();
+  }
+
   bool Globals = options().getAttributeGlobal();
   bool Locals = options().getAttributeLocal();
   if ((Globals && Locals) || (!Globals && !Locals)) {
@@ -794,7 +830,8 @@ void LVScope::printEncodedArgs(raw_ostream &OS, bool Full) const {
 void LVScope::print(raw_ostream &OS, bool Full) const {
   if (getIncludeInPrint() && getReader().doPrintScope(this)) {
     // For a summary (printed elements), do not count the scope root.
-    if (!(getIsRoot()))
+    // For a summary (selected elements) do not count a compile unit.
+    if (!(getIsRoot() || (getIsCompileUnit() && options().getSelectExecute())))
       getReaderCompileUnit()->incrementPrintedScopes();
     LVElement::print(OS, Full);
     printExtra(OS, Full);
@@ -939,9 +976,28 @@ void LVScopeCompileUnit::addSize(LVScope *Scope, LVOffset Lower,
     CUContributionSize = Size;
 }
 
+// Update parents and children with pattern information.
+void LVScopeCompileUnit::propagatePatternMatch() {
+  // At this stage, we have finished creating the Scopes tree and we have
+  // a list of elements that match the pattern specified in the command line.
+  // The pattern corresponds to a scope or element; mark parents and/or
+  // children as having that pattern, before any printing is done.
+  if (!options().getSelectExecute())
+    return;
+
+  if (MatchedScopes.size()) {
+    for (LVScope *Scope : MatchedScopes)
+      Scope->traverseParentsAndChildren(&LVScope::getHasPattern,
+                                        &LVScope::setHasPattern);
+  } else {
+    // Mark the compile unit as having a pattern to enable any requests to
+    // print sizes and summary as that information is recorded at that level.
+    setHasPattern();
+  }
+}
+
 void LVScopeCompileUnit::processRangeLocationCoverage(
     LVValidLocation ValidLocation) {
-
   if (options().getAttributeRange()) {
     // Traverse the scopes to get scopes that have invalid ranges.
     LVLocations Locations;
@@ -975,10 +1031,18 @@ StringRef LVScopeCompileUnit::getFilename(size_t Index) const {
   return getStringPool().getString(Filenames[Index - 1]);
 }
 
-void LVScopeCompileUnit::incrementPrintedLines() { ++Printed.Lines; }
-void LVScopeCompileUnit::incrementPrintedScopes() { ++Printed.Scopes; }
-void LVScopeCompileUnit::incrementPrintedSymbols() { ++Printed.Symbols; }
-void LVScopeCompileUnit::incrementPrintedTypes() { ++Printed.Types; }
+void LVScopeCompileUnit::incrementPrintedLines() {
+  options().getSelectExecute() ? ++Found.Lines : ++Printed.Lines;
+}
+void LVScopeCompileUnit::incrementPrintedScopes() {
+  options().getSelectExecute() ? ++Found.Scopes : ++Printed.Scopes;
+}
+void LVScopeCompileUnit::incrementPrintedSymbols() {
+  options().getSelectExecute() ? ++Found.Symbols : ++Printed.Symbols;
+}
+void LVScopeCompileUnit::incrementPrintedTypes() {
+  options().getSelectExecute() ? ++Found.Types : ++Printed.Types;
+}
 
 // Values are used by '--summary' option (allocated).
 void LVScopeCompileUnit::increment(LVLine *Line) {
@@ -1074,6 +1138,13 @@ void LVScopeCompileUnit::printSizes(raw_ostream &OS) const {
   // Recursively print the contributions for each scope.
   std::function<void(const LVScope *Scope)> PrintScope =
       [&](const LVScope *Scope) {
+        // If we have selection criteria, then use only the selected scopes.
+        if (options().getSelectExecute() && options().getReportAnyView()) {
+          for (const LVScope *Scope : MatchedScopes)
+            if (Scope->getLevel() < options().getOutputLevel())
+              printScopeSize(Scope, OS);
+          return;
+        }
         if (Scope->getLevel() < options().getOutputLevel()) {
           if (const LVScopes *Scopes = Scope->getScopes())
             for (const LVScope *Scope : *Scopes) {
@@ -1108,7 +1179,7 @@ void LVScopeCompileUnit::printSizes(raw_ostream &OS) const {
 }
 
 void LVScopeCompileUnit::printSummary(raw_ostream &OS) const {
-  printSummary(OS, Printed, "Printed");
+  printSummary(OS, options().getSelectExecute() ? Found : Printed, "Printed");
 }
 
 // Print summary details for the scopes tree.

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
index 4e9b05ee89188..05d6b845b78e4 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
@@ -51,6 +51,15 @@ const char *LVSymbol::kind() const {
   return Kind;
 }
 
+LVSymbolDispatch LVSymbol::Dispatch = {
+    {LVSymbolKind::IsCallSiteParameter, &LVSymbol::getIsCallSiteParameter},
+    {LVSymbolKind::IsConstant, &LVSymbol::getIsConstant},
+    {LVSymbolKind::IsInheritance, &LVSymbol::getIsInheritance},
+    {LVSymbolKind::IsMember, &LVSymbol::getIsMember},
+    {LVSymbolKind::IsParameter, &LVSymbol::getIsParameter},
+    {LVSymbolKind::IsUnspecified, &LVSymbol::getIsUnspecified},
+    {LVSymbolKind::IsVariable, &LVSymbol::getIsVariable}};
+
 // Add a Location Entry.
 void LVSymbol::addLocation(dwarf::Attribute Attr, LVAddress LowPC,
                            LVAddress HighPC, LVUnsigned SectionOffset,
@@ -212,6 +221,9 @@ void LVSymbol::resolveName() {
   setIsResolvedName();
 
   LVElement::resolveName();
+
+  // Resolve any given pattern.
+  patterns().resolvePatternMatch(this);
 }
 
 void LVSymbol::resolveReferences() {

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
index 625b9768a447c..18b5d76ce8ecb 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
@@ -83,6 +83,28 @@ const char *LVType::kind() const {
   return Kind;
 }
 
+LVTypeDispatch LVType::Dispatch = {
+    {LVTypeKind::IsBase, &LVType::getIsBase},
+    {LVTypeKind::IsConst, &LVType::getIsConst},
+    {LVTypeKind::IsEnumerator, &LVType::getIsEnumerator},
+    {LVTypeKind::IsImport, &LVType::getIsImport},
+    {LVTypeKind::IsImportDeclaration, &LVType::getIsImportDeclaration},
+    {LVTypeKind::IsImportModule, &LVType::getIsImportModule},
+    {LVTypeKind::IsPointer, &LVType::getIsPointer},
+    {LVTypeKind::IsPointerMember, &LVType::getIsPointerMember},
+    {LVTypeKind::IsReference, &LVType::getIsReference},
+    {LVTypeKind::IsRestrict, &LVType::getIsRestrict},
+    {LVTypeKind::IsRvalueReference, &LVType::getIsRvalueReference},
+    {LVTypeKind::IsSubrange, &LVType::getIsSubrange},
+    {LVTypeKind::IsTemplateParam, &LVType::getIsTemplateParam},
+    {LVTypeKind::IsTemplateTemplateParam, &LVType::getIsTemplateTemplateParam},
+    {LVTypeKind::IsTemplateTypeParam, &LVType::getIsTemplateTypeParam},
+    {LVTypeKind::IsTemplateValueParam, &LVType::getIsTemplateValueParam},
+    {LVTypeKind::IsTypedef, &LVType::getIsTypedef},
+    {LVTypeKind::IsUnaligned, &LVType::getIsUnaligned},
+    {LVTypeKind::IsUnspecified, &LVType::getIsUnspecified},
+    {LVTypeKind::IsVolatile, &LVType::getIsVolatile}};
+
 void LVType::resolveReferences() {
   // Some DWARF tags are the representation of types. However, we associate
   // some of them to scopes. The ones associated with types, do not have
@@ -136,6 +158,9 @@ void LVType::resolveName() {
     generateName();
 
   LVElement::resolveName();
+
+  // Resolve any given pattern.
+  patterns().resolvePatternMatch(this);
 }
 
 StringRef LVType::resolveReferencesChain() {

diff  --git a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
index 65001520c6e7b..1b66e05922f15 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
+  SelectElementsTest.cpp
   LocationRangesTest.cpp
   LogicalElementsTest.cpp
   StringPoolTest.cpp

diff  --git a/llvm/unittests/DebugInfo/LogicalView/SelectElementsTest.cpp b/llvm/unittests/DebugInfo/LogicalView/SelectElementsTest.cpp
new file mode 100644
index 0000000000000..d590942eed4d7
--- /dev/null
+++ b/llvm/unittests/DebugInfo/LogicalView/SelectElementsTest.cpp
@@ -0,0 +1,399 @@
+//===- llvm/unittest/DebugInfo/LogicalView/SelectElementsTest.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/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 {
+
+class ReaderTestSelection : public LVReader {
+  // Types.
+  LVType *IntegerType = nullptr;
+
+  // Scopes.
+  LVScope *NestedScope = nullptr;
+  LVScopeAggregate *Aggregate = nullptr;
+  LVScopeFunction *Function = nullptr;
+  LVScopeNamespace *Namespace = nullptr;
+
+  // Symbols.
+  LVSymbol *ClassMember = nullptr;
+  LVSymbol *LocalVariable = nullptr;
+  LVSymbol *NestedVariable = nullptr;
+  LVSymbol *Parameter = nullptr;
+
+  // Lines.
+  LVLine *LineOne = nullptr;
+  LVLine *LineTwo = nullptr;
+  LVLine *LineThree = nullptr;
+  LVLine *LineFour = nullptr;
+  LVLine *LineFive = 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:
+  ReaderTestSelection(ScopedPrinter &W) : LVReader("", "", W) {
+    setInstance(this);
+  }
+
+  Error createScopes() { return LVReader::createScopes(); }
+
+  void createElements();
+  void addElements();
+  void initElements();
+  void resolvePatterns(LVPatterns &Patterns);
+  void checkFlexiblePatterns();
+  void checkGenericPatterns();
+  void checkKindPatterns();
+};
+
+// Helper function to add a logical element to a given scope.
+void ReaderTestSelection::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 ReaderTestSelection::set(LVElement *Element, StringRef Name,
+                              LVOffset Offset, uint32_t LineNumber,
+                              LVElement *Type) {
+  Element->setName(Name);
+  Element->setOffset(Offset);
+  Element->setLineNumber(LineNumber);
+  Element->setType(Type);
+  EXPECT_EQ(Element->getName(), Name);
+  EXPECT_EQ(Element->getOffset(), Offset);
+  EXPECT_EQ(Element->getLineNumber(), LineNumber);
+  EXPECT_EQ(Element->getType(), Type);
+}
+
+// Create the logical elements.
+void ReaderTestSelection::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);
+
+  // Create the logical scopes.
+  CompileUnit = create<LVScopeCompileUnit, LVScopeSetFunction>(
+      &LVScope::setIsCompileUnit);
+  Function =
+      create<LVScopeFunction, LVScopeSetFunction>(&LVScope::setIsFunction);
+  NestedScope =
+      create<LVScope, LVScopeSetFunction>(&LVScope::setIsLexicalBlock);
+  Namespace =
+      create<LVScopeNamespace, LVScopeSetFunction>(&LVScope::setIsNamespace);
+  Aggregate =
+      create<LVScopeAggregate, LVScopeSetFunction>(&LVScope::setIsAggregate);
+
+  // Create the logical symbols.
+  ClassMember = create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsMember);
+  LocalVariable =
+      create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable);
+  NestedVariable =
+      create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable);
+  Parameter = create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsParameter);
+
+  // Create the logical lines.
+  LineOne = create<LVLine, LVLineSetFunction>(&LVLine::setIsLineDebug);
+  LineTwo = create<LVLine, LVLineSetFunction>(&LVLine::setIsBasicBlock);
+  LineThree = create<LVLine, LVLineSetFunction>(&LVLine::setIsNewStatement);
+  LineFour = create<LVLine, LVLineSetFunction>(&LVLine::setIsPrologueEnd);
+  LineFive = create<LVLine, LVLineSetFunction>(&LVLine::setIsLineAssembler);
+}
+
+// Create the logical view adding the created logical elements.
+void ReaderTestSelection::addElements() {
+  setCompileUnit(CompileUnit);
+
+  // Root
+  //   CompileUnit
+  //     IntegerType
+  //     Namespace
+  //       Aggregate
+  //         ClassMember
+  //     Function
+  //       Parameter
+  //       LocalVariable
+  //       LineOne
+  //       LineTwo
+  //       NestedScope
+  //         NestedVariable
+  //         LineThree
+  //         LineFour
+  //       LineFive
+
+  // Add elements to Root.
+  add(Root, CompileUnit);
+
+  // Add elements to CompileUnit.
+  add(CompileUnit, IntegerType);
+  add(CompileUnit, Namespace);
+  add(CompileUnit, Function);
+
+  // Add elements to Namespace.
+  add(Namespace, Aggregate);
+
+  // Add elements to Function.
+  add(Function, Parameter);
+  add(Function, LocalVariable);
+  add(Function, LineOne);
+  add(Function, LineTwo);
+  add(Function, LineFive);
+  add(Function, NestedScope);
+
+  // Add elements to Aggregate.
+  add(Aggregate, ClassMember);
+
+  // Add elements to NestedScope.
+  add(NestedScope, NestedVariable);
+  add(NestedScope, LineThree);
+  add(NestedScope, LineFour);
+}
+
+void ReaderTestSelection::resolvePatterns(LVPatterns &Patterns) {
+  // Traverse the given scope and its children applying the pattern match.
+  // Before applying the pattern, reset previous matched state.
+  std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) {
+    auto Traverse = [&](const auto *Set) {
+      if (Set)
+        for (const auto &Entry : *Set) {
+          Entry->resetIsMatched();
+          Patterns.resolvePatternMatch(Entry);
+        }
+    };
+
+    Parent->resetIsMatched();
+    Patterns.resolvePatternMatch(Parent);
+
+    Traverse(Parent->getSymbols());
+    Traverse(Parent->getTypes());
+    Traverse(Parent->getLines());
+
+    if (const LVScopes *Scopes = Parent->getScopes())
+      for (LVScope *Scope : *Scopes) {
+        Scope->resetIsMatched();
+        Patterns.resolvePatternMatch(Scope);
+        TraverseScope(Scope);
+      }
+  };
+
+  // Start traversing the scopes root and apply any matching pattern.
+  TraverseScope(Root);
+}
+
+// Set initial values to logical elements.
+void ReaderTestSelection::initElements() {
+  // Types.
+  set(IntegerType, "int", 0x1000);
+
+  // Scopes.
+  set(CompileUnit, "test.cpp", 0x2000);
+  set(Namespace, "anyNamespace", 0x3000, 300);
+  set(Aggregate, "anyClass", 0x4000, 400);
+  set(Function, "anyFunction", 0x5000, 500, IntegerType);
+  set(NestedScope, "", 0x6000, 600);
+
+  // Symbols.
+  set(Parameter, "Param", 0x5100, 510, IntegerType);
+  set(LocalVariable, "LocalVariable", 0x5200, 520, IntegerType);
+  set(NestedVariable, "NestedVariable", 0x6200, 620, IntegerType);
+
+  // Lines.
+  set(LineOne, "", 0x5110, 511);
+  set(LineTwo, "", 0x5210, 521);
+  set(LineThree, "", 0x6110, 611);
+  set(LineFour, "", 0x6210, 621);
+  set(LineFive, "", 0x7110, 711);
+}
+
+// Check logical elements kind patterns.
+void ReaderTestSelection::checkKindPatterns() {
+  // Add patterns.
+  LVPatterns &Patterns = patterns();
+  Patterns.clear();
+
+  LVElementKindSet KindElements; // --select-elements=<Kind>
+  LVLineKindSet KindLines;       // --select-lines=<Kind>
+  LVScopeKindSet KindScopes;     // --select-scopes=<Kind>
+  LVSymbolKindSet KindSymbols;   // --select-symbols=<Kind>
+  LVTypeKindSelection KindTypes; // --select-types=<Kind>
+
+  KindElements.insert(LVElementKind::Global);
+  KindLines.insert(LVLineKind::IsLineDebug);
+  KindLines.insert(LVLineKind::IsNewStatement);
+  KindLines.insert(LVLineKind::IsLineAssembler);
+  KindScopes.insert(LVScopeKind::IsLexicalBlock);
+  KindSymbols.insert(LVSymbolKind::IsMember);
+  KindSymbols.insert(LVSymbolKind::IsParameter);
+  KindTypes.insert(LVTypeKind::IsBase);
+
+  // Add requests based on the element kind.
+  Patterns.addRequest(KindElements);
+  Patterns.addRequest(KindLines);
+  Patterns.addRequest(KindScopes);
+  Patterns.addRequest(KindSymbols);
+  Patterns.addRequest(KindTypes);
+
+  // Apply the collected patterns.
+  resolvePatterns(Patterns);
+
+  EXPECT_FALSE(CompileUnit->getIsMatched());
+  EXPECT_FALSE(Namespace->getIsMatched());
+  EXPECT_FALSE(Aggregate->getIsMatched());
+  EXPECT_FALSE(Function->getIsMatched());
+  EXPECT_TRUE(NestedScope->getIsMatched());
+
+  EXPECT_TRUE(IntegerType->getIsMatched());
+
+  EXPECT_TRUE(ClassMember->getIsMatched());
+  EXPECT_TRUE(Parameter->getIsMatched());
+  EXPECT_FALSE(LocalVariable->getIsMatched());
+  EXPECT_FALSE(NestedVariable->getIsMatched());
+
+  EXPECT_TRUE(LineOne->getIsMatched());
+  EXPECT_FALSE(LineTwo->getIsMatched());
+  EXPECT_TRUE(LineThree->getIsMatched());
+  EXPECT_FALSE(LineFour->getIsMatched());
+  EXPECT_TRUE(LineFive->getIsMatched());
+}
+
+// Check logical elements generic patterns (Case sensitive).
+void ReaderTestSelection::checkGenericPatterns() {
+  // Add patterns.
+  LVPatterns &Patterns = patterns();
+  Patterns.clear();
+
+  StringSet<> Generic;                      // --select=<Pattern>
+  Generic.insert(Function->getName());      // anyFunction
+  Generic.insert(Namespace->getName());     // anyNamespace
+  Generic.insert(LocalVariable->getName()); // LocalVariable
+
+  LVOffsetSet Offsets; // --select-offset=<Offset>
+  Offsets.insert(IntegerType->getOffset());
+  Offsets.insert(LineOne->getOffset());
+  Offsets.insert(LineTwo->getOffset());
+
+  // Add requests based on the generic string and offset.
+  Patterns.addGenericPatterns(Generic);
+  Patterns.addOffsetPatterns(Offsets);
+
+  // Apply the collected patterns.
+  resolvePatterns(Patterns);
+
+  EXPECT_FALSE(CompileUnit->getIsMatched());
+  EXPECT_TRUE(Namespace->getIsMatched());
+  EXPECT_FALSE(Aggregate->getIsMatched());
+  EXPECT_TRUE(Function->getIsMatched());
+  EXPECT_FALSE(NestedScope->getIsMatched());
+
+  EXPECT_TRUE(IntegerType->getIsMatched());
+
+  EXPECT_FALSE(ClassMember->getIsMatched());
+  EXPECT_FALSE(Parameter->getIsMatched());
+  EXPECT_TRUE(LocalVariable->getIsMatched());
+  EXPECT_FALSE(NestedVariable->getIsMatched());
+
+  EXPECT_TRUE(LineOne->getIsMatched());
+  EXPECT_TRUE(LineTwo->getIsMatched());
+  EXPECT_FALSE(LineThree->getIsMatched());
+  EXPECT_FALSE(LineFour->getIsMatched());
+  EXPECT_FALSE(LineFive->getIsMatched());
+}
+
+// Check logical elements flexible patterns (case insensitive, RegEx).
+void ReaderTestSelection::checkFlexiblePatterns() {
+  options().setSelectIgnoreCase();
+  options().setSelectUseRegex();
+
+  // Add patterns.
+  LVPatterns &Patterns = patterns();
+  Patterns.clear();
+
+  StringSet<> Generic; // --select=<Pattern>
+  Generic.insert("function");
+  Generic.insert("NaMeSpAcE");
+  Generic.insert("[a-z]*Variable");
+  Generic.insert("[0-9]21");
+
+  // Add requests based on the flexible string.
+  Patterns.addGenericPatterns(Generic);
+
+  // Apply the collected patterns.
+  resolvePatterns(Patterns);
+
+  EXPECT_FALSE(CompileUnit->getIsMatched());
+  EXPECT_TRUE(Namespace->getIsMatched()); // anyNamespace
+  EXPECT_FALSE(Aggregate->getIsMatched());
+  EXPECT_TRUE(Function->getIsMatched()); // anyFunction
+  EXPECT_FALSE(NestedScope->getIsMatched());
+
+  EXPECT_FALSE(IntegerType->getIsMatched());
+
+  EXPECT_FALSE(ClassMember->getIsMatched());
+  EXPECT_FALSE(Parameter->getIsMatched());
+  EXPECT_TRUE(LocalVariable->getIsMatched());  // LocalVariable
+  EXPECT_TRUE(NestedVariable->getIsMatched()); // NestedVariable
+
+  EXPECT_FALSE(LineOne->getIsMatched());
+  EXPECT_TRUE(LineTwo->getIsMatched()); // 521
+  EXPECT_FALSE(LineThree->getIsMatched());
+  EXPECT_TRUE(LineFour->getIsMatched()); // 621
+  EXPECT_FALSE(LineFive->getIsMatched());
+}
+
+TEST(LogicalViewTest, SelectElements) {
+  ScopedPrinter W(outs());
+  ReaderTestSelection Reader(W);
+
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setPrintAll();
+  ReaderOptions.setReportList();
+  ReaderOptions.setReportAnyView();
+
+  ReaderOptions.resolveDependencies();
+  options().setOptions(&ReaderOptions);
+
+  Reader.createElements();
+  Reader.addElements();
+  Reader.initElements();
+  Reader.checkKindPatterns();
+  Reader.checkGenericPatterns();
+  Reader.checkFlexiblePatterns();
+}
+
+} // namespace


        


More information about the llvm-commits mailing list