diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_no_merge_comments.ll.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_no_merge_comments.ll.expected --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_no_merge_comments.ll.expected +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_no_merge_comments.ll.expected @@ -28,3 +28,7 @@ %sub = sub i32 %mul, %add ret i32 %sub } + + +; NOTE: These prefixes are unused: +; GCN: {{.*}} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/redundant-and-unmatching-prefixes.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/redundant-and-unmatching-prefixes.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/redundant-and-unmatching-prefixes.ll @@ -0,0 +1,18 @@ +; RUN: llc < %s -mtriple=i686-unknown-linux-gnu -mattr=+sse2 | FileCheck %s --check-prefixes=A,B,REDUNDANT +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefixes=C,A,UNUSED + +; prefix 'A' has conflicting outputs, while the REDUNDANT and UNUSED ones are +; unused +declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>) + +define <2 x i64> @function_1() { +entry: + %r = call <2 x i64> @llvm.bswap.v2i64(<2 x i64> ) + ret <2 x i64> %r +} + +define <2 x i64> @function_2() { +entry: + %r = call <2 x i64> @llvm.bswap.v2i64(<2 x i64> ) + ret <2 x i64> %r +} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/common-label-different-bodies.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/common-label-different-bodies.test --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/common-label-different-bodies.test +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/common-label-different-bodies.test @@ -6,9 +6,12 @@ # RUN: %update_llc_test_checks %t-1.ll # RUN: %update_llc_test_checks %t-2.ll # RUN: %update_llc_test_checks %t-3.ll -# RUN: FileCheck --input-file=%t-1.ll %s +# RUN: FileCheck --input-file=%t-1.ll %s --check-prefixes=CHECK,CHECK-UNUSED # RUN: FileCheck --input-file=%t-2.ll %s # RUN: FileCheck --input-file=%t-3.ll %s # CHECK: B-LABEL: fold_v2i64 -# CHECK-NOT: A-LABEL: fold_v2i64 \ No newline at end of file +# CHECK-NOT: A-LABEL: fold_v2i64 +# CHECK: NOTE: These prefixes are unused: +# CHECK-NEXT: A: +# CHECK-UNUSED-NEXT: UNUSED: \ No newline at end of file diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/prefix-never-matches.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/prefix-never-matches.test --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/prefix-never-matches.test +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/prefix-never-matches.test @@ -1,8 +1,8 @@ # REQUIRES: x86-registered-target # RUN: cp -f %S/Inputs/prefix-never-matches.ll %t.ll -# RUN: %update_llc_test_checks %t.ll 2>&1 | FileCheck %s +# RUN: %update_llc_test_checks --no-generate-body-for-unused-prefixes %t.ll 2>&1 | FileCheck %s # RUN: FileCheck --input-file=%t.ll %s --check-prefix=OUTPUT # CHECK: WARNING: Prefix A had conflicting output # OUTPUT-NOT: A: \ No newline at end of file diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/redundant-and-unmatched-prefixes.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/redundant-and-unmatched-prefixes.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/redundant-and-unmatched-prefixes.test @@ -0,0 +1,18 @@ +# REQUIRES: x86-registered-target + +# RUN: cp -f %S/Inputs/redundant-and-unmatching-prefixes.ll %t-1.ll +# RUN: %update_llc_test_checks %t-1.ll +# RUN: FileCheck --input-file=%t-1.ll %s + +# CHECK: B-LABEL: function_1: +# CHECK-NOT: A-LABEL: function_1 +# CHECK-NOT: REDUNDANT-LABEL: function_1: + +# CHECK: B-LABEL: function_2: +# CHECK-NOT: A-LABEL: function_2: +# CHECK-NOT: UNUSED-LABEL: function_2: + +# CHECK: NOTE: These prefixes are unused: +# CHECK-NEXT: A: +# CHECK-NEXT: REDUNDANT: +# CHECK-NEXT: UNUSED: \ No newline at end of file diff --git a/llvm/utils/UpdateTestChecks/asm.py b/llvm/utils/UpdateTestChecks/asm.py --- a/llvm/utils/UpdateTestChecks/asm.py +++ b/llvm/utils/UpdateTestChecks/asm.py @@ -486,6 +486,6 @@ # Label format is based on ASM string. check_label_format = '{} %s-LABEL: %s%s%s'.format(comment_marker) global_vars_seen_dict = {} - common.add_checks(output_lines, comment_marker, prefix_list, func_dict, + return common.add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, True, False, global_vars_seen_dict, is_filtered = is_filtered) diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py --- a/llvm/utils/UpdateTestChecks/common.py +++ b/llvm/utils/UpdateTestChecks/common.py @@ -9,6 +9,8 @@ import sys import shlex +from typing import List + ##### Common utilities for update_*test_checks.py @@ -128,6 +130,11 @@ help='List of regular expressions that a global value declaration must match to generate a check (has no effect if checking globals is not enabled)') parser.add_argument('--global-hex-value-regex', nargs='+', default=[], help='List of regular expressions such that, for matching global value declarations, literal integer values should be encoded in hex in the associated FileCheck directives') + parser.add_argument('--generate-body-for-unused-prefixes', + action=argparse.BooleanOptionalAction, + dest='gen_unused_prefix_body', + default=True, + help='Generate a function body that always matches for unused prefixes. This is useful when unused prefixes are desired, and it avoids needing to annotate each FileCheck as allowing them.') args = parser.parse_args() global _verbose, _global_value_regex, _global_hex_value_regex _verbose = args.verbose @@ -187,6 +194,23 @@ continue yield line_info + def get_checks_for_unused_prefixes(self, run_list, used_prefixes: List[str]) -> List[str]: + unused_prefixes = set( + [prefix for sublist in run_list for prefix in sublist[0]]).difference(set(used_prefixes)) + + ret = [] + if not unused_prefixes: + return ret + ret.append('\n\n{comment} NOTE: These prefixes are unused:'.format( + comment=self.comment_prefix)) + for unused in sorted(unused_prefixes): + ret.append('{comment} {prefix}: {match_everything}'.format( + comment=self.comment_prefix, + prefix=unused, + match_everything=r"""{{.*}}""" + )) + return ret + def itertests(test_patterns, parser, script_name, comment_prefix=None, argparse_callback=None): for pattern in test_patterns: # On Windows we must expand the patterns ourselves. @@ -470,7 +494,7 @@ self._global_var_dict.update({prefix:dict()}) def finish_and_get_func_dict(self): - for prefix in self._get_failed_prefixes(): + for prefix in self.get_failed_prefixes(): warn('Prefix %s had conflicting output from different RUN lines for all functions in test %s' % (prefix,self._path,)) return self._func_dict @@ -576,11 +600,10 @@ scrubbed_body, scrubbed_extra, args_and_sig, attrs, func_name_separator) self._func_order[prefix].append(func) - def _get_failed_prefixes(self): + def get_failed_prefixes(self): # This returns the list of those prefixes that failed to match any function, # because there were conflicting bodies produced by different RUN lines, in - # all instances of the prefix. Effectively, this prefix is unused and should - # be removed. + # all instances of the prefix. for prefix in self._func_dict: if (self._func_dict[prefix] and (not [fct for fct in self._func_dict[prefix] @@ -922,6 +945,7 @@ if key not in global_vars_seen_before: global_vars_seen_dict[checkprefix][key] = global_vars_seen[key] break + return printed_prefixes def add_ir_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, preserve_names, function_sig, @@ -929,16 +953,16 @@ # Label format is based on IR string. function_def_regex = 'define {{[^@]+}}' if function_sig else '' check_label_format = '{} %s-LABEL: {}@%s%s%s'.format(comment_marker, function_def_regex) - add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, - check_label_format, False, preserve_names, global_vars_seen_dict, - is_filtered) + return add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, + check_label_format, False, preserve_names, global_vars_seen_dict, + is_filtered) def add_analyze_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, is_filtered): check_label_format = '{} %s-LABEL: \'%s%s%s\''.format(comment_marker) global_vars_seen_dict = {} - add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, - check_label_format, False, True, global_vars_seen_dict, - is_filtered) + return add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, + check_label_format, False, True, global_vars_seen_dict, + is_filtered) def build_global_values_dictionary(glob_val_dict, raw_tool_output, prefixes): for nameless_value in nameless_values: @@ -1137,6 +1161,7 @@ def add_checks_at_end(output_lines, prefix_list, func_order, comment_string, check_generator): added = set() + generated_prefixes = [] for prefix in prefix_list: prefixes = prefix[0] tool_args = prefix[1] @@ -1160,6 +1185,7 @@ # single prefix before moving on to the next prefix. So checks # are ordered by prefix instead of by function as in "normal" # mode. - check_generator(output_lines, + generated_prefixes.extend(check_generator(output_lines, [([prefix], tool_args)], - func) + func)) + return generated_prefixes diff --git a/llvm/utils/UpdateTestChecks/isel.py b/llvm/utils/UpdateTestChecks/isel.py --- a/llvm/utils/UpdateTestChecks/isel.py +++ b/llvm/utils/UpdateTestChecks/isel.py @@ -52,6 +52,6 @@ # Label format is based on iSel string. check_label_format = '{} %s-LABEL: %s%s%s'.format(comment_marker) global_vars_seen_dict = {} - common.add_checks(output_lines, comment_marker, prefix_list, func_dict, + return common.add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, True, False, global_vars_seen_dict, is_filtered = is_filtered) diff --git a/llvm/utils/update_llc_test_checks.py b/llvm/utils/update_llc_test_checks.py --- a/llvm/utils/update_llc_test_checks.py +++ b/llvm/utils/update_llc_test_checks.py @@ -152,6 +152,7 @@ '--include-generated-funcs', True) + generated_prefixes = [] if include_generated_funcs: # Generate the appropriate checks for each function. We need to emit # these in the order according to the generated output so that CHECK-LABEL @@ -163,13 +164,14 @@ common.dump_input_lines(output_lines, ti, prefix_set, ';') # Now generate all the checks. - common.add_checks_at_end(output_lines, run_list, builder.func_order(), - check_indent + ';', - lambda my_output_lines, prefixes, func: - output_type.add_checks(my_output_lines, - check_indent + ';', - prefixes, func_dict, func, - is_filtered=builder.is_filtered())) + generated_prefixes = common.add_checks_at_end( + output_lines, run_list, builder.func_order(), + check_indent + ';', + lambda my_output_lines, prefixes, func: + output_type.add_checks(my_output_lines, + check_indent + ';', + prefixes, func_dict, func, + is_filtered=builder.is_filtered())) else: for input_info in ti.iterlines(output_lines): input_line = input_info.line @@ -184,9 +186,10 @@ continue # Print out the various check lines here. - output_type.add_checks(output_lines, check_indent + ';', run_list, - func_dict, func_name, - is_filtered=builder.is_filtered()) + generated_prefixes.extend( + output_type.add_checks(output_lines, check_indent + ';', run_list, + func_dict, func_name, + is_filtered=builder.is_filtered())) is_in_function_start = False if is_in_function: @@ -211,8 +214,11 @@ continue is_in_function = is_in_function_start = True + if ti.args.gen_unused_prefix_body: + output_lines.extend(ti.get_checks_for_unused_prefixes( + run_list, generated_prefixes)) + common.debug('Writing %d lines to %s...' % (len(output_lines), ti.path)) - with open(ti.path, 'wb') as f: f.writelines(['{}\n'.format(l).encode('utf-8') for l in output_lines])