[llvm] Reapply "[utils][UpdateLLCTestChecks] Add MIR support to update_llc_test_checks.py." (#164965) (PR #166575)
Valery Pykhtin via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 6 00:00:57 PST 2025
https://github.com/vpykhtin updated https://github.com/llvm/llvm-project/pull/166575
>From 241e8bd5c698e375cc30a38219bef3b33d2f8721 Mon Sep 17 00:00:00 2001
From: Valery Pykhtin <valery.pykhtin at amd.com>
Date: Wed, 5 Nov 2025 15:41:32 +0000
Subject: [PATCH 1/2] Reapply "[utils][UpdateLLCTestChecks] Add MIR support to
update_llc_test_checks.py." (#166549)
This reverts commit ba1dbdd44a1db9a5a0912830afc05d7b18cbf666.
---
.../Inputs/x86_asm_mir_mixed.ll | 17 ++++
.../Inputs/x86_asm_mir_mixed.ll.expected | 45 +++++++++
.../Inputs/x86_asm_mir_same_prefix.ll | 13 +++
.../x86_asm_mir_same_prefix.ll.expected | 16 ++++
.../x86-asm-mir-mixed.test | 9 ++
.../x86-asm-mir-same-prefix.test | 7 ++
llvm/utils/UpdateTestChecks/common.py | 1 +
llvm/utils/UpdateTestChecks/mir.py | 11 ++-
llvm/utils/update_llc_test_checks.py | 94 +++++++++++++++----
9 files changed, 194 insertions(+), 19 deletions(-)
create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_mixed.ll
create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_mixed.ll.expected
create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_same_prefix.ll
create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_same_prefix.ll.expected
create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-mixed.test
create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-same-prefix.test
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_mixed.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_mixed.ll
new file mode 100644
index 0000000000000..292637177591f
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_mixed.ll
@@ -0,0 +1,17 @@
+; RUN: llc -mtriple=x86_64 < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -mtriple=x86_64 -stop-after=finalize-isel < %s | FileCheck %s --check-prefix=MIR
+
+define i64 @test1(i64 %i) nounwind readnone {
+ %loc = alloca i64
+ %j = load i64, ptr %loc
+ %r = add i64 %i, %j
+ ret i64 %r
+}
+
+define i64 @test2(i32 %i) nounwind readnone {
+ %loc = alloca i32
+ %j = load i32, ptr %loc
+ %r = add i32 %i, %j
+ %ext = zext i32 %r to i64
+ ret i64 %ext
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_mixed.ll.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_mixed.ll.expected
new file mode 100644
index 0000000000000..88cb03e85204a
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_mixed.ll.expected
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=x86_64 < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -mtriple=x86_64 -stop-after=finalize-isel < %s | FileCheck %s --check-prefix=MIR
+
+define i64 @test1(i64 %i) nounwind readnone {
+; ASM-LABEL: test1:
+; ASM: # %bb.0:
+; ASM-NEXT: movq %rdi, %rax
+; ASM-NEXT: addq -{{[0-9]+}}(%rsp), %rax
+; ASM-NEXT: retq
+; MIR-LABEL: name: test1
+; MIR: bb.0 (%ir-block.0):
+; MIR-NEXT: liveins: $rdi
+; MIR-NEXT: {{ $}}
+; MIR-NEXT: [[COPY:%[0-9]+]]:gr64 = COPY $rdi
+; MIR-NEXT: [[ADD64rm:%[0-9]+]]:gr64 = ADD64rm [[COPY]], %stack.0.loc, 1, $noreg, 0, $noreg, implicit-def dead $eflags :: (dereferenceable load (s64) from %ir.loc)
+; MIR-NEXT: $rax = COPY [[ADD64rm]]
+; MIR-NEXT: RET 0, $rax
+ %loc = alloca i64
+ %j = load i64, ptr %loc
+ %r = add i64 %i, %j
+ ret i64 %r
+}
+
+define i64 @test2(i32 %i) nounwind readnone {
+; ASM-LABEL: test2:
+; ASM: # %bb.0:
+; ASM-NEXT: movl %edi, %eax
+; ASM-NEXT: addl -{{[0-9]+}}(%rsp), %eax
+; ASM-NEXT: retq
+; MIR-LABEL: name: test2
+; MIR: bb.0 (%ir-block.0):
+; MIR-NEXT: liveins: $edi
+; MIR-NEXT: {{ $}}
+; MIR-NEXT: [[COPY:%[0-9]+]]:gr32 = COPY $edi
+; MIR-NEXT: [[ADD32rm:%[0-9]+]]:gr32 = ADD32rm [[COPY]], %stack.0.loc, 1, $noreg, 0, $noreg, implicit-def dead $eflags :: (dereferenceable load (s32) from %ir.loc)
+; MIR-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, killed [[ADD32rm]], %subreg.sub_32bit
+; MIR-NEXT: $rax = COPY [[SUBREG_TO_REG]]
+; MIR-NEXT: RET 0, $rax
+ %loc = alloca i32
+ %j = load i32, ptr %loc
+ %r = add i32 %i, %j
+ %ext = zext i32 %r to i64
+ ret i64 %ext
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_same_prefix.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_same_prefix.ll
new file mode 100644
index 0000000000000..7167bcf258e68
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_same_prefix.ll
@@ -0,0 +1,13 @@
+; RUN: llc -mtriple=x86_64 < %s | FileCheck %s --check-prefix=CHECK
+; RUN: llc -mtriple=x86_64 -stop-after=finalize-isel < %s | FileCheck %s --check-prefix=CHECK
+
+define i32 @add(i32 %a, i32 %b) {
+ %sum = add i32 %a, %b
+ ret i32 %sum
+}
+
+define i32 @sub(i32 %a, i32 %b) {
+ %diff = sub i32 %a, %b
+ ret i32 %diff
+}
+
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_same_prefix.ll.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_same_prefix.ll.expected
new file mode 100644
index 0000000000000..1ba920d1de8b0
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86_asm_mir_same_prefix.ll.expected
@@ -0,0 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=x86_64 < %s | FileCheck %s --check-prefix=CHECK
+; RUN: llc -mtriple=x86_64 -stop-after=finalize-isel < %s | FileCheck %s --check-prefix=CHECK
+
+define i32 @add(i32 %a, i32 %b) {
+ %sum = add i32 %a, %b
+ ret i32 %sum
+}
+
+define i32 @sub(i32 %a, i32 %b) {
+ %diff = sub i32 %a, %b
+ ret i32 %diff
+}
+
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-mixed.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-mixed.test
new file mode 100644
index 0000000000000..6fc57b583b37d
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-mixed.test
@@ -0,0 +1,9 @@
+# REQUIRES: x86-registered-target
+## Test checking that update_llc_test_checks.py can generate both ASM and MIR checks in the same file
+
+# RUN: cp -f %S/Inputs/x86_asm_mir_mixed.ll %t.ll && %update_llc_test_checks %t.ll
+# RUN: diff -u %S/Inputs/x86_asm_mir_mixed.ll.expected %t.ll
+
+## Verify that running the script again on an already updated file doesn't add duplicate checks
+# RUN: %update_llc_test_checks %t.ll
+# RUN: diff -u %S/Inputs/x86_asm_mir_mixed.ll.expected %t.ll
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-same-prefix.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-same-prefix.test
new file mode 100644
index 0000000000000..bb91a44678f1a
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-same-prefix.test
@@ -0,0 +1,7 @@
+## Test that using the same prefix for both ASM and MIR outputs generates a warning
+## and doesn't produce any checks.
+
+# RUN: cp -f %S/Inputs/x86_asm_mir_same_prefix.ll %t.ll && %update_llc_test_checks %t.ll 2>&1 | FileCheck %s --check-prefix=WARNING
+# RUN: diff -u %S/Inputs/x86_asm_mir_same_prefix.ll.expected %t.ll
+
+# WARNING: WARNING: The following prefixes are used for both ASM and MIR output, which will cause FileCheck failures: CHECK
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index 2dad16a8eebb7..baa0377cd8b81 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -605,6 +605,7 @@ def invoke_tool(exe, cmd_args, ir, preprocess_cmd=None, verbose=False):
TRIPLE_ARG_RE = re.compile(r"-m?triple[= ]([^ ]+)")
MARCH_ARG_RE = re.compile(r"-march[= ]([^ ]+)")
DEBUG_ONLY_ARG_RE = re.compile(r"-debug-only[= ]([^ ]+)")
+STOP_PASS_RE = re.compile(r"-stop-(before|after)=(\w+)")
IS_DEBUG_RECORD_RE = re.compile(r"^(\s+)#dbg_")
IS_SWITCH_CASE_RE = re.compile(r"^\s+i\d+ \d+, label %\S+")
diff --git a/llvm/utils/UpdateTestChecks/mir.py b/llvm/utils/UpdateTestChecks/mir.py
index 24bb8b341d335..01ee0e19f7cb9 100644
--- a/llvm/utils/UpdateTestChecks/mir.py
+++ b/llvm/utils/UpdateTestChecks/mir.py
@@ -163,13 +163,15 @@ def add_mir_checks_for_function(
print_fixed_stack,
first_check_is_next,
at_the_function_name,
+ check_indent=None,
):
printed_prefixes = set()
for run in run_list:
for prefix in run[0]:
if prefix in printed_prefixes:
break
- if not func_dict[prefix][func_name]:
+ # func_info can be empty if there was a prefix conflict.
+ if not func_dict[prefix].get(func_name):
continue
if printed_prefixes:
# Add some space between different check prefixes.
@@ -185,6 +187,7 @@ def add_mir_checks_for_function(
func_dict[prefix][func_name],
print_fixed_stack,
first_check_is_next,
+ check_indent,
)
break
else:
@@ -204,6 +207,7 @@ def add_mir_check_lines(
func_info,
print_fixed_stack,
first_check_is_next,
+ check_indent=None,
):
func_body = str(func_info).splitlines()
if single_bb:
@@ -220,7 +224,10 @@ def add_mir_check_lines(
first_line = func_body[0]
indent = len(first_line) - len(first_line.lstrip(" "))
# A check comment, indented the appropriate amount
- check = "{:>{}}; {}".format("", indent, prefix)
+ if check_indent is not None:
+ check = "{}; {}".format(check_indent, prefix)
+ else:
+ check = "{:>{}}; {}".format("", indent, prefix)
output_lines.append("{}-LABEL: name: {}".format(check, func_name))
diff --git a/llvm/utils/update_llc_test_checks.py b/llvm/utils/update_llc_test_checks.py
index 8c57e75f34f75..98864be62875b 100755
--- a/llvm/utils/update_llc_test_checks.py
+++ b/llvm/utils/update_llc_test_checks.py
@@ -15,7 +15,7 @@
import os # Used to advertise this file's name ("autogenerated_note").
import sys
-from UpdateTestChecks import common
+from UpdateTestChecks import common, mir
# llc is the only llc-like in the LLVM tree but downstream forks can add
# additional ones here if they have them.
@@ -33,6 +33,7 @@ def update_test(ti: common.TestInfo):
break
run_list = []
+ mir_run_list = []
for l in ti.run_lines:
if "|" not in l:
common.warn("Skipping unparsable RUN line: " + l)
@@ -57,9 +58,14 @@ def update_test(ti: common.TestInfo):
if m:
march_in_cmd = m.groups()[0]
+ target_list = run_list
m = common.DEBUG_ONLY_ARG_RE.search(llc_cmd)
if m and m.groups()[0] == "isel":
from UpdateTestChecks import isel as output_type
+ elif not m and common.STOP_PASS_RE.search(llc_cmd):
+ # MIR output mode. If -debug-only is present assume
+ # the debug output is the main point of interest.
+ target_list = mir_run_list
else:
from UpdateTestChecks import asm as output_type
@@ -84,7 +90,7 @@ def update_test(ti: common.TestInfo):
# FIXME: We should use multiple check prefixes to common check lines. For
# now, we just ignore all but the last.
- run_list.append(
+ target_list.append(
(
check_prefixes,
llc_tool,
@@ -119,14 +125,20 @@ def update_test(ti: common.TestInfo):
ginfo=ginfo,
)
- for (
- prefixes,
- llc_tool,
- llc_args,
- preprocess_cmd,
- triple_in_cmd,
- march_in_cmd,
- ) in run_list:
+ # Dictionary to store MIR function bodies separately
+ mir_func_dict = {}
+ for run_tuple, is_mir in [(run, False) for run in run_list] + [
+ (run, True) for run in mir_run_list
+ ]:
+ (
+ prefixes,
+ llc_tool,
+ llc_args,
+ preprocess_cmd,
+ triple_in_cmd,
+ march_in_cmd,
+ ) = run_tuple
+
common.debug("Extracted LLC cmd:", llc_tool, llc_args)
common.debug("Extracted FileCheck prefixes:", str(prefixes))
@@ -141,22 +153,54 @@ def update_test(ti: common.TestInfo):
if not triple:
triple = common.get_triple_from_march(march_in_cmd)
- scrubber, function_re = output_type.get_run_handler(triple)
- if 0 == builder.process_run_line(
- function_re, scrubber, raw_tool_output, prefixes
- ):
- common.warn(
- "Couldn't match any function. Possibly the wrong target triple has been provided"
+ if is_mir:
+ # MIR output mode
+ common.debug("Detected MIR output mode for prefixes:", str(prefixes))
+ for prefix in prefixes:
+ if prefix not in mir_func_dict:
+ mir_func_dict[prefix] = {}
+
+ mir.build_function_info_dictionary(
+ ti.path,
+ raw_tool_output,
+ triple,
+ prefixes,
+ mir_func_dict,
+ ti.args.verbose,
)
- builder.processed_prefixes(prefixes)
+ else:
+ # ASM output mode
+ scrubber, function_re = output_type.get_run_handler(triple)
+ if 0 == builder.process_run_line(
+ function_re, scrubber, raw_tool_output, prefixes
+ ):
+ common.warn(
+ "Couldn't match any function. Possibly the wrong target triple has been provided"
+ )
+ builder.processed_prefixes(prefixes)
func_dict = builder.finish_and_get_func_dict()
+
+ # Check for conflicts: same prefix used for both ASM and MIR
+ conflicting_prefixes = set(func_dict.keys()) & set(mir_func_dict.keys())
+ if conflicting_prefixes:
+ common.warn(
+ "The following prefixes are used for both ASM and MIR output, which will cause FileCheck failures: {}".format(
+ ", ".join(sorted(conflicting_prefixes))
+ ),
+ test_file=ti.path,
+ )
+ for prefix in conflicting_prefixes:
+ mir_func_dict[prefix] = {}
+ func_dict[prefix] = {}
+
global_vars_seen_dict = {}
is_in_function = False
is_in_function_start = False
func_name = None
prefix_set = set([prefix for p in run_list for prefix in p[0]])
+ prefix_set.update([prefix for p in mir_run_list for prefix in p[0]])
common.debug("Rewriting FileCheck prefixes:", str(prefix_set))
output_lines = []
@@ -221,6 +265,22 @@ def update_test(ti: common.TestInfo):
is_filtered=builder.is_filtered(),
)
)
+
+ # Also add MIR checks if we have them for this function
+ if mir_run_list and func_name:
+ mir.add_mir_checks_for_function(
+ ti.path,
+ output_lines,
+ mir_run_list,
+ mir_func_dict,
+ func_name,
+ single_bb=False, # Don't skip basic block labels.
+ print_fixed_stack=False, # Don't print fixed stack (ASM tests don't need it).
+ first_check_is_next=False, # First check is LABEL, not NEXT.
+ at_the_function_name=False, # Use "name:" not "@name".
+ check_indent="", # No indentation for IR files (not MIR files).
+ )
+
is_in_function_start = False
if is_in_function:
>From 0a7bd4bcc100cfeccc4c4d48f42cebc36d50b9d2 Mon Sep 17 00:00:00 2001
From: Valery Pykhtin <valery.pykhtin at amd.com>
Date: Wed, 5 Nov 2025 15:44:31 +0000
Subject: [PATCH 2/2] Add missing "# REQUIRES: x86-registered-target"
---
.../update_llc_test_checks/x86-asm-mir-same-prefix.test | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-same-prefix.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-same-prefix.test
index bb91a44678f1a..0f8aaa549afa4 100644
--- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-same-prefix.test
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-asm-mir-same-prefix.test
@@ -1,3 +1,4 @@
+# REQUIRES: x86-registered-target
## Test that using the same prefix for both ASM and MIR outputs generates a warning
## and doesn't produce any checks.
More information about the llvm-commits
mailing list