Skip to content

update_test_checks: Fix preservation of meta variable names with --include-generated-funcs #86160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

jasilvanus
Copy link
Contributor

With --include-generated-funcs, check lines for function bodies are separate from
the IR function bodies. This needs to be handled differently by the UTC parser
for existing check lines.

This caused existing check lines to not be detected with --include-generated-funcs,
which in turn effectively disabled the mechanism to preserve variable meta names
where possible.

This is fixed in this patch.

@llvmbot
Copy link
Member

llvmbot commented Mar 21, 2024

@llvm/pr-subscribers-testing-tools

Author: Jannik Silvanus (jasilvanus)

Changes

With --include-generated-funcs, check lines for function bodies are separate from
the IR function bodies. This needs to be handled differently by the UTC parser
for existing check lines.

This caused existing check lines to not be detected with --include-generated-funcs,
which in turn effectively disabled the mechanism to preserve variable meta names
where possible.

This is fixed in this patch.


Full diff: https://github.com/llvm/llvm-project/pull/86160.diff

4 Files Affected:

  • (added) llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/stable_ir_values5.ll (+22)
  • (added) llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/stable_ir_values5.ll.expected (+23)
  • (added) llvm/test/tools/UpdateTestChecks/update_test_checks/stable_ir_values5.test (+2)
  • (modified) llvm/utils/UpdateTestChecks/common.py (+68-23)
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/stable_ir_values5.ll b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/stable_ir_values5.ll
new file mode 100644
index 00000000000000..a788c82872a07f
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/stable_ir_values5.ll
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs --version 3
+; RUN: opt < %s -S | FileCheck %s
+
+; With --include-generated-funcs, check lines are separate from IR function bodies.
+; This needs to be handled separately by the UTC parser for existing check lines.
+; This test tests this case.
+
+define i32 @func({i32, i32} %x, i32 %y) {
+  %x.i34 = extractvalue {i32, i32} %x, 0
+  %1 = add i32 %y, 1
+  %2 = add i32 %x.i34, %1
+  %3 = mul i32 %2, 3
+  ret i32 %3
+}
+
+; CHECK-LABEL: define i32 @func(
+; CHECK-SAME: { i32, i32 } [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[X_I33:%.*]] = extractvalue { i32, i32 } [[X]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X_I33]], [[Y]]
+; CHECK-NEXT:    [[TMP2:%.*]] = mul i32 [[TMP1]], 3
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/stable_ir_values5.ll.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/stable_ir_values5.ll.expected
new file mode 100644
index 00000000000000..09df76d9dadc62
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/stable_ir_values5.ll.expected
@@ -0,0 +1,23 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs --version 3
+; RUN: opt < %s -S | FileCheck %s
+
+; With --include-generated-funcs, check lines are separate from IR function bodies.
+; This needs to be handled separately by the UTC parser for existing check lines.
+; This test tests this case.
+
+define i32 @func({i32, i32} %x, i32 %y) {
+  %x.i34 = extractvalue {i32, i32} %x, 0
+  %1 = add i32 %y, 1
+  %2 = add i32 %x.i34, %1
+  %3 = mul i32 %2, 3
+  ret i32 %3
+}
+
+; CHECK-LABEL: define i32 @func(
+; CHECK-SAME: { i32, i32 } [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[X_I33:%.*]] = extractvalue { i32, i32 } [[X]], 0
+; CHECK-NEXT:    [[TMP3:%.*]] = add i32 [[Y]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X_I33]], [[TMP3]]
+; CHECK-NEXT:    [[TMP2:%.*]] = mul i32 [[TMP1]], 3
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/stable_ir_values5.test b/llvm/test/tools/UpdateTestChecks/update_test_checks/stable_ir_values5.test
new file mode 100644
index 00000000000000..a04a9fa3e90785
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/stable_ir_values5.test
@@ -0,0 +1,2 @@
+# RUN: cp -f %S/Inputs/stable_ir_values5.ll %t.ll && %update_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/stable_ir_values5.ll.expected
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index ecb19d233a8d1a..01ed6d5ce6e067 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -430,36 +430,81 @@ def collect_original_check_lines(ti: TestInfo, prefix_set: set):
     result[func_name][prefix] is filled with a list of right-hand-sides of check
     lines.
     """
-    result = {}
 
+    # We need to detect check lines, and associate them with the correct functions and prefixes.
+    # There are two formats how IR and check lines are combined. In the standard format,
+    # they are interleaved, and it suffices to parse IR function definitions in order to keep
+    # track of the current function:
+    #
+    #    define i32 @func1(i32 %x) {
+    #    ; CHECK-LABEL: define i32 @func1(
+    #    ; CHECK-NEXT:    /* check lines */
+    #    ;
+    #      %1 = /* IR body of @func1 */
+    #
+    #    define i32 @func2(i32 %x) {
+    #    ; CHECK-LABEL: define i32 @func2(
+    #    ; CHECK-NEXT:    /* check lines */
+    #    ;
+    #      %1 = /* IR body of @func2 */
+    #
+    # However, with --include-generated-funcs, check lines are separate from IR function bodies,
+    # and we also need to parse CHECK lines of function definitions:
+    #
+    #    define i32 @func1(i32 %x) {
+    #      /* IR body */
+    #
+    #    define i32 @func2(..) {
+    #      /* IR body */
+    #
+    #    ; CHECK-LABEL: define i32 @func1
+    #    ; CHECK-NEXT /* check lines for func1 */
+    #
+    #    ; CHECK-LABEL: define i32 @func2
+    #    ; CHECK-NEXT /* check lines for func2 */
+
+    result = collections.defaultdict(dict)
     current_function = None
+
+    def update_current_function(line):
+        m = IR_FUNCTION_RE.match(line)
+        if m is None:
+            return
+        func_name = m.group(1)
+        if ti.args.function is not None and func_name != ti.args.function:
+            # When filtering on a specific function, skip all others.
+            return
+
+        nonlocal current_function
+        current_function = result[func_name]
+
     for input_line_info in ti.ro_iterlines():
         input_line = input_line_info.line
-        if current_function is not None:
-            if input_line == "":
-                continue
-            if input_line.lstrip().startswith(";"):
-                m = CHECK_RE.match(input_line)
-                if (
-                    m is not None
-                    and m.group(1) in prefix_set
-                    and m.group(2) not in ["LABEL", "SAME"]
-                ):
-                    if m.group(1) not in current_function:
-                        current_function[m.group(1)] = []
-                    current_function[m.group(1)].append(input_line[m.end() :].strip())
-                continue
+        if input_line == "":
+            continue
+        m = None
+        if input_line.lstrip().startswith(";"):
+            m = CHECK_RE.match(input_line)
+            if m is not None and m.group(2) == "LABEL":
+                # Update current_function if the current line is a CHECK of a function definition
+                line_remainder = input_line[len(m.group(0)):]
+                update_current_function(line_remainder)
+        else:
             current_function = None
 
-        m = IR_FUNCTION_RE.match(input_line)
-        if m is not None:
-            func_name = m.group(1)
-            if ti.args.function is not None and func_name != ti.args.function:
-                # When filtering on a specific function, skip all others.
-                continue
+        if current_function is not None:
+            if (
+                m is not None
+                and m.group(1) in prefix_set
+                and m.group(2) not in ["LABEL", "SAME"]
+            ):
+                if m.group(1) not in current_function:
+                    current_function[m.group(1)] = []
+                current_function[m.group(1)].append(input_line[m.end() :].strip())
+            continue
 
-            assert func_name not in result
-            current_function = result[func_name] = {}
+        # Update current_function if the current line is an IR function definition
+        update_current_function(input_line)
 
     return result
 

Copy link

github-actions bot commented Mar 21, 2024

✅ With the latest revision this PR passed the Python code formatter.

…clude-generated-funcs

With --include-generated-funcs, check lines for function bodies are separate from
the IR function bodies. This needs to be handled differently by the UTC parser
for existing check lines.

This caused existing check lines to not be detected with --include-generated-funcs,
which in turn effectively disabled the mechanism to preserve variable meta names
where possible.

This is fixed in this patch.
@jasilvanus jasilvanus force-pushed the jsilvanu/preserve-variable-names-with-include-generated-funcs branch from 450fc07 to 175b7bd Compare March 21, 2024 18:00
@jasilvanus
Copy link
Contributor Author

Closing in favour of #87988.

@jasilvanus jasilvanus closed this Apr 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants