https://github.com/jofrn updated 
https://github.com/llvm/llvm-project/pull/200618

>From cefc58c17bd972f5f695f73fc1cf73bccbce30a0 Mon Sep 17 00:00:00 2001
From: jofrn <[email protected]>
Date: Thu, 21 May 2026 15:01:13 -0700
Subject: [PATCH 1/2] [lit] Add --check to run only selected RUN lines from a
 test

`llvm-lit --check=LIST <test>` keeps only the listed RUN directives in
the test and discards the rest. LIST is a comma-separated mix
of 0-indexed integers and ranges (e.g. `--check=0,2,4-6`). The
selection is applied to the parseIntegratedTestScript output.

Run tests via
`llvm-lit --check=0 llvm/utils/lit/tests/Inputs/check-filter/sample.ll`,
`llvm-lit --check=1 llvm/utils/lit/tests/Inputs/check-filter/sample.ll`,
`llvm/utils/lit/lit.py llvm/utils/lit/tests/check-filter.py`.
---
 llvm/utils/lit/lit/LitConfig.py               |  2 ++
 llvm/utils/lit/lit/TestRunner.py              | 18 ++++++++++
 llvm/utils/lit/lit/cl_arguments.py            | 36 +++++++++++++++++++
 llvm/utils/lit/lit/main.py                    |  1 +
 .../lit/tests/Inputs/check-filter/lit.cfg     |  7 ++++
 .../lit/tests/Inputs/check-filter/sample.ll   |  4 +++
 llvm/utils/lit/tests/check-filter.py          | 23 ++++++++++++
 7 files changed, 91 insertions(+)
 create mode 100644 llvm/utils/lit/tests/Inputs/check-filter/lit.cfg
 create mode 100644 llvm/utils/lit/tests/Inputs/check-filter/sample.ll
 create mode 100644 llvm/utils/lit/tests/check-filter.py

diff --git a/llvm/utils/lit/lit/LitConfig.py b/llvm/utils/lit/lit/LitConfig.py
index 4be2a0f6d8121..43af8ed989508 100644
--- a/llvm/utils/lit/lit/LitConfig.py
+++ b/llvm/utils/lit/lit/LitConfig.py
@@ -42,6 +42,7 @@ def __init__(
         per_test_coverage=False,
         gtest_sharding=True,
         update_tests=False,
+        checkFilter=None,
     ):
         # The name of the test runner.
         self.progname = progname
