update_mir_test_checks: Better handling of common prefixes
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Tue, 24 May 2022 23:57:14 +0000 (01:57 +0200)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Wed, 1 Jun 2022 20:53:32 +0000 (15:53 -0500)
Support the pattern where a test file uses multiple prefixes per run line:
one prefix that is unique to the run line, and additional prefixes that are
common with other run lines.

Decide on a per-function basis which prefix(es) to emit, based on which run
lines have the same output.

Move the renaming of vregs earlier, so that we can compare the output as it
would actually be printed in check lines.

Differential Revision: https://reviews.llvm.org/D126411

llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-multiple-prefixes.ll [new file with mode: 0644]
llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-multiple-prefixes.ll.expected [new file with mode: 0644]
llvm/test/tools/UpdateTestChecks/update_mir_test_checks/x86-multiple-prefixes.test [new file with mode: 0644]
llvm/utils/update_mir_test_checks.py

diff --git a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-multiple-prefixes.ll b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-multiple-prefixes.ll
new file mode 100644 (file)
index 0000000..2b5e9fb
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: llc < %s -mtriple=x86_64-apple-darwin -stop-after=finalize-isel | FileCheck --check-prefixes=CHECK,NOAVX %s
+; RUN: llc < %s -mtriple=x86_64-apple-darwin -stop-after=finalize-isel -mattr=avx | FileCheck --check-prefixes=CHECK,AVX %s
+
+@x = common global float zeroinitializer, align 4
+@z = common global <4 x float> zeroinitializer, align 16
+
+define void @zero32() nounwind ssp {
+  store float zeroinitializer, ptr @x, align 4
+  ret void
+}
+
+define void @zero128() nounwind ssp {
+  store <4 x float> zeroinitializer, ptr @z, align 16
+  ret void
+}
+
diff --git a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-multiple-prefixes.ll.expected b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/Inputs/x86-multiple-prefixes.ll.expected
new file mode 100644 (file)
index 0000000..1f51a86
--- /dev/null
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-apple-darwin -stop-after=finalize-isel | FileCheck --check-prefixes=CHECK,NOAVX %s
+; RUN: llc < %s -mtriple=x86_64-apple-darwin -stop-after=finalize-isel -mattr=avx | FileCheck --check-prefixes=CHECK,AVX %s
+
+@x = common global float zeroinitializer, align 4
+@z = common global <4 x float> zeroinitializer, align 16
+
+define void @zero32() nounwind ssp {
+  ; CHECK-LABEL: name: zero32
+  ; CHECK: bb.0 (%ir-block.0):
+  ; CHECK-NEXT:   [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @x, $noreg :: (load (s64) from got)
+  ; CHECK-NEXT:   MOV32mi killed [[MOV64rm]], 1, $noreg, 0, $noreg, 0 :: (store (s32) into @x)
+  ; CHECK-NEXT:   RET 0
+  store float zeroinitializer, ptr @x, align 4
+  ret void
+}
+
+define void @zero128() nounwind ssp {
+  ; NOAVX-LABEL: name: zero128
+  ; NOAVX: bb.0 (%ir-block.0):
+  ; NOAVX-NEXT:   [[V_SET0_:%[0-9]+]]:vr128 = V_SET0
+  ; NOAVX-NEXT:   [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @z, $noreg :: (load (s64) from got, align 16)
+  ; NOAVX-NEXT:   MOVAPSmr killed [[MOV64rm]], 1, $noreg, 0, $noreg, killed [[V_SET0_]] :: (store (s128) into @z)
+  ; NOAVX-NEXT:   RET 0
+  ; AVX-LABEL: name: zero128
+  ; AVX: bb.0 (%ir-block.0):
+  ; AVX-NEXT:   [[V_SET0_:%[0-9]+]]:vr128 = V_SET0
+  ; AVX-NEXT:   [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @z, $noreg :: (load (s64) from got, align 16)
+  ; AVX-NEXT:   VMOVAPSmr killed [[MOV64rm]], 1, $noreg, 0, $noreg, killed [[V_SET0_]] :: (store (s128) into @z)
+  ; AVX-NEXT:   RET 0
+  store <4 x float> zeroinitializer, ptr @z, align 16
+  ret void
+}
+
diff --git a/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/x86-multiple-prefixes.test b/llvm/test/tools/UpdateTestChecks/update_mir_test_checks/x86-multiple-prefixes.test
new file mode 100644 (file)
index 0000000..58eba12
--- /dev/null
@@ -0,0 +1,5 @@
+# REQUIRES: x86-registered-target
+## Check that update_mir_test_checks handles multiple check prefixes
+
+# RUN: cp -f %S/Inputs/x86-multiple-prefixes.ll %t.ll && %update_mir_test_checks %t.ll
+# RUN: diff -u %S/Inputs/x86-multiple-prefixes.ll.expected %t.ll
index d50ab41..adf8e49 100755 (executable)
@@ -139,13 +139,12 @@ def build_run_list(test, run_lines, verbose=False):
 
         run_list.append(Run(check_prefixes, cmd_args, triple))
 
-    # Remove any common prefixes. We'll just leave those entirely alone.
-    common_prefixes = set([prefix for prefix in all_prefixes
-                           if all_prefixes.count(prefix) > 1])
+    # Sort prefixes that are shared between run lines before unshared prefixes.
+    # This causes us to prefer printing shared prefixes.
     for run in run_list:
-        run.prefixes = [p for p in run.prefixes if p not in common_prefixes]
+        run.prefixes.sort(key=lambda prefix: -all_prefixes.count(prefix))
 
-    return run_list, common_prefixes
+    return run_list
 
 
 def find_functions_with_one_bb(lines, verbose=False):
@@ -176,11 +175,30 @@ def build_function_body_dictionary(test, raw_tool_output, triple, prefixes,
             log('Processing function: {}'.format(func))
             for l in body.splitlines():
                 log('  {}'.format(l))
+
+        # Vreg mangling
+        mangled = []
+        vreg_map = {}
+        for func_line in body.splitlines(keepends=True):
+            m = VREG_DEF_RE.match(func_line)
+            if m:
+                for vreg in VREG_RE.finditer(m.group('vregs')):
+                    name = mangle_vreg(m.group('opcode'), vreg_map.values())
+                    vreg_map[vreg.group(1)] = name
+                    func_line = func_line.replace(
+                        vreg.group(1), '[[{}:%[0-9]+]]'.format(name), 1)
+            for number, name in vreg_map.items():
+                func_line = re.sub(r'{}\b'.format(number), '[[{}]]'.format(name),
+                                func_line)
+            mangled.append(func_line)
+        body = ''.join(mangled)
+
         for prefix in prefixes:
-            if func in func_dict[prefix] and func_dict[prefix][func] != body:
-                common.warn('Found conflicting asm for prefix: {}'.format(prefix),
-                     test_file=test)
-            func_dict[prefix][func] = body
+            if func in func_dict[prefix]:
+                if func_dict[prefix][func] != body:
+                    func_dict[prefix][func] = None
+            else:
+                func_dict[prefix][func] = body
 
 
 def add_checks_for_function(test, output_lines, run_list, func_dict, func_name,
@@ -189,7 +207,7 @@ def add_checks_for_function(test, output_lines, run_list, func_dict, func_name,
     for run in run_list:
         for prefix in run.prefixes:
             if prefix in printed_prefixes:
-                continue
+                break
             if not func_dict[prefix][func_name]:
                 continue
             # if printed_prefixes:
@@ -200,6 +218,10 @@ def add_checks_for_function(test, output_lines, run_list, func_dict, func_name,
             add_check_lines(test, output_lines, prefix, func_name, single_bb,
                             func_dict[prefix][func_name].splitlines())
             break
+        else:
+            common.warn(
+                'Found conflicting asm for function: {}'.format(func_name),
+                test_file=test)
     return output_lines
 
 
@@ -222,22 +244,11 @@ def add_check_lines(test, output_lines, prefix, func_name, single_bb,
     output_lines.append('{}-LABEL: name: {}'.format(check, func_name))
     first_check = True
 
-    vreg_map = {}
     for func_line in func_body:
         if not func_line.strip():
             # The mir printer prints leading whitespace so we can't use CHECK-EMPTY:
             output_lines.append(check + '-NEXT: {{' + func_line + '$}}')
             continue
-        m = VREG_DEF_RE.match(func_line)
-        if m:
-            for vreg in VREG_RE.finditer(m.group('vregs')):
-                name = mangle_vreg(m.group('opcode'), vreg_map.values())
-                vreg_map[vreg.group(1)] = name
-                func_line = func_line.replace(
-                    vreg.group(1), '[[{}:%[0-9]+]]'.format(name), 1)
-        for number, name in vreg_map.items():
-            func_line = re.sub(r'{}\b'.format(number), '[[{}]]'.format(name),
-                               func_line)
         filecheck_directive = check if first_check else check + '-NEXT'
         first_check = False
         check_line = '{}: {}'.format(filecheck_directive, func_line[indent:]).rstrip()
@@ -302,7 +313,7 @@ def update_test_file(args, test):
 
     triple_in_ir = find_triple_in_ir(input_lines, args.verbose)
     run_lines = common.find_run_lines(test, input_lines)
-    run_list, common_prefixes = build_run_list(test, run_lines, args.verbose)
+    run_list = build_run_list(test, run_lines, args.verbose)
 
     simple_functions = find_functions_with_one_bb(input_lines, args.verbose)
 
@@ -328,12 +339,6 @@ def update_test_file(args, test):
     prefix_set = set([prefix for run in run_list for prefix in run.prefixes])
     log('Rewriting FileCheck prefixes: {}'.format(prefix_set), args.verbose)
 
-    if args.remove_common_prefixes:
-        prefix_set.update(common_prefixes)
-    elif common_prefixes:
-        common.warn('Ignoring common prefixes: {}'.format(common_prefixes),
-             test_file=test)
-
     comment_char = '#' if test.endswith('.mir') else ';'
     autogenerated_note = ('{} NOTE: Assertions have been autogenerated by '
                           'utils/{}'.format(comment_char, script_name))
@@ -420,9 +425,6 @@ def main():
         description=__doc__, formatter_class=argparse.RawTextHelpFormatter)
     parser.add_argument('--llc-binary', dest='llc', default='llc', type=LLC,
                         help='The "llc" binary to generate the test case with')
-    parser.add_argument('--remove-common-prefixes', action='store_true',
-                        help='Remove existing check lines whose prefixes are '
-                             'shared between multiple commands')
     parser.add_argument('tests', nargs='+')
     args = common.parse_commandline_args(parser)