diff --git a/llvm/utils/update_test_checks.py b/llvm/utils/update_test_checks.py index cace9023106f..073d43d8e4da 100755 --- a/llvm/utils/update_test_checks.py +++ b/llvm/utils/update_test_checks.py @@ -1,13 +1,13 @@ #!/usr/bin/env python2.7 -"""A script to generate FileCheck statements for regression tests. +"""A script to generate FileCheck statements for 'opt' regression tests. -This script is a utility to update LLVM opt or llc test cases with new +This script is a utility to update LLVM opt test cases with new FileCheck patterns. It can either update all of the tests in the file or a single test function. Example usage: -$ update_test_checks.py --tool=../bin/opt test/foo.ll +$ update_test_checks.py --opt=../bin/opt test/foo.ll Workflow: 1. Make a compiler patch that requires updating some number of FileCheck lines @@ -45,23 +45,11 @@ ADVERT = '; NOTE: Assertions have been autogenerated by ' SCRUB_LEADING_WHITESPACE_RE = re.compile(r'^(\s+)') SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M) SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M) -SCRUB_X86_SHUFFLES_RE = ( - re.compile( - r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$', - flags=re.M)) -SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)') -SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)') -SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+') SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n') SCRUB_IR_COMMENT_RE = re.compile(r'\s*;.*') RUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$') IR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@([\w-]+)\s*\(') -LLC_FUNCTION_RE = re.compile( - r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' - r'(?P^##?[ \t]+[^:]+:.*?)\s*' - r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section)', - flags=(re.M | re.S)) OPT_FUNCTION_RE = re.compile( r'^\s*define\s+(?:internal\s+)?[^@]*@(?P[\w-]+?)\s*\(' r'(\s+)?[^)]*[^{]*\{\n(?P.*?)^\}$', @@ -76,29 +64,14 @@ IR_VALUE_RE = re.compile(r'(\s+)%([\w\.]+?)([,\s\(\)]|\Z)') # Invoke the tool that is being tested. def invoke_tool(args, cmd_args, ir): with open(ir) as ir_file: - stdout = subprocess.check_output(args.tool_binary + ' ' + cmd_args, + stdout = subprocess.check_output(args.opt_binary + ' ' + cmd_args, shell=True, stdin=ir_file) # Fix line endings to unix CR style. stdout = stdout.replace('\r\n', '\n') return stdout -# FIXME: Separate the x86-specific scrubbers, so this can be used for other targets. -def scrub_asm(asm): - # Detect shuffle asm comments and hide the operands in favor of the comments. - asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm) - # Generically match the stack offset of a memory operand. - asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm) - # Generically match a RIP-relative memory operand. - asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm) - # Generically match a LCP symbol. - asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm) - # Strip kill operands inserted into the asm. - asm = SCRUB_KILL_COMMENT_RE.sub('', asm) - return asm - - -def scrub_body(body, tool_basename): +def scrub_body(body, opt_basename): # Scrub runs of whitespace out of the assembly, but leave the leading # whitespace in place. body = SCRUB_WHITESPACE_RE.sub(r' ', body) @@ -106,22 +79,17 @@ def scrub_body(body, tool_basename): body = string.expandtabs(body, 2) # Strip trailing whitespace. body = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', body) - if tool_basename == "llc": - body = scrub_asm(body) return body # Build up a dictionary of all the function bodies. -def build_function_body_dictionary(raw_tool_output, prefixes, func_dict, verbose, tool_basename): - if tool_basename == "llc": - func_regex = LLC_FUNCTION_RE - else: - func_regex = OPT_FUNCTION_RE +def build_function_body_dictionary(raw_tool_output, prefixes, func_dict, verbose, opt_basename): + func_regex = OPT_FUNCTION_RE for m in func_regex.finditer(raw_tool_output): if not m: continue func = m.group('func') - scrubbed_body = scrub_body(m.group('body'), tool_basename) + scrubbed_body = scrub_body(m.group('body'), opt_basename) if func.startswith('stress'): # We only use the last line of the function body for stress tests. scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:]) @@ -188,12 +156,9 @@ def genericize_check_lines(lines): return lines -def add_checks(output_lines, prefix_list, func_dict, func_name, tool_basename): - # Select a label format based on the whether we're checking asm or IR. - if tool_basename == "llc": - check_label_format = "; %s-LABEL: %s:" - else: - check_label_format = "; %s-LABEL: @%s(" +def add_checks(output_lines, prefix_list, func_dict, func_name, opt_basename): + # Label format is based on IR string. + check_label_format = "; %s-LABEL: @%s(" printed_prefixes = [] for checkprefixes, _ in prefix_list: @@ -212,8 +177,7 @@ def add_checks(output_lines, prefix_list, func_dict, func_name, tool_basename): # For IR output, change all defs to FileCheck variables, so we're immune # to variable naming fashions. - if tool_basename == "opt": - func_body = genericize_check_lines(func_body) + func_body = genericize_check_lines(func_body) # This could be selectively enabled with an optional invocation argument. # Disabled for now: better to check everything. Be safe rather than sorry. @@ -226,20 +190,14 @@ def add_checks(output_lines, prefix_list, func_dict, func_name, tool_basename): # output_lines.append('; %s: %s' % (checkprefix, func_body[0])) # is_blank_line = False - # For llc tests, there may be asm directives between the label and the - # first checked line (most likely that first checked line is "# BB#0"). - if tool_basename == "opt": - is_blank_line = False - else: - is_blank_line = True; + is_blank_line = False for func_line in func_body: if func_line.strip() == '': is_blank_line = True continue # Do not waste time checking IR comments. - if tool_basename == "opt": - func_line = SCRUB_IR_COMMENT_RE.sub(r'', func_line) + func_line = SCRUB_IR_COMMENT_RE.sub(r'', func_line) # Skip blank lines instead of checking them. if is_blank_line == True: @@ -275,8 +233,8 @@ def main(): parser = argparse.ArgumentParser(description=__doc__, formatter_class=RawTextHelpFormatter) parser.add_argument('-v', '--verbose', action='store_true', help='Show verbose output') - parser.add_argument('--tool-binary', default='llc', - help='The tool used to generate the test case') + parser.add_argument('--opt-binary', default='opt', + help='The opt binary used to generate the test case') parser.add_argument( '--function', help='The function in the test file to update') parser.add_argument('tests', nargs='+') @@ -284,9 +242,9 @@ def main(): autogenerated_note = (ADVERT + 'utils/' + os.path.basename(__file__)) - tool_basename = os.path.basename(args.tool_binary) - if (tool_basename != "llc" and tool_basename != "opt"): - print >>sys.stderr, 'ERROR: Unexpected tool name: ' + tool_basename + opt_basename = os.path.basename(args.opt_binary) + if (opt_basename != "opt"): + print >>sys.stderr, 'ERROR: Unexpected opt name: ' + opt_basename sys.exit(1) for test in args.tests: @@ -313,15 +271,15 @@ def main(): for l in run_lines: (tool_cmd, filecheck_cmd) = tuple([cmd.strip() for cmd in l.split('|', 1)]) - if not tool_cmd.startswith(tool_basename + ' '): - print >>sys.stderr, 'WARNING: Skipping non-%s RUN line: %s' % (tool_basename, l) + if not tool_cmd.startswith(opt_basename + ' '): + print >>sys.stderr, 'WARNING: Skipping non-%s RUN line: %s' % (opt_basename, l) continue if not filecheck_cmd.startswith('FileCheck '): print >>sys.stderr, 'WARNING: Skipping non-FileChecked RUN line: ' + l continue - tool_cmd_args = tool_cmd[len(tool_basename):].strip() + 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 CHECK_PREFIX_RE.finditer(filecheck_cmd) @@ -337,13 +295,13 @@ def main(): for prefixes, _ in prefix_list: for prefix in prefixes: func_dict.update({prefix: dict()}) - for prefixes, tool_args in prefix_list: + for prefixes, opt_args in prefix_list: if args.verbose: - print >>sys.stderr, 'Extracted tool cmd: ' + tool_basename + ' ' + tool_args + print >>sys.stderr, 'Extracted opt cmd: ' + opt_basename + ' ' + opt_args print >>sys.stderr, 'Extracted FileCheck prefixes: ' + str(prefixes) - raw_tool_output = invoke_tool(args, tool_args, test) - build_function_body_dictionary(raw_tool_output, prefixes, func_dict, args.verbose, tool_basename) + raw_tool_output = invoke_tool(args, opt_args, test) + build_function_body_dictionary(raw_tool_output, prefixes, func_dict, args.verbose, opt_basename) is_in_function = False is_in_function_start = False @@ -364,7 +322,7 @@ def main(): continue # Print out the various check lines here. - output_lines = add_checks(output_lines, prefix_list, func_dict, name, tool_basename) + output_lines = add_checks(output_lines, prefix_list, func_dict, name, opt_basename) is_in_function_start = False if is_in_function: