[llvm] 6e6a3d8 - [llvm-remarkutil] Introduce filter command (#159784)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 24 07:07:41 PDT 2025


Author: Tobias Stadler
Date: 2025-09-24T15:07:37+01:00
New Revision: 6e6a3d83245e3fbd5f51a6457b5ee492cb84db2b

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

LOG: [llvm-remarkutil] Introduce filter command (#159784)

Add a filter command to llvm-remarkutil. This can be used to extract
remarks for a certain function, pass, type, etc. from a large remarks
file to a new remarks file. This uses the same filter arguments as the
count command.

Depends on #156715. Thanks to this change, we don't need to buffer all
remarks before reserializing them, so we should be able to process
arbitrarily large files.

Pull Request: https://github.com/llvm/llvm-project/pull/159784

Added: 
    llvm/test/tools/llvm-remarkutil/Inputs/filter.yaml
    llvm/test/tools/llvm-remarkutil/filter.test
    llvm/tools/llvm-remarkutil/RemarkFilter.cpp

Modified: 
    llvm/test/tools/llvm-remarkutil/broken-bitstream-remark-magic.test
    llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
    llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
    llvm/test/tools/llvm-remarkutil/empty-file.test
    llvm/tools/llvm-remarkutil/CMakeLists.txt
    llvm/tools/llvm-remarkutil/RemarkCounter.cpp
    llvm/tools/llvm-remarkutil/RemarkCounter.h
    llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
    llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-remarkutil/Inputs/filter.yaml b/llvm/test/tools/llvm-remarkutil/Inputs/filter.yaml
new file mode 100644
index 0000000000000..89def7fc4c0e5
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/Inputs/filter.yaml
@@ -0,0 +1,28 @@
+--- !Passed
+Pass:            pass1
+Name:            Remark1
+DebugLoc:        { File: 'path/to/func1.c', Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - String:          ' text'
+  - arg1:            argval1
+...
+--- !Missed
+Pass:            pass2
+Name:            Remark2
+DebugLoc:        { File: 'path/to/func2.c', Line: 1, Column: 2 }
+Function:        func2
+Args:
+  - String:          ' text'
+  - arg2:            argval2
+...
+--- !Analysis
+Pass:            pass3
+Name:            Remark3
+DebugLoc:        { File: 'path/to/func3.c', Line: 1, Column: 2 }
+Function:        func3
+Args:
+  - String:          ' text'
+  - arg3:            argval3
+    DebugLoc:        { File: 'path/to/func3.c', Line: 2, Column: 2 }
+...

diff  --git a/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark-magic.test b/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark-magic.test
index f469eadc07f99..c21dbd72a2a18 100644
--- a/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark-magic.test
+++ b/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark-magic.test
@@ -2,5 +2,6 @@ RUN: not llvm-remarkutil instruction-count %p/Inputs/broken-remark-magic.bitstre
 RUN: not llvm-remarkutil instruction-mix %p/Inputs/broken-remark-magic.bitstream -o - 2>&1 | FileCheck %s
 RUN: not llvm-remarkutil annotation-count --annotation-type=remark %p/Inputs/broken-remark-magic.bitstream -o - 2>&1 | FileCheck %s
 RUN: not llvm-remarkutil count %p/Inputs/broken-remark-magic.bitstream -o - 2>&1 | FileCheck %s
+RUN: not llvm-remarkutil filter %p/Inputs/broken-remark-magic.bitstream -o - 2>&1 | FileCheck %s
 
 CHECK: error: Automatic detection of remark format failed. Unknown magic number: '1234'

diff  --git a/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test b/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
index 78011aece08f7..339f082d4825b 100644
--- a/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
+++ b/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
@@ -2,5 +2,6 @@ RUN: not llvm-remarkutil bitstream2yaml %p/Inputs/broken-remark -o - 2>&1 | File
 RUN: not llvm-remarkutil instruction-count --parser=bitstream %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 RUN: not llvm-remarkutil annotation-count --parser=bitstream --annotation-type=remark %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 RUN: not llvm-remarkutil count --parser=bitstream %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
+RUN: not llvm-remarkutil filter --parser=bitstream %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 
 CHECK: error: Unknown magic number: expecting RMRK, got --- .

diff  --git a/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test b/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
index 464d0b80c4ad0..9da3de4034b0f 100644
--- a/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
+++ b/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
@@ -3,5 +3,6 @@ RUN: not llvm-remarkutil instruction-count --parser=yaml %p/Inputs/broken-remark
 RUN: not llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 RUN: not llvm-remarkutil annotation-count --parser=yaml --annotation-type=remark %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 RUN: not llvm-remarkutil count --parser=yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
+RUN: not llvm-remarkutil filter --parser=yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 
 CHECK: error: Type, Pass, Name or Function missing

diff  --git a/llvm/test/tools/llvm-remarkutil/empty-file.test b/llvm/test/tools/llvm-remarkutil/empty-file.test
index d9820a088ea8f..9b2b000e9c24b 100644
--- a/llvm/test/tools/llvm-remarkutil/empty-file.test
+++ b/llvm/test/tools/llvm-remarkutil/empty-file.test
@@ -3,16 +3,19 @@ RUN: not llvm-remarkutil instruction-count --parser=yaml %p/Inputs/empty-file -o
 RUN: not llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
 RUN: not llvm-remarkutil annotation-count --parser=yaml --annotation-type=remark %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
 RUN: not llvm-remarkutil count --parser=yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
+RUN: not llvm-remarkutil filter --parser=yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
 RUN: llvm-remarkutil bitstream2yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=BITSTREAM2YAML
 RUN: llvm-remarkutil instruction-count --parser=bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=SIZEBITSTREAM
 RUN: llvm-remarkutil instruction-mix --parser=bitstream %p/Inputs/empty-file --report_style=csv -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=MIXBITSTREAM
 RUN: llvm-remarkutil annotation-count --parser=bitstream --annotation-type=remark %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=ANNOTATIONBITSTREAM
 RUN: llvm-remarkutil count --parser=bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=COUNTBITSTREAM
+RUN: llvm-remarkutil filter --parser=bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=FILTERBITSTREAM
 ; Parser format auto-detection should treat empty files as bitstream files
 RUN: llvm-remarkutil instruction-count %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=SIZEBITSTREAM
 RUN: llvm-remarkutil instruction-mix %p/Inputs/empty-file --report_style=csv -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=MIXBITSTREAM
 RUN: llvm-remarkutil annotation-count --annotation-type=remark %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=ANNOTATIONBITSTREAM
 RUN: llvm-remarkutil count %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=COUNTBITSTREAM
+RUN: llvm-remarkutil filter %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=FILTERBITSTREAM
 
 ; YAMLPARSER: error: document root is not of mapping type.
 
@@ -30,3 +33,5 @@ RUN: llvm-remarkutil count %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow
 
 ; MIXBITSTREAM-LABEL: Instruction,Count
 ; MIXBITSTREAM-EMPTY:
+
+; FILTERBITSTREAM-NOT: {{.}}

diff  --git a/llvm/test/tools/llvm-remarkutil/filter.test b/llvm/test/tools/llvm-remarkutil/filter.test
new file mode 100644
index 0000000000000..8304b9f0129a8
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/filter.test
@@ -0,0 +1,59 @@
+RUN: llvm-remarkutil filter %p/Inputs/filter.yaml | 
diff  %p/Inputs/filter.yaml -
+RUN: llvm-remarkutil filter --rfunction=func %p/Inputs/filter.yaml | 
diff  %p/Inputs/filter.yaml -
+RUN: llvm-remarkutil filter --rremark-name=Remark %p/Inputs/filter.yaml | 
diff  %p/Inputs/filter.yaml -
+RUN: llvm-remarkutil filter --rpass-name=pass %p/Inputs/filter.yaml | 
diff  %p/Inputs/filter.yaml -
+RUN: llvm-remarkutil filter --rfilter-arg-by=argval %p/Inputs/filter.yaml | 
diff  %p/Inputs/filter.yaml -
+
+RUN: llvm-remarkutil filter --rfunction=unc1 %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK1
+RUN: llvm-remarkutil filter --rremark-name=ark3 %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK3
+RUN: llvm-remarkutil filter --rpass-name=s1 %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK1
+RUN: llvm-remarkutil filter --filter-arg-by=argval2 %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK2
+RUN: llvm-remarkutil filter --function=func1 %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK1
+RUN: llvm-remarkutil filter --pass-name=pass2 %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK2
+RUN: llvm-remarkutil filter --remark-name=Remark3 %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK3
+RUN: llvm-remarkutil filter --function=func1 --pass-name=pass1 --remark-name=Remark1 %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK1
+RUN: llvm-remarkutil filter --remark-type=passed %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK1
+RUN: llvm-remarkutil filter --remark-type=missed %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK2
+RUN: llvm-remarkutil filter --remark-type=analysis %p/Inputs/filter.yaml | FileCheck %s --strict-whitespace --check-prefix=REMARK3
+
+RUN: llvm-remarkutil yaml2bitstream -o %t.opt.bitstream %p/Inputs/filter.yaml
+RUN: llvm-remarkutil filter --function=func1 %t.opt.bitstream | FileCheck %s --strict-whitespace --check-prefix=REMARK1
+
+RUN: llvm-remarkutil filter --function=func1 %t.opt.bitstream -o %t.r1.opt.bitstream
+RUN: llvm-remarkutil bitstream2yaml %t.r1.opt.bitstream | FileCheck %s --strict-whitespace --check-prefix=REMARK1
+
+RUN: llvm-remarkutil filter --function=func %p/Inputs/filter.yaml | FileCheck %s --allow-empty --strict-whitespace --check-prefix=EMPTY
+
+; REMARK1: --- !Passed
+; REMARK1-NEXT: Pass:            pass1
+; REMARK1-NEXT: Name:            Remark1
+; REMARK1-NEXT: DebugLoc:        { File: 'path/to/func1.c', Line: 1, Column: 2 }
+; REMARK1-NEXT: Function:        func1
+; REMARK1-NEXT: Args:
+; REMARK1-NEXT:   - String:          ' text'
+; REMARK1-NEXT:   - arg1:            argval1
+; REMARK1-NEXT: ...
+; REMARK1-NOT: {{.}}
+; REMARK2: --- !Missed
+; REMARK2-NEXT: Pass:            pass2
+; REMARK2-NEXT: Name:            Remark2
+; REMARK2-NEXT: DebugLoc:        { File: 'path/to/func2.c', Line: 1, Column: 2 }
+; REMARK2-NEXT: Function:        func2
+; REMARK2-NEXT: Args:
+; REMARK2-NEXT:   - String:          ' text'
+; REMARK2-NEXT:   - arg2:            argval2
+; REMARK2-NEXT: ...
+; REMARK2-NOT: {{.}}
+; REMARK3: --- !Analysis
+; REMARK3-NEXT: Pass:            pass3
+; REMARK3-NEXT: Name:            Remark3
+; REMARK3-NEXT: DebugLoc:        { File: 'path/to/func3.c', Line: 1, Column: 2 }
+; REMARK3-NEXT: Function:        func3
+; REMARK3-NEXT: Args:
+; REMARK3-NEXT:   - String:          ' text'
+; REMARK3-NEXT:   - arg3:            argval3
+; REMARK3-NEXT:     DebugLoc:        { File: 'path/to/func3.c', Line: 2, Column: 2 }
+; REMARK3-NEXT: ...
+; REMARK3-NOT: {{.}}
+
+; EMPTY-NOT: {{.}}

diff  --git a/llvm/tools/llvm-remarkutil/CMakeLists.txt b/llvm/tools/llvm-remarkutil/CMakeLists.txt
index ed398ad272024..c6e9334d87c04 100644
--- a/llvm/tools/llvm-remarkutil/CMakeLists.txt
+++ b/llvm/tools/llvm-remarkutil/CMakeLists.txt
@@ -8,6 +8,7 @@ add_llvm_tool(llvm-remarkutil
   RemarkConvert.cpp
   RemarkCount.cpp
   RemarkCounter.cpp
+  RemarkFilter.cpp
   RemarkInstructionMix.cpp
   RemarkSizeDiff.cpp
   RemarkUtil.cpp

diff  --git a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
index 7d5c84815b3bb..2e842c8c2d72e 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
@@ -25,6 +25,9 @@ static cl::SubCommand CountSub("count",
 
 INPUT_FORMAT_COMMAND_LINE_OPTIONS(CountSub)
 INPUT_OUTPUT_COMMAND_LINE_OPTIONS(CountSub)
+REMARK_FILTER_COMMAND_LINE_OPTIONS(CountSub)
+
+REMARK_FILTER_SETUP_FUNC()
 
 static cl::list<std::string>
     Keys("args", cl::desc("Specify remark argument/s to count by."),
@@ -34,45 +37,7 @@ static cl::list<std::string> RKeys(
     cl::desc(
         "Specify remark argument/s to count (accepts regular expressions)."),
     cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional);
-static cl::opt<std::string>
-    RemarkNameOpt("remark-name",
-                  cl::desc("Optional remark name to filter collection by."),
-                  cl::ValueOptional, cl::sub(CountSub));
-static cl::opt<std::string>
-    PassNameOpt("pass-name", cl::ValueOptional,
-                cl::desc("Optional remark pass name to filter collection by."),
-                cl::sub(CountSub));
 
-static cl::opt<std::string> RemarkFilterArgByOpt(
-    "filter-arg-by", cl::desc("Optional remark arg to filter collection by."),
-    cl::ValueOptional, cl::sub(CountSub));
-static cl::opt<std::string>
-    RemarkNameOptRE("rremark-name",
-                    cl::desc("Optional remark name to filter collection by "
-                             "(accepts regular expressions)."),
-                    cl::ValueOptional, cl::sub(CountSub));
-static cl::opt<std::string>
-    RemarkArgFilterOptRE("rfilter-arg-by",
-                         cl::desc("Optional remark arg to filter collection by "
-                                  "(accepts regular expressions)."),
-                         cl::sub(CountSub), cl::ValueOptional);
-static cl::opt<std::string>
-    PassNameOptRE("rpass-name", cl::ValueOptional,
-                  cl::desc("Optional remark pass name to filter collection "
-                           "by (accepts regular expressions)."),
-                  cl::sub(CountSub));
-static cl::opt<Type> RemarkTypeOpt(
-    "remark-type", cl::desc("Optional remark type to filter collection by."),
-    cl::values(clEnumValN(Type::Unknown, "unknown", "UNKOWN"),
-               clEnumValN(Type::Passed, "passed", "PASSED"),
-               clEnumValN(Type::Missed, "missed", "MISSED"),
-               clEnumValN(Type::Analysis, "analysis", "ANALYSIS"),
-               clEnumValN(Type::AnalysisFPCommute, "analysis-fp-commute",
-                          "ANALYSIS_FP_COMMUTE"),
-               clEnumValN(Type::AnalysisAliasing, "analysis-aliasing",
-                          "ANALYSIS_ALIASING"),
-               clEnumValN(Type::Failure, "failure", "FAILURE")),
-    cl::init(Type::Failure), cl::sub(CountSub));
 static cl::opt<CountBy> CountByOpt(
     "count-by", cl::desc("Specify the property to collect remarks by."),
     cl::values(
@@ -112,21 +77,6 @@ static unsigned getValForKey(StringRef Key, const Remark &Remark) {
   return *RemarkArg->getValAsInt();
 }
 
-bool Filters::filterRemark(const Remark &Remark) {
-  if (RemarkNameFilter && !RemarkNameFilter->match(Remark.RemarkName))
-    return false;
-  if (PassNameFilter && !PassNameFilter->match(Remark.PassName))
-    return false;
-  if (RemarkTypeFilter)
-    return *RemarkTypeFilter == Remark.RemarkType;
-  if (ArgFilter) {
-    if (!any_of(Remark.Args,
-                [this](Argument Arg) { return ArgFilter->match(Arg.Val); }))
-      return false;
-  }
-  return true;
-}
-
 Error ArgumentCounter::getAllMatchingArgumentsInRemark(
     StringRef Buffer, ArrayRef<FilterMatcher> Arguments, Filters &Filter) {
   auto MaybeParser = createRemarkParser(InputFormat, Buffer);
@@ -223,33 +173,6 @@ Error RemarkCounter::print(StringRef OutputFileName) {
   return Error::success();
 }
 
-Expected<Filters> getRemarkFilter() {
-  // Create Filter properties.
-  auto MaybeRemarkNameFilter =
-      FilterMatcher::createExactOrRE(RemarkNameOpt, RemarkNameOptRE);
-  if (!MaybeRemarkNameFilter)
-    return MaybeRemarkNameFilter.takeError();
-
-  auto MaybePassNameFilter =
-      FilterMatcher::createExactOrRE(PassNameOpt, PassNameOptRE);
-  if (!MaybePassNameFilter)
-    return MaybePassNameFilter.takeError();
-
-  auto MaybeRemarkArgFilter = FilterMatcher::createExactOrRE(
-      RemarkFilterArgByOpt, RemarkArgFilterOptRE);
-  if (!MaybeRemarkArgFilter)
-    return MaybeRemarkArgFilter.takeError();
-
-  std::optional<Type> RemarkType;
-  if (RemarkTypeOpt != Type::Failure)
-    RemarkType = RemarkTypeOpt;
-
-  // Create RemarkFilter.
-  return Filters{std::move(*MaybeRemarkNameFilter),
-                 std::move(*MaybePassNameFilter),
-                 std::move(*MaybeRemarkArgFilter), RemarkType};
-}
-
 Error useCollectRemark(StringRef Buffer, Counter &Counter, Filters &Filter) {
   // Create Parser.
   auto MaybeParser = createRemarkParser(InputFormat, Buffer);
@@ -278,7 +201,7 @@ static Error collectRemarks() {
   if (!MaybeBuf)
     return MaybeBuf.takeError();
   StringRef Buffer = (*MaybeBuf)->getBuffer();
-  auto MaybeFilter = getRemarkFilter();
+  auto MaybeFilter = getRemarkFilters();
   if (!MaybeFilter)
     return MaybeFilter.takeError();
   auto &Filter = *MaybeFilter;

diff  --git a/llvm/tools/llvm-remarkutil/RemarkCounter.h b/llvm/tools/llvm-remarkutil/RemarkCounter.h
index 3b977791d87c2..69e552e3742ec 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.h
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.h
@@ -14,6 +14,7 @@
 #include "RemarkUtilHelpers.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/Support/Regex.h"
+#include <map>
 
 namespace llvm {
 namespace remarks {
@@ -45,18 +46,6 @@ inline std::string groupByToStr(GroupBy GroupBy) {
   }
 }
 
-/// Filter out remarks based on remark properties based on name, pass name,
-/// argument and type.
-struct Filters {
-  std::optional<FilterMatcher> RemarkNameFilter;
-  std::optional<FilterMatcher> PassNameFilter;
-  std::optional<FilterMatcher> ArgFilter;
-  std::optional<Type> RemarkTypeFilter;
-
-  /// Returns true if \p Remark satisfies all the provided filters.
-  bool filterRemark(const Remark &Remark);
-};
-
 /// Abstract counter class used to define the general required methods for
 /// counting a remark.
 struct Counter {

diff  --git a/llvm/tools/llvm-remarkutil/RemarkFilter.cpp b/llvm/tools/llvm-remarkutil/RemarkFilter.cpp
new file mode 100644
index 0000000000000..acfef6608677c
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkFilter.cpp
@@ -0,0 +1,84 @@
+//===- RemarkFilter.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic tool to filter remarks
+//
+//===----------------------------------------------------------------------===//
+
+#include "RemarkUtilHelpers.h"
+#include "RemarkUtilRegistry.h"
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Regex.h"
+
+using namespace llvm;
+using namespace remarks;
+using namespace llvm::remarkutil;
+
+namespace filter {
+
+static cl::SubCommand FilterSub("filter",
+                                "Filter remarks based on specified criteria.");
+
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(FilterSub)
+OUTPUT_FORMAT_COMMAND_LINE_OPTIONS(FilterSub)
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(FilterSub)
+REMARK_FILTER_COMMAND_LINE_OPTIONS(FilterSub)
+
+REMARK_FILTER_SETUP_FUNC()
+
+static Error tryFilter() {
+  auto MaybeFilter = getRemarkFilters();
+  if (!MaybeFilter)
+    return MaybeFilter.takeError();
+  Filters &Filter = *MaybeFilter;
+
+  auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+  if (!MaybeBuf)
+    return MaybeBuf.takeError();
+  auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+  if (!MaybeParser)
+    return MaybeParser.takeError();
+  auto &Parser = **MaybeParser;
+
+  Format SerializerFormat = OutputFormat;
+  if (SerializerFormat == Format::Auto) {
+    SerializerFormat = Parser.ParserFormat;
+    if (OutputFileName.empty() || OutputFileName == "-")
+      SerializerFormat = Format::YAML;
+  }
+
+  auto MaybeOF = getOutputFileForRemarks(OutputFileName, SerializerFormat);
+  if (!MaybeOF)
+    return MaybeOF.takeError();
+  auto OF = std::move(*MaybeOF);
+
+  auto MaybeSerializer = createRemarkSerializer(SerializerFormat, OF->os());
+  if (!MaybeSerializer)
+    return MaybeSerializer.takeError();
+  auto &Serializer = **MaybeSerializer;
+
+  auto MaybeRemark = Parser.next();
+  for (; MaybeRemark; MaybeRemark = Parser.next()) {
+    Remark &Remark = **MaybeRemark;
+    if (!Filter.filterRemark(Remark))
+      continue;
+    Serializer.emit(Remark);
+  }
+
+  auto E = MaybeRemark.takeError();
+  if (!E.isA<EndOfFileError>())
+    return E;
+  consumeError(std::move(E));
+  OF->keep();
+  return Error::success();
+}
+
+static CommandRegistration FilterReg(&FilterSub, tryFilter);
+
+} // namespace filter

diff  --git a/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
index ad6c46eceb8f2..be529480e7d24 100644
--- a/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.cpp
@@ -92,5 +92,22 @@ FilterMatcher::createExactOrRE(const llvm::cl::opt<std::string> &ExactArg,
   return std::nullopt;
 }
 
+bool Filters::filterRemark(const Remark &Remark) {
+  if (FunctionFilter && !FunctionFilter->match(Remark.FunctionName))
+    return false;
+  if (RemarkNameFilter && !RemarkNameFilter->match(Remark.RemarkName))
+    return false;
+  if (PassNameFilter && !PassNameFilter->match(Remark.PassName))
+    return false;
+  if (RemarkTypeFilter)
+    return *RemarkTypeFilter == Remark.RemarkType;
+  if (ArgFilter) {
+    if (!any_of(Remark.Args,
+                [this](Argument Arg) { return ArgFilter->match(Arg.Val); }))
+      return false;
+  }
+  return true;
+}
+
 } // namespace remarks
 } // namespace llvm

diff  --git a/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
index 894ac8354e18b..0dd550765c1c6 100644
--- a/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
+++ b/llvm/tools/llvm-remarkutil/RemarkUtilHelpers.h
@@ -9,12 +9,11 @@
 // Helpers for remark utilites
 //
 //===----------------------------------------------------------------------===//
-#include "llvm-c/Remarks.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Remarks/Remark.h"
 #include "llvm/Remarks/RemarkFormat.h"
 #include "llvm/Remarks/RemarkParser.h"
-#include "llvm/Remarks/YAMLRemarkSerializer.h"
+#include "llvm/Remarks/RemarkSerializer.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
@@ -43,6 +42,16 @@
           clEnumValN(Format::Bitstream, "bitstream", "Bitstream")),            \
       cl::sub(SUBOPT));
 
+#define OUTPUT_FORMAT_COMMAND_LINE_OPTIONS(SUBOPT)                             \
+  static cl::opt<Format> OutputFormat(                                         \
+      "serializer", cl::init(Format::Auto),                                    \
+      cl::desc("Output remark format to serialize"),                           \
+      cl::values(clEnumValN(Format::Auto, "auto",                              \
+                            "Follow the parser format (default)"),             \
+                 clEnumValN(Format::YAML, "yaml", "YAML"),                     \
+                 clEnumValN(Format::Bitstream, "bitstream", "Bitstream")),     \
+      cl::sub(SUBOPT));
+
 #define DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(SUBOPT)                            \
   static cl::opt<bool> UseDebugLoc(                                            \
       "use-debug-loc",                                                         \
@@ -52,6 +61,87 @@
           "number)"),                                                          \
       cl::init(false), cl::sub(SUBOPT));
 
+#define REMARK_FILTER_COMMAND_LINE_OPTIONS(SUBOPT)                             \
+  static cl::opt<std::string> FunctionOpt(                                     \
+      "function", cl::sub(SUBOPT), cl::ValueOptional,                          \
+      cl::desc("Optional function name to filter collection by."));            \
+  static cl::opt<std::string> FunctionOptRE(                                   \
+      "rfunction", cl::sub(SUBOPT), cl::ValueOptional,                         \
+      cl::desc("Optional function name to filter collection by "               \
+               "(accepts regular expressions)."));                             \
+  static cl::opt<std::string> RemarkNameOpt(                                   \
+      "remark-name",                                                           \
+      cl::desc("Optional remark name to filter collection by."),               \
+      cl::ValueOptional, cl::sub(SUBOPT));                                     \
+  static cl::opt<std::string> RemarkNameOptRE(                                 \
+      "rremark-name",                                                          \
+      cl::desc("Optional remark name to filter collection by "                 \
+               "(accepts regular expressions)."),                              \
+      cl::ValueOptional, cl::sub(SUBOPT));                                     \
+  static cl::opt<std::string> PassNameOpt(                                     \
+      "pass-name", cl::ValueOptional,                                          \
+      cl::desc("Optional remark pass name to filter collection by."),          \
+      cl::sub(SUBOPT));                                                        \
+  static cl::opt<std::string> PassNameOptRE(                                   \
+      "rpass-name", cl::ValueOptional,                                         \
+      cl::desc("Optional remark pass name to filter collection "               \
+               "by (accepts regular expressions)."),                           \
+      cl::sub(SUBOPT));                                                        \
+  static cl::opt<Type> RemarkTypeOpt(                                          \
+      "remark-type",                                                           \
+      cl::desc("Optional remark type to filter collection by."),               \
+      cl::values(clEnumValN(Type::Unknown, "unknown", "UNKOWN"),               \
+                 clEnumValN(Type::Passed, "passed", "PASSED"),                 \
+                 clEnumValN(Type::Missed, "missed", "MISSED"),                 \
+                 clEnumValN(Type::Analysis, "analysis", "ANALYSIS"),           \
+                 clEnumValN(Type::AnalysisFPCommute, "analysis-fp-commute",    \
+                            "ANALYSIS_FP_COMMUTE"),                            \
+                 clEnumValN(Type::AnalysisAliasing, "analysis-aliasing",       \
+                            "ANALYSIS_ALIASING"),                              \
+                 clEnumValN(Type::Failure, "failure", "FAILURE")),             \
+      cl::sub(SUBOPT));                                                        \
+  static cl::opt<std::string> RemarkFilterArgByOpt(                            \
+      "filter-arg-by",                                                         \
+      cl::desc("Optional remark arg to filter collection by."),                \
+      cl::ValueOptional, cl::sub(SUBOPT));                                     \
+  static cl::opt<std::string> RemarkArgFilterOptRE(                            \
+      "rfilter-arg-by",                                                        \
+      cl::desc("Optional remark arg to filter collection by "                  \
+               "(accepts regular expressions)."),                              \
+      cl::sub(SUBOPT), cl::ValueOptional);
+
+#define REMARK_FILTER_SETUP_FUNC()                                             \
+  static Expected<Filters> getRemarkFilters() {                                \
+    auto MaybeFunctionFilter =                                                 \
+        FilterMatcher::createExactOrRE(FunctionOpt, FunctionOptRE);            \
+    if (!MaybeFunctionFilter)                                                  \
+      return MaybeFunctionFilter.takeError();                                  \
+                                                                               \
+    auto MaybeRemarkNameFilter =                                               \
+        FilterMatcher::createExactOrRE(RemarkNameOpt, RemarkNameOptRE);        \
+    if (!MaybeRemarkNameFilter)                                                \
+      return MaybeRemarkNameFilter.takeError();                                \
+                                                                               \
+    auto MaybePassNameFilter =                                                 \
+        FilterMatcher::createExactOrRE(PassNameOpt, PassNameOptRE);            \
+    if (!MaybePassNameFilter)                                                  \
+      return MaybePassNameFilter.takeError();                                  \
+                                                                               \
+    auto MaybeRemarkArgFilter = FilterMatcher::createExactOrRE(                \
+        RemarkFilterArgByOpt, RemarkArgFilterOptRE);                           \
+    if (!MaybeRemarkArgFilter)                                                 \
+      return MaybeRemarkArgFilter.takeError();                                 \
+                                                                               \
+    std::optional<Type> TypeFilter;                                            \
+    if (RemarkTypeOpt.getNumOccurrences())                                     \
+      TypeFilter = RemarkTypeOpt.getValue();                                   \
+                                                                               \
+    return Filters{std::move(*MaybeFunctionFilter),                            \
+                   std::move(*MaybeRemarkNameFilter),                          \
+                   std::move(*MaybePassNameFilter),                            \
+                   std::move(*MaybeRemarkArgFilter), TypeFilter};              \
+  }
+
 namespace llvm {
 namespace remarks {
 Expected<std::unique_ptr<MemoryBuffer>>
@@ -95,5 +185,18 @@ class FilterMatcher {
   }
 };
 
+/// Filter out remarks based on remark properties (function, remark name, pass
+/// name, argument values and type).
+struct Filters {
+  std::optional<FilterMatcher> FunctionFilter;
+  std::optional<FilterMatcher> RemarkNameFilter;
+  std::optional<FilterMatcher> PassNameFilter;
+  std::optional<FilterMatcher> ArgFilter;
+  std::optional<Type> RemarkTypeFilter;
+
+  /// Returns true if \p Remark satisfies all the provided filters.
+  bool filterRemark(const Remark &Remark);
+};
+
 } // namespace remarks
 } // namespace llvm


        


More information about the llvm-commits mailing list