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

Reply via email to