From f3c5f46ed12c67a987207e4d1ab736261baed01e Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Thu, 24 Mar 2016 17:15:42 +0000 Subject: [PATCH] reorganize llc checks script to allow more flexibility, part 2; NFCI The goal is to enhance this script to be used with opt and clang: Break 'main' into functions and change variable names to be more generic because we want to handle more than x86 asm output. llvm-svn: 264307 --- llvm/utils/update_llc_test_checks.py | 175 ++++++++++++++++----------- 1 file changed, 103 insertions(+), 72 deletions(-) diff --git a/llvm/utils/update_llc_test_checks.py b/llvm/utils/update_llc_test_checks.py index 781fab54f69b..55af9f1759f7 100755 --- a/llvm/utils/update_llc_test_checks.py +++ b/llvm/utils/update_llc_test_checks.py @@ -9,6 +9,8 @@ a single test function. import argparse import itertools +# Could be used to advertise this file's name ("autogenerated_note"). +# import os import string import subprocess import sys @@ -40,7 +42,7 @@ SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n') RUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$') IR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@(\w+)\s*\(') ASM_FUNCTION_RE = re.compile( - r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=f)\n[^:]*?' + 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)) @@ -67,6 +69,70 @@ def scrub_asm(asm): return asm +# Build up a dictionary of all the function bodies. +def build_function_body_dictionary(raw_tool_output, prefixes, func_dict, verbose): + for m in ASM_FUNCTION_RE.finditer(raw_tool_output): + if not m: + continue + func = m.group('func') + scrubbed_body = scrub_asm(m.group('body')) + 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:]) + if verbose: + print >>sys.stderr, 'Processing function: ' + func + for l in scrubbed_body.splitlines(): + print >>sys.stderr, ' ' + l + for prefix in prefixes: + if func in func_dict[prefix] and func_dict[prefix][func] != scrubbed_body: + if prefix == prefixes[-1]: + print >>sys.stderr, ('WARNING: Found conflicting asm under the ' + 'same prefix: %r!' % (prefix,)) + else: + func_dict[prefix][func] = None + continue + + func_dict[prefix][func] = scrubbed_body + + +def add_checks(output_lines, prefix_list, func_dict, func_name): + printed_prefixes = [] + for checkprefixes, _ in prefix_list: + for checkprefix in checkprefixes: + if checkprefix in printed_prefixes: + break + if not func_dict[checkprefix][func_name]: + continue + # Add some space between different check prefixes. + if len(printed_prefixes) != 0: + output_lines.append(';') + printed_prefixes.append(checkprefix) + output_lines.append('; %s-LABEL: %s:' % (checkprefix, func_name)) + func_body = func_dict[checkprefix][func_name].splitlines() + output_lines.append('; %s: %s' % (checkprefix, func_body[0])) + for func_line in func_body[1:]: + output_lines.append('; %s-NEXT: %s' % (checkprefix, func_line)) + # Add space between different check prefixes and the first line of code. + # output_lines.append(';') + break + return output_lines + + +def should_add_line_to_output(input_line, prefix_set): + # Skip any blank comment lines in the IR. + if input_line.strip() == ';': + return False + # Skip any blank lines in the IR. + #if input_line.strip() == '': + # return False + # And skip any CHECK lines. We're building our own. + m = CHECK_RE.match(input_line) + if m and m.group(1) in prefix_set: + return False + + return True + + def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('-v', '--verbose', action='store_true', @@ -78,23 +144,25 @@ def main(): parser.add_argument('tests', nargs='+') args = parser.parse_args() + # FIXME: we don't need to hardcode this name. autogenerated_note = ('; NOTE: Assertions have been autogenerated by ' 'utils/update_llc_test_checks.py') + # + os.path.basename(__file__)) for test in args.tests: if args.verbose: print >>sys.stderr, 'Scanning for RUN lines in test file: %s' % (test,) with open(test) as f: - test_lines = [l.rstrip() for l in f] + input_lines = [l.rstrip() for l in f] run_lines = [m.group(1) - for m in [RUN_LINE_RE.match(l) for l in test_lines] if m] + for m in [RUN_LINE_RE.match(l) for l in input_lines] if m] if args.verbose: print >>sys.stderr, 'Found %d RUN lines:' % (len(run_lines),) for l in run_lines: print >>sys.stderr, ' RUN: ' + l - checks = [] + prefix_list = [] for l in run_lines: (llc_cmd, filecheck_cmd) = tuple([cmd.strip() for cmd in l.split('|', 1)]) if not llc_cmd.startswith('llc '): @@ -115,96 +183,59 @@ def main(): # FIXME: We should use multiple check prefixes to common check lines. For # now, we just ignore all but the last. - checks.append((check_prefixes, llc_cmd_args)) + prefix_list.append((check_prefixes, llc_cmd_args)) - asm = {} - for prefixes, _ in checks: + func_dict = {} + for prefixes, _ in prefix_list: for prefix in prefixes: - asm.update({prefix: dict()}) - for prefixes, llc_args in checks: + func_dict.update({prefix: dict()}) + for prefixes, llc_args in prefix_list: if args.verbose: print >>sys.stderr, 'Extracted LLC cmd: llc ' + llc_args print >>sys.stderr, 'Extracted FileCheck prefixes: ' + str(prefixes) - raw_asm = llc(args, llc_args, test) - # Build up a dictionary of all the function bodies. - for m in ASM_FUNCTION_RE.finditer(raw_asm): - if not m: - continue - f = m.group('f') - f_asm = scrub_asm(m.group('body')) - if f.startswith('stress'): - # We only use the last line of the asm for stress tests. - f_asm = '\n'.join(f_asm.splitlines()[-1:]) - if args.verbose: - print >>sys.stderr, 'Processing asm for function: ' + f - for l in f_asm.splitlines(): - print >>sys.stderr, ' ' + l - for prefix in prefixes: - if f in asm[prefix] and asm[prefix][f] != f_asm: - if prefix == prefixes[-1]: - print >>sys.stderr, ('WARNING: Found conflicting asm under the ' - 'same prefix: %r!' % (prefix,)) - else: - asm[prefix][f] = None - continue - asm[prefix][f] = f_asm + raw_tool_output = llc(args, llc_args, test) + build_function_body_dictionary(raw_tool_output, prefixes, func_dict, args.verbose) is_in_function = False is_in_function_start = False - prefix_set = set([prefix for prefixes, _ in checks for prefix in prefixes]) + prefix_set = set([prefix for prefixes, _ in prefix_list for prefix in prefixes]) if args.verbose: print >>sys.stderr, 'Rewriting FileCheck prefixes: %s' % (prefix_set,) - fixed_lines = [] - fixed_lines.append(autogenerated_note) + output_lines = [] + output_lines.append(autogenerated_note) - for l in test_lines: + for input_line in input_lines: if is_in_function_start: - if l.lstrip().startswith(';'): - m = CHECK_RE.match(l) + if input_line == '': + continue + if input_line.lstrip().startswith(';'): + m = CHECK_RE.match(input_line) if not m or m.group(1) not in prefix_set: - fixed_lines.append(l) + output_lines.append(input_line) continue - # Print out the various check lines here - printed_prefixes = [] - for prefixes, _ in checks: - for prefix in prefixes: - if prefix in printed_prefixes: - break - if not asm[prefix][name]: - continue - if len(printed_prefixes) != 0: - fixed_lines.append(';') - printed_prefixes.append(prefix) - fixed_lines.append('; %s-LABEL: %s:' % (prefix, name)) - asm_lines = asm[prefix][name].splitlines() - fixed_lines.append('; %s: %s' % (prefix, asm_lines[0])) - for asm_line in asm_lines[1:]: - fixed_lines.append('; %s-NEXT: %s' % (prefix, asm_line)) - break + # Print out the various check lines here. + output_lines = add_checks(output_lines, prefix_list, func_dict, name) is_in_function_start = False if is_in_function: - # Skip any blank comment lines in the IR. - if l.strip() == ';': + if should_add_line_to_output(input_line, prefix_set) == True: + # This input line of the function body will go as-is into the output. + output_lines.append(input_line) + else: continue - # And skip any CHECK lines. We'll build our own. - m = CHECK_RE.match(l) - if m and m.group(1) in prefix_set: - continue - # Collect the remaining lines in the function body and look for the end - # of the function. - fixed_lines.append(l) - if l.strip() == '}': + if input_line.strip() == '}': is_in_function = False continue - if l == autogenerated_note: + if input_line == autogenerated_note: continue - fixed_lines.append(l) - m = IR_FUNCTION_RE.match(l) + # If it's outside a function, it just gets copied to the output. + output_lines.append(input_line) + + m = IR_FUNCTION_RE.match(input_line) if not m: continue name = m.group(1) @@ -214,10 +245,10 @@ def main(): is_in_function = is_in_function_start = True if args.verbose: - print>>sys.stderr, 'Writing %d fixed lines to %s...' % ( - len(fixed_lines), test) + print>>sys.stderr, 'Writing %d lines to %s...' % (len(output_lines), test) + with open(test, 'wb') as f: - f.writelines([l + '\n' for l in fixed_lines]) + f.writelines([l + '\n' for l in output_lines]) if __name__ == '__main__':