[llvm] Remark Util introduce remark count (PR #66214)

Zain Jaffal via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 12 06:14:25 PDT 2023


https://github.com/zjaffal updated https://github.com/llvm/llvm-project/pull/66214

>From a81a53557980aa447b96e39d2f0368cad47092c8 Mon Sep 17 00:00:00 2001
From: Zain Jaffal <z_jaffal at apple.com>
Date: Fri, 18 Aug 2023 16:49:55 +0100
Subject: [PATCH 1/7] Remark Util introduce remark count

This tool is a generic remark counter reporting count based on specified
properties. The counter can be used to count remarks individually and
filter them based on name, type and pass or count using remark
arguments.
---
 llvm/docs/CommandGuide/llvm-remarkutil.rst    |  73 ++++
 llvm/include/llvm/Remarks/Remark.h            |   6 +-
 llvm/lib/Remarks/Remark.cpp                   |  11 +
 .../annotation-count-with-dbg-loc.test        |   7 +
 .../llvm-remarkutil/annotation-count.test     |   7 +
 .../broken-bitstream-remark.test              |   2 +
 .../llvm-remarkutil/broken-yaml-remark.test   |   2 +
 .../count/Inputs/remark-count-by.yaml         |  43 +++
 .../count/Inputs/remark-filter-by.yaml        |  40 +++
 .../count/Inputs/remark-group-by.yaml         |  54 +++
 .../llvm-remarkutil/count/count-by-keys.test  |  20 ++
 .../count/count-by-remark.test                |  20 ++
 .../count/filter-by-pass-name.test            |  10 +
 .../count/filter-by-remark-name.test          |  10 +
 .../llvm-remarkutil/count/filter-by-type.test |  16 +
 .../count/group-by-function-with-loc.test     |   7 +
 .../count/group-by-function.test              |   7 +
 .../count/group-by-source.test                |   6 +
 .../tools/llvm-remarkutil/empty-file.test     |   5 +
 .../instruction-count-with-dbg-loc.test       |   7 +
 .../llvm-remarkutil/instruction-count.test    |   7 +
 llvm/tools/llvm-remarkutil/CMakeLists.txt     |   1 +
 llvm/tools/llvm-remarkutil/RemarkCounter.cpp  | 339 ++++++++++++++++++
 llvm/tools/llvm-remarkutil/RemarkCounter.h    | 198 ++++++++++
 24 files changed, 897 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/Inputs/remark-count-by.yaml
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/Inputs/remark-filter-by.yaml
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/Inputs/remark-group-by.yaml
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/count-by-keys.test
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/count-by-remark.test
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/filter-by-pass-name.test
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/filter-by-remark-name.test
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/filter-by-type.test
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/group-by-function-with-loc.test
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/group-by-function.test
 create mode 100644 llvm/test/tools/llvm-remarkutil/count/group-by-source.test
 create mode 100644 llvm/tools/llvm-remarkutil/RemarkCounter.cpp
 create mode 100644 llvm/tools/llvm-remarkutil/RemarkCounter.h

diff --git a/llvm/docs/CommandGuide/llvm-remarkutil.rst b/llvm/docs/CommandGuide/llvm-remarkutil.rst
index d13a51707a93c58..6c9b9d7b239f96a 100644
--- a/llvm/docs/CommandGuide/llvm-remarkutil.rst
+++ b/llvm/docs/CommandGuide/llvm-remarkutil.rst
@@ -110,6 +110,79 @@ if `--use-debug-loc` is passed then the CSV will include the source path, line n
   Source,Function,Count
   path:line:column,foo,3
 
+.. _count_subcommand:
+
+count
+~~~~~
+
+..program:: llvm-remarkutil count
+
+USAGE: :program:`llvm-remarkutil` count [*options*] <input file>
+
+Summary
+^^^^^^^
+
+:program:`llvm-remarkutil count` counts `remakrs <https://llvm.org/docs/Remarks.html>` based on specified properties. 
+By default the tool will count the remarks based on how many are there in a source, function or total count for the file. 
+The tool also supports collecting count based on specific remark arguments. The specified arguments should have an integer value to be able to report a count.
+
+OPTIONS
+-------
+
+.. option:: --parser=<yaml|bitstream>
+
+  Select the type of input remark parser. Required.
+  * ``yaml``: The tool will parse YAML remarks.
+  * ``bitstream``: The tool will parse bitstream remarks.
+
+.. option:: --count-by<value>
+  Select option to collect remarks by.
+  * ``remark-name``: count how many individual remarks exist.
+  * ``arg``: count remarks based on specified arguments passed by --(r)args. The argument value must be a number.
+
+.. option:: --group-by=<value>
+  group count of remarks by property.
+  * ``source``: Count will be collected per source path. Requires remarks to have debug loc info
+  * ``function``: Count is collected per function.
+  * ``function-with-loc``: Count is collected per function per source. Requires remarks to have debug loc info 
+  * ``Total``: Report a count for the provided remark file.
+
+.. option:: --args[=arguments]
+  If `count-by` is set to `arg` this flag can be used to collect from specified remark arguments represented as a comma seperated string.
+  The arguments must have a numeral value to be able to count remarks by
+  
+.. option:: --rargs[=arguments]
+  If `count-by` is set to `arg` this flag can be used to collect from specified remark arguments using regular expression.
+  The arguments must have a numeral value to be able to count remarks by
+
+.. option:: --pass-name[=<string>]
+  Filter count by pass name.
+
+.. option:: --rpass-name[=<string>]
+  Filter count by pass name using regular expressions.
+
+.. option:: --remark-name[=<string>]
+  Filter count by name.
+
+.. option:: --rremark-name[=<string>]
+  Filter count by name using regular expressions.
+
+.. option:: --filter-arg-by[=<string>]
+  Filter count by argument.
+
+.. option:: --rfilter-arg-by[=<string>]
+  Filter count by argument using regular expressions.
+
+.. option:: --remark-type=<value>
+  Filter remarks by type with the following options.
+  * ``unknown``
+  * ``passed``               
+  * ``missed``               
+  * ``analysis``             
+  * ``analysis-fp-commute``
+  * ``analysis-aliasing``    
+  * ``failure``              
+
 .. _size-diff_subcommand:
 
 size-diff
diff --git a/llvm/include/llvm/Remarks/Remark.h b/llvm/include/llvm/Remarks/Remark.h
index a66f7ed73f2f507..6c7c69f5ceb1566 100644
--- a/llvm/include/llvm/Remarks/Remark.h
+++ b/llvm/include/llvm/Remarks/Remark.h
@@ -52,6 +52,10 @@ struct Argument {
 
   /// Implement operator<< on Argument.
   void print(raw_ostream &OS) const;
+  /// Return the value of argument as int.
+  std::optional<int> getValAsInt() const;
+  /// Check if the argument value can be parsed as int.
+  bool isValInt() const;
 };
 
 // Create wrappers for C Binding types (see CBindingWrapping.h).
@@ -132,7 +136,7 @@ struct Remark {
   /// In order to avoid unwanted copies, "delete" the copy constructor.
   /// If a copy is needed, it should be done through `Remark::clone()`.
   Remark(const Remark &) = default;
-  Remark& operator=(const Remark &) = default;
+  Remark &operator=(const Remark &) = default;
 };
 
 // Create wrappers for C Binding types (see CBindingWrapping.h).
diff --git a/llvm/lib/Remarks/Remark.cpp b/llvm/lib/Remarks/Remark.cpp
index 1b248db41747ed0..ef42271a3c8da6f 100644
--- a/llvm/lib/Remarks/Remark.cpp
+++ b/llvm/lib/Remarks/Remark.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Remarks/Remark.h"
+#include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include <optional>
 
@@ -25,6 +26,16 @@ std::string Remark::getArgsAsMsg() const {
   return OS.str();
 }
 
+/// Returns the value of a specified key parsed from StringRef.
+std::optional<int> Argument::getValAsInt() const {
+  APInt KeyVal;
+  if (Val.getAsInteger(10, KeyVal))
+    return std::nullopt;
+  return KeyVal.getSExtValue();
+}
+
+bool Argument::isValInt() const { return getValAsInt().has_value(); }
+
 void RemarkLocation::print(raw_ostream &OS) const {
   OS << "{ "
      << "File: " << SourceFilePath << ", Line: " << SourceLine
diff --git a/llvm/test/tools/llvm-remarkutil/annotation-count-with-dbg-loc.test b/llvm/test/tools/llvm-remarkutil/annotation-count-with-dbg-loc.test
index cdc731c003f6a04..673a38001f760b4 100644
--- a/llvm/test/tools/llvm-remarkutil/annotation-count-with-dbg-loc.test
+++ b/llvm/test/tools/llvm-remarkutil/annotation-count-with-dbg-loc.test
@@ -1,7 +1,14 @@
 RUN: llvm-remarkutil annotation-count --use-debug-loc --parser=yaml --annotation-type=remark %p/Inputs/annotation-count-with-dbg-loc.yaml | FileCheck %s
 RUN: llvm-remarkutil yaml2bitstream %p/Inputs/annotation-count-with-dbg-loc.yaml | llvm-remarkutil annotation-count --use-debug-loc --parser=bitstream --annotation-type=remark | FileCheck %s
+RUN: llvm-remarkutil count --parser=yaml --count-by=arg --group-by=function-with-loc --remark-name="AnnotationSummary" %p/Inputs/annotation-count-with-dbg-loc.yaml | FileCheck %s --check-prefix=COUNT-CHECK
+RUN: llvm-remarkutil yaml2bitstream %p/Inputs/annotation-count-with-dbg-loc.yaml | llvm-remarkutil count --parser=bitstream --count-by=arg --group-by=function-with-loc --remark-name="AnnotationSummary" | FileCheck %s --check-prefix=COUNT-CHECK
 
 ; CHECK-LABEL: Source,Function,Count
 ; CHECK: path/to/anno.c:1:2,func1,1
 ; CHECK: path/to/anno2.c:1:2,func2,2
 ; CHECK: path/to/anno3.c:1:2,func3,3
+
+; COUNT-CHECK-LABEL: FuctionWithDebugLoc,count
+; COUNT-CHECK: path/to/anno.c:func1,1
+; COUNT-CHECK: path/to/anno2.c:func2,2
+; COUNT-CHECK: path/to/anno3.c:func3,3
diff --git a/llvm/test/tools/llvm-remarkutil/annotation-count.test b/llvm/test/tools/llvm-remarkutil/annotation-count.test
index 73582402201dc98..e006220c64f38fc 100644
--- a/llvm/test/tools/llvm-remarkutil/annotation-count.test
+++ b/llvm/test/tools/llvm-remarkutil/annotation-count.test
@@ -1,7 +1,14 @@
 RUN: llvm-remarkutil annotation-count --parser=yaml --annotation-type=remark %p/Inputs/annotation-count.yaml | FileCheck %s
 RUN: llvm-remarkutil yaml2bitstream %p/Inputs/annotation-count.yaml | llvm-remarkutil annotation-count --parser=bitstream --annotation-type=remark | FileCheck %s
+RUN: llvm-remarkutil count --parser=yaml --count-by=arg --group-by=function --remark-name="AnnotationSummary" %p/Inputs/annotation-count.yaml | FileCheck %s --check-prefix=COUNT-CHECK
+RUN: llvm-remarkutil yaml2bitstream %p/Inputs/annotation-count.yaml | llvm-remarkutil count --parser=bitstream --count-by=arg --group-by=function --remark-name="AnnotationSummary" | FileCheck %s --check-prefix=COUNT-CHECK
 
 ; CHECK-LABEL: Function,Count
 ; CHECK: func1,1
 ; CHECK: func2,2
 ; CHECK: func3,3
+
+; COUNT-CHECK-LABEL: Function,count
+; COUNT-CHECK: func1,1
+; COUNT-CHECK: func2,2
+; COUNT-CHECK: func3,3
diff --git a/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test b/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
index 515c096f540eb47..78011aece08f720 100644
--- a/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
+++ b/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
@@ -1,4 +1,6 @@
 RUN: not llvm-remarkutil bitstream2yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 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
+
 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 df87e3db80442ef..0f0650660336379 100644
--- a/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
+++ b/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
@@ -1,4 +1,6 @@
 RUN: not llvm-remarkutil yaml2bitstream %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 RUN: not llvm-remarkutil instruction-count --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
+
 CHECK: error: Type, Pass, Name or Function missing
diff --git a/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-count-by.yaml b/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-count-by.yaml
new file mode 100644
index 000000000000000..3bd0783b7a0a12b
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-count-by.yaml
@@ -0,0 +1,43 @@
+--- !Analysis
+Pass:            generic-remarks-pass
+Name:            Remark 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count1:           '1'
+  - count2:           '2'
+  - count3:           '3'
+  - count4:           '4'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Analysis
+Pass:            generic-remarks-pass
+Name:            Remark2
+DebugLoc:        { File: path/to/anno2.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count1:           '1'
+  - count2:           '2'
+  - count3:           '3'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Analysis
+Pass:            generic-remarks-pass
+Name:            Remark3 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count1:           '1'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Analysis
+Pass:            generic-remarks-pass
+Name:            Remark 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func2
+Args:
+  - count1:           '1'
+  - count2:           '2'
+  - count3:           '3'
+  - String:          ' instructions with '
+  - type:            remark
diff --git a/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-filter-by.yaml b/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-filter-by.yaml
new file mode 100644
index 000000000000000..e9267bd9404848e
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-filter-by.yaml
@@ -0,0 +1,40 @@
+--- !Analysis
+Pass:            generic-remarks-pass
+Name:            Remark 
+DebugLoc:        { File: path/to/anno2.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count1:           '1'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Analysis
+Pass:            generic-remarks-pass2
+Name:            Remark2
+DebugLoc:        { File: path/to/anno2.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count1:           '1'
+  - count2:           '2'
+  - count3:           '3'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Missed
+Pass:            generic-remarks-pass
+Name:            Remark3 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count1:           '1'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Passed
+Pass:            generic-remarks-pass
+Name:            Remark 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count1:           '1'
+  - count2:           '2'
+  - count3:           '3'
+  - String:          ' instructions with '
+  - type:            remark
diff --git a/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-group-by.yaml b/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-group-by.yaml
new file mode 100644
index 000000000000000..5f9222214f2c7bf
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/Inputs/remark-group-by.yaml
@@ -0,0 +1,54 @@
+--- !Analysis
+Pass:            generic-remarks-pass
+Name:            Remark 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count:           '1'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Missed
+Pass:            generic-remarks-pass
+Name:            Remark 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count:           '3'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Passed
+Pass:            generic-remarks-pass
+Name:            Remark 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func2
+Args:
+  - count:           '3'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Analysis
+Pass:            generic-remarks-pass2
+Name:            Remark 
+DebugLoc:        { File: path/to/anno3.c, Line: 1, Column: 2 }
+Function:        func1
+Args:
+  - count:           '3'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Analysis
+Pass:            generic-remarks-pass3
+Name:            Remark 
+DebugLoc:        { File: path/to/anno.c, Line: 1, Column: 2 }
+Function:        func2
+Args:
+  - count:           '2'
+  - String:          ' instructions with '
+  - type:            remark
+--- !Analysis
+Pass:            generic-remarks-pass4
+Name:            Remark 
+DebugLoc:        { File: path/to/anno2.c, Line: 1, Column: 2 }
+Function:        func3
+Args:
+  - count:           '2'
+  - String:          ' instructions with '
+  - type:            remark
diff --git a/llvm/test/tools/llvm-remarkutil/count/count-by-keys.test b/llvm/test/tools/llvm-remarkutil/count/count-by-keys.test
new file mode 100644
index 000000000000000..dc414620c3aa550
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/count-by-keys.test
@@ -0,0 +1,20 @@
+RUN: llvm-remarkutil count --parser=yaml --count-by=arg --group-by=source %p/Inputs/remark-count-by.yaml | FileCheck %s
+RUN: llvm-remarkutil count --parser=yaml --count-by=arg --group-by=function %p/Inputs/remark-count-by.yaml | FileCheck %s --check-prefix=CHECKFUNC
+RUN: llvm-remarkutil count --parser=yaml --count-by=arg --group-by=function-with-loc %p/Inputs/remark-count-by.yaml | FileCheck %s --check-prefix=CHECKFUNCLOC
+RUN: llvm-remarkutil count --parser=yaml --count-by=arg --group-by=total %p/Inputs/remark-count-by.yaml | FileCheck %s --check-prefix=CHECKTOTAL 
+
+; CHECK-LABEL: Source,count1,count2,count3,count4
+; CHECK: path/to/anno.c,3,4,6,4
+; CHECK: path/to/anno2.c,1,2,3,0
+
+; CHECKFUNC-LABEL: Function,count1,count2,count3,count4
+; CHECKFUNC: func1,3,4,6,4
+; CHECKFUNC: func2,1,2,3,0
+
+; CHECKFUNCLOC-LABEL: FuctionWithDebugLoc,count1,count2,count3,count4
+; CHECKFUNCLOC: path/to/anno.c:func1,2,2,3,4
+; CHECKFUNCLOC: path/to/anno.c:func2,1,2,3,0
+; CHECKFUNCLOC: path/to/anno2.c:func1,1,2,3,0
+
+; CHECKTOTAL-LABEL: Total,count1,count2,count3,count4
+; CHECKTOTAL: Total,4,6,9,4
diff --git a/llvm/test/tools/llvm-remarkutil/count/count-by-remark.test b/llvm/test/tools/llvm-remarkutil/count/count-by-remark.test
new file mode 100644
index 000000000000000..b0248b9b6ec7111
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/count-by-remark.test
@@ -0,0 +1,20 @@
+RUN: llvm-remarkutil count --parser=yaml --count-by=remark-name --group-by=source %p/Inputs/remark-count-by.yaml | FileCheck %s
+RUN: llvm-remarkutil count --parser=yaml --count-by=remark-name --group-by=function %p/Inputs/remark-count-by.yaml | FileCheck %s --check-prefix=CHECKFUNC
+RUN: llvm-remarkutil count --parser=yaml --count-by=remark-name --group-by=function-with-loc %p/Inputs/remark-count-by.yaml | FileCheck %s --check-prefix=CHECKFUNCLOC
+RUN: llvm-remarkutil count --parser=yaml --count-by=remark-name --group-by=total %p/Inputs/remark-count-by.yaml | FileCheck %s --check-prefix=CHECKTOTAL 
+
+; CHECK-LABEL: Source,Count
+; CHECK: path/to/anno.c,3
+; CHECK: path/to/anno2.c,1
+
+; CHECKFUNC-LABEL: Function,Count
+; CHECKFUNC: func1,3
+; CHECKFUNC: func2,1
+
+; CHECKFUNCLOC-LABEL: FuctionWithDebugLoc,Count
+; CHECKFUNCLOC: path/to/anno.c:func1,2
+; CHECKFUNCLOC: path/to/anno.c:func2,1
+; CHECKFUNCLOC: path/to/anno2.c:func1,1
+
+; CHECKTOTAL-LABEL: Total,Count
+; CHECKTOTAL: Total,4
diff --git a/llvm/test/tools/llvm-remarkutil/count/filter-by-pass-name.test b/llvm/test/tools/llvm-remarkutil/count/filter-by-pass-name.test
new file mode 100644
index 000000000000000..481d6fd2f5820b8
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/filter-by-pass-name.test
@@ -0,0 +1,10 @@
+RUN: llvm-remarkutil count --parser=yaml --pass-name=generic-remarks-pass %p/Inputs/remark-filter-by.yaml | FileCheck %s 
+RUN: llvm-remarkutil count --parser=yaml --rpass-name=.* %p/Inputs/remark-filter-by.yaml | FileCheck %s --check-prefix=CHECKALL 
+
+; CHECK-LABEL: Source,Count
+; CHECK: path/to/anno.c,2
+; CHECK: path/to/anno2.c,1
+
+; CHECKALL-LABEL: Source,Count
+; CHECKALL: path/to/anno.c,2
+; CHECKALL: path/to/anno2.c,2
diff --git a/llvm/test/tools/llvm-remarkutil/count/filter-by-remark-name.test b/llvm/test/tools/llvm-remarkutil/count/filter-by-remark-name.test
new file mode 100644
index 000000000000000..20684d57f648cd6
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/filter-by-remark-name.test
@@ -0,0 +1,10 @@
+RUN: llvm-remarkutil count --parser=yaml --remark-name=Remark %p/Inputs/remark-filter-by.yaml | FileCheck %s 
+RUN: llvm-remarkutil count --parser=yaml --rremark-name=R.* %p/Inputs/remark-filter-by.yaml | FileCheck %s --check-prefix=CHECKALL 
+
+; CHECK-LABEL: Source,Count
+; CHECK: path/to/anno.c,1
+; CHECK: path/to/anno2.c,1
+
+; CHECKALL-LABEL: Source,Count
+; CHECKALL: path/to/anno.c,2
+; CHECKALL: path/to/anno2.c,2
diff --git a/llvm/test/tools/llvm-remarkutil/count/filter-by-type.test b/llvm/test/tools/llvm-remarkutil/count/filter-by-type.test
new file mode 100644
index 000000000000000..c392fe43aa199e5
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/filter-by-type.test
@@ -0,0 +1,16 @@
+RUN: llvm-remarkutil count --parser=yaml --remark-type=missed %p/Inputs/remark-filter-by.yaml | FileCheck %s --check-prefix=MISSED
+RUN: llvm-remarkutil count --parser=yaml --remark-type=passed %p/Inputs/remark-filter-by.yaml | FileCheck %s --check-prefix=PASSED
+RUN: llvm-remarkutil count --parser=yaml --remark-type=analysis %p/Inputs/remark-filter-by.yaml | FileCheck %s --check-prefix=ANALYSIS
+RUN: llvm-remarkutil count --parser=yaml --remark-type=unknown %p/Inputs/remark-filter-by.yaml | FileCheck %s --check-prefix=UNKNOWN
+
+; MISSED-LABEL: Source,Count
+; MISSED: path/to/anno.c,1
+
+; PASSED-LABEL: Source,Count
+; PASSED: path/to/anno.c,1
+
+; ANALYSIS-LABEL: Source,Count
+; ANALYSIS: path/to/anno2.c,2
+
+; UNKNOWN: Source,Count
+; UNKNOWN-EMPTY: 
diff --git a/llvm/test/tools/llvm-remarkutil/count/group-by-function-with-loc.test b/llvm/test/tools/llvm-remarkutil/count/group-by-function-with-loc.test
new file mode 100644
index 000000000000000..2ceb45b38f29f6e
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/group-by-function-with-loc.test
@@ -0,0 +1,7 @@
+RUN: llvm-remarkutil count --parser=yaml --group-by=function-with-loc %p/Inputs/remark-group-by.yaml | FileCheck %s
+
+; CHECK-LABEL: FuctionWithDebugLoc,Count
+; CHECK: path/to/anno.c:func1,2
+; CHECK: path/to/anno.c:func2,2
+; CHECK: path/to/anno2.c:func3,1
+; CHECK: path/to/anno3.c:func1,1
diff --git a/llvm/test/tools/llvm-remarkutil/count/group-by-function.test b/llvm/test/tools/llvm-remarkutil/count/group-by-function.test
new file mode 100644
index 000000000000000..f3d04bb00c269a9
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/group-by-function.test
@@ -0,0 +1,7 @@
+
+RUN: llvm-remarkutil count --parser=yaml --group-by=function %p/Inputs/remark-group-by.yaml | FileCheck %s
+
+; CHECK-LABEL: Function,Count
+; CHECK: func1,3
+; CHECK: func2,2
+; CHECK: func3,1 
diff --git a/llvm/test/tools/llvm-remarkutil/count/group-by-source.test b/llvm/test/tools/llvm-remarkutil/count/group-by-source.test
new file mode 100644
index 000000000000000..0a11ac63925f174
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/count/group-by-source.test
@@ -0,0 +1,6 @@
+RUN: llvm-remarkutil count --parser=yaml --group-by=source %p/Inputs/remark-group-by.yaml | FileCheck %s
+
+; CHECK-LABEL: Source,Count
+; CHECK: path/to/anno.c,4
+; CHECK: path/to/anno2.c,1
+; CHECK: path/to/anno3.c,1
diff --git a/llvm/test/tools/llvm-remarkutil/empty-file.test b/llvm/test/tools/llvm-remarkutil/empty-file.test
index aa2ee41dd70bdf8..abbf8e02cfa308b 100644
--- a/llvm/test/tools/llvm-remarkutil/empty-file.test
+++ b/llvm/test/tools/llvm-remarkutil/empty-file.test
@@ -1,9 +1,11 @@
 RUN: not llvm-remarkutil yaml2bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
 RUN: not llvm-remarkutil instruction-count --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: 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 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
 
 ; YAMLPARSER: error: document root is not of mapping type.
 
@@ -15,3 +17,6 @@ RUN: llvm-remarkutil annotation-count --parser=bitstream --annotation-type=remar
 
 ; ANNOTATIONBITSTREAM-LABEL: Function,Count
 ; ANNOTATIONBITSTREAM-EMPTY: 
+
+; COUNTBITSTREAM-LABEL: Source,Count
+; COUNTBITSTREAM-EMPTY:
diff --git a/llvm/test/tools/llvm-remarkutil/instruction-count-with-dbg-loc.test b/llvm/test/tools/llvm-remarkutil/instruction-count-with-dbg-loc.test
index ac6c8256febe0ed..f1efd44d688d88f 100644
--- a/llvm/test/tools/llvm-remarkutil/instruction-count-with-dbg-loc.test
+++ b/llvm/test/tools/llvm-remarkutil/instruction-count-with-dbg-loc.test
@@ -1,7 +1,14 @@
 RUN: llvm-remarkutil instruction-count --use-debug-loc --parser=yaml %p/Inputs/instruction-count-with-dbg-loc.yaml | FileCheck %s
 RUN: llvm-remarkutil yaml2bitstream %p/Inputs/instruction-count-with-dbg-loc.yaml | llvm-remarkutil instruction-count --use-debug-loc --parser=bitstream | FileCheck %s
+RUN: llvm-remarkutil count --parser=yaml --count-by=arg --group-by=function-with-loc --remark-name="InstructionCount" %p/Inputs/instruction-count-with-dbg-loc.yaml | FileCheck %s --check-prefix=COUNT-CHECK
+RUN: llvm-remarkutil yaml2bitstream %p/Inputs/instruction-count-with-dbg-loc.yaml  | llvm-remarkutil count --parser=bitstream --count-by=arg --group-by=function-with-loc --remark-name="InstructionCount" | FileCheck %s --check-prefix=COUNT-CHECK
 
 ; CHECK-LABEL: Source,Function,InstructionCount
 ; CHECK: path/to/inst.c:1:2,func1,1
 ; CHECK: path/to/inst2.c:1:2,func2,2
 ; CHECK: path/to/inst3.c:1:2,func3,3
+
+; COUNT-CHECK-LABEL: FuctionWithDebugLoc,NumInstructions
+; COUNT-CHECK: path/to/inst.c:func1,1
+; COUNT-CHECK: path/to/inst2.c:func2,2
+; COUNT-CHECK: path/to/inst3.c:func3,3
diff --git a/llvm/test/tools/llvm-remarkutil/instruction-count.test b/llvm/test/tools/llvm-remarkutil/instruction-count.test
index d5f62e36c13eeef..c4bc3e5780e3f55 100644
--- a/llvm/test/tools/llvm-remarkutil/instruction-count.test
+++ b/llvm/test/tools/llvm-remarkutil/instruction-count.test
@@ -1,7 +1,14 @@
 RUN: llvm-remarkutil instruction-count --parser=yaml %p/Inputs/instruction-count.yaml | FileCheck %s
 RUN: llvm-remarkutil yaml2bitstream %p/Inputs/instruction-count.yaml | llvm-remarkutil instruction-count --parser=bitstream | FileCheck %s
+RUN: llvm-remarkutil count --parser=yaml --count-by=arg --group-by=function --remark-name="InstructionCount" %p/Inputs/instruction-count.yaml | FileCheck %s --check-prefix=COUNT-CHECK
+RUN: llvm-remarkutil yaml2bitstream %p/Inputs/instruction-count.yaml  | llvm-remarkutil count --parser=bitstream --count-by=arg --group-by=function --remark-name="InstructionCount" | FileCheck %s --check-prefix=COUNT-CHECK
 
 ; CHECK-LABEL: Function,InstructionCount
 ; CHECK: func1,1
 ; CHECK: func2,2
 ; CHECK: func3,3
+
+; COUNT-CHECK-LABEL: Function,NumInstructions
+; COUNT-CHECK: func1,1
+; COUNT-CHECK: func2,2
+; COUNT-CHECK: func3,3
diff --git a/llvm/tools/llvm-remarkutil/CMakeLists.txt b/llvm/tools/llvm-remarkutil/CMakeLists.txt
index c1dd311e979843a..48aeb9397cda16d 100644
--- a/llvm/tools/llvm-remarkutil/CMakeLists.txt
+++ b/llvm/tools/llvm-remarkutil/CMakeLists.txt
@@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS
 add_llvm_tool(llvm-remarkutil
   RemarkConvert.cpp
   RemarkCount.cpp
+  RemarkCounter.cpp
   RemarkSizeDiff.cpp
   RemarkUtil.cpp
   RemarkUtilHelpers.cpp
diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
new file mode 100644
index 000000000000000..a23d03646a9a991
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
@@ -0,0 +1,339 @@
+//===- RemarkCounter.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 count remarks based on properties
+//
+//===----------------------------------------------------------------------===//
+#include "RemarkCounter.h"
+#include "RemarkUtilRegistry.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Regex.h"
+
+using namespace llvm;
+using namespace remarks;
+using namespace llvm::remarkutil;
+
+static cl::SubCommand CountSub("count",
+                               "Collect remarks based on specified criteria.");
+
+INPUT_FORMAT_COMMAND_LINE_OPTIONS(CountSub)
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(CountSub)
+
+static cl::list<std::string>
+    Keys("args", cl::desc("Specify remark argument/s to count by."),
+         cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional);
+static cl::list<std::string> RKeys(
+    "rargs",
+    cl::desc(
+        "Specify remark argument/s to count by. using 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("filter collection by remark type."),
+    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(
+        clEnumValN(
+            CountBy::REMARK, "remark-name",
+            "Counts individual remarks based on how many of the remark exists"),
+        clEnumValN(CountBy::ARGUMENT, "arg",
+                   "Counts based on the value each specified argument has. The "
+                   "argument has to have a number value to be considered.")),
+    cl::init(CountBy::REMARK), cl::sub(CountSub));
+static cl::opt<GroupBy> GroupByOpt(
+    "group-by", cl::desc("Specify the property to group remarks by."),
+    cl::values(
+        clEnumValN(
+            GroupBy::PER_SOURCE, "source",
+            "Display the count broken down by the filepath of each remark "
+            "emitted. Requires remarks to have DebugLoc information."),
+        clEnumValN(GroupBy::PER_FUNCTION, "function",
+                   "Breakdown the count by function name."),
+        clEnumValN(
+            GroupBy::PER_FUNCTION_WITH_DEBUG_LOC, "function-with-loc",
+            "Breakdown the count by function name taking into consideration "
+            "the filepath info from the DebugLoc of the remark."),
+        clEnumValN(GroupBy::TOTAL, "total",
+                   "Output the total number corresponding to the count for the "
+                   "provided input file.")),
+    cl::init(GroupBy::PER_SOURCE), cl::sub(CountSub));
+
+/// Look for matching argument for \p Key in \p Remark and return the parsed
+/// integer value.
+static unsigned getValForKey(StringRef Key, const Remark &Remark) {
+  auto *RemarkArg = find_if(Remark.Args, [&Key](const Argument &Arg) {
+    return Arg.Key == Key && Arg.isValInt();
+  });
+  if (RemarkArg == Remark.Args.end())
+    return 0;
+  return *RemarkArg->getValAsInt();
+}
+
+Error Filters::regexArgumentsValid() {
+  if (RemarkNameFilter.has_value() && RemarkNameFilter->IsRegex)
+    if (auto E = checkRegex(std::get<Regex>(RemarkNameFilter->FilterRE)))
+      return E;
+  if (PassNameFilter.has_value() && PassNameFilter->IsRegex)
+    if (auto E = checkRegex(std::get<Regex>(PassNameFilter->FilterRE)))
+      return E;
+  if (ArgFilter.has_value() && ArgFilter->IsRegex)
+    if (auto E = checkRegex(std::get<Regex>(ArgFilter->FilterRE)))
+      return E;
+  return Error::success();
+}
+
+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) {
+    bool IsMatch = false;
+    for (auto Arg : Remark.Args)
+      IsMatch |= ArgFilter->match(Arg.Val);
+    if (!IsMatch)
+      return false;
+  }
+  return true;
+}
+
+Error KeyCounter::getAllKeysInRemarks(StringRef Buffer,
+                                      SmallVector<FilterMatcher, 4> &Keys,
+                                      Filters &Filter) {
+  auto MaybeParser = createRemarkParser(InputFormat, Buffer);
+  if (!MaybeParser)
+    return MaybeParser.takeError();
+  auto &Parser = **MaybeParser;
+  auto MaybeRemark = Parser.next();
+  for (; MaybeRemark; MaybeRemark = Parser.next()) {
+    auto &Remark = **MaybeRemark;
+    // Only collect keys from remarks included in the filter.
+    if (!Filter.filterRemark(Remark))
+      continue;
+    for (auto &Key : Keys) {
+      for (Argument Arg : Remark.Args)
+        if (Key.match(Arg.Key) && Arg.isValInt())
+          KeySetIdxMap.insert({Arg.Key, KeySetIdxMap.size()});
+    }
+  }
+
+  auto E = MaybeRemark.takeError();
+  if (!E.isA<EndOfFileError>())
+    return E;
+  consumeError(std::move(E));
+  return Error::success();
+}
+
+std::optional<std::string> Counter::getGroupByKey(const Remark &Remark) {
+
+  std::string Key;
+  switch (GroupBy) {
+  case GroupBy::PER_FUNCTION:
+    return Key = Remark.FunctionName;
+  case GroupBy::TOTAL:
+    return Key = "Total";
+  case GroupBy::PER_SOURCE:
+  case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:
+    if (!Remark.Loc.has_value())
+      return std::nullopt;
+
+    if (GroupBy == GroupBy::PER_FUNCTION_WITH_DEBUG_LOC)
+      return Remark.Loc->SourceFilePath.str() + ":" + Remark.FunctionName.str();
+    return Remark.Loc->SourceFilePath.str();
+  }
+}
+
+void KeyCounter::collect(const Remark &Remark) {
+  SmallVector<int, 4> Row(KeySetIdxMap.size());
+  std::optional<std::string> GroupByKey = getGroupByKey(Remark);
+  // Early return if we don't have a value
+  if (!GroupByKey.has_value())
+    return;
+  auto GroupVal = *GroupByKey;
+  CountByKeysMap.insert({GroupVal, Row});
+  for (auto [Key, Idx] : KeySetIdxMap) {
+    auto Count = getValForKey(Key, Remark);
+    CountByKeysMap[GroupVal][Idx] += Count;
+  }
+}
+
+void RemarkCounter::collect(const Remark &Remark) {
+  std::optional<std::string> Key = getGroupByKey(Remark);
+  if (!Key.has_value())
+    return;
+  auto Iter = CountedByRemarksMap.insert({*Key, 1});
+  if (!Iter.second)
+    Iter.first->second += 1;
+}
+
+Error KeyCounter::print(StringRef OutputFileName) {
+  auto MaybeOF =
+      getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
+  if (!MaybeOF)
+    return MaybeOF.takeError();
+
+  auto OF = std::move(*MaybeOF);
+  OF->os() << groupByToStr(GroupBy) << ",";
+  unsigned Idx = 0;
+  for (auto [Key, _] : KeySetIdxMap) {
+    OF->os() << Key;
+    if (Idx != KeySetIdxMap.size() - 1)
+      OF->os() << ",";
+    Idx++;
+  }
+  OF->os() << "\n";
+  for (auto [Header, CountVector] : CountByKeysMap) {
+    OF->os() << Header << ",";
+    unsigned Idx = 0;
+    for (auto Count : CountVector) {
+      OF->os() << Count;
+      if (Idx != KeySetIdxMap.size() - 1)
+        OF->os() << ",";
+      Idx++;
+    }
+    OF->os() << "\n";
+  }
+  return Error::success();
+}
+Error RemarkCounter::print(StringRef OutputFileName) {
+  auto MaybeOF =
+      getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
+  if (!MaybeOF)
+    return MaybeOF.takeError();
+
+  auto OF = std::move(*MaybeOF);
+  OF->os() << groupByToStr(GroupBy) << ","
+           << "Count\n";
+  for (auto [Key, Count] : CountedByRemarksMap)
+    OF->os() << Key << "," << Count << "\n";
+  OF->keep();
+  return Error::success();
+}
+
+Expected<Filters> getRemarkFilter() {
+  // Create Filter properties.
+  std::optional<FilterMatcher> RemarkNameFilter;
+  std::optional<FilterMatcher> PassNameFilter;
+  std::optional<FilterMatcher> RemarkArgFilter;
+  std::optional<Type> RemarkType;
+  if (!RemarkNameOpt.empty())
+    RemarkNameFilter = {RemarkNameOpt, false};
+  else if (!RemarkNameOptRE.empty())
+    RemarkNameFilter = {RemarkNameOptRE, true};
+  if (!PassNameOpt.empty())
+    PassNameFilter = {PassNameOpt, false};
+  else if (!PassNameOptRE.empty())
+    PassNameFilter = {PassNameOptRE, true};
+  if (RemarkTypeOpt != Type::Failure)
+    RemarkType = RemarkTypeOpt;
+  if (!RemarkFilterArgByOpt.empty())
+    RemarkArgFilter = {RemarkFilterArgByOpt, false};
+  else if (!RemarkArgFilterOptRE.empty())
+    RemarkArgFilter = {RemarkArgFilterOptRE, true};
+  // Create RemarkFilter.
+  return Filters::createRemarkFilter(std::move(RemarkNameFilter),
+                                     std::move(PassNameFilter),
+                                     std::move(RemarkArgFilter), RemarkType);
+}
+
+Error useCollectRemark(StringRef Buffer, Counter &Counter, Filters &Filter) {
+  // Create Parser.
+  auto MaybeParser = createRemarkParser(InputFormat, Buffer);
+  if (!MaybeParser)
+    return MaybeParser.takeError();
+  auto &Parser = **MaybeParser;
+  auto MaybeRemark = Parser.next();
+  for (; MaybeRemark; MaybeRemark = Parser.next()) {
+    const Remark &Remark = **MaybeRemark;
+    if (Filter.filterRemark(Remark))
+      Counter.collect(Remark);
+  }
+
+  if (auto E = Counter.print(OutputFileName))
+    return E;
+  auto E = MaybeRemark.takeError();
+  if (!E.isA<EndOfFileError>())
+    return E;
+  consumeError(std::move(E));
+  return Error::success();
+}
+
+static Error collectRemarks() {
+  // Create a parser for the user-specified input format.
+  auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+  if (!MaybeBuf)
+    return MaybeBuf.takeError();
+  StringRef Buffer = (*MaybeBuf)->getBuffer();
+  auto MaybeFilter = getRemarkFilter();
+  if (!MaybeFilter)
+    return MaybeFilter.takeError();
+  auto &Filter = *MaybeFilter;
+  if (CountByOpt == CountBy::REMARK) {
+    RemarkCounter RC(GroupByOpt);
+    if (auto E = useCollectRemark(Buffer, RC, Filter))
+      return E;
+  } else if (CountByOpt == CountBy::ARGUMENT) {
+    SmallVector<FilterMatcher, 4> KeysVector;
+    if (!Keys.empty()) {
+      for (auto &Key : Keys)
+        KeysVector.push_back({Key, false});
+    } else if (!RKeys.empty())
+      for (auto Key : RKeys)
+        KeysVector.push_back({Key, true});
+    else
+      KeysVector.push_back({".*", true});
+
+    Expected<KeyCounter> KC =
+        KeyCounter::createKeyCounter(GroupByOpt, KeysVector, Buffer, Filter);
+    if (!KC)
+      return KC.takeError();
+    if (auto E = useCollectRemark(Buffer, *KC, Filter))
+      return E;
+  }
+  return Error::success();
+}
+
+static CommandRegistration CountReg(&CountSub, collectRemarks);
diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.h b/llvm/tools/llvm-remarkutil/RemarkCounter.h
new file mode 100644
index 000000000000000..8d4007d57935c7b
--- /dev/null
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.h
@@ -0,0 +1,198 @@
+//===- RemarkCounter.h ----------------------------------------------------===//
+//
+// 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 count remarks based on properties
+//
+//===----------------------------------------------------------------------===//
+#ifndef TOOLS_LLVM_REMARKCOUNTER_H
+#define TOOLS_LLVM_REMARKCOUNTER_H
+#include "RemarkUtilHelpers.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/Regex.h"
+#include <list>
+
+namespace llvm {
+namespace remarks {
+
+/// Collect remarks by counting the existance of a remark or by looking through
+/// the keys and summing through the total count.
+enum class CountBy { REMARK, ARGUMENT };
+
+/// Summarize the count by either emitting one count for the remark file, or
+/// grouping the count by source file or by function name.
+enum class GroupBy {
+  TOTAL,
+  PER_SOURCE,
+  PER_FUNCTION,
+  PER_FUNCTION_WITH_DEBUG_LOC
+};
+
+/// Convert \p GroupBy to a std::string.
+inline std::string groupByToStr(GroupBy GroupBy) {
+  switch (GroupBy) {
+  default:
+    return "Total";
+  case GroupBy::PER_FUNCTION:
+    return "Function";
+  case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:
+    return "FuctionWithDebugLoc";
+  case GroupBy::PER_SOURCE:
+    return "Source";
+  }
+}
+
+/// Filter object which can be either a string or a regex to match with the
+/// remark properties.
+struct FilterMatcher {
+  std::variant<Regex, std::string> FilterRE, FilterStr;
+  bool IsRegex;
+  FilterMatcher(std::string Filter, bool IsRegex) : IsRegex(IsRegex) {
+    if (IsRegex)
+      FilterRE = Regex(Filter);
+    else
+      FilterStr = Filter;
+  }
+
+  bool match(StringRef StringToMatch) {
+    if (IsRegex)
+      return std::get<Regex>(FilterRE).match(StringToMatch);
+    std::string FString = std::get<std::string>(FilterStr);
+    return FString == StringToMatch.trim().str();
+  }
+};
+
+/// 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 a filter object if all the arguments provided are valid regex
+  /// types otherwise return an error.
+  static Expected<Filters>
+  createRemarkFilter(std::optional<FilterMatcher> RemarkNameFilter,
+                     std::optional<FilterMatcher> PassNameFilter,
+                     std::optional<FilterMatcher> ArgFilter,
+                     std::optional<Type> RemarkTypeFilter) {
+    Filters Filter;
+    Filter.RemarkNameFilter = std::move(RemarkNameFilter);
+    Filter.PassNameFilter = std::move(PassNameFilter);
+    Filter.ArgFilter = std::move(ArgFilter);
+    Filter.RemarkTypeFilter = std::move(RemarkTypeFilter);
+    if (auto E = Filter.regexArgumentsValid())
+      return E;
+    return Filter;
+  }
+  /// Returns true if \p Remark satisfies all the provided filters.
+  bool filterRemark(const Remark &Remark);
+
+private:
+  /// Check if arguments can be parsed as valid regex types.
+  Error regexArgumentsValid();
+};
+
+/// Convert Regex string error to an error object.
+inline Error checkRegex(const Regex &Regex) {
+  std::string Error;
+  if (!Regex.isValid(Error))
+    return createStringError(make_error_code(std::errc::invalid_argument),
+                             Twine("Regex: ", Error));
+  return Error::success();
+}
+
+/// Abstract counter class used to define the general required methods for
+/// counting a remark.
+struct Counter {
+  GroupBy GroupBy;
+  Counter(){};
+  Counter(enum GroupBy GroupBy) : GroupBy(GroupBy) {}
+  std::optional<std::string> getGroupByKey(const Remark &Remark);
+
+  /// Collect count information from \p Remark organized based on \p GroupBy
+  /// property.
+  virtual void collect(const Remark &) = 0;
+  /// Output the final count to the file \p OutputFileName
+  virtual Error print(StringRef OutputFileName) = 0;
+  virtual ~Counter() = default;
+};
+
+/// Count remarks based on the provided \p Keys argument and summing up the
+/// value for each matching key organized by source, function or reporting a
+/// total for the specified remark file.
+/// Reporting count grouped by source:
+///
+///  | source        | key1 | key2 | key3 |
+///  |---------------|------|------|------|
+///  | path/to/file1 | 0    | 1    | 3    |
+///  | path/to/file2 | 1    | 0    | 2    |
+///  | path/to/file3 | 2    | 3    | 1    |
+///
+/// Reporting count grouped by function:
+///
+///  | Function      | key1 | key2 | key3 |
+///  |---------------|------|------|------|
+///  | function1     | 0    | 1    | 3    |
+///  | function2     | 1    | 0    | 2    |
+///  | function3     | 2    | 3    | 1    |
+struct KeyCounter : Counter {
+  /// The internal object to keep the count for the remarks. The first argument
+  /// corresponds to the property we are collecting for this can be either a
+  /// source or function. The second argument is a row of integers where each
+  /// item in the row is the count for a specified key.
+  std::map<std::string, SmallVector<int, 4>> CountByKeysMap;
+  /// A set of all the keys found in the remark file. The second argument is the
+  /// index of each of those keys which can be used in `CountByKeysMap` to fill
+  /// count information for that key.
+  MapVector<StringRef, int> KeySetIdxMap;
+  KeyCounter(){};
+  /// Create a key counte. If the provided \p Keys represent a regex vector then
+  /// we need to check that the provided regular expressions are valid if not we
+  /// return an Error.
+  static Expected<KeyCounter>
+  createKeyCounter(enum GroupBy GroupBy, SmallVector<FilterMatcher, 4> &Keys,
+                   StringRef Buffer, Filters &Filter) {
+    KeyCounter KC;
+    KC.GroupBy = GroupBy;
+    for (auto &Key : Keys) {
+      if (Key.IsRegex) {
+        if (auto E = checkRegex(std::get<Regex>(Key.FilterRE)))
+          return E;
+      }
+    }
+    if (auto E = KC.getAllKeysInRemarks(Buffer, Keys, Filter))
+      return E;
+    return KC;
+  }
+  void collect(const Remark &) override;
+  Error print(StringRef OutputFileName) override;
+
+private:
+  /// collect all the keys that match the list of \p Keys provided by parsing
+  /// through \p Buffer of remarks and filling \p KeySetIdxMap acting as a row
+  /// for for all the keys that we are interested in collecting information for.
+  Error getAllKeysInRemarks(StringRef Buffer,
+                            SmallVector<FilterMatcher, 4> &Keys,
+                            Filters &Filter);
+};
+
+/// Collect remarks based by counting the existance of individual remarks. The
+/// reported table will be structured based on the provided \p GroupBy argument
+/// by reporting count for functions, source or total count for the provided
+/// remark file.
+struct RemarkCounter : Counter {
+  std::map<std::string, int> CountedByRemarksMap;
+  RemarkCounter(enum GroupBy GroupBy) : Counter(GroupBy) {}
+  void collect(const Remark &) override;
+  Error print(StringRef OutputFileName) override;
+};
+} // namespace remarks
+
+} // namespace llvm
+#endif // TOOLS_LLVM_REMARKCOUNTER_H

>From a21dd6420571f024d7a795ed29562fc66a081f80 Mon Sep 17 00:00:00 2001
From: Zain Jaffal <z_jaffal at apple.com>
Date: Thu, 28 Sep 2023 13:25:04 +0100
Subject: [PATCH 2/7] [Remark] Remove unrelated change for Remark header.

---
 llvm/include/llvm/Remarks/Remark.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Remarks/Remark.h b/llvm/include/llvm/Remarks/Remark.h
index 6c7c69f5ceb1566..de81c5a992805b4 100644
--- a/llvm/include/llvm/Remarks/Remark.h
+++ b/llvm/include/llvm/Remarks/Remark.h
@@ -136,7 +136,7 @@ struct Remark {
   /// In order to avoid unwanted copies, "delete" the copy constructor.
   /// If a copy is needed, it should be done through `Remark::clone()`.
   Remark(const Remark &) = default;
-  Remark &operator=(const Remark &) = default;
+  Remark& operator=(const Remark &) = default;
 };
 
 // Create wrappers for C Binding types (see CBindingWrapping.h).

>From 4951bd7cc917d8d4d264b3393e4a5692ae8fb419 Mon Sep 17 00:00:00 2001
From: Zain Jaffal <z_jaffal at apple.com>
Date: Thu, 28 Sep 2023 13:26:07 +0100
Subject: [PATCH 3/7] Update remark.rst file

---
 llvm/docs/CommandGuide/llvm-remarkutil.rst | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-remarkutil.rst b/llvm/docs/CommandGuide/llvm-remarkutil.rst
index 6c9b9d7b239f96a..c92cb1d7e768868 100644
--- a/llvm/docs/CommandGuide/llvm-remarkutil.rst
+++ b/llvm/docs/CommandGuide/llvm-remarkutil.rst
@@ -123,9 +123,10 @@ Summary
 ^^^^^^^
 
 :program:`llvm-remarkutil count` counts `remakrs <https://llvm.org/docs/Remarks.html>` based on specified properties. 
-By default the tool will count the remarks based on how many are there in a source, function or total count for the file. 
+By default the tool counts remarks based on how many occour in a source file or function or total for the generated remark file.
 The tool also supports collecting count based on specific remark arguments. The specified arguments should have an integer value to be able to report a count.
 
+The tool contains utilities to filter the remark count based on remark name, pass name, argument value and remark type.
 OPTIONS
 -------
 
@@ -162,16 +163,16 @@ OPTIONS
   Filter count by pass name using regular expressions.
 
 .. option:: --remark-name[=<string>]
-  Filter count by name.
+  Filter count by remark name.
 
 .. option:: --rremark-name[=<string>]
-  Filter count by name using regular expressions.
+  Filter count by remark name using regular expressions.
 
 .. option:: --filter-arg-by[=<string>]
-  Filter count by argument.
+  Filter count by argument value.
 
 .. option:: --rfilter-arg-by[=<string>]
-  Filter count by argument using regular expressions.
+  Filter count by argument value using regular expressions.
 
 .. option:: --remark-type=<value>
   Filter remarks by type with the following options.

>From 779a3e1b394cb0345cb22748e842b90ef38bcf9d Mon Sep 17 00:00:00 2001
From: Zain Jaffal <z_jaffal at apple.com>
Date: Thu, 28 Sep 2023 13:29:06 +0100
Subject: [PATCH 4/7] Address nit comments from PR

1. Change the description for command line options to be more consistent
2. Fix doumentation issues
3. Change argumetns to use ArrayRef
4. Use unsigned instead of signed when reporting count.
5. Simplify some of the code by using `any_of`
---
 llvm/tools/llvm-remarkutil/RemarkCounter.cpp | 45 +++++++++-----------
 llvm/tools/llvm-remarkutil/RemarkCounter.h   | 31 ++++++++------
 2 files changed, 39 insertions(+), 37 deletions(-)

diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
index a23d03646a9a991..f5e92d93fd300e8 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
@@ -30,37 +30,37 @@ static cl::list<std::string>
 static cl::list<std::string> RKeys(
     "rargs",
     cl::desc(
-        "Specify remark argument/s to count by. using regular expressions"),
+        "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::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::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."),
+    "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 "
+                    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 "
+                         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 "
+                  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("filter collection by remark type."),
+    "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"),
@@ -72,11 +72,11 @@ static cl::opt<Type> RemarkTypeOpt(
                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"),
+    "count-by", cl::desc("Specify the property to collect remarks by."),
     cl::values(
-        clEnumValN(
-            CountBy::REMARK, "remark-name",
-            "Counts individual remarks based on how many of the remark exists"),
+        clEnumValN(CountBy::REMARK, "remark-name",
+                   "Counts individual remarks based on how many of the remark "
+                   "exists."),
         clEnumValN(CountBy::ARGUMENT, "arg",
                    "Counts based on the value each specified argument has. The "
                    "argument has to have a number value to be considered.")),
@@ -99,8 +99,8 @@ static cl::opt<GroupBy> GroupByOpt(
                    "provided input file.")),
     cl::init(GroupBy::PER_SOURCE), cl::sub(CountSub));
 
-/// Look for matching argument for \p Key in \p Remark and return the parsed
-/// integer value.
+/// Look for matching argument with \p Key in \p Remark and return the parsed
+/// integer value or 0 if it is has no integer value.
 static unsigned getValForKey(StringRef Key, const Remark &Remark) {
   auto *RemarkArg = find_if(Remark.Args, [&Key](const Argument &Arg) {
     return Arg.Key == Key && Arg.isValInt();
@@ -131,17 +131,15 @@ bool Filters::filterRemark(const Remark &Remark) {
   if (RemarkTypeFilter)
     return *RemarkTypeFilter == Remark.RemarkType;
   if (ArgFilter) {
-    bool IsMatch = false;
-    for (auto Arg : Remark.Args)
-      IsMatch |= ArgFilter->match(Arg.Val);
-    if (!IsMatch)
+    if (!any_of(Remark.Args,
+                [this](Argument Arg) { return ArgFilter->match(Arg.Val); }))
       return false;
   }
   return true;
 }
 
 Error KeyCounter::getAllKeysInRemarks(StringRef Buffer,
-                                      SmallVector<FilterMatcher, 4> &Keys,
+                                      ArrayRef<FilterMatcher> Keys,
                                       Filters &Filter) {
   auto MaybeParser = createRemarkParser(InputFormat, Buffer);
   if (!MaybeParser)
@@ -169,12 +167,11 @@ Error KeyCounter::getAllKeysInRemarks(StringRef Buffer,
 
 std::optional<std::string> Counter::getGroupByKey(const Remark &Remark) {
 
-  std::string Key;
   switch (GroupBy) {
   case GroupBy::PER_FUNCTION:
-    return Key = Remark.FunctionName;
+    return Remark.FunctionName.str();
   case GroupBy::TOTAL:
-    return Key = "Total";
+    return "Total";
   case GroupBy::PER_SOURCE:
   case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:
     if (!Remark.Loc.has_value())
@@ -187,10 +184,10 @@ std::optional<std::string> Counter::getGroupByKey(const Remark &Remark) {
 }
 
 void KeyCounter::collect(const Remark &Remark) {
-  SmallVector<int, 4> Row(KeySetIdxMap.size());
+  SmallVector<unsigned, 4> Row(KeySetIdxMap.size());
   std::optional<std::string> GroupByKey = getGroupByKey(Remark);
   // Early return if we don't have a value
-  if (!GroupByKey.has_value())
+  if (!GroupByKey)
     return;
   auto GroupVal = *GroupByKey;
   CountByKeysMap.insert({GroupVal, Row});
diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.h b/llvm/tools/llvm-remarkutil/RemarkCounter.h
index 8d4007d57935c7b..fc0e723f23c5cd6 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.h
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.h
@@ -59,7 +59,7 @@ struct FilterMatcher {
       FilterStr = Filter;
   }
 
-  bool match(StringRef StringToMatch) {
+  bool match(StringRef StringToMatch) const {
     if (IsRegex)
       return std::get<Regex>(FilterRE).match(StringToMatch);
     std::string FString = std::get<std::string>(FilterStr);
@@ -113,6 +113,9 @@ struct Counter {
   GroupBy GroupBy;
   Counter(){};
   Counter(enum GroupBy GroupBy) : GroupBy(GroupBy) {}
+  /// Obtain the field for collecting remark info based on how we are
+  /// collecting. Remarks are grouped by FunctionName, Source, Source and
+  /// Function or collect by file.
   std::optional<std::string> getGroupByKey(const Remark &Remark);
 
   /// Collect count information from \p Remark organized based on \p GroupBy
@@ -146,18 +149,18 @@ struct KeyCounter : Counter {
   /// corresponds to the property we are collecting for this can be either a
   /// source or function. The second argument is a row of integers where each
   /// item in the row is the count for a specified key.
-  std::map<std::string, SmallVector<int, 4>> CountByKeysMap;
+  std::map<std::string, SmallVector<unsigned, 4>> CountByKeysMap;
   /// A set of all the keys found in the remark file. The second argument is the
   /// index of each of those keys which can be used in `CountByKeysMap` to fill
   /// count information for that key.
-  MapVector<StringRef, int> KeySetIdxMap;
-  KeyCounter(){};
-  /// Create a key counte. If the provided \p Keys represent a regex vector then
-  /// we need to check that the provided regular expressions are valid if not we
-  /// return an Error.
-  static Expected<KeyCounter>
-  createKeyCounter(enum GroupBy GroupBy, SmallVector<FilterMatcher, 4> &Keys,
-                   StringRef Buffer, Filters &Filter) {
+  MapVector<StringRef, unsigned> KeySetIdxMap;
+  /// Create a key counter. If the provided \p Keys represent a regex vector
+  /// then we need to check that the provided regular expressions are valid if
+  /// not we return an Error.
+  static Expected<KeyCounter> createKeyCounter(enum GroupBy GroupBy,
+                                               ArrayRef<FilterMatcher> Keys,
+                                               StringRef Buffer,
+                                               Filters &Filter) {
     KeyCounter KC;
     KC.GroupBy = GroupBy;
     for (auto &Key : Keys) {
@@ -170,15 +173,17 @@ struct KeyCounter : Counter {
       return E;
     return KC;
   }
+
+  /// collect remark count for the passed remark.
   void collect(const Remark &) override;
+
   Error print(StringRef OutputFileName) override;
 
 private:
   /// collect all the keys that match the list of \p Keys provided by parsing
   /// through \p Buffer of remarks and filling \p KeySetIdxMap acting as a row
   /// for for all the keys that we are interested in collecting information for.
-  Error getAllKeysInRemarks(StringRef Buffer,
-                            SmallVector<FilterMatcher, 4> &Keys,
+  Error getAllKeysInRemarks(StringRef Buffer, ArrayRef<FilterMatcher> Keys,
                             Filters &Filter);
 };
 
@@ -187,7 +192,7 @@ struct KeyCounter : Counter {
 /// by reporting count for functions, source or total count for the provided
 /// remark file.
 struct RemarkCounter : Counter {
-  std::map<std::string, int> CountedByRemarksMap;
+  std::map<std::string, unsigned> CountedByRemarksMap;
   RemarkCounter(enum GroupBy GroupBy) : Counter(GroupBy) {}
   void collect(const Remark &) override;
   Error print(StringRef OutputFileName) override;

>From b1dca6d47295eb8d4a1ed3fd8cba76ee33962f19 Mon Sep 17 00:00:00 2001
From: Zain Jaffal <z_jaffal at apple.com>
Date: Tue, 10 Oct 2023 12:12:03 +0100
Subject: [PATCH 5/7] Rename `KeyCounter` to `ArgumentCounter`

The class and the subsiquent variables are used to collect count
information from remark arguments. It is easier for any future
contributers and users of the count tool to get that when the naming
align with the specified function
---
 llvm/tools/llvm-remarkutil/RemarkCounter.cpp | 43 +++++++++---------
 llvm/tools/llvm-remarkutil/RemarkCounter.h   | 47 ++++++++++----------
 2 files changed, 46 insertions(+), 44 deletions(-)

diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
index f5e92d93fd300e8..8892f07b1cd699e 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
@@ -9,6 +9,7 @@
 // Generic tool to count remarks based on properties
 //
 //===----------------------------------------------------------------------===//
+
 #include "RemarkCounter.h"
 #include "RemarkUtilRegistry.h"
 #include "llvm/Support/CommandLine.h"
@@ -138,9 +139,8 @@ bool Filters::filterRemark(const Remark &Remark) {
   return true;
 }
 
-Error KeyCounter::getAllKeysInRemarks(StringRef Buffer,
-                                      ArrayRef<FilterMatcher> Keys,
-                                      Filters &Filter) {
+Error ArgumentCounter::getAllMatchingArgumentsInRemark(
+    StringRef Buffer, ArrayRef<FilterMatcher> Arguments, Filters &Filter) {
   auto MaybeParser = createRemarkParser(InputFormat, Buffer);
   if (!MaybeParser)
     return MaybeParser.takeError();
@@ -151,10 +151,10 @@ Error KeyCounter::getAllKeysInRemarks(StringRef Buffer,
     // Only collect keys from remarks included in the filter.
     if (!Filter.filterRemark(Remark))
       continue;
-    for (auto &Key : Keys) {
+    for (auto &Key : Arguments) {
       for (Argument Arg : Remark.Args)
         if (Key.match(Arg.Key) && Arg.isValInt())
-          KeySetIdxMap.insert({Arg.Key, KeySetIdxMap.size()});
+          ArgumentSetIdxMap.insert({Arg.Key, ArgumentSetIdxMap.size()});
     }
   }
 
@@ -183,15 +183,15 @@ std::optional<std::string> Counter::getGroupByKey(const Remark &Remark) {
   }
 }
 
-void KeyCounter::collect(const Remark &Remark) {
-  SmallVector<unsigned, 4> Row(KeySetIdxMap.size());
+void ArgumentCounter::collect(const Remark &Remark) {
+  SmallVector<unsigned, 4> Row(ArgumentSetIdxMap.size());
   std::optional<std::string> GroupByKey = getGroupByKey(Remark);
   // Early return if we don't have a value
   if (!GroupByKey)
     return;
   auto GroupVal = *GroupByKey;
   CountByKeysMap.insert({GroupVal, Row});
-  for (auto [Key, Idx] : KeySetIdxMap) {
+  for (auto [Key, Idx] : ArgumentSetIdxMap) {
     auto Count = getValForKey(Key, Remark);
     CountByKeysMap[GroupVal][Idx] += Count;
   }
@@ -206,7 +206,7 @@ void RemarkCounter::collect(const Remark &Remark) {
     Iter.first->second += 1;
 }
 
-Error KeyCounter::print(StringRef OutputFileName) {
+Error ArgumentCounter::print(StringRef OutputFileName) {
   auto MaybeOF =
       getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
   if (!MaybeOF)
@@ -215,9 +215,9 @@ Error KeyCounter::print(StringRef OutputFileName) {
   auto OF = std::move(*MaybeOF);
   OF->os() << groupByToStr(GroupBy) << ",";
   unsigned Idx = 0;
-  for (auto [Key, _] : KeySetIdxMap) {
+  for (auto [Key, _] : ArgumentSetIdxMap) {
     OF->os() << Key;
-    if (Idx != KeySetIdxMap.size() - 1)
+    if (Idx != ArgumentSetIdxMap.size() - 1)
       OF->os() << ",";
     Idx++;
   }
@@ -227,7 +227,7 @@ Error KeyCounter::print(StringRef OutputFileName) {
     unsigned Idx = 0;
     for (auto Count : CountVector) {
       OF->os() << Count;
-      if (Idx != KeySetIdxMap.size() - 1)
+      if (Idx != ArgumentSetIdxMap.size() - 1)
         OF->os() << ",";
       Idx++;
     }
@@ -235,6 +235,7 @@ Error KeyCounter::print(StringRef OutputFileName) {
   }
   return Error::success();
 }
+
 Error RemarkCounter::print(StringRef OutputFileName) {
   auto MaybeOF =
       getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
@@ -313,21 +314,21 @@ static Error collectRemarks() {
     if (auto E = useCollectRemark(Buffer, RC, Filter))
       return E;
   } else if (CountByOpt == CountBy::ARGUMENT) {
-    SmallVector<FilterMatcher, 4> KeysVector;
+    SmallVector<FilterMatcher, 4> ArgumentsVector;
     if (!Keys.empty()) {
       for (auto &Key : Keys)
-        KeysVector.push_back({Key, false});
+        ArgumentsVector.push_back({Key, false});
     } else if (!RKeys.empty())
       for (auto Key : RKeys)
-        KeysVector.push_back({Key, true});
+        ArgumentsVector.push_back({Key, true});
     else
-      KeysVector.push_back({".*", true});
+      ArgumentsVector.push_back({".*", true});
 
-    Expected<KeyCounter> KC =
-        KeyCounter::createKeyCounter(GroupByOpt, KeysVector, Buffer, Filter);
-    if (!KC)
-      return KC.takeError();
-    if (auto E = useCollectRemark(Buffer, *KC, Filter))
+    Expected<ArgumentCounter> AC = ArgumentCounter::createArgumentCounter(
+        GroupByOpt, ArgumentsVector, Buffer, Filter);
+    if (!AC)
+      return AC.takeError();
+    if (auto E = useCollectRemark(Buffer, *AC, Filter))
       return E;
   }
   return Error::success();
diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.h b/llvm/tools/llvm-remarkutil/RemarkCounter.h
index fc0e723f23c5cd6..f277ef717a544ba 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.h
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.h
@@ -144,34 +144,33 @@ struct Counter {
 ///  | function1     | 0    | 1    | 3    |
 ///  | function2     | 1    | 0    | 2    |
 ///  | function3     | 2    | 3    | 1    |
-struct KeyCounter : Counter {
+struct ArgumentCounter : Counter {
   /// The internal object to keep the count for the remarks. The first argument
   /// corresponds to the property we are collecting for this can be either a
   /// source or function. The second argument is a row of integers where each
   /// item in the row is the count for a specified key.
   std::map<std::string, SmallVector<unsigned, 4>> CountByKeysMap;
-  /// A set of all the keys found in the remark file. The second argument is the
-  /// index of each of those keys which can be used in `CountByKeysMap` to fill
-  /// count information for that key.
-  MapVector<StringRef, unsigned> KeySetIdxMap;
-  /// Create a key counter. If the provided \p Keys represent a regex vector
-  /// then we need to check that the provided regular expressions are valid if
-  /// not we return an Error.
-  static Expected<KeyCounter> createKeyCounter(enum GroupBy GroupBy,
-                                               ArrayRef<FilterMatcher> Keys,
-                                               StringRef Buffer,
-                                               Filters &Filter) {
-    KeyCounter KC;
-    KC.GroupBy = GroupBy;
-    for (auto &Key : Keys) {
-      if (Key.IsRegex) {
-        if (auto E = checkRegex(std::get<Regex>(Key.FilterRE)))
+  /// A set of all the remark argument found in the remark file. The second
+  /// argument is the index of each of those arguments which can be used in
+  /// `CountByKeysMap` to fill count information for that argument.
+  MapVector<StringRef, unsigned> ArgumentSetIdxMap;
+  /// Create an argument counter. If the provided \p Arguments represent a regex
+  /// vector then we need to check that the provided regular expressions are
+  /// valid if not we return an Error.
+  static Expected<ArgumentCounter>
+  createArgumentCounter(enum GroupBy GroupBy, ArrayRef<FilterMatcher> Arguments,
+                        StringRef Buffer, Filters &Filter) {
+    ArgumentCounter AC;
+    AC.GroupBy = GroupBy;
+    for (auto &Arg : Arguments) {
+      if (Arg.IsRegex) {
+        if (auto E = checkRegex(std::get<Regex>(Arg.FilterRE)))
           return E;
       }
     }
-    if (auto E = KC.getAllKeysInRemarks(Buffer, Keys, Filter))
+    if (auto E = AC.getAllMatchingArgumentsInRemark(Buffer, Arguments, Filter))
       return E;
-    return KC;
+    return AC;
   }
 
   /// collect remark count for the passed remark.
@@ -180,10 +179,12 @@ struct KeyCounter : Counter {
   Error print(StringRef OutputFileName) override;
 
 private:
-  /// collect all the keys that match the list of \p Keys provided by parsing
-  /// through \p Buffer of remarks and filling \p KeySetIdxMap acting as a row
-  /// for for all the keys that we are interested in collecting information for.
-  Error getAllKeysInRemarks(StringRef Buffer, ArrayRef<FilterMatcher> Keys,
+  /// collect all the arguments that match the list of \p Arguments provided by
+  /// parsing through \p Buffer of remarks and filling \p ArgumentSetIdxMap
+  /// acting as a row for for all the keys that we are interested in collecting
+  /// information for.
+  Error getAllMatchingArgumentsInRemark(StringRef Buffer,
+                                        ArrayRef<FilterMatcher> Arguments,
                             Filters &Filter);
 };
 

>From d757f71c6d642eaaeb02bb77788c8c318fb50d01 Mon Sep 17 00:00:00 2001
From: Zain Jaffal <z_jaffal at apple.com>
Date: Tue, 10 Oct 2023 12:50:25 +0100
Subject: [PATCH 6/7] Update documentation for functions and nit comments from
 PR

---
 llvm/docs/CommandGuide/llvm-remarkutil.rst |  6 +++---
 llvm/tools/llvm-remarkutil/RemarkCounter.h | 17 +++++++++++++++--
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-remarkutil.rst b/llvm/docs/CommandGuide/llvm-remarkutil.rst
index c92cb1d7e768868..2e4953eb188ae7b 100644
--- a/llvm/docs/CommandGuide/llvm-remarkutil.rst
+++ b/llvm/docs/CommandGuide/llvm-remarkutil.rst
@@ -122,7 +122,7 @@ USAGE: :program:`llvm-remarkutil` count [*options*] <input file>
 Summary
 ^^^^^^^
 
-:program:`llvm-remarkutil count` counts `remakrs <https://llvm.org/docs/Remarks.html>` based on specified properties. 
+:program:`llvm-remarkutil count` counts `remarks <https://llvm.org/docs/Remarks.html>` based on specified properties. 
 By default the tool counts remarks based on how many occour in a source file or function or total for the generated remark file.
 The tool also supports collecting count based on specific remark arguments. The specified arguments should have an integer value to be able to report a count.
 
@@ -143,9 +143,9 @@ OPTIONS
 
 .. option:: --group-by=<value>
   group count of remarks by property.
-  * ``source``: Count will be collected per source path. Requires remarks to have debug loc info
+  * ``source``: Count will be collected per source path. Remarks with no debug location will not be counted. 
   * ``function``: Count is collected per function.
-  * ``function-with-loc``: Count is collected per function per source. Requires remarks to have debug loc info 
+  * ``function-with-loc``: Count is collected per function per source. Remarks with no debug location will not be counted. 
   * ``Total``: Report a count for the provided remark file.
 
 .. option:: --args[=arguments]
diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.h b/llvm/tools/llvm-remarkutil/RemarkCounter.h
index f277ef717a544ba..af5df958d23509c 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.h
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.h
@@ -173,9 +173,14 @@ struct ArgumentCounter : Counter {
     return AC;
   }
 
-  /// collect remark count for the passed remark.
+  /// Update the internal count map based on the remark integer arguments that
+  /// correspond the the user specified argument keys to collect for.
   void collect(const Remark &) override;
 
+  /// Print a CSV table consisting of an index which is specified by \p
+  /// `GroupBy` and can be a function name, source file name or function name
+  /// with the full source path and columns of user specified remark arguments
+  /// to collect the count for.
   Error print(StringRef OutputFileName) override;
 
 private:
@@ -185,7 +190,7 @@ struct ArgumentCounter : Counter {
   /// information for.
   Error getAllMatchingArgumentsInRemark(StringRef Buffer,
                                         ArrayRef<FilterMatcher> Arguments,
-                            Filters &Filter);
+                                        Filters &Filter);
 };
 
 /// Collect remarks based by counting the existance of individual remarks. The
@@ -195,7 +200,15 @@ struct ArgumentCounter : Counter {
 struct RemarkCounter : Counter {
   std::map<std::string, unsigned> CountedByRemarksMap;
   RemarkCounter(enum GroupBy GroupBy) : Counter(GroupBy) {}
+
+  /// Advance the internal map count broken by \p GroupBy when
+  /// seeing \p Remark.
   void collect(const Remark &) override;
+
+  /// Print a CSV table consisting of an index which is specified by \p
+  /// `GroupBy` and can be a function name, source file name or function name
+  /// with the full source path and a counts column corresponding to the count
+  /// of each individual remark at th index.
   Error print(StringRef OutputFileName) override;
 };
 } // namespace remarks

>From 2e96508601fbb6844270a57f6583159f8f6843f2 Mon Sep 17 00:00:00 2001
From: Zain Jaffal <z_jaffal at apple.com>
Date: Thu, 12 Oct 2023 14:12:29 +0100
Subject: [PATCH 7/7] Remove std::variant from FilterMatcher class

std::variant is available in c++17 but LLVM defaults to c++14.
---
 llvm/tools/llvm-remarkutil/RemarkCounter.cpp | 12 ++++++------
 llvm/tools/llvm-remarkutil/RemarkCounter.h   | 10 +++++-----
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
index 8892f07b1cd699e..b7cbebc0ca8e688 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
@@ -112,14 +112,14 @@ static unsigned getValForKey(StringRef Key, const Remark &Remark) {
 }
 
 Error Filters::regexArgumentsValid() {
-  if (RemarkNameFilter.has_value() && RemarkNameFilter->IsRegex)
-    if (auto E = checkRegex(std::get<Regex>(RemarkNameFilter->FilterRE)))
+  if (RemarkNameFilter && RemarkNameFilter->IsRegex)
+    if (auto E = checkRegex(RemarkNameFilter->FilterRE))
       return E;
-  if (PassNameFilter.has_value() && PassNameFilter->IsRegex)
-    if (auto E = checkRegex(std::get<Regex>(PassNameFilter->FilterRE)))
+  if (PassNameFilter && PassNameFilter->IsRegex)
+    if (auto E = checkRegex(PassNameFilter->FilterRE))
       return E;
-  if (ArgFilter.has_value() && ArgFilter->IsRegex)
-    if (auto E = checkRegex(std::get<Regex>(ArgFilter->FilterRE)))
+  if (ArgFilter && ArgFilter->IsRegex)
+    if (auto E = checkRegex(ArgFilter->FilterRE))
       return E;
   return Error::success();
 }
diff --git a/llvm/tools/llvm-remarkutil/RemarkCounter.h b/llvm/tools/llvm-remarkutil/RemarkCounter.h
index af5df958d23509c..aa9eaf698849cb2 100644
--- a/llvm/tools/llvm-remarkutil/RemarkCounter.h
+++ b/llvm/tools/llvm-remarkutil/RemarkCounter.h
@@ -50,7 +50,8 @@ inline std::string groupByToStr(GroupBy GroupBy) {
 /// Filter object which can be either a string or a regex to match with the
 /// remark properties.
 struct FilterMatcher {
-  std::variant<Regex, std::string> FilterRE, FilterStr;
+  Regex FilterRE;
+  std::string FilterStr;
   bool IsRegex;
   FilterMatcher(std::string Filter, bool IsRegex) : IsRegex(IsRegex) {
     if (IsRegex)
@@ -61,9 +62,8 @@ struct FilterMatcher {
 
   bool match(StringRef StringToMatch) const {
     if (IsRegex)
-      return std::get<Regex>(FilterRE).match(StringToMatch);
-    std::string FString = std::get<std::string>(FilterStr);
-    return FString == StringToMatch.trim().str();
+      return FilterRE.match(StringToMatch);
+    return FilterStr == StringToMatch.trim().str();
   }
 };
 
@@ -164,7 +164,7 @@ struct ArgumentCounter : Counter {
     AC.GroupBy = GroupBy;
     for (auto &Arg : Arguments) {
       if (Arg.IsRegex) {
-        if (auto E = checkRegex(std::get<Regex>(Arg.FilterRE)))
+        if (auto E = checkRegex(Arg.FilterRE))
           return E;
       }
     }



More information about the llvm-commits mailing list