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
