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 Keys("args", cl::desc("Specify remark argument/s to count by."), @@ -34,45 +37,7 @@ static cl::list RKeys( cl::desc( "Specify remark argument/s to count (accepts regular expressions)."), cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional); -static cl::opt - RemarkNameOpt("remark-name", - cl::desc("Optional remark name to filter collection by."), - cl::ValueOptional, cl::sub(CountSub)); -static cl::opt - PassNameOpt("pass-name", cl::ValueOptional, - cl::desc("Optional remark pass name to filter collection by."), - cl::sub(CountSub)); -static cl::opt RemarkFilterArgByOpt( - "filter-arg-by", cl::desc("Optional remark arg to filter collection by."), - cl::ValueOptional, cl::sub(CountSub)); -static cl::opt - RemarkNameOptRE("rremark-name", - cl::desc("Optional remark name to filter collection by " - "(accepts regular expressions)."), - cl::ValueOptional, cl::sub(CountSub)); -static cl::opt - RemarkArgFilterOptRE("rfilter-arg-by", - cl::desc("Optional remark arg to filter collection by " - "(accepts regular expressions)."), - cl::sub(CountSub), cl::ValueOptional); -static cl::opt - PassNameOptRE("rpass-name", cl::ValueOptional, - cl::desc("Optional remark pass name to filter collection " - "by (accepts regular expressions)."), - cl::sub(CountSub)); -static cl::opt 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 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 Arguments, Filters &Filter) { auto MaybeParser = createRemarkParser(InputFormat, Buffer); @@ -223,33 +173,6 @@ Error RemarkCounter::print(StringRef OutputFileName) { return Error::success(); } -Expected 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 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 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 RemarkNameFilter; - std::optional PassNameFilter; - std::optional ArgFilter; - std::optional 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()) + 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 &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 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 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 FunctionOpt( \ + "function", cl::sub(SUBOPT), cl::ValueOptional, \ + cl::desc("Optional function name to filter collection by.")); \ + static cl::opt FunctionOptRE( \ + "rfunction", cl::sub(SUBOPT), cl::ValueOptional, \ + cl::desc("Optional function name to filter collection by " \ + "(accepts regular expressions).")); \ + static cl::opt RemarkNameOpt( \ + "remark-name", \ + cl::desc("Optional remark name to filter collection by."), \ + cl::ValueOptional, cl::sub(SUBOPT)); \ + static cl::opt RemarkNameOptRE( \ + "rremark-name", \ + cl::desc("Optional remark name to filter collection by " \ + "(accepts regular expressions)."), \ + cl::ValueOptional, cl::sub(SUBOPT)); \ + static cl::opt PassNameOpt( \ + "pass-name", cl::ValueOptional, \ + cl::desc("Optional remark pass name to filter collection by."), \ + cl::sub(SUBOPT)); \ + static cl::opt PassNameOptRE( \ + "rpass-name", cl::ValueOptional, \ + cl::desc("Optional remark pass name to filter collection " \ + "by (accepts regular expressions)."), \ + cl::sub(SUBOPT)); \ + static cl::opt 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 RemarkFilterArgByOpt( \ + "filter-arg-by", \ + cl::desc("Optional remark arg to filter collection by."), \ + cl::ValueOptional, cl::sub(SUBOPT)); \ + static cl::opt 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 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 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> @@ -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 FunctionFilter; + std::optional RemarkNameFilter; + std::optional PassNameFilter; + std::optional ArgFilter; + std::optional RemarkTypeFilter; + + /// Returns true if \p Remark satisfies all the provided filters. + bool filterRemark(const Remark &Remark); +}; + } // namespace remarks } // namespace llvm