@@ -96,6 +97,7 @@ def __init__(
         self.gtest_sharding = bool(gtest_sharding)
         self.update_tests = update_tests
         self.test_updaters = [diff_test_updater]
+        self.checkFilter = checkFilter
 
     @property
     def maxIndividualTestTime(self):
diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py
index 82852f1852705..4a0a969b1d804 100644
--- a/llvm/utils/lit/lit/TestRunner.py
+++ b/llvm/utils/lit/lit/TestRunner.py
@@ -1921,6 +1921,23 @@ def _replaceReadFile(match):
         commandLine = "%s && test -e %s" % (commandLine, filePath)
     return commandLine
 
+def _applyCheckFilter(test, check_filter):
+    """Keep only CommandDirective entries whose 0-indexed integer(s)
+    is/are in check_filter.
+    """
+    if check_filter is None:
+        return test
+    out = []
+    n = -1
+    for d in test:
+        if isinstance(d, CommandDirective):
+            n += 1
+            if n not in check_filter:
+                continue
+        out.append(d)
+    return out
+
+
 def executeShTest(
     test, litConfig, useExternalSh, extra_substitutions=[], 
preamble_commands=[]
 ):
@@ -1933,6 +1950,7 @@ def executeShTest(
     parsed = parseIntegratedTestScript(test, require_script=not script)
     if isinstance(parsed, lit.Test.Result):
         return parsed
+    parsed = _applyCheckFilter(parsed, litConfig.checkFilter)
     script += parsed
 
     if litConfig.noExecute:
diff --git a/llvm/utils/lit/lit/cl_arguments.py 
b/llvm/utils/lit/lit/cl_arguments.py
index bebde4b762b0e..209fd456d805e 100644
--- a/llvm/utils/lit/lit/cl_arguments.py
+++ b/llvm/utils/lit/lit/cl_arguments.py
@@ -427,6 +427,15 @@ def parse_args():
         help="Only run tests with paths matching the given regular expression",
         default=os.environ.get("LIT_FILTER", ".*"),
     )
+    selection_group.add_argument(
+        "--check",
+        dest="checkFilter",
+        metavar="LIST",
+        type=_check_filter,
+        default=None,
+        help="Within each test file, keep only the listed RUN lines. "
+        "LIST is comma-separated 0-indexed integers or ranges: '1,3-5'.",
+    )
     selection_group.add_argument(
         "--filter-out",
         metavar="REGEX",
@@ -587,6 +596,33 @@ def _semicolon_list(arg):
     return arg.split(";")
 
 
+def _check_filter(arg):
+    out = []
+    for tok in arg.split(","):
+        tok = tok.strip()
+        if not tok:
+            continue
+        if "-" in tok and tok[0] != "-":
+            a, sep, b = tok.partition("-")
+            if a.isdigit() and b.isdigit():
+                lo, hi = int(a), int(b)
+                if hi < lo:
+                    raise _error(
+                        "range '{}' is empty (high < low)", tok
+                    )
+                out.extend(range(lo, hi + 1))
+                continue
+        if tok.isdigit():
+            out.append(int(tok))
+        else:
+            raise _error(
+                "expected integer or integer range, got '{}'", tok
+            )
+    if not out:
+        raise _error("empty selector list")
+    return out
+
+
 def _error(desc, *args):
     msg = desc.format(*args)
     return argparse.ArgumentTypeError(msg)
diff --git a/llvm/utils/lit/lit/main.py b/llvm/utils/lit/lit/main.py
index 77b23bf560c6e..ae2964e157fbc 100755
--- a/llvm/utils/lit/lit/main.py
+++ b/llvm/utils/lit/lit/main.py
@@ -44,6 +44,7 @@ def main(builtin_params={}):
         gtest_sharding=opts.gtest_sharding,
         maxRetriesPerTest=opts.maxRetriesPerTest,
         update_tests=opts.update_tests,
+        checkFilter=opts.checkFilter,
     )
 
     discovered_tests = lit.discovery.find_tests_for_inputs(
diff --git a/llvm/utils/lit/tests/Inputs/check-filter/lit.cfg 
b/llvm/utils/lit/tests/Inputs/check-filter/lit.cfg
new file mode 100644
index 0000000000000..756e2d63e8fb0
--- /dev/null
+++ b/llvm/utils/lit/tests/Inputs/check-filter/lit.cfg
@@ -0,0 +1,7 @@
+import lit.formats
+
+config.name = "check-filter"
+config.suffixes = [".ll", ".mir", ".s"]
+config.test_format = lit.formats.ShTest()
+config.test_source_root = None
+config.test_exec_root = None
diff --git a/llvm/utils/lit/tests/Inputs/check-filter/sample.ll 
b/llvm/utils/lit/tests/Inputs/check-filter/sample.ll
new file mode 100644
index 0000000000000..27c686974a056
--- /dev/null
+++ b/llvm/utils/lit/tests/Inputs/check-filter/sample.ll
@@ -0,0 +1,4 @@
+; RUN: echo FIRST-RUN
+; RUN: echo SECOND-RUN
+define i32 @foo(i32 %a) { ret i32 0 }
+define i32 @bar() { ret i32 1 }
diff --git a/llvm/utils/lit/tests/check-filter.py 
b/llvm/utils/lit/tests/check-filter.py
new file mode 100644
index 0000000000000..5352136c1ea82
--- /dev/null
+++ b/llvm/utils/lit/tests/check-filter.py
@@ -0,0 +1,23 @@
+# Verify lit's --check filter. --check=N drops every CommandDirective except
+# the Nth (0-indexed).
+
+# --- --check=0: keep only the first RUN ---
+# RUN: %{lit} -a --check=0 %{inputs}/check-filter/sample.ll \
+# RUN:   | FileCheck --check-prefix=CHECK-0 \
+# RUN:       --implicit-check-not="executed command: echo SECOND-RUN" %s
+#
+# CHECK-0:     executed command: echo FIRST-RUN
+
+# --- --check=1: skip the first, keep the second ---
+# RUN: %{lit} -a --check=1 %{inputs}/check-filter/sample.ll \
+# RUN:   | FileCheck --check-prefix=CHECK-1 \
+# RUN:       --implicit-check-not="executed command: echo FIRST-RUN" %s
+#
+# CHECK-1:     executed command: echo SECOND-RUN
+
+# --- No filter: both RUNs execute ---
+# RUN: %{lit} -a %{inputs}/check-filter/sample.ll \
+# RUN:   | FileCheck --check-prefix=NO-FILTER %s
+#
+# NO-FILTER:   executed command: echo FIRST-RUN
+# NO-FILTER:   executed command: echo SECOND-RUN

>From a63ed38900170263b8db07973dba3f3932dde7af Mon Sep 17 00:00:00 2001
From: jofrn <[email protected]>
Date: Sat, 30 May 2026 16:52:22 -0700
Subject: [PATCH 2/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      | 12 ++++++
 5 files changed, 97 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..41a1921c014dc 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -143,6 +143,12 @@ enum DumpInputFilterValue {
   DumpInputFilterAll
 };
 
+static cl::list<std::string> FilterLabel(
+    "filter-label", cl::CommaSeparated,
+    cl::desc("Keep only CHECKs in CHECK-LABEL sections whose label\n"
+             "matches one of the given names."),
+    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 +874,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);

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to