https://github.com/jofrn updated https://github.com/llvm/llvm-project/pull/200350
>From 0064cee8f2d0e5bceb05b51dd24d664e47d92c1b Mon Sep 17 00:00:00 2001 From: jofrn <[email protected]> Date: Sat, 30 May 2026 16:52:22 -0700 Subject: [PATCH 1/2] [FileCheck] Add --filter-label to drop CHECKs outside selected CHECK-LABEL sections --- llvm/include/llvm/FileCheck/FileCheck.h | 5 +++ llvm/lib/FileCheck/FileCheck.cpp | 24 ++++++++++++ llvm/lib/FileCheck/FileCheckImpl.h | 5 +++ llvm/test/FileCheck/filter-label.txt | 51 +++++++++++++++++++++++++ llvm/utils/FileCheck/FileCheck.cpp | 14 +++++++ 5 files changed, 99 insertions(+) create mode 100644 llvm/test/FileCheck/filter-label.txt diff --git a/llvm/include/llvm/FileCheck/FileCheck.h b/llvm/include/llvm/FileCheck/FileCheck.h index b000f5b0dac73..fbca647672e9e 100644 --- a/llvm/include/llvm/FileCheck/FileCheck.h +++ b/llvm/include/llvm/FileCheck/FileCheck.h @@ -13,6 +13,7 @@ #ifndef LLVM_FILECHECK_FILECHECK_H #define LLVM_FILECHECK_FILECHECK_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" @@ -502,6 +503,10 @@ class FileCheck { LLVM_ABI StringRef CanonicalizeFile(MemoryBuffer &MB, SmallVectorImpl<char> &OutputBuffer); + /// Drops CHECKs whose CHECK-LABEL section's literal text doesn't match any + /// of \p Names. CHECKs before the first label are dropped. Nop if empty. + LLVM_ABI void filterByLabel(ArrayRef<StringRef> Names); + /// Checks the input to FileCheck provided in the \p Buffer against the /// expected strings read from the check file and record diagnostics emitted /// in \p Diags. Errors are recorded against \p SM. diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp index ae25a078713e7..6a4f9c5a8343b 100644 --- a/llvm/lib/FileCheck/FileCheck.cpp +++ b/llvm/lib/FileCheck/FileCheck.cpp @@ -2531,6 +2531,30 @@ static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes, return true; } +void FileCheck::filterByLabel(ArrayRef<StringRef> Names) { + if (Names.empty()) + return; + + // (name1|name2|...) bracketed by non-chars (or string ends). + std::string Alts; + for (StringRef Name : Names) { + if (!Alts.empty()) + Alts += '|'; + Alts += Regex::escape(Name); + } + Regex Re("(^|[^[:alnum:]_])(" + Alts + ")([^[:alnum:]_]|$)"); + + std::vector<FileCheckString> Filtered; + bool Keeping = false; + for (auto &CS : CheckStrings) { + if (CS.Pat.getCheckTy() == Check::CheckLabel) + Keeping = Re.match(CS.Pat.getFixedStr()); + if (Keeping) + Filtered.push_back(std::move(CS)); + } + CheckStrings = std::move(Filtered); +} + bool FileCheck::ValidateCheckPrefixes() { StringSet<> UniquePrefixes; // Add default prefixes to catch user-supplied duplicates of them below. diff --git a/llvm/lib/FileCheck/FileCheckImpl.h b/llvm/lib/FileCheck/FileCheckImpl.h index 5393650020a30..b156daaf40ab1 100644 --- a/llvm/lib/FileCheck/FileCheckImpl.h +++ b/llvm/lib/FileCheck/FileCheckImpl.h @@ -745,6 +745,11 @@ class Pattern { Check::FileCheckType getCheckTy() const { return CheckTy; } + /// \returns the literal pattern text, or an empty StringRef if the pattern + /// requires a regex match. Used by FileCheck::filterByLabel to identify + /// CHECK-LABEL sections by their literal text. + StringRef getFixedStr() const { return FixedStr; } + int getCount() const { return CheckTy.getCount(); } private: diff --git a/llvm/test/FileCheck/filter-label.txt b/llvm/test/FileCheck/filter-label.txt new file mode 100644 index 0000000000000..db5d5e3df3671 --- /dev/null +++ b/llvm/test/FileCheck/filter-label.txt @@ -0,0 +1,51 @@ +; Verify --filter-label drops CHECKs whose CHECK-LABEL section's literal text +; doesn't match any of the given names. + +; RUN: FileCheck --filter-label=foo -input-file %s %s -check-prefix=ALL +; RUN: FileCheck --filter-label=bar -input-file %s %s -check-prefix=ALL +; RUN: FileCheck --filter-label=foo,bar -input-file %s %s -check-prefix=ALL +; RUN: FileCheck --filter-label=bar,foo -input-file %s %s -check-prefix=ALL + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck --filter-label=foobar -input-file %s %s -check-prefix=ALL 2>&1 \ +; RUN: | FileCheck %s -check-prefix=FAIL-ERR + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -input-file %s %s -check-prefix=ALL 2>&1 \ +; RUN: | FileCheck %s -check-prefix=FAIL-ERR + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck --filter-label=baz -input-file %s %s -check-prefix=BAZ 2>&1 \ +; RUN: | FileCheck %s -check-prefix=FAIL-ERR + + +@foo: +a +b + +@bar: +c +d + +@foobar: +e +f + +@baz: +g +h + +; ALL-LABEL: @foo: +; ALL: {{^}}a +; ALL: {{^}}b +; ALL-LABEL: @bar: +; ALL: {{^}}c +; ALL: {{^}}d +; ALL-LABEL: @foobar: +; ALL: {{^}}e +; ALL: {{^}}MISMATCH +; BAZ-LABEL: @baz: +; BAZ: {{^}}g +; BAZ: {{^}}i + +; FAIL-ERR: expected string not found in input diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp index 63b745469b8ee..82c71b0975534 100644 --- a/llvm/utils/FileCheck/FileCheck.cpp +++ b/llvm/utils/FileCheck/FileCheck.cpp @@ -143,6 +143,14 @@ enum DumpInputFilterValue { DumpInputFilterAll }; +static cl::list<std::string> FilterLabel( + "filter-label", cl::CommaSeparated, + cl::desc("Drop CHECKs whose enclosing CHECK-LABEL section's literal text\n" + "doesn't word-match any of the given labels. CHECKs before the\n" + "first label are dropped. Useful for narrowing checks to a subset\n" + "of functions."), + cl::value_desc("name")); + static cl::list<DumpInputFilterValue> DumpInputFilters( "dump-input-filter", cl::desc("In the dump requested by -dump-input, print only input lines of\n" @@ -868,6 +876,12 @@ int main(int argc, char **argv) { if (FC.readCheckFile(SM, CheckFileText, &ImpPatBufferIDRange)) return 2; + if (!FilterLabel.empty()) { + SmallVector<StringRef, 4> FilterLabelRefs(FilterLabel.begin(), + FilterLabel.end()); + FC.filterByLabel(FilterLabelRefs); + } + // Open the file to check and add it to SourceMgr. ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr = MemoryBuffer::getFileOrSTDIN(InputFilename, /*IsText=*/true); >From 80ed9c8e6fa5c21676fa381b955c6b11fa0ea77e Mon Sep 17 00:00:00 2001 From: jofrn <[email protected]> Date: Fri, 29 May 2026 01:09:16 -0700 Subject: [PATCH 2/2] [lit] Add lit.llvm.fn_param shared helper for --param fn= substitutions --- llvm/test/lit.cfg.py | 6 ++++ llvm/utils/lit/lit/llvm/fn_param.py | 46 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 llvm/utils/lit/lit/llvm/fn_param.py diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py index 09df1e3fd6281..f4b9e8aaed6ef 100644 --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -39,6 +39,12 @@ ) config.test_format = lit.formats.ShTest(not use_lit_shell, extra_substitutions) +# --param fn=NAMES narrows compilation to the named functions and their +# transitive dependencies. See lit.llvm.fn_param.install for dispatch details. +from lit.llvm import fn_param + +fn_param.install(config, lit_config) + # suffixes: A list of file extensions to treat as test files. This is overriden # by individual lit.local.cfg files in the test subdirectories. config.suffixes = [".ll", ".c", ".test", ".txt", ".s", ".mir", ".yaml", ".spv"] diff --git a/llvm/utils/lit/lit/llvm/fn_param.py b/llvm/utils/lit/lit/llvm/fn_param.py new file mode 100644 index 0000000000000..48d8400b80155 --- /dev/null +++ b/llvm/utils/lit/lit/llvm/fn_param.py @@ -0,0 +1,46 @@ +"""Shared building blocks for `--param fn=NAMES`-driven lit substitutions. + +Used by `lit.llvm.fn_selection` and `lit.llvm.fn_extract` to narrow compilation +to a subset of functions. Kept here so the two helpers stay short and share +parsing + capture-substitution wiring.""" + +from lit.TestingConfig import SubstituteCaptures + + +def parse_fn_names(lit_config, param="fn"): + """Return the comma-separated list passed via `--param <param>=NAMES`, + or an empty list when the param is absent or empty.""" + val = lit_config.params.get(param) + if not val: + return [] + return [n.strip() for n in val.split(",") if n.strip()] + + +def add_capture_sub(config, pattern, replacement): + """Append a substitution that preserves regex backreferences in `replacement`.""" + config.substitutions.append((pattern, SubstituteCaptures(replacement))) + + +def install(config, lit_config): + """Dispatch `--param fn=NAMES` to the right helper, and ask FileCheck to + drop CHECKs outside the selected CHECK-LABEL sections. + + `--param fn-pass=1` opts into `lit.llvm.fn_selection` (the select-function + pass, opt-only); otherwise `lit.llvm.fn_extract` is used (prepends + llvm-extract, tool-agnostic).""" + names = parse_fn_names(lit_config) + if not names: + return + # Splice `--filter-label=NAMES` after any FileCheck invocation so the + # downstream FileCheck only checks the CHECK-LABEL sections we kept. + add_capture_sub( + config, r"(\S*FileCheck)\b", r"\1 --filter-label=" + ",".join(names) + ) + if lit_config.params.get("fn-pass"): + # from lit.llvm import fn_selection + # fn_selection.install(config, lit_config) + pass + else: + # from lit.llvm import fn_extract + # fn_extract.install(config, lit_config) + pass _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
