[llvm] [UTC] Don't rename %. inside quoted strings in test checkseg (PR #218767)

Krzysztof Drewniak via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 11:53:38 PDT 2026


https://github.com/krzysz00 updated https://github.com/llvm/llvm-project/pull/218767

>From 1d0aea70b0fc9eec3874bdf71c92364a4a59e60c Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Thu, 20 Aug 2026 23:45:38 +0000
Subject: [PATCH 1/2] [utils] Don't rename %. inside quoted strings in test
 checkseg

Replacing `%.foo` with `%dotfoo` everywhere also caught any `%.foo`
inside metadata, which would then cause incorrect CHECK lines to be
generated (since the value in the metedata isn't going to be
modified).

This commit fixes the issue by matching quoted strings in a regex
before looking for %. to replace.

AI disclosure: Claude found and fixed this, I wrote the commit message
---
 .../Inputs/dot_value_in_metadata_string.ll    | 11 ++++++++++
 .../dot_value_in_metadata_string.ll.expected  | 22 +++++++++++++++++++
 .../dot_value_in_metadata_string.test         |  7 ++++++
 llvm/utils/UpdateTestChecks/common.py         | 11 +++++++++-
 4 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/dot_value_in_metadata_string.ll
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/dot_value_in_metadata_string.ll.expected
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/dot_value_in_metadata_string.test

diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/dot_value_in_metadata_string.ll b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/dot_value_in_metadata_string.ll
new file mode 100644
index 0000000000000..844a1087b61cf
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/dot_value_in_metadata_string.ll
@@ -0,0 +1,11 @@
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define i32 @dot_value_and_metadata_string(ptr %p, i32 %n) {
+  %.sum = add i32 %n, 1
+  store i32 %.sum, ptr %p, align 4, !alias.scope !0
+  ret i32 %.sum
+}
+
+!0 = !{!1}
+!1 = distinct !{!1, !2, !"callee: %.arg"}
+!2 = distinct !{!2, !"callee"}
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/dot_value_in_metadata_string.ll.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/dot_value_in_metadata_string.ll.expected
new file mode 100644
index 0000000000000..2fc57109e00d0
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/dot_value_in_metadata_string.ll.expected
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define i32 @dot_value_and_metadata_string(ptr %p, i32 %n) {
+; CHECK-LABEL: @dot_value_and_metadata_string(
+; CHECK-NEXT:    [[DOTSUM:%.*]] = add i32 [[N:%.*]], 1
+; CHECK-NEXT:    store i32 [[DOTSUM]], ptr [[P:%.*]], align 4, !alias.scope [[META0:![0-9]+]]
+; CHECK-NEXT:    ret i32 [[DOTSUM]]
+;
+  %.sum = add i32 %n, 1
+  store i32 %.sum, ptr %p, align 4, !alias.scope !0
+  ret i32 %.sum
+}
+
+!0 = !{!1}
+!1 = distinct !{!1, !2, !"callee: %.arg"}
+!2 = distinct !{!2, !"callee"}
+;.
+; CHECK: [[META0]] = !{[[META1:![0-9]+]]}
+; CHECK: [[META1]] = distinct !{[[META1]], [[META2:![0-9]+]], !"callee: %.arg"}
+; CHECK: [[META2]] = distinct !{[[META2]], !"callee"}
+;.
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/dot_value_in_metadata_string.test b/llvm/test/tools/UpdateTestChecks/update_test_checks/dot_value_in_metadata_string.test
new file mode 100644
index 0000000000000..a61f093cf7091
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/dot_value_in_metadata_string.test
@@ -0,0 +1,7 @@
+# Verify that an IR value whose name starts with a '.' is still renamed to
+# derive a FileCheck variable name, while a '%.' inside a quoted metadata
+# string is left alone.
+# RUN: cp -f %S/Inputs/dot_value_in_metadata_string.ll %t.ll && %update_test_checks %t.ll --check-globals all
+# RUN: diff -u %t.ll %S/Inputs/dot_value_in_metadata_string.ll.expected
+# Verify that the generated check lines match the input they were taken from.
+# RUN: opt < %t.ll -passes=instsimplify -S | FileCheck %t.ll
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index fdd2e20d2f386..8305e32eafb92 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -1145,6 +1145,9 @@ def processed_prefixes(self, prefixes):
 # Comments to indicate the predecessors of a block in the IR.
 SCRUB_PRED_COMMENT_RE = re.compile(r"\s*; preds = .*")
 SCRUB_IR_FUNC_META_RE = re.compile(r"((?:\!(?!dbg\b)[a-zA-Z_]\w*(?:\s+![0-9]+)?)\s*)+")
+# A quoted string, or an IR variable whose name starts with a '.'. Matching the
+# strings too keeps the rename below from reaching inside one.
+IR_QUOTED_STRING_OR_DOT_VALUE_RE = re.compile(r"\"[^\"]*\"|%\.")
 
 # TODO: We should also derive check lines for global, debug, loop declarations, etc..
 
@@ -1927,7 +1930,13 @@ def escape_braces(match_obj):
     if ginfo.is_ir():
         for i, line in enumerate(lines):
             # An IR variable named '%.' matches the FileCheck regex string.
-            line = line.replace("%.", "%dot")
+            # Skip quoted strings: a '%.' inside one, as in the description of
+            # an alias scope named after a callee's argument, is text that
+            # nothing later generalizes away, so renaming it would leave a
+            # check line that cannot match the input it came from.
+            line = IR_QUOTED_STRING_OR_DOT_VALUE_RE.sub(
+                lambda m: m.group(0) if m.group(0).startswith('"') else "%dot", line
+            )
             for regex in _global_hex_value_regex:
                 if re.match("^@" + regex + " = ", line):
                     line = re.sub(

>From e348236bcc2ad0c50c67c2d69f0c8bb8b3f76446 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Wed, 26 Aug 2026 18:52:41 +0000
Subject: [PATCH 2/2] A better fix

---
 .../dot_value_in_metadata_string.test               |  3 +++
 llvm/utils/UpdateTestChecks/common.py               | 13 ++-----------
 2 files changed, 5 insertions(+), 11 deletions(-)

diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/dot_value_in_metadata_string.test b/llvm/test/tools/UpdateTestChecks/update_test_checks/dot_value_in_metadata_string.test
index a61f093cf7091..729af94aaa3d9 100644
--- a/llvm/test/tools/UpdateTestChecks/update_test_checks/dot_value_in_metadata_string.test
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/dot_value_in_metadata_string.test
@@ -5,3 +5,6 @@
 # RUN: diff -u %t.ll %S/Inputs/dot_value_in_metadata_string.ll.expected
 # Verify that the generated check lines match the input they were taken from.
 # RUN: opt < %t.ll -passes=instsimplify -S | FileCheck %t.ll
+# RUN: cp -f %t.ll %t.first.ll && %update_test_checks %t.ll --check-globals all
+# Verify script is idempotent
+# RUN: diff -u %t.ll %t.first.ll
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index 8305e32eafb92..3da99528ace63 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -1145,9 +1145,6 @@ def processed_prefixes(self, prefixes):
 # Comments to indicate the predecessors of a block in the IR.
 SCRUB_PRED_COMMENT_RE = re.compile(r"\s*; preds = .*")
 SCRUB_IR_FUNC_META_RE = re.compile(r"((?:\!(?!dbg\b)[a-zA-Z_]\w*(?:\s+![0-9]+)?)\s*)+")
-# A quoted string, or an IR variable whose name starts with a '.'. Matching the
-# strings too keeps the rename below from reaching inside one.
-IR_QUOTED_STRING_OR_DOT_VALUE_RE = re.compile(r"\"[^\"]*\"|%\.")
 
 # TODO: We should also derive check lines for global, debug, loop declarations, etc..
 
@@ -1206,6 +1203,8 @@ def get_ir_regex(self):
     def get_value_name(self, var: str, check_prefix: str):
         var = var.replace("!", "")
         var = var.replace("%", "")
+        if (var.startswith(".")):
+            var = var.replace(".", "dot", 1)
         if self.replace_number_with_counter:
             assert var
             replacement = self.variable_mapping.get(var, None)
@@ -1929,14 +1928,6 @@ def escape_braces(match_obj):
 
     if ginfo.is_ir():
         for i, line in enumerate(lines):
-            # An IR variable named '%.' matches the FileCheck regex string.
-            # Skip quoted strings: a '%.' inside one, as in the description of
-            # an alias scope named after a callee's argument, is text that
-            # nothing later generalizes away, so renaming it would leave a
-            # check line that cannot match the input it came from.
-            line = IR_QUOTED_STRING_OR_DOT_VALUE_RE.sub(
-                lambda m: m.group(0) if m.group(0).startswith('"') else "%dot", line
-            )
             for regex in _global_hex_value_regex:
                 if re.match("^@" + regex + " = ", line):
                     line = re.sub(



More information about the llvm-commits mailing list