[llvm] [llvm-utils][Tools] fix mir-check filter to handle scattered check-lines (PR #209226)

Gang Chen via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 17 08:57:37 PDT 2026


https://github.com/cmc-rep updated https://github.com/llvm/llvm-project/pull/209226

>From 759aacc898c294f04f7ef4f36874b65da80f9596 Mon Sep 17 00:00:00 2001
From: Gang Chen <Gang.Chen at amd.com>
Date: Mon, 13 Jul 2026 07:56:40 -0700
Subject: [PATCH 1/2] [llvm-utils][Tools] fix mir-check filter to handle
 scattered check-lines

---
 .../Inputs/x86-filter.mir.filter-out.expected |  4 +-
 .../Inputs/x86-filter.mir.filter.expected     |  5 +-
 llvm/utils/UpdateTestChecks/mir.py            | 65 ++++++++++++++++++-
 3 files changed, 69 insertions(+), 5 deletions(-)

diff --git a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-filter.mir.filter-out.expected b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-filter.mir.filter-out.expected
index 87c3670a10421..ea924dd74d398 100644
--- a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-filter.mir.filter-out.expected
+++ b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-filter.mir.filter-out.expected
@@ -32,7 +32,7 @@ body:             |
     ; CHECK-LABEL: name: ptrtoint_s8
     ; CHECK: liveins: $rdi
     ; CHECK-NEXT: {{  $}}
-    ; CHECK-NEXT: $al = COPY [[COPY1]]
+    ; CHECK: $al = COPY [[COPY1]]
     ; CHECK-NEXT: RET 0, implicit $al
     %0:gpr(p0) = COPY $rdi
     %1:gpr(s8) = G_PTRTOINT %0(p0)
@@ -57,7 +57,7 @@ body:             |
     ; CHECK: liveins: $rdi
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64 = COPY $rdi
-    ; CHECK-NEXT: $eax = COPY [[COPY1]]
+    ; CHECK: $eax = COPY [[COPY1]]
     ; CHECK-NEXT: RET 0, implicit $eax
     %0:gpr(p0) = COPY $rdi
     %1:gpr(s32) = G_PTRTOINT %0(p0)
diff --git a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-filter.mir.filter.expected b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-filter.mir.filter.expected
index 39064f9a3ae3c..4141015cf9059 100644
--- a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-filter.mir.filter.expected
+++ b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-filter.mir.filter.expected
@@ -30,7 +30,8 @@ body:             |
     liveins: $rdi
 
     ; CHECK-LABEL: name: ptrtoint_s8
-    ; CHECK: [[COPY1:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit
+    ; CHECK: [[COPY:%[0-9]+]]:gr64_with_sub_8bit = COPY $rdi
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit
     %0:gpr(p0) = COPY $rdi
     %1:gpr(s8) = G_PTRTOINT %0(p0)
     $al = COPY %1(s8)
@@ -50,6 +51,8 @@ body:             |
   bb.1.entry:
     liveins: $rdi
 
+    ; CHECK-LABEL: name: ptrtoint_s32
+    ; CHECK: [[COPY1:%[0-9]+]]:gr32 = COPY [[COPY]].sub_32bit
     %0:gpr(p0) = COPY $rdi
     %1:gpr(s32) = G_PTRTOINT %0(p0)
     $eax = COPY %1(s32)
diff --git a/llvm/utils/UpdateTestChecks/mir.py b/llvm/utils/UpdateTestChecks/mir.py
index e75d3dd2ff368..5b269167b8db8 100644
--- a/llvm/utils/UpdateTestChecks/mir.py
+++ b/llvm/utils/UpdateTestChecks/mir.py
@@ -50,6 +50,52 @@
     flags=(re.M | re.S),
 )
 
+MD_PTR_RE = re.compile(r"\<0x[a-f0-9]+\>", re.IGNORECASE)
+
+# A marker inserted into a filtered MIR function body to record that one or more
+# lines were removed by --filter between two retained lines. When emitting
+# checks, the retained line that follows a marker is printed as CHECK (rather
+# than CHECK-NEXT) because it is not guaranteed to immediately follow the
+# previous match in the tool output.
+MIR_FILTER_GAP_MARKER = "; UTC-MIR-FILTER-GAP"
+
+
+def filter_mir_body(body, filters):
+    """Filter a MIR function body while keeping the generated checks correct.
+
+    Behaves like common.do_filter, with two MIR-specific adjustments that make
+    --filter usable for tests whose interesting instructions are scattered
+    through the function:
+
+      * Basic block label lines are always retained.  This keeps the check
+        comments at the block-level indentation (so the surrounding "body: |"
+        block scalar stays valid) and documents the control-flow structure.
+      * A marker line is inserted wherever one or more lines were removed
+        between two retained lines.  add_mir_check_lines turns the retained line
+        after a marker into a CHECK instead of a CHECK-NEXT, since filtered-out
+        instructions may sit between the two matches in the tool output.
+    """
+    if not filters:
+        return body
+    if common.has_filter_out_after(filters):
+        lines = common.filter_out_after(body, filters)
+    else:
+        lines = body.splitlines()
+    result = []
+    have_gap = False
+    for line in lines:
+        keep = common.apply_filters(line, filters) or bool(
+            MIR_BASIC_BLOCK_RE.match(line)
+        )
+        if not keep:
+            have_gap = True
+            continue
+        if have_gap and result:
+            result.append(MIR_FILTER_GAP_MARKER)
+        result.append(line)
+        have_gap = False
+    return "\n".join(result)
+
 
 def build_function_info_dictionary(
     test, raw_tool_output, triple, prefixes, func_dict, verbose, filters=None
@@ -84,7 +130,7 @@ def build_function_info_dictionary(
                 )
             mangled.append(func_line)
         body = "".join(mangled)
-        filtered_body = common.do_filter(body, filters)
+        filtered_body = filter_mir_body(body, filters)
 
         for prefix in prefixes:
             info = common.function_body(
@@ -215,6 +261,12 @@ def add_mir_check_lines(
         # Don't bother checking the basic block label for a single BB
         func_body.pop(0)
 
+    # A gap marker carries no information before the first retained line, and
+    # popping the basic block label above may have exposed one.  Drop any such
+    # leading markers so indentation is computed from a real instruction line.
+    while func_body and func_body[0] == MIR_FILTER_GAP_MARKER:
+        func_body.pop(0)
+
     if not func_body:
         warn(
             "Function has no instructions to check: {}".format(func_name),
@@ -240,6 +292,12 @@ def add_mir_check_lines(
 
     first_check = not first_check_is_next
     for func_line in func_body:
+        if func_line == MIR_FILTER_GAP_MARKER:
+            # One or more lines were filtered out here, so the next retained
+            # line is not necessarily adjacent to the previous match: emit it as
+            # CHECK rather than CHECK-NEXT.
+            first_check = True
+            continue
         if not func_line.strip():
             # The mir printer prints leading whitespace so we can't use CHECK-EMPTY:
             output_lines.append(check + "-NEXT: {{" + func_line + "$}}")
@@ -277,7 +335,10 @@ def add_mir_checks(
     func_name = None
     state = "toplevel"
     for input_line in input_lines:
-        if input_line == autogenerated_note:
+        if common.UTC_ADVERT in input_line:
+            # Discard any previous autogenerated note.  Matching on the advert
+            # text (rather than the exact note) ensures a stale note is dropped
+            # even when the arguments differ, e.g. when --filter was added.
             continue
 
         if state == "toplevel":

>From bae4f8a3cf88d1268304e0fa0819ae9f6dbdbde2 Mon Sep 17 00:00:00 2001
From: Gang Chen <Gang.Chen at amd.com>
Date: Thu, 16 Jul 2026 11:49:54 -0700
Subject: [PATCH 2/2] [LLVM][Utils] Add tests for the fix of mir-check filter

---
 .../Inputs/amdgpu-scattered-filter.mir        | 64 ++++++++++++++
 ...mdgpu-scattered-filter.mir.filter.expected | 84 +++++++++++++++++++
 .../update_mir_test_checks/amdgpu-filter.test | 13 +++
 llvm/utils/UpdateTestChecks/mir.py            |  3 -
 4 files changed, 161 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/amdgpu-scattered-filter.mir
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/amdgpu-scattered-filter.mir.filter.expected
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_mir_test_checks/amdgpu-filter.test

diff --git a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/amdgpu-scattered-filter.mir b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/amdgpu-scattered-filter.mir
new file mode 100644
index 0000000000000..85380526a3d59
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/amdgpu-scattered-filter.mir
@@ -0,0 +1,64 @@
+# RUN: llc -mtriple=amdgpu10.10 -run-pass=none -verify-machineinstrs -o - %s | FileCheck -check-prefixes=GFX10 %s
+
+---
+name:            _amdgpu_hs_main
+alignment:       1
+tracksRegLiveness: true
+machineFunctionInfo:
+  isEntryFunction: true
+body:             |
+  bb.0:
+    successors: %bb.1(0x40000000), %bb.2(0x40000000)
+
+    %2:vgpr_32 = IMPLICIT_DEF
+    %3:sreg_32 = S_MOV_B32 8
+    %5:vgpr_32 = V_BFE_U32_e64 %2, 8, 5, implicit $exec
+    %6:sreg_32 = S_MOV_B32 5
+    %7:sreg_32 = V_CMP_NE_U32_e64 %5, killed %6, implicit $exec
+    %8:sreg_32 = S_XOR_B32 %7, -1, implicit-def $scc
+    %9:sreg_32 = S_AND_B32 %8, $exec_lo, implicit-def $scc
+    %10:sreg_32 = S_XOR_B32 $exec_lo, %9, implicit-def $scc
+    $exec_lo = S_MOV_B32_term %9
+    S_CBRANCH_EXECZ %bb.2, implicit $exec
+    S_BRANCH %bb.1
+
+  bb.1:
+    successors: %bb.2(0x80000000)
+
+    %0:sgpr_32 = IMPLICIT_DEF
+    S_BRANCH %bb.2
+
+  bb.2:
+    successors: %bb.3(0x40000000), %bb.4(0x40000000)
+
+    $exec_lo = S_OR_B32 $exec_lo, %10, implicit-def $scc
+    %4:vgpr_32 = V_LSHRREV_B32_e64 %3, %2, implicit $exec
+    %11:sreg_32 = S_MOV_B32 31
+    %12:sreg_32 = V_CMP_NE_U32_e64 %5, killed %11, implicit $exec
+    %13:sreg_32 = S_XOR_B32 %12, -1, implicit-def $scc
+    %14:sreg_32 = S_AND_B32 %13, $exec_lo, implicit-def $scc
+    %15:sreg_32 = S_XOR_B32 $exec_lo, %14, implicit-def $scc
+    $exec_lo = S_MOV_B32_term %14
+    S_CBRANCH_EXECZ %bb.4, implicit $exec
+    S_BRANCH %bb.3
+
+  bb.3:
+    successors: %bb.4(0x80000000)
+
+    S_BRANCH %bb.4
+
+  bb.4:
+    successors: %bb.5(0x80000000)
+
+    $exec_lo = S_OR_B32 $exec_lo, %15, implicit-def $scc
+    %1:sreg_32 = IMPLICIT_DEF
+    %16:sreg_32 = S_MOV_B32 16
+    %17:sreg_32 = S_MOV_B32 4
+    %18:vgpr_32 = nuw nsw V_LSHL_ADD_U32_e64 %4, %17, killed %16, implicit $exec
+    S_BRANCH %bb.5
+
+  bb.5:
+    $exec_lo = S_OR_B32 $exec_lo, %1, implicit-def $scc
+    S_ENDPGM 0
+
+...
diff --git a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/amdgpu-scattered-filter.mir.filter.expected b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/amdgpu-scattered-filter.mir.filter.expected
new file mode 100644
index 0000000000000..05bcd9b82df54
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/amdgpu-scattered-filter.mir.filter.expected
@@ -0,0 +1,84 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --filter "exec_lo|IMPLICIT_DEF"
+# RUN: llc -mtriple=amdgpu10.10 -run-pass=none -verify-machineinstrs -o - %s | FileCheck -check-prefixes=GFX10 %s
+
+---
+name:            _amdgpu_hs_main
+alignment:       1
+tracksRegLiveness: true
+machineFunctionInfo:
+  isEntryFunction: true
+body:             |
+  ; GFX10-LABEL: name: _amdgpu_hs_main
+  ; GFX10: bb.0:
+  ; GFX10:   [[DEF:%[0-9]+]]:vgpr_32 = IMPLICIT_DEF
+  ; GFX10:   [[S_AND_B32_:%[0-9]+]]:sreg_32 = S_AND_B32 [[S_XOR_B32_]], $exec_lo, implicit-def $scc
+  ; GFX10-NEXT:   [[S_XOR_B32_1:%[0-9]+]]:sreg_32 = S_XOR_B32 $exec_lo, [[S_AND_B32_]], implicit-def $scc
+  ; GFX10-NEXT:   $exec_lo = S_MOV_B32_term [[S_AND_B32_]]
+  ; GFX10: bb.1:
+  ; GFX10:   [[DEF1:%[0-9]+]]:sgpr_32 = IMPLICIT_DEF
+  ; GFX10: bb.2:
+  ; GFX10:   $exec_lo = S_OR_B32 $exec_lo, [[S_XOR_B32_1]], implicit-def $scc
+  ; GFX10:   [[S_AND_B32_1:%[0-9]+]]:sreg_32 = S_AND_B32 [[S_XOR_B32_2]], $exec_lo, implicit-def $scc
+  ; GFX10-NEXT:   [[S_XOR_B32_3:%[0-9]+]]:sreg_32 = S_XOR_B32 $exec_lo, [[S_AND_B32_1]], implicit-def $scc
+  ; GFX10-NEXT:   $exec_lo = S_MOV_B32_term [[S_AND_B32_1]]
+  ; GFX10: bb.3:
+  ; GFX10: bb.4:
+  ; GFX10:   $exec_lo = S_OR_B32 $exec_lo, [[S_XOR_B32_3]], implicit-def $scc
+  ; GFX10-NEXT:   [[DEF2:%[0-9]+]]:sreg_32 = IMPLICIT_DEF
+  ; GFX10: bb.5:
+  ; GFX10-NEXT:   $exec_lo = S_OR_B32 $exec_lo, [[DEF2]], implicit-def $scc
+  bb.0:
+    successors: %bb.1(0x40000000), %bb.2(0x40000000)
+
+    %2:vgpr_32 = IMPLICIT_DEF
+    %3:sreg_32 = S_MOV_B32 8
+    %5:vgpr_32 = V_BFE_U32_e64 %2, 8, 5, implicit $exec
+    %6:sreg_32 = S_MOV_B32 5
+    %7:sreg_32 = V_CMP_NE_U32_e64 %5, killed %6, implicit $exec
+    %8:sreg_32 = S_XOR_B32 %7, -1, implicit-def $scc
+    %9:sreg_32 = S_AND_B32 %8, $exec_lo, implicit-def $scc
+    %10:sreg_32 = S_XOR_B32 $exec_lo, %9, implicit-def $scc
+    $exec_lo = S_MOV_B32_term %9
+    S_CBRANCH_EXECZ %bb.2, implicit $exec
+    S_BRANCH %bb.1
+
+  bb.1:
+    successors: %bb.2(0x80000000)
+
+    %0:sgpr_32 = IMPLICIT_DEF
+    S_BRANCH %bb.2
+
+  bb.2:
+    successors: %bb.3(0x40000000), %bb.4(0x40000000)
+
+    $exec_lo = S_OR_B32 $exec_lo, %10, implicit-def $scc
+    %4:vgpr_32 = V_LSHRREV_B32_e64 %3, %2, implicit $exec
+    %11:sreg_32 = S_MOV_B32 31
+    %12:sreg_32 = V_CMP_NE_U32_e64 %5, killed %11, implicit $exec
+    %13:sreg_32 = S_XOR_B32 %12, -1, implicit-def $scc
+    %14:sreg_32 = S_AND_B32 %13, $exec_lo, implicit-def $scc
+    %15:sreg_32 = S_XOR_B32 $exec_lo, %14, implicit-def $scc
+    $exec_lo = S_MOV_B32_term %14
+    S_CBRANCH_EXECZ %bb.4, implicit $exec
+    S_BRANCH %bb.3
+
+  bb.3:
+    successors: %bb.4(0x80000000)
+
+    S_BRANCH %bb.4
+
+  bb.4:
+    successors: %bb.5(0x80000000)
+
+    $exec_lo = S_OR_B32 $exec_lo, %15, implicit-def $scc
+    %1:sreg_32 = IMPLICIT_DEF
+    %16:sreg_32 = S_MOV_B32 16
+    %17:sreg_32 = S_MOV_B32 4
+    %18:vgpr_32 = nuw nsw V_LSHL_ADD_U32_e64 %4, %17, killed %16, implicit $exec
+    S_BRANCH %bb.5
+
+  bb.5:
+    $exec_lo = S_OR_B32 $exec_lo, %1, implicit-def $scc
+    S_ENDPGM 0
+
+...
diff --git a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/amdgpu-filter.test b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/amdgpu-filter.test
new file mode 100644
index 0000000000000..3c9f88c2a1517
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/amdgpu-filter.test
@@ -0,0 +1,13 @@
+# REQUIRES: amdgpu-registered-target
+
+## Check that --filter works properly.
+# RUN: cp -f %S/Inputs/amdgpu-scattered-filter.mir %t.mir && %update_mir_test_checks --filter="exec_lo|IMPLICIT_DEF" %t.mir
+# RUN: diff -u %t.mir %S/Inputs/amdgpu-scattered-filter.mir.filter.expected
+
+## Check that running the script again does not change the result:
+# RUN: %update_mir_test_checks --filter="exec_lo|IMPLICIT_DEF" %t.mir
+# RUN: diff -u %t.mir %S/Inputs/amdgpu-scattered-filter.mir.filter.expected
+
+# RUN: cp -f %S/Inputs/amdgpu-scattered-filter.mir %t.mir && %update_mir_test_checks %t.mir
+# RUN: %update_mir_test_checks --filter="exec_lo|IMPLICIT_DEF" %t.mir
+# RUN: diff -u %t.mir %S/Inputs/amdgpu-scattered-filter.mir.filter.expected
diff --git a/llvm/utils/UpdateTestChecks/mir.py b/llvm/utils/UpdateTestChecks/mir.py
index 5b269167b8db8..e5f381edcb343 100644
--- a/llvm/utils/UpdateTestChecks/mir.py
+++ b/llvm/utils/UpdateTestChecks/mir.py
@@ -50,8 +50,6 @@
     flags=(re.M | re.S),
 )
 
-MD_PTR_RE = re.compile(r"\<0x[a-f0-9]+\>", re.IGNORECASE)
-
 # A marker inserted into a filtered MIR function body to record that one or more
 # lines were removed by --filter between two retained lines. When emitting
 # checks, the retained line that follows a marker is printed as CHECK (rather
@@ -59,7 +57,6 @@
 # previous match in the tool output.
 MIR_FILTER_GAP_MARKER = "; UTC-MIR-FILTER-GAP"
 
-
 def filter_mir_body(body, filters):
     """Filter a MIR function body while keeping the generated checks correct.
 



More information about the llvm-commits mailing list