llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-testing-tools

Author: Alexander Richardson (arichardson)

<details>
<summary>Changes</summary>

This simplifies update_mc_test_checks.py to feed the entire input file
into llvm-mc, rather than invoking it line-by-line. It leverages the new
--show-source-loc option in llvm-mc to map generated instruction outputs
back to their original lines. Line comments corresponding to MacroLoc
are automatically filtered out during test generation so they do not
clutter generated checks.

We also add a combined test case covering both ifdefs, macros, and .include
directives to maintain robust automated test coverage.


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


5 Files Affected:

- (added) 
llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/assembler_directives.s
 (+21) 
- (added) 
llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/assembler_directives.s.expected
 (+26) 
- (added) 
llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/include_file.inc 
(+1) 
- (added) 
llvm/test/tools/UpdateTestChecks/update_mc_test_checks/assembler-directives.test
 (+8) 
- (modified) llvm/utils/update_mc_test_checks.py (+116-67) 


``````````diff
diff --git 
a/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/assembler_directives.s
 
b/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/assembler_directives.s
new file mode 100644
index 0000000000000..b28a9e8c26a68
--- /dev/null
+++ 
b/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/assembler_directives.s
@@ -0,0 +1,21 @@
+// RUN: llvm-mc -triple=riscv32 -I %S %s | FileCheck 
--check-prefixes=CHECK,CHECK-32 %s
+// RUN: llvm-mc -triple=riscv64 -I %S --defsym=RV64=1 %s | FileCheck 
--check-prefixes=CHECK,CHECK-64 %s
+
+/// Check that instructions inside .ifdef/.else are correctly checked with 
their respective prefixes
+.ifdef RV64
+ld a0, 0(a1)
+.else
+lw a0, 0(a1)
+.endif
+
+/// The macro definition itself should not get check lines
+.macro load_reg reg, addr
+  lw \reg, 0(\addr)
+  sw \reg, 0(\addr)
+.endm
+
+/// Macro instantiations should get check lines
+load_reg a0, a1
+
+/// We should not add check lines for instructions originating from .include 
files
+.include "include_file.inc"
diff --git 
a/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/assembler_directives.s.expected
 
b/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/assembler_directives.s.expected
new file mode 100644
index 0000000000000..4710a36db0989
--- /dev/null
+++ 
b/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/assembler_directives.s.expected
@@ -0,0 +1,26 @@
+// NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py
+// RUN: llvm-mc -triple=riscv32 -I %S %s | FileCheck 
--check-prefixes=CHECK,CHECK-32 %s
+// RUN: llvm-mc -triple=riscv64 -I %S --defsym=RV64=1 %s | FileCheck 
--check-prefixes=CHECK,CHECK-64 %s
+
+/// Check that instructions inside .ifdef/.else are correctly checked with 
their respective prefixes
+.ifdef RV64
+ld a0, 0(a1)
+// CHECK-64: ld        a0, 0(a1)
+.else
+lw a0, 0(a1)
+// CHECK-32: lw        a0, 0(a1)
+.endif
+
+/// The macro definition itself should not get check lines
+.macro load_reg reg, addr
+  lw \reg, 0(\addr)
+  sw \reg, 0(\addr)
+.endm
+
+/// Macro instantiations should get check lines
+load_reg a0, a1
+// CHECK: lw   a0, 0(a1)
+// CHECK-NEXT: sw      a0, 0(a1)
+
+/// We should not add check lines for instructions originating from .include 
files
+.include "include_file.inc"
diff --git 
a/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/include_file.inc
 
b/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/include_file.inc
new file mode 100644
index 0000000000000..155c9b5f584d8
--- /dev/null
+++ 
b/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/Inputs/include_file.inc
@@ -0,0 +1 @@
+add a0, a0, a1
diff --git 
a/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/assembler-directives.test
 
b/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/assembler-directives.test
new file mode 100644
index 0000000000000..3d60cdb9b8925
--- /dev/null
+++ 
b/llvm/test/tools/UpdateTestChecks/update_mc_test_checks/assembler-directives.test
@@ -0,0 +1,8 @@
+# REQUIRES: riscv-registered-target
+## Check that .ifdef and macros are handled correctly
+
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: cp -f %S/Inputs/assembler_directives.s %t/assembler_directives.s
+# RUN: cp -f %S/Inputs/include_file.inc %t/include_file.inc
+# RUN: %update_mc_test_checks %t/assembler_directives.s
+# RUN: diff -u %S/Inputs/assembler_directives.s.expected 
%t/assembler_directives.s
diff --git a/llvm/utils/update_mc_test_checks.py 
b/llvm/utils/update_mc_test_checks.py
index a109fba5fc075..e7ff701efec51 100755
--- a/llvm/utils/update_mc_test_checks.py
+++ b/llvm/utils/update_mc_test_checks.py
@@ -8,6 +8,7 @@
 from sys import stderr
 from traceback import print_exc
 import argparse
+import collections
 import functools
 import os  # Used to advertise this file's name ("autogenerated_note").
 import subprocess
@@ -21,7 +22,7 @@
 ]
 ERROR_RE = re.compile(r":\d+: (warning|error): .*")
 ERROR_CHECK_RE = re.compile(r"# COM: .*")
-OUTPUT_SKIPPED_RE = re.compile(r"(.text)")
+OUTPUT_SKIPPED_RE = re.compile(r"(\.text|^\s*[a-zA-Z0-9_]+\s*=)")
 COMMENT = {"asm": "//", "dasm": "#"}
 
 SUBSTITUTIONS = [
@@ -34,18 +35,24 @@ def __init__(self, test_info, line_no, msg):
         super().__init__(f"{test_info.path}:{line_no}: {msg}")
 
 
-def invoke_tool(exe, check_rc, cmd_args, testline, verbose=False):
-    substs = SUBSTITUTIONS + [(t, exe) for t in mc_LIKE_TOOLS]
-    args = [common.applySubstitutions(cmd, substs) for cmd in 
cmd_args.split("|")]
+def invoke_tool(exe, check_rc, cmd_args, full_input, verbose=False, 
sourcepath=None):
+    substitutions = (
+        common.getSubstitutions(sourcepath)
+        + SUBSTITUTIONS
+        + [(t, exe) for t in mc_LIKE_TOOLS]
+    )
+    args = [
+        common.applySubstitutions(cmd, substitutions) for cmd in 
cmd_args.split("|")
+    ]
 
-    testline = testline.replace('"', '\\"')
-    cmd = 'echo "' + testline + '" | ' + exe + " " + " | ".join(args)
+    cmd = exe + " " + " | ".join(args)
     if verbose:
         print("Command: ", cmd)
 
     out = subprocess.run(
         cmd,
         shell=True,
+        input=full_input.encode(),
         check=check_rc,
         stdout=subprocess.PIPE,
         stderr=subprocess.DEVNULL,
@@ -55,19 +62,6 @@ def invoke_tool(exe, check_rc, cmd_args, testline, 
verbose=False):
     return out.decode().replace("\r\n", "\n")
 
 
-# create tests line-by-line, here we just filter out the check lines and 
comments
-# and treat all others as tests
-def isTestLine(input_line, mc_mode):
-    line = input_line.strip()
-    # Skip empty and comment lines
-    if not line or line.startswith(COMMENT[mc_mode]):
-        return False
-    # skip any CHECK lines.
-    elif common.CHECK_RE.match(input_line):
-        return False
-    return True
-
-
 def isRunLine(l):
     return common.RUN_LINE_RE.match(l)
 
@@ -108,7 +102,10 @@ def should_add_line_to_output(input_line, prefix_set, 
mc_mode):
         return False
     else:
         return common.should_add_line_to_output(
-            input_line, prefix_set, comment_marker=COMMENT[mc_mode]
+            input_line,
+            prefix_set,
+            comment_marker=COMMENT[mc_mode],
+            skip_global_checks=True,
         )
 
 
@@ -262,21 +259,26 @@ def update_test(ti: common.TestInfo):
             )
         )
 
-    # find all test line from input
-    testlines = [l for l in ti.input_lines if isTestLine(l, mc_mode)]
-    # remove duplicated lines to save running time
-    testlines = list(dict.fromkeys(testlines))
-    common.debug("Valid test line found: ", len(testlines))
-
-    # Where instruction templates are specified, use them instead.
-    use_asm_templates = False
+    # Where instruction templates are specified, expand them in-place in 
ti.input_lines.
     if mc_mode == "asm":
         tokens = parse_token_defs(ti)
         if "INSTS" in tokens:
             testlines = list(expand_insts(tokens))
-            use_asm_templates = True
-
-    raw_output = []
+            # Keep only leading comments and empty lines (the template 
definitions)
+            template_comments = []
+            for line in ti.input_lines:
+                if not line or line.startswith(COMMENT[mc_mode]):
+                    template_comments.append(line)
+                else:
+                    break
+            while template_comments and not template_comments[-1]:
+                template_comments.pop()
+            # Append the expanded instructions
+            ti.input_lines = template_comments
+            for inst in testlines:
+                ti.input_lines.extend(["", inst])
+
+    all_runs_line_outputs = []
     raw_prefixes = []
     for (
         prefixes,
@@ -295,22 +297,80 @@ def update_test(ti: common.TestInfo):
         if not triple:
             triple = common.get_triple_from_march(march_in_cmd)
 
-        raw_output.append([])
-        for line in testlines:
-            # get output for each testline
-            out = invoke_tool(
-                ti.args.llvm_mc_binary or mc_tool,
-                check_rc,
-                mc_args,
+        full_input = "\n".join(ti.input_lines)
+
+        if "--show-source-loc" not in mc_args:
+            mc_args += " --show-source-loc"
+
+        full_out = invoke_tool(
+            ti.args.llvm_mc_binary or mc_tool,
+            check_rc,
+            mc_args,
+            full_input,
+            verbose=ti.args.verbose,
+            sourcepath=ti.path,
+        )
+        line_outputs = collections.defaultdict(list)
+        pending_lines = []
+        ignore_count = 0
+        discard_pending = False
+        for line in full_out.splitlines():
+            if ignore_count > 0:
+                ignore_count -= 1
+                continue
+            m_loc = re.search(
+                
r"(?:#|//|;)\s*<(SourceLoc|MacroLoc|IncludeLoc):\s*([^:]+):(\d+):\d+>",
                 line,
-                verbose=ti.args.verbose,
             )
-            raw_output[-1].append(out)
+            if m_loc:
+                loc_type = m_loc.group(1)
+                filename = m_loc.group(2)
+                line_num = int(m_loc.group(3))
+
+                if filename != "<stdin>":
+                    discard_pending = True
+
+                if discard_pending:
+                    pending_lines = []
+                elif loc_type in ("SourceLoc", "IncludeLoc") and filename == 
"<stdin>":
+                    line_outputs[line_num].extend(pending_lines)
+                    pending_lines = []
+                continue
 
-        common.debug("Collect raw tool lines:", str(len(raw_output[-1])))
+            m_err = re.match(r"<stdin>:(\d+):\d+: (?:warning|error):", line)
+            if m_err:
+                err_line_num = int(m_err.group(1))
+                line_outputs[err_line_num].append(line)
+                ignore_count = 2
+                discard_pending = False
+            else:
+                if discard_pending:
+                    discard_pending = False
+                pending_lines.append(line)
 
+        all_runs_line_outputs.append(line_outputs)
         raw_prefixes.append(prefixes)
 
+    # Collect the union of all line numbers across all runs
+    all_line_nums = sorted(
+        list(
+            set().union(
+                *(line_outputs.keys() for line_outputs in 
all_runs_line_outputs)
+            )
+        )
+    )
+    common.debug("Valid test line found: ", len(all_line_nums))
+
+    # Reconstruct raw_output for each run based on all_line_nums
+    raw_output = []
+    for line_outputs in all_runs_line_outputs:
+        run_outputs = []
+        for line_num in all_line_nums:
+            out_lines = line_outputs.get(line_num, [])
+            run_outputs.append("\n".join(out_lines))
+        raw_output.append(run_outputs)
+        common.debug("Collect raw tool lines:", str(len(raw_output[-1])))
+
     generated_prefixes = {}
     sort_keys = {}
     used_prefixes = set()
@@ -318,7 +378,9 @@ def update_test(ti: common.TestInfo):
     common.debug("Rewriting FileCheck prefixes:", str(prefix_set))
     ginfo = common.make_asm_generalizer(version=1)
 
-    for test_id, input_line in enumerate(testlines):
+    num_tests = len(all_line_nums)
+    for test_id, line_num in enumerate(all_line_nums):
+        input_line = line_num
         # a {prefix : output, [runid] } dict
         # insert output to a prefix-key dict, and do a max sorting
         # to select the most-used prefix which share the same output string
@@ -369,6 +431,7 @@ def update_test(ti: common.TestInfo):
                 if o is not None and "encoding:" in o
             ]
             sort_keys[input_line] = min(instr_outs) if instr_outs else 
input_line
+            sort_keys[ti.input_lines[input_line - 1]] = sort_keys[input_line]
 
         # Generate check lines in alphabetical order.
         check_lines = []
@@ -393,31 +456,16 @@ def update_test(ti: common.TestInfo):
 
     # write output
     output_lines = []
-    if use_asm_templates:
-        # Keep all leading comments and empty lines.
-        for input_info in ti.iterlines(output_lines):
-            input_line = input_info.line
-            if not input_line or input_line.startswith(COMMENT[mc_mode]):
-                output_lines.append(input_line)
-                continue
-            break
-
-        # Remove tail empty lines.
-        while not output_lines[-1]:
-            del output_lines[-1]
-
-        # Emit test and check lines.
-        for input_line in testlines:
-            output_lines.extend(["", input_line, 
generated_prefixes[input_line]])
-    else:
-        for input_info in ti.iterlines(output_lines):
-            input_line = input_info.line
-            if input_line in testlines:
-                output_lines.append(input_line)
-                output_lines.append(generated_prefixes[input_line])
+    for input_info in ti.iterlines(output_lines):
+        input_line = input_info.line
+        line_num = input_info.line_number + 1
+        if line_num in all_line_nums:
+            output_lines.append(input_line)
+            if generated_prefixes.get(line_num):
+                output_lines.append(generated_prefixes[line_num])
 
-            elif should_add_line_to_output(input_line, prefix_set, mc_mode):
-                output_lines.append(input_line)
+        elif should_add_line_to_output(input_line, prefix_set, mc_mode):
+            output_lines.append(input_line)
 
     if ti.args.unique or ti.args.sort:
         # split with double newlines
@@ -430,7 +478,8 @@ def update_test(ti: common.TestInfo):
             for l in lines:
                 # if contains multiple lines, use
                 # the first testline or runline as key
-                if isTestLine(l, mc_mode):
+                l_strip = l.strip()
+                if l_strip and not l_strip.startswith(ti.comment_prefix):
                     test_dic[unit] = l
                     break
                 if isRunLine(l):

``````````

</details>


https://github.com/llvm/llvm-project/pull/199305
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to