Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[utils] update_llc_test_checks --downstream-target-handler-path option #135879

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

vporpo
Copy link
Contributor

@vporpo vporpo commented Apr 15, 2025

This patch adds a new option to update_llc_test_checks.py that points to a downstream python module implementing handler functions for a downstream compiler.

RFC: https://discourse.llvm.org/t/rfc-update-llc-test-checks-support-downstream-targets-with-a-new-option-pointing-to-downstream-handlers/85883

Copy link

github-actions bot commented Apr 15, 2025

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

This patch adds a new option to update_llce_test_checks that points to
a downstream python module implementing handler functions for a downstream
compiler.
@vporpo vporpo requested a review from tru April 16, 2025 21:21
@vporpo vporpo marked this pull request as ready for review April 17, 2025 18:24
@llvmbot
Copy link
Member

llvmbot commented Apr 17, 2025

@llvm/pr-subscribers-testing-tools

Author: vporpo (vporpo)

Changes

This patch adds a new option to update_llc_test_checks.py that points to a downstream python module implementing handler functions for a downstream compiler.

RFC: https://discourse.llvm.org/t/rfc-update-llc-test-checks-support-downstream-targets-with-a-new-option-pointing-to-downstream-handlers/85883


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

5 Files Affected:

  • (added) llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.ll (+4)
  • (added) llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.ll.expected (+8)
  • (added) llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.py (+65)
  • (added) llvm/test/tools/UpdateTestChecks/update_llc_test_checks/downstream_target.test (+7)
  • (modified) llvm/utils/update_llc_test_checks.py (+31-3)
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.ll
new file mode 100644
index 0000000000000..1003194769a61
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.ll
@@ -0,0 +1,4 @@
+; RUN: llc < %s -mtriple=i686-- | FileCheck %s
+define void @foo() {
+  ret void
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.ll.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.ll.expected
new file mode 100644
index 0000000000000..263c787c910a1
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.ll.expected
@@ -0,0 +1,8 @@
+; RUN: llc < %s -mtriple=i686-- | FileCheck %s
+define void @foo() {
+; CHECK-LABEL: foo:
+; CHECK:       Test
+; CHECK-NEXT:  Downstream
+; CHECK-NEXT:  Target
+  ret void
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.py b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.py
new file mode 100644
index 0000000000000..6df7421b92ab6
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/downstream_target.py
@@ -0,0 +1,65 @@
+# This is an example of a downstream module, which in this case is for i686.
+# The goal is to test the updater's downstream-target-module-path option.
+#
+# This target module implements a simple scrubber that returns a fixed string,
+# a regex that matches the fixed strings generated by the scrubber.
+#
+# This module needs to define:
+# 2. The `downstream_scrub(asm, arg)` scrubber function
+# 3. The `downstream_asm_fn_re` regex for matching func, body, etc.
+
+import re
+import sys
+import os
+from pathlib import Path
+
+common_dir = Path(__file__).parent / "../../../../../utils/"
+sys.path.append(common_dir)
+from UpdateTestChecks import common
+
+
+# The asm scrubber returns the scrubbed asm.
+# In this test we return a fixed string.
+def scrub(asm, args):
+    return "Test\n" "Downstream\n" "Target\n"
+
+
+# The regular expression for matching func, body, etc.
+regex = re.compile(
+    r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*(@"?(?P=func)"?| -- Begin function (?P=func))\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?'
+    r"(?:\.L(?P=func)\$local:\n)?"  # drop .L<func>$local:
+    r"(?:\s*\.type\s+\.L(?P=func)\$local,@function\n)?"  # drop .type .L<func>$local
+    r"(?:[ \t]*(?:\.cfi_startproc|\.cfi_personality|\.cfi_lsda|\.seh_proc|\.seh_handler)\b[^\n]*\n)*"  # drop optional cfi
+    r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
+    r"^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section|#+ -- End function)",
+    flags=(re.M | re.S),
+)
+
+
+def get_run_handler(triple):
+    return (scrub, regex)
+
+
+def add_checks(
+    output_lines,
+    comment_marker,
+    prefix_list,
+    func_dict,
+    func_name,
+    ginfo: common.GeneralizerInfo,
+    global_vars_seen_dict,
+    is_filtered,
+):
+    # Label format is based on ASM string.
+    check_label_format = "{} %s-LABEL: %s%s%s%s".format(comment_marker)
+    return common.add_checks(
+        output_lines,
+        comment_marker,
+        prefix_list,
+        func_dict,
+        func_name,
+        check_label_format,
+        ginfo,
+        global_vars_seen_dict,
+        is_filtered=is_filtered,
+    )
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/downstream_target.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/downstream_target.test
new file mode 100644
index 0000000000000..dc7f9b8da95fa
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/downstream_target.test
@@ -0,0 +1,7 @@
+# REQUIRES: x86-registered-target
+## Tests that the downstream module support works
+
+# RUN: cp -f %S/Inputs/downstream_target.ll %t.ll && %update_llc_test_checks %t.ll --downstream-target-handler-path=%S/Inputs/downstream_target.py
+# RUN: grep -v '^; NOTE:' %t.ll > %t.ll.expected
+# RUN: diff -b -u %S/Inputs/downstream_target.ll.expected %t.ll.expected
+
diff --git a/llvm/utils/update_llc_test_checks.py b/llvm/utils/update_llc_test_checks.py
index 3e9380d95e3f6..05d370d794d15 100755
--- a/llvm/utils/update_llc_test_checks.py
+++ b/llvm/utils/update_llc_test_checks.py
@@ -11,6 +11,8 @@
 
 import argparse
 import os  # Used to advertise this file's name ("autogenerated_note").
+import sys
+import importlib.util
 
 from UpdateTestChecks import common
 
@@ -21,6 +23,19 @@
 ]
 
 
+# Helper that imports module from `module_path` and returns it.
+def import_module(module_path):
+    if not os.path.exists(module_path):
+        common.error("Path does not exist", module_path)
+        sys.exit(1)
+    module_name_with_ext = os.path.basename(module_path)
+    module_name = os.path.splitext(module_name_with_ext)[0]
+    spec = importlib.util.spec_from_file_location(module_name, module_path)
+    module = importlib.util.module_from_spec(spec)
+    sys.modules[module_name] = module
+    spec.loader.exec_module(module)
+    return module
+
 def main():
     parser = argparse.ArgumentParser(description=__doc__)
     parser.add_argument(
@@ -67,6 +82,12 @@ def main():
         help="Set a default -march for when neither triple nor arch are found in a RUN line",
     )
     parser.add_argument("tests", nargs="+")
+    parser.add_argument(
+        "--downstream-target-handler-path",
+        default=None,
+        dest="downstream_target_handler_path",
+        help="The path of a python module that implements the scrubber and the regex generator and adds it to the targets handlers map for a downstream target",
+    )
     initial_args = common.parse_commandline_args(parser)
 
     script_name = os.path.basename(__file__)
@@ -107,10 +128,17 @@ def main():
                 march_in_cmd = m.groups()[0]
 
             m = common.DEBUG_ONLY_ARG_RE.search(llc_cmd)
-            if m and m.groups()[0] == "isel":
-                from UpdateTestChecks import isel as output_type
+            if initial_args.downstream_target_handler_path:
+                common.warn(
+                    "Downstream handlers provided by '%s'"
+                    % initial_args.downstream_target_handler_path
+                )
+                output_type = import_module(initial_args.downstream_target_handler_path)
             else:
-                from UpdateTestChecks import asm as output_type
+                if m and m.groups()[0] == "isel":
+                    from UpdateTestChecks import isel as output_type
+                else:
+                    from UpdateTestChecks import asm as output_type
 
             common.verify_filecheck_prefixes(filecheck_cmd)
 

@vporpo vporpo requested review from nhaehnle and MaskRay April 24, 2025 16:46
@vporpo
Copy link
Contributor Author

vporpo commented Apr 24, 2025

Adding a few more folks who have worked on this tool. @MaskRay @nhaehnle any thoughts?

@MaskRay
Copy link
Member

MaskRay commented Apr 25, 2025

(I am travelling with limited computer access until May 4th, and my response time may be delayed..)
I share @jrtc27's maintenance concerns raised in the LLVM Discourse thread: https://discourse.llvm.org/t/rfc-update-llc-test-checks-support-downstream-targets-with-a-new-option-pointing-to-downstream-handlers/85883/2.

The target-specific component is highly stable. Downstream targets typically require only a few lines of script, which rarely need updates, even after a year or two. I don't see sufficient justification for the proposed loaded module patch.

@vporpo
Copy link
Contributor Author

vporpo commented Apr 28, 2025

Thank you for your reply @MaskRay . These scripts are indeed stable, so they won't probably cause any merge conflicts. But there is a downstream cost for each one of these patches as they have to go through a process for getting them added in or getting them updated, which could be saved if we added this simple feature.

@arichardson
Copy link
Member

If the patches don't change I don't see how this adds a lot of maintainance on your side? I have worked on a fork with huge diff relative to upstream llvm including changes to this script and I think we only needed to resolve one (trivial) conflict over many years.

@rnk
Copy link
Collaborator

rnk commented Apr 28, 2025

I think LLVM knows that downstream out-of-tree targets exist, and we should be willing to take reasonable, low-cost steps to make them easier to maintain. The entire TargetMachine backend interface is virtual, so we did 80% of the work to make LLVM support out-of-tree plugins as loadable modules, but then we stopped at some point and started adding Triple ISA checks throughout the compiler, compromising the abstraction. I think we ought to lean in the direction of minimizing target awareness and increasing abstraction over all targets, and that's the intuition I'd use the judge this. If it handles out of tree targets uniformly with our in-tree set, then it's a reasonable cost for us to bear.

@vporpo
Copy link
Contributor Author

vporpo commented Apr 30, 2025

Thanks for your feedback @arichardson . The main argument is along the lines of what @rnk mentioned above. The patch provides a way to decouple downstream from upstream and make the update_llc_test_checks.py script target unaware, which I think is overall considered desirable from the design and maintenance perspective. I agree that maintaining the downstream patches won't probably be an issue as conflicts are unlikely. But since there is a way to avoid the patches in the first place I am arguing that this should be the preferred solution.

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.

5 participants