From 3598b810029dee4abfd5545f02ec256d33f79e71 Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Thu, 10 Oct 2019 12:08:21 -0500 Subject: [PATCH] [Utils] Allow update_test_checks to check function information Summary: This adds a switch to the update_test_checks that triggers arguments and other function annotations, e.g., personality, to be present in the check line. If not set, the behavior should be the same as before. If arguments are recorded, their names are scrubbed from the IR to allow merging. This patch includes D68153. Reviewers: lebedev.ri, greened, spatel, xbolva00, RKSimon, mehdi_amini Subscribers: bollu, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D68819 --- llvm/utils/UpdateTestChecks/common.py | 57 ++++++++++++++++++++++++++------ llvm/utils/update_analyze_test_checks.py | 2 +- llvm/utils/update_mir_test_checks.py | 2 +- llvm/utils/update_test_checks.py | 5 ++- 4 files changed, 52 insertions(+), 14 deletions(-) diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py index b521e16..76b9d4e 100644 --- a/llvm/utils/UpdateTestChecks/common.py +++ b/llvm/utils/UpdateTestChecks/common.py @@ -48,11 +48,11 @@ def invoke_tool(exe, cmd_args, ir): RUN_LINE_RE = re.compile(r'^\s*[;#]\s*RUN:\s*(.*)$') CHECK_PREFIX_RE = re.compile(r'--?check-prefix(?:es)?[= ](\S+)') PREFIX_RE = re.compile('^[a-zA-Z0-9_-]+$') -CHECK_RE = re.compile(r'^\s*[;#]\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:') +CHECK_RE = re.compile(r'^\s*[;#]\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL|-SAME)?:') OPT_FUNCTION_RE = re.compile( - r'^\s*define\s+(?:internal\s+)?[^@]*@(?P[\w-]+?)\s*\(' - r'(\s+)?[^)]*[^{]*\{\n(?P.*?)^\}$', + r'^\s*define\s+(?:internal\s+)?[^@]*@(?P[\w-]+?)\s*' + r'(?P\((\)|(.*?[\w\.\-]+?)\))[^{]*)\{\n(?P.*?)^\}$', flags=(re.M | re.S)) ANALYZE_FUNCTION_RE = re.compile( @@ -102,18 +102,45 @@ def do_scrub(body, scrubber, scrubber_args, extra): # Build up a dictionary of all the function bodies. class function_body(object): - def __init__(self, string, extra): + def __init__(self, string, extra, args_and_sig): self.scrub = string self.extrascrub = extra + self.args_and_sig = args_and_sig + def is_same_except_arg_names(self, extrascrub, args_and_sig): + arg_names = set() + def drop_arg_names(match): + arg_names.add(match.group(2)) + return match.group(1) + match.group(3) + def repl_arg_names(match): + if match.group(2) in arg_names: + return match.group(1) + match.group(3) + return match.group(1) + match.group(2) + match.group(3) + ans0 = IR_VALUE_RE.sub(drop_arg_names, self.args_and_sig) + ans1 = IR_VALUE_RE.sub(drop_arg_names, args_and_sig) + if ans0 != ans1: + return False + es0 = IR_VALUE_RE.sub(repl_arg_names, self.extrascrub) + es1 = IR_VALUE_RE.sub(repl_arg_names, extrascrub) + es0 = SCRUB_IR_COMMENT_RE.sub(r'', es0) + es1 = SCRUB_IR_COMMENT_RE.sub(r'', es1) + return es0 == es1 + def __str__(self): return self.scrub -def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, verbose): +def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, verbose, record_args): for m in function_re.finditer(raw_tool_output): if not m: continue func = m.group('func') body = m.group('body') + # Determine if we print arguments, the opening brace, or nothing after the function name + if record_args and 'args_and_sig' in m.groupdict(): + args_and_sig = scrub_body(m.group('args_and_sig').strip()) + elif 'args_and_sig' in m.groupdict(): + args_and_sig = '(' + else: + args_and_sig = '' scrubbed_body = do_scrub(body, scrubber, scrubber_args, extra = False) scrubbed_extra = do_scrub(body, scrubber, scrubber_args, extra = True) if 'analysis' in m.groupdict(): @@ -128,9 +155,10 @@ def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_too for l in scrubbed_body.splitlines(): print(' ' + l, file=sys.stderr) for prefix in prefixes: - if func in func_dict[prefix] and str(func_dict[prefix][func]) != scrubbed_body: - if func_dict[prefix][func] and func_dict[prefix][func].extrascrub == scrubbed_extra: + if func in func_dict[prefix] and (str(func_dict[prefix][func]) != scrubbed_body or (func_dict[prefix][func] and func_dict[prefix][func].args_and_sig != args_and_sig)): + if func_dict[prefix][func] and func_dict[prefix][func].is_same_except_arg_names(scrubbed_extra, args_and_sig): func_dict[prefix][func].scrub = scrubbed_extra + func_dict[prefix][func].args_and_sig = args_and_sig continue else: if prefix == prefixes[-1]: @@ -139,7 +167,7 @@ def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_too func_dict[prefix][func] = None continue - func_dict[prefix][func] = function_body(scrubbed_body, scrubbed_extra) + func_dict[prefix][func] = function_body(scrubbed_body, scrubbed_extra, args_and_sig) ##### Generator of LLVM IR CHECK lines @@ -219,7 +247,13 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, output_lines.append(comment_marker) printed_prefixes.append(checkprefix) - output_lines.append(check_label_format % (checkprefix, func_name)) + args_and_sig = str(func_dict[checkprefix][func_name].args_and_sig) + args_and_sig = genericize_check_lines([args_and_sig], is_analyze)[0] + if '[[' in args_and_sig: + output_lines.append(check_label_format % (checkprefix, func_name, '')) + output_lines.append('%s %s-SAME: %s' % (comment_marker, checkprefix, args_and_sig)) + else: + output_lines.append(check_label_format % (checkprefix, func_name, args_and_sig)) func_body = str(func_dict[checkprefix][func_name]).splitlines() # For ASM output, just emit the check lines. @@ -270,12 +304,13 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, def add_ir_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, preserve_names): # Label format is based on IR string. - check_label_format = '{} %s-LABEL: @%s('.format(comment_marker) + function_def_regex = 'define {{[^@]+}}' + check_label_format = '{} %s-LABEL: {}@%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) def add_analyze_checks(output_lines, comment_marker, prefix_list, func_dict, func_name): - check_label_format = '{} %s-LABEL: \'%s\''.format(comment_marker) + check_label_format = '{} %s-LABEL: \'%s%s\''.format(comment_marker) add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, False, True) diff --git a/llvm/utils/update_analyze_test_checks.py b/llvm/utils/update_analyze_test_checks.py index db9be13..9708912 100755 --- a/llvm/utils/update_analyze_test_checks.py +++ b/llvm/utils/update_analyze_test_checks.py @@ -146,7 +146,7 @@ def main(): for raw_tool_output in re.split(r'Printing analysis ', raw_tool_outputs): common.build_function_body_dictionary( common.ANALYZE_FUNCTION_RE, common.scrub_body, [], - raw_tool_output, prefixes, func_dict, args.verbose) + raw_tool_output, prefixes, func_dict, args.verbose, False) is_in_function = False is_in_function_start = False diff --git a/llvm/utils/update_mir_test_checks.py b/llvm/utils/update_mir_test_checks.py index e6c1671..e0bc018 100755 --- a/llvm/utils/update_mir_test_checks.py +++ b/llvm/utils/update_mir_test_checks.py @@ -333,7 +333,7 @@ def update_test_file(args, test): build_function_body_dictionary(test, raw_tool_output, triple_in_cmd or triple_in_ir, - prefixes, func_dict, args.verbose) + prefixes, func_dict, args.verbose, False) state = 'toplevel' func_name = None diff --git a/llvm/utils/update_test_checks.py b/llvm/utils/update_test_checks.py index ec02602..6cb302b 100755 --- a/llvm/utils/update_test_checks.py +++ b/llvm/utils/update_test_checks.py @@ -66,6 +66,8 @@ def main(): help='Only update test if it was already autogened') parser.add_argument('-p', '--preserve-names', action='store_true', help='Do not scrub IR names') + parser.add_argument('--function-signature', action='store_true', + help='Keep function signature information around for the check line') parser.add_argument('tests', nargs='+') args = parser.parse_args() @@ -155,7 +157,8 @@ def main(): raw_tool_output = common.invoke_tool(args.opt_binary, opt_args, test) common.build_function_body_dictionary( common.OPT_FUNCTION_RE, common.scrub_body, [], - raw_tool_output, prefixes, func_dict, args.verbose) + raw_tool_output, prefixes, func_dict, args.verbose, + args.function_signature) is_in_function = False is_in_function_start = False -- 2.7.4