diff --git a/clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.funcsig.expected b/clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.funcsig.expected --- a/clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.funcsig.expected +++ b/clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.funcsig.expected @@ -1,4 +1,4 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature // Example input for update_cc_test_checks // RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s diff --git a/clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c b/clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c new file mode 100644 --- /dev/null +++ b/clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +int checks_please() { + return 1; +} + +// UTC_ARGS: --disable + +int no_checks_please() { + // Manual CHECK line should be retained: + // CHECK: manual check line + return -1; +} + +// UTC_ARGS: --enable + + +int checks_again() { + return 2; +} diff --git a/clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c.expected b/clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c.expected new file mode 100644 --- /dev/null +++ b/clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c.expected @@ -0,0 +1,29 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: @checks_please( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +int checks_please() { + return 1; +} + +// UTC_ARGS: --disable + +int no_checks_please() { + // Manual CHECK line should be retained: + // CHECK: manual check line + return -1; +} + +// UTC_ARGS: --enable + + +// CHECK-LABEL: @checks_again( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +int checks_again() { + return 2; +} diff --git a/clang/test/utils/update_cc_test_checks/mangled_names.test b/clang/test/utils/update_cc_test_checks/mangled_names.test --- a/clang/test/utils/update_cc_test_checks/mangled_names.test +++ b/clang/test/utils/update_cc_test_checks/mangled_names.test @@ -8,6 +8,11 @@ ## Also try the --function-signature flag # RUN: %update_cc_test_checks %t.c --function-signature # RUN: diff -u %t.c %S/Inputs/mangled_names.c.funcsig.expected -## Verify that running without the --function-signature flag removes the -SAME: lines: +## Running it again should implicitly add the function-signature flag due to UTC_ARGS: # RUN: %update_cc_test_checks %t.c -# RUN: diff -u %t.c %S/Inputs/mangled_names.c.expected +# RUN: diff -u %t.c %S/Inputs/mangled_names.c.funcsig.expected +## Verify that running without the --function-signature flag removes the -SAME: lines: +## We have to remove the UTC_ARGS comment first: +# RUN: grep -v UTC_ARGS %t.c > %t-no-args.c +# RUN: %update_cc_test_checks %t-no-args.c +# RUN: diff -u %t-no-args.c %S/Inputs/mangled_names.c.expected diff --git a/clang/test/utils/update_cc_test_checks/on_the_fly_arg_change.test b/clang/test/utils/update_cc_test_checks/on_the_fly_arg_change.test new file mode 100644 --- /dev/null +++ b/clang/test/utils/update_cc_test_checks/on_the_fly_arg_change.test @@ -0,0 +1,6 @@ +# RUN: cp -f %S/Inputs/on_the_fly_arg_change.c %t.c +# RUN: %update_cc_test_checks %t.c +# RUN: diff -u %t.c %S/Inputs/on_the_fly_arg_change.c.expected +## Check that running the script again does not change the result: +# RUN: %update_cc_test_checks %t.c +# RUN: diff -u %t.c %S/Inputs/on_the_fly_arg_change.c.expected diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/basic.ll.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/basic.ll.expected --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/basic.ll.expected +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/basic.ll.expected @@ -1,4 +1,3 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; Example input for update_llc_test_checks (taken from CodeGen/X86/iabs.ll) ; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s --check-prefix=X86 --check-prefix=X86-NO-CMOV ; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+cmov | FileCheck %s --check-prefix=X86 --check-prefix=X86-CMOV diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll @@ -0,0 +1,22 @@ +; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s + +declare void @foo() + +define i64 @check_lines_1() { + ret i64 1 +} + +; UTC_ARGS: --disable + +define i64 @no_check_lines() { +; A check line that would not be auto-generated (should not be removed!). +; CHECK: manual check line + ret i64 2 +} + +; UTC_ARGS: --enable --no_x86_scrub_rip + +define i64 @check_lines_2() { + %result = call i64 @no_check_lines() + ret i64 %result +} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll.expected new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll.expected @@ -0,0 +1,32 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s + +declare void @foo() + +define i64 @check_lines_1() { +; CHECK-LABEL: check_lines_1: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $1, %eax +; CHECK-NEXT: xorl %edx, %edx +; CHECK-NEXT: retl + ret i64 1 +} + +; UTC_ARGS: --disable + +define i64 @no_check_lines() { +; A check line that would not be auto-generated (should not be removed!). +; CHECK: manual check line + ret i64 2 +} + +; UTC_ARGS: --enable --no_x86_scrub_rip + +define i64 @check_lines_2() { +; CHECK-LABEL: check_lines_2: +; CHECK: # %bb.0: +; CHECK-NEXT: calll no_check_lines +; CHECK-NEXT: retl + %result = call i64 @no_check_lines() + ret i64 %result +} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/basic.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/basic.test --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/basic.test +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/basic.test @@ -2,14 +2,24 @@ ## Basic test checking that update_llc_test_checks.py can update a file with multiple check prefixes # RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks %t.ll -# RUN: diff -u %S/Inputs/basic.ll.expected %t.ll -## The flags --x86_scrub_rip and --extra_scrub should have any effect for this +# RUN: echo '; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py' > %t.expected.ll +# RUN: cat %S/Inputs/basic.ll.expected >> %t.expected.ll +# RUN: diff -u %t.expected.ll %t.ll + +## The flags --x86_scrub_rip and --extra_scrub should not have any effect on this ## test. Check the output is identical. -# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks --extra_scrub %t.ll -# RUN: diff -u %S/Inputs/basic.ll.expected %t.ll -# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks --x86_scrub_rip %t.ll -# RUN: diff -u %S/Inputs/basic.ll.expected %t.ll +# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks --extra_scrub %t.ll +# RUN: echo '; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --extra_scrub' > %t.expected.ll +# RUN: cat %S/Inputs/basic.ll.expected >> %t.expected.ll +# RUN: diff -u %t.expected.ll %t.ll +# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks --no_x86_scrub_rip %t.ll +# RUN: echo '; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no_x86_scrub_rip' > %t.expected.ll +# RUN: cat %S/Inputs/basic.ll.expected >> %t.expected.ll +# RUN: diff -u %t.expected.ll %t.ll + ## Finally, run the script on an already updated file and verify that all previous ## CHECK lines are removed. # RUN: %update_llc_test_checks %t.ll -# RUN: diff -u %S/Inputs/basic.ll.expected %t.ll +# RUN: echo '; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no_x86_scrub_rip' > %t.expected.ll +# RUN: cat %S/Inputs/basic.ll.expected >> %t.expected.ll +# RUN: diff -u %t.expected.ll %t.ll diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/on_the_fly_arg_change.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/on_the_fly_arg_change.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/on_the_fly_arg_change.test @@ -0,0 +1,6 @@ +# RUN: cp -f %S/Inputs/on_the_fly_arg_change.ll %t.ll +# RUN: %update_llc_test_checks %t.ll +# RUN: diff -u %t.ll %S/Inputs/on_the_fly_arg_change.ll.expected +## Check that running the script again does not change the result: +# RUN: %update_llc_test_checks %t.ll +# RUN: diff -u %t.ll %S/Inputs/on_the_fly_arg_change.ll.expected 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 @@ -1,9 +1,10 @@ from __future__ import print_function + +import copy +import glob import re -import string import subprocess import sys -import copy if sys.version_info[0] > 2: class string: @@ -21,11 +22,85 @@ help='Show verbose output') parser.add_argument('-u', '--update-only', action='store_true', help='Only update test if it was already autogened') + parser.add_argument('--force-update', action='store_true', + help='Update test even if it was autogened by a different script') + parser.add_argument('--enable', action='store_true', dest='enabled', default=True, + help='Activate CHECK line generation from this point forward') + parser.add_argument('--disable', action='store_false', dest='enabled', + help='Deactivate CHECK line generation from this point forward') args = parser.parse_args() global _verbose _verbose = args.verbose return args + +class InputLineInfo(object): + def __init__(self, line, line_number, args, argv): + self.line = line + self.line_number = line_number + self.args = args + self.argv = argv + + +class TestInfo(object): + def __init__(self, test, parser, script_name, input_lines, args, argv, + comment_prefix): + self.parser = parser + self.path = test + self.args = args + self.argv = argv + self.input_lines = input_lines + self.run_lines = find_run_lines(test, self.input_lines) + self.comment_prefix = comment_prefix + if self.comment_prefix is None: + if self.path.endswith('.mir'): + self.comment_prefix = '#' + else: + self.comment_prefix = ';' + 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) + + def iterlines(self, output_lines): + output_lines.append(self.test_autogenerated_note) + for line_num, input_line in enumerate(self.input_lines): + # Discard any previous script advertising. + if input_line.startswith(self.autogenerated_note_prefix): + continue + self.args, self.argv = check_for_command(input_line, self.parser, + self.args, self.argv) + if not self.args.enabled: + output_lines.append(input_line) + continue + yield InputLineInfo(input_line, line_num, self.args, self.argv) + + +def itertests(test_patterns, parser, script_name, comment_prefix=None): + for pattern in test_patterns: + # On Windows we must expand the patterns ourselves. + tests_list = glob.glob(pattern) + if not tests_list: + warn("Test file pattern '%s' was not found. Ignoring it." % (pattern,)) + continue + for test in tests_list: + with open(test) as f: + input_lines = [l.rstrip() for l in f] + args = parser.parse_args() + argv = sys.argv[:] + first_line = input_lines[0] if input_lines else "" + if 'autogenerated' in first_line: + if script_name not in first_line and not args.force_update: + warn("Skipping test which wasn't autogenerated by " + script_name, test) + continue + args, argv = check_for_command(first_line, parser, args, argv) + elif args.update_only: + assert 'autogenerated' not in first_line + warn("Skipping test which isn't autogenerated: " + test) + continue + yield TestInfo(test, parser, script_name, input_lines, args, argv, + comment_prefix) + + def should_add_line_to_output(input_line, prefix_set): # Skip any blank comment lines in the IR. if input_line.strip() == ';': @@ -57,7 +132,6 @@ return stdout.replace('\r\n', '\n') ##### LLVM IR parser - 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_-]+$') @@ -65,6 +139,7 @@ UTC_ARGS_KEY = 'UTC_ARGS:' UTC_ARGS_CMD = re.compile(r'.*' + UTC_ARGS_KEY + '\s*(?P.*)\s*$') +UTC_ADVERT = 'NOTE: Assertions have been autogenerated by ' OPT_FUNCTION_RE = re.compile( r'^\s*define\s+(?:internal\s+)?[^@]*@(?P[\w.-]+?)\s*' @@ -396,19 +471,31 @@ if prefixes.count(prefix) > 1: warn("Supplied prefix '%s' is not unique in the prefix list." % (prefix,)) + def get_autogennote_suffix(parser, args): - autogenerated_note_args = '' - for k, v in args._get_kwargs(): - if parser.get_default(k) == v or k == 'tests' or k == 'update_only' or k == 'opt_binary': - continue - k = k.replace('_', '-') - if type(v) is bool: - autogenerated_note_args += '--%s ' % (k) - else: - autogenerated_note_args += '--%s %s ' % (k, v) - if autogenerated_note_args: - autogenerated_note_args = ' %s %s' % (UTC_ARGS_KEY, autogenerated_note_args[:-1]) - return autogenerated_note_args + import argparse + autogenerated_note_args = '' + for action in parser._actions: + if not hasattr(args, action.dest): + continue # Ignore options such as --help that aren't included in args + # Ignore parameters such as paths to the binary or the list of tests + if action.dest in ('tests', 'update_only', 'opt_binary', 'llc_binary', + 'clang', 'opt', 'llvm_bin', 'verbose'): + continue + value = getattr(args, action.dest) + if action.const is not None: # action stores a constant (usually True/False) + # Skip actions with different constant values (this happens with boolean + # --foo/--no-foo options) + if value != action.const: + continue + if parser.get_default(action.dest) == value: + continue # Don't add default values + autogenerated_note_args += action.option_strings[0] + ' ' + if action.const is None: # action takes a parameter + autogenerated_note_args += '%s ' % value + if autogenerated_note_args: + autogenerated_note_args = ' %s %s' % (UTC_ARGS_KEY, autogenerated_note_args[:-1]) + return autogenerated_note_args def check_for_command(line, parser, args, argv): diff --git a/llvm/utils/update_cc_test_checks.py b/llvm/utils/update_cc_test_checks.py --- a/llvm/utils/update_cc_test_checks.py +++ b/llvm/utils/update_cc_test_checks.py @@ -19,16 +19,13 @@ import distutils.spawn import json import os +import re import shlex -import string import subprocess import sys -import re import tempfile -from UpdateTestChecks import asm, common - -ADVERT = '// NOTE: Assertions have been autogenerated by ' +from UpdateTestChecks import common SUBST = { '%clang': [], @@ -97,6 +94,11 @@ return ret +def str_to_commandline(value): + if not value: + return [] + return shlex.split(value) + def config(): parser = argparse.ArgumentParser( description=__doc__, @@ -104,7 +106,7 @@ parser.add_argument('--llvm-bin', help='llvm $prefix/bin path') parser.add_argument('--clang', help='"clang" executable, defaults to $llvm_bin/clang') - parser.add_argument('--clang-args', + parser.add_argument('--clang-args', default=[], type=str_to_commandline, help='Space-separated extra args to clang, e.g. --clang-args=-v') parser.add_argument('--opt', help='"opt" executable, defaults to $llvm_bin/opt') @@ -118,7 +120,6 @@ help='Keep function signature information around for the check line') parser.add_argument('tests', nargs='+') args = common.parse_commandline_args(parser) - args.clang_args = shlex.split(args.clang_args or '') if args.clang is None: if args.llvm_bin is None: @@ -152,7 +153,7 @@ # defer this error message until we find that opt is actually needed. args.opt = None - return args + return args, parser def get_function_body(args, filename, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict): @@ -183,31 +184,15 @@ def main(): - args = config() + initial_args, parser = config() script_name = os.path.basename(__file__) - autogenerated_note = (ADVERT + 'utils/' + script_name) - - for filename in args.tests: - with open(filename) as f: - input_lines = [l.rstrip() for l in f] - - first_line = input_lines[0] if input_lines else "" - if 'autogenerated' in first_line and script_name not in first_line: - common.warn("Skipping test which wasn't autogenerated by " + script_name, filename) - continue - - if args.update_only: - if not first_line or 'autogenerated' not in first_line: - common.warn("Skipping test which isn't autogenerated: " + filename) - continue - - # Extract RUN lines. - run_lines = common.find_run_lines(filename, input_lines) + for ti in common.itertests(initial_args.tests, parser, 'utils/' + script_name, + comment_prefix='//'): # Build a list of clang command lines and check prefixes from RUN lines. run_list = [] line2spell_and_mangled_list = collections.defaultdict(list) - for l in run_lines: + for l in ti.run_lines: commands = [cmd.strip() for cmd in l.split('|')] triple_in_cmd = None @@ -221,7 +206,7 @@ print('WARNING: Skipping non-clang RUN line: ' + l, file=sys.stderr) continue clang_args[0:1] = SUBST[clang_args[0]] - clang_args = [filename if i == '%s' else i for i in clang_args] + args.clang_args + clang_args = [ti.path if i == '%s' else i for i in clang_args] + ti.args.clang_args # Permit piping the output through opt if not (len(commands) == 2 or @@ -240,18 +225,6 @@ check_prefixes = ['CHECK'] run_list.append((check_prefixes, clang_args, commands[1:-1], triple_in_cmd)) - # Strip CHECK lines which are in `prefix_set`, update test file. - prefix_set = set([prefix for p in run_list for prefix in p[0]]) - input_lines = [] - with open(filename, 'r+') as f: - for line in f: - m = common.CHECK_RE.match(line) - if not (m and m.group(1) in prefix_set) and line != '//\n': - input_lines.append(line) - f.seek(0) - f.writelines(input_lines) - f.truncate() - # Execute clang, generate LLVM IR, and extract functions. func_dict = {} for p in run_list: @@ -262,18 +235,23 @@ common.debug('Extracted clang cmd: clang {}'.format(clang_args)) common.debug('Extracted FileCheck prefixes: {}'.format(prefixes)) - get_function_body(args, filename, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict) + get_function_body(ti.args, ti.path, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict) # Invoke clang -Xclang -ast-dump=json to get mapping from start lines to # mangled names. Forward all clang args for now. - for k, v in get_line2spell_and_mangled(args, clang_args).items(): + for k, v in get_line2spell_and_mangled(ti.args, clang_args).items(): line2spell_and_mangled_list[k].append(v) - output_lines = [autogenerated_note] - for idx, line in enumerate(input_lines): - # Discard any previous script advertising. - if line.startswith(ADVERT): - continue + prefix_set = set([prefix for p in run_list for prefix in p[0]]) + output_lines = [] + for line_info in ti.iterlines(output_lines): + idx = line_info.line_number + line = line_info.line + args = line_info.args + include_line = True + m = common.CHECK_RE.match(line) + if m and m.group(1) in prefix_set: + continue # Don't append the existing CHECK lines if idx in line2spell_and_mangled_list: added = set() for spell, mangled in line2spell_and_mangled_list[idx]: @@ -285,16 +263,25 @@ if mangled in added or spell not in line: continue if args.functions is None or any(re.search(regex, spell) for regex in args.functions): + last_line = output_lines[-1].strip() + while last_line == '//': + # Remove the comment line since we will generate a new comment + # line as part of common.add_ir_checks() + output_lines.pop() + last_line = output_lines[-1].strip() if added: output_lines.append('//') added.add(mangled) common.add_ir_checks(output_lines, '//', run_list, func_dict, mangled, False, args.function_signature) - output_lines.append(line.rstrip('\n')) + if line.rstrip('\n') == '//': + include_line = False + if include_line: + output_lines.append(line.rstrip('\n')) - common.debug('Writing %d lines to %s...' % (len(output_lines), filename)) - with open(filename, 'wb') as f: + 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]) return 0 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 @@ -10,17 +10,10 @@ from __future__ import print_function import argparse -import glob -import os # Used to advertise this file's name ("autogenerated_note"). -import string -import subprocess -import sys -import re +import os # Used to advertise this file's name ("autogenerated_note"). from UpdateTestChecks import asm, common -ADVERT = ' NOTE: Assertions have been autogenerated by ' - def main(): parser = argparse.ArgumentParser(description=__doc__) @@ -40,35 +33,21 @@ '--no_x86_scrub_mem_shuffle', action='store_true', default=False, help='Reduce scrubbing shuffles with memory operands') parser.add_argument('tests', nargs='+') - args = common.parse_commandline_args(parser) + initial_args = common.parse_commandline_args(parser) script_name = os.path.basename(__file__) - test_paths = [test for pattern in args.tests for test in glob.glob(pattern)] - for test in test_paths: - with open(test) as f: - input_lines = [l.rstrip() for l in f] - - first_line = input_lines[0] if input_lines else "" - if 'autogenerated' in first_line and script_name not in first_line: - common.warn("Skipping test which wasn't autogenerated by " + script_name, test) - continue - - if args.update_only: - if not first_line or 'autogenerated' not in first_line: - common.warn("Skipping test which isn't autogenerated: " + test) - continue - + for ti in common.itertests(initial_args.tests, parser, + script_name='utils/' + script_name): triple_in_ir = None - for l in input_lines: + for l in ti.input_lines: m = common.TRIPLE_IR_RE.match(l) if m: triple_in_ir = m.groups()[0] break - run_lines = common.find_run_lines(test, input_lines) run_list = [] - for l in run_lines: + for l in ti.run_lines: if '|' not in l: common.warn('Skipping unparseable RUN line: ' + l) continue @@ -101,7 +80,7 @@ llc_cmd_args = llc_cmd[len(llc_tool):].strip() llc_cmd_args = llc_cmd_args.replace('< %s', '').replace('%s', '').strip() - if test.endswith('.mir'): + if ti.path.endswith('.mir'): llc_cmd_args += ' -x mir' check_prefixes = [item for m in common.CHECK_PREFIX_RE.finditer(filecheck_cmd) for item in m.group(1).split(',')] @@ -112,13 +91,10 @@ # now, we just ignore all but the last. run_list.append((check_prefixes, llc_cmd_args, triple_in_cmd, march_in_cmd)) - if test.endswith('.mir'): - comment_sym = '#' + if ti.path.endswith('.mir'): check_indent = ' ' else: - comment_sym = ';' check_indent = '' - autogenerated_note = (comment_sym + ADVERT + 'utils/' + script_name) func_dict = {} for p in run_list: @@ -129,12 +105,12 @@ common.debug('Extracted LLC cmd:', llc_tool, llc_args) common.debug('Extracted FileCheck prefixes:', str(prefixes)) - raw_tool_output = common.invoke_tool(args.llc_binary, llc_args, test) + raw_tool_output = common.invoke_tool(ti.args.llc_binary, llc_args, ti.path) triple = triple_in_cmd or triple_in_ir if not triple: triple = asm.get_triple_from_march(march_in_cmd) - asm.build_function_body_dictionary_for_triple(args, raw_tool_output, + asm.build_function_body_dictionary_for_triple(ti.args, raw_tool_output, triple, prefixes, func_dict) is_in_function = False @@ -143,9 +119,9 @@ prefix_set = set([prefix for p in run_list for prefix in p[0]]) common.debug('Rewriting FileCheck prefixes:', str(prefix_set)) output_lines = [] - output_lines.append(autogenerated_note) - - for input_line in input_lines: + for input_info in ti.iterlines(output_lines): + input_line = input_info.line + args = input_info.args if is_in_function_start: if input_line == '': continue @@ -169,10 +145,6 @@ is_in_function = False continue - # Discard any previous script advertising. - if input_line.startswith(comment_sym + ADVERT): - continue - # If it's outside a function, it just gets copied to the output. output_lines.append(input_line) @@ -185,9 +157,9 @@ continue is_in_function = is_in_function_start = True - common.debug('Writing %d lines to %s...' % (len(output_lines), test)) + common.debug('Writing %d lines to %s...' % (len(output_lines), ti.path)) - with open(test, 'wb') as f: + with open(ti.path, 'wb') as f: f.writelines(['{}\n'.format(l).encode('utf-8') for l in output_lines]) diff --git a/llvm/utils/update_test_checks.py b/llvm/utils/update_test_checks.py --- a/llvm/utils/update_test_checks.py +++ b/llvm/utils/update_test_checks.py @@ -32,18 +32,12 @@ from __future__ import print_function import argparse -import glob -import itertools -import os # Used to advertise this file's name ("autogenerated_note"). -import string -import subprocess -import sys -import tempfile +import os # Used to advertise this file's name ("autogenerated_note"). import re +import sys from UpdateTestChecks import common -ADVERT = '; NOTE: Assertions have been autogenerated by ' def main(): from argparse import RawTextHelpFormatter @@ -58,58 +52,26 @@ help='Keep function signature information around for the check line') parser.add_argument('--scrub-attributes', action='store_true', help='Remove attribute annotations (#0) from the end of check line') - parser.add_argument('--enable', action='store_true', dest='enabled', default=True, - help='Activate CHECK line generation from this point forward') - parser.add_argument('--disable', action='store_false', dest='enabled', - help='Deactivate CHECK line generation from this point forward') parser.add_argument('tests', nargs='+') - args = common.parse_commandline_args(parser) + initial_args = common.parse_commandline_args(parser) script_name = os.path.basename(__file__) - autogenerated_note = (ADVERT + 'utils/' + script_name) - - opt_basename = os.path.basename(args.opt_binary) + opt_basename = os.path.basename(initial_args.opt_binary) if not re.match(r'^opt(-\d+)?$', opt_basename): common.error('Unexpected opt name: ' + opt_basename) sys.exit(1) opt_basename = 'opt' - for test in args.tests: - if not glob.glob(test): - common.warn("Test file pattern '%s' was not found. Ignoring it." % (test,)) - continue - - # On Windows we must expand the patterns ourselves. - test_paths = [test for pattern in args.tests for test in glob.glob(pattern)] - for test in test_paths: - argv = sys.argv[:] - args = parser.parse_args() - with open(test) as f: - input_lines = [l.rstrip() for l in f] - - first_line = input_lines[0] if input_lines else "" - if 'autogenerated' in first_line and script_name not in first_line: - common.warn("Skipping test which wasn't autogenerated by " + script_name, test) - continue - if first_line and 'autogenerated' in first_line: - args, argv = common.check_for_command(first_line, parser, args, argv) - test_autogenerated_note = autogenerated_note + common.get_autogennote_suffix(parser, args) - - if args.update_only: - if not first_line or 'autogenerated' not in first_line: - common.warn("Skipping test which isn't autogenerated: " + test) - continue - - run_lines = common.find_run_lines(test, input_lines) - + for ti in common.itertests(initial_args.tests, parser, + script_name='utils/' + script_name): # If requested we scrub trailing attribute annotations, e.g., '#0', together with whitespaces - if args.scrub_attributes: + if ti.args.scrub_attributes: common.SCRUB_TRAILING_WHITESPACE_TEST_RE = common.SCRUB_TRAILING_WHITESPACE_AND_ATTRIBUTES_RE else: common.SCRUB_TRAILING_WHITESPACE_TEST_RE = common.SCRUB_TRAILING_WHITESPACE_RE prefix_list = [] - for l in run_lines: + for l in ti.run_lines: if '|' not in l: common.warn('Skipping unparseable RUN line: ' + l) continue @@ -127,8 +89,9 @@ tool_cmd_args = tool_cmd[len(opt_basename):].strip() tool_cmd_args = tool_cmd_args.replace('< %s', '').replace('%s', '').strip() - check_prefixes = [item for m in common.CHECK_PREFIX_RE.finditer(filecheck_cmd) - for item in m.group(1).split(',')] + check_prefixes = [item for m in + common.CHECK_PREFIX_RE.finditer(filecheck_cmd) + for item in m.group(1).split(',')] if not check_prefixes: check_prefixes = ['CHECK'] @@ -144,28 +107,21 @@ common.debug('Extracted opt cmd: ' + opt_basename + ' ' + opt_args) common.debug('Extracted FileCheck prefixes: ' + str(prefixes)) - raw_tool_output = common.invoke_tool(args.opt_binary, opt_args, test) + raw_tool_output = common.invoke_tool(ti.args.opt_binary, opt_args, ti.path) common.build_function_body_dictionary( common.OPT_FUNCTION_RE, common.scrub_body, [], - raw_tool_output, prefixes, func_dict, args.verbose, - args.function_signature) + raw_tool_output, prefixes, func_dict, ti.args.verbose, + ti.args.function_signature) is_in_function = False is_in_function_start = False + func_name = 'error-this-should-not-be-dereferenced-yet' prefix_set = set([prefix for prefixes, _ in prefix_list for prefix in prefixes]) common.debug('Rewriting FileCheck prefixes:', str(prefix_set)) output_lines = [] - output_lines.append(test_autogenerated_note) - - for input_line in input_lines: - # Discard any previous script advertising. - if input_line.startswith(ADVERT): - continue - - args, argv = common.check_for_command(input_line, parser, args, argv) - if not args.enabled: - output_lines.append(input_line) - continue + for input_line_info in ti.iterlines(output_lines): + input_line = input_line_info.line + args = input_line_info.args if is_in_function_start: if input_line == '': continue @@ -204,9 +160,9 @@ continue is_in_function = is_in_function_start = True - common.debug('Writing %d lines to %s...' % (len(output_lines), test)) + common.debug('Writing %d lines to %s...' % (len(output_lines), ti.path)) - with open(test, 'wb') as f: + with open(ti.path, 'wb') as f: f.writelines(['{}\n'.format(l).encode('utf-8') for l in output_lines])