aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/UpdateTestChecks/common.py
diff options
context:
space:
mode:
authorMircea Trofin <mtrofin@google.com>2022-04-22 12:49:15 -0700
committerMircea Trofin <mtrofin@google.com>2022-05-26 10:23:10 -0700
commitf15c60218d5c88c9f32942bce119e7ac25cb6d73 (patch)
tree108a1cce28d7ae63b5399ba45ba5c9153896000a /llvm/utils/UpdateTestChecks/common.py
parent6af5f5697c8560e09c305d5cfd74a7bda0d4d311 (diff)
downloadllvm-f15c60218d5c88c9f32942bce119e7ac25cb6d73.zip
llvm-f15c60218d5c88c9f32942bce119e7ac25cb6d73.tar.gz
llvm-f15c60218d5c88c9f32942bce119e7ac25cb6d73.tar.bz2
[UpdateTestChecks] Auto-generate stub bodies for unused prefixes
This is scoped to autogenerated tests. The goal is to support having each RUN line specify a list of check-prefixes where one can specify potentially redundant prefixes. For example, for X86, if one specified prefixes for both AVX1 and AVX2, and the codegen happened to match today, one of the prefixes would be used and the onther one not. If the unused prefix were dropped, and later, codegen differences were introduced, one would have to go figure out where to add what prefix (paraphrasing https://lists.llvm.org/pipermail/llvm-dev/2021-February/148326.html) To avoid getting errors due to unused prefixes, whole directories can be opted out (as discussed on that thread), but that means that tests that aren't autogenerated in such directories could have undetected unused prefix bugs. This patch proposes an alternative that both avoids the above, dir-level optout, and supports the main autogen scenario discussed first. The autogen tool appends at the end of the test file the list of unused prefixes, together with a note explaining that is the case. Each prefix is set up to always pass. This way, unexpected unused prefixes are easily discoverable, and expected cases "just work". Differential Revision: https://reviews.llvm.org/D124306
Diffstat (limited to 'llvm/utils/UpdateTestChecks/common.py')
-rw-r--r--llvm/utils/UpdateTestChecks/common.py58
1 files changed, 45 insertions, 13 deletions
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index 90dd326..7ca546c 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -10,6 +10,8 @@ import subprocess
import sys
import shlex
+from typing import List
+
##### Common utilities for update_*test_checks.py
@@ -129,6 +131,11 @@ def parse_commandline_args(parser):
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
@@ -167,6 +174,7 @@ class TestInfo(object):
self.autogenerated_note_prefix = self.comment_prefix + ' ' + UTC_ADVERT
self.test_autogenerated_note = self.autogenerated_note_prefix + script_name
self.test_autogenerated_note += get_autogennote_suffix(parser, self.args)
+ self.test_unused_note = self.comment_prefix + self.comment_prefix + ' ' + UNUSED_NOTE
def ro_iterlines(self):
for line_num, input_line in enumerate(self.input_lines):
@@ -188,6 +196,22 @@ class TestInfo(object):
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(self.test_unused_note)
+ 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.
@@ -212,7 +236,12 @@ def itertests(test_patterns, parser, script_name, comment_prefix=None, argparse_
assert UTC_ADVERT not in first_line
warn("Skipping test which isn't autogenerated: " + test)
continue
- yield TestInfo(test, parser, script_name, input_lines, args, argv,
+ final_input_lines = []
+ for l in input_lines:
+ if UNUSED_NOTE in l:
+ break
+ final_input_lines.append(l)
+ yield TestInfo(test, parser, script_name, final_input_lines, args, argv,
comment_prefix, argparse_callback)
@@ -293,6 +322,7 @@ CHECK_RE = re.compile(r'^\s*(?://|[;#])\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL|-SAM
UTC_ARGS_KEY = 'UTC_ARGS:'
UTC_ARGS_CMD = re.compile(r'.*' + UTC_ARGS_KEY + '\s*(?P<cmd>.*)\s*$')
UTC_ADVERT = 'NOTE: Assertions have been autogenerated by '
+UNUSED_NOTE = 'NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:'
OPT_FUNCTION_RE = re.compile(
r'^(\s*;\s*Function\sAttrs:\s(?P<attrs>[\w\s]+?))?\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w.$-]+?)\s*'
@@ -471,7 +501,7 @@ class FunctionTestBuilder:
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
@@ -577,11 +607,10 @@ class FunctionTestBuilder:
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]
@@ -974,6 +1003,7 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
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,
@@ -981,16 +1011,16 @@ def add_ir_checks(output_lines, comment_marker, prefix_list, func_dict,
# 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 itertools.chain(ir_nameless_values, asm_nameless_values):
@@ -1189,6 +1219,7 @@ def dump_input_lines(output_lines, test_info, prefix_set, comment_string):
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]
@@ -1212,6 +1243,7 @@ def add_checks_at_end(output_lines, prefix_list, func_order,
# 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