1*9880d681SAndroid Build Coastguard Worker#!/usr/bin/env python2.7 2*9880d681SAndroid Build Coastguard Worker 3*9880d681SAndroid Build Coastguard Worker"""A script to generate FileCheck statements for regression tests. 4*9880d681SAndroid Build Coastguard Worker 5*9880d681SAndroid Build Coastguard WorkerThis script is a utility to update LLVM opt or llc test cases with new 6*9880d681SAndroid Build Coastguard WorkerFileCheck patterns. It can either update all of the tests in the file or 7*9880d681SAndroid Build Coastguard Workera single test function. 8*9880d681SAndroid Build Coastguard Worker 9*9880d681SAndroid Build Coastguard WorkerExample usage: 10*9880d681SAndroid Build Coastguard Worker$ update_test_checks.py --tool=../bin/opt test/foo.ll 11*9880d681SAndroid Build Coastguard Worker 12*9880d681SAndroid Build Coastguard WorkerWorkflow: 13*9880d681SAndroid Build Coastguard Worker1. Make a compiler patch that requires updating some number of FileCheck lines 14*9880d681SAndroid Build Coastguard Worker in regression test files. 15*9880d681SAndroid Build Coastguard Worker2. Save the patch and revert it from your local work area. 16*9880d681SAndroid Build Coastguard Worker3. Update the RUN-lines in the affected regression tests to look canonical. 17*9880d681SAndroid Build Coastguard Worker Example: "; RUN: opt < %s -instcombine -S | FileCheck %s" 18*9880d681SAndroid Build Coastguard Worker4. Refresh the FileCheck lines for either the entire file or select functions by 19*9880d681SAndroid Build Coastguard Worker running this script. 20*9880d681SAndroid Build Coastguard Worker5. Commit the fresh baseline of checks. 21*9880d681SAndroid Build Coastguard Worker6. Apply your patch from step 1 and rebuild your local binaries. 22*9880d681SAndroid Build Coastguard Worker7. Re-run this script on affected regression tests. 23*9880d681SAndroid Build Coastguard Worker8. Check the diffs to ensure the script has done something reasonable. 24*9880d681SAndroid Build Coastguard Worker9. Submit a patch including the regression test diffs for review. 25*9880d681SAndroid Build Coastguard Worker 26*9880d681SAndroid Build Coastguard WorkerA common pattern is to have the script insert complete checking of every 27*9880d681SAndroid Build Coastguard Workerinstruction. Then, edit it down to only check the relevant instructions. 28*9880d681SAndroid Build Coastguard WorkerThe script is designed to make adding checks to a test case fast, it is *not* 29*9880d681SAndroid Build Coastguard Workerdesigned to be authoratitive about what constitutes a good test! 30*9880d681SAndroid Build Coastguard Worker""" 31*9880d681SAndroid Build Coastguard Worker 32*9880d681SAndroid Build Coastguard Workerimport argparse 33*9880d681SAndroid Build Coastguard Workerimport itertools 34*9880d681SAndroid Build Coastguard Workerimport os # Used to advertise this file's name ("autogenerated_note"). 35*9880d681SAndroid Build Coastguard Workerimport string 36*9880d681SAndroid Build Coastguard Workerimport subprocess 37*9880d681SAndroid Build Coastguard Workerimport sys 38*9880d681SAndroid Build Coastguard Workerimport tempfile 39*9880d681SAndroid Build Coastguard Workerimport re 40*9880d681SAndroid Build Coastguard Worker 41*9880d681SAndroid Build Coastguard WorkerADVERT = '; NOTE: Assertions have been autogenerated by ' 42*9880d681SAndroid Build Coastguard Worker 43*9880d681SAndroid Build Coastguard Worker# RegEx: this is where the magic happens. 44*9880d681SAndroid Build Coastguard Worker 45*9880d681SAndroid Build Coastguard WorkerSCRUB_LEADING_WHITESPACE_RE = re.compile(r'^(\s+)') 46*9880d681SAndroid Build Coastguard WorkerSCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M) 47*9880d681SAndroid Build Coastguard WorkerSCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M) 48*9880d681SAndroid Build Coastguard WorkerSCRUB_X86_SHUFFLES_RE = ( 49*9880d681SAndroid Build Coastguard Worker re.compile( 50*9880d681SAndroid Build Coastguard Worker r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$', 51*9880d681SAndroid Build Coastguard Worker flags=re.M)) 52*9880d681SAndroid Build Coastguard WorkerSCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)') 53*9880d681SAndroid Build Coastguard WorkerSCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)') 54*9880d681SAndroid Build Coastguard WorkerSCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+') 55*9880d681SAndroid Build Coastguard WorkerSCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n') 56*9880d681SAndroid Build Coastguard WorkerSCRUB_IR_COMMENT_RE = re.compile(r'\s*;.*') 57*9880d681SAndroid Build Coastguard Worker 58*9880d681SAndroid Build Coastguard WorkerRUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$') 59*9880d681SAndroid Build Coastguard WorkerIR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@([\w-]+)\s*\(') 60*9880d681SAndroid Build Coastguard WorkerLLC_FUNCTION_RE = re.compile( 61*9880d681SAndroid Build Coastguard Worker r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' 62*9880d681SAndroid Build Coastguard Worker r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*' 63*9880d681SAndroid Build Coastguard Worker r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section)', 64*9880d681SAndroid Build Coastguard Worker flags=(re.M | re.S)) 65*9880d681SAndroid Build Coastguard WorkerOPT_FUNCTION_RE = re.compile( 66*9880d681SAndroid Build Coastguard Worker r'^\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w-]+?)\s*\(' 67*9880d681SAndroid Build Coastguard Worker r'(\s+)?[^{]*\{\n(?P<body>.*?)\}', 68*9880d681SAndroid Build Coastguard Worker flags=(re.M | re.S)) 69*9880d681SAndroid Build Coastguard WorkerCHECK_PREFIX_RE = re.compile('--check-prefix=(\S+)') 70*9880d681SAndroid Build Coastguard WorkerCHECK_RE = re.compile(r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:') 71*9880d681SAndroid Build Coastguard WorkerIR_VALUE_DEF_RE = re.compile(r'\s+%(.*) =') 72*9880d681SAndroid Build Coastguard Worker 73*9880d681SAndroid Build Coastguard Worker 74*9880d681SAndroid Build Coastguard Worker# Invoke the tool that is being tested. 75*9880d681SAndroid Build Coastguard Workerdef invoke_tool(args, cmd_args, ir): 76*9880d681SAndroid Build Coastguard Worker with open(ir) as ir_file: 77*9880d681SAndroid Build Coastguard Worker stdout = subprocess.check_output(args.tool_binary + ' ' + cmd_args, 78*9880d681SAndroid Build Coastguard Worker shell=True, stdin=ir_file) 79*9880d681SAndroid Build Coastguard Worker # Fix line endings to unix CR style. 80*9880d681SAndroid Build Coastguard Worker stdout = stdout.replace('\r\n', '\n') 81*9880d681SAndroid Build Coastguard Worker return stdout 82*9880d681SAndroid Build Coastguard Worker 83*9880d681SAndroid Build Coastguard Worker 84*9880d681SAndroid Build Coastguard Worker# FIXME: Separate the x86-specific scrubbers, so this can be used for other targets. 85*9880d681SAndroid Build Coastguard Workerdef scrub_asm(asm): 86*9880d681SAndroid Build Coastguard Worker # Detect shuffle asm comments and hide the operands in favor of the comments. 87*9880d681SAndroid Build Coastguard Worker asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm) 88*9880d681SAndroid Build Coastguard Worker # Generically match the stack offset of a memory operand. 89*9880d681SAndroid Build Coastguard Worker asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm) 90*9880d681SAndroid Build Coastguard Worker # Generically match a RIP-relative memory operand. 91*9880d681SAndroid Build Coastguard Worker asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm) 92*9880d681SAndroid Build Coastguard Worker # Generically match a LCP symbol. 93*9880d681SAndroid Build Coastguard Worker asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm) 94*9880d681SAndroid Build Coastguard Worker # Strip kill operands inserted into the asm. 95*9880d681SAndroid Build Coastguard Worker asm = SCRUB_KILL_COMMENT_RE.sub('', asm) 96*9880d681SAndroid Build Coastguard Worker return asm 97*9880d681SAndroid Build Coastguard Worker 98*9880d681SAndroid Build Coastguard Worker 99*9880d681SAndroid Build Coastguard Workerdef scrub_body(body, tool_basename): 100*9880d681SAndroid Build Coastguard Worker # Scrub runs of whitespace out of the assembly, but leave the leading 101*9880d681SAndroid Build Coastguard Worker # whitespace in place. 102*9880d681SAndroid Build Coastguard Worker body = SCRUB_WHITESPACE_RE.sub(r' ', body) 103*9880d681SAndroid Build Coastguard Worker # Expand the tabs used for indentation. 104*9880d681SAndroid Build Coastguard Worker body = string.expandtabs(body, 2) 105*9880d681SAndroid Build Coastguard Worker # Strip trailing whitespace. 106*9880d681SAndroid Build Coastguard Worker body = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', body) 107*9880d681SAndroid Build Coastguard Worker if tool_basename == "llc": 108*9880d681SAndroid Build Coastguard Worker body = scrub_asm(body) 109*9880d681SAndroid Build Coastguard Worker return body 110*9880d681SAndroid Build Coastguard Worker 111*9880d681SAndroid Build Coastguard Worker 112*9880d681SAndroid Build Coastguard Worker# Build up a dictionary of all the function bodies. 113*9880d681SAndroid Build Coastguard Workerdef build_function_body_dictionary(raw_tool_output, prefixes, func_dict, verbose, tool_basename): 114*9880d681SAndroid Build Coastguard Worker if tool_basename == "llc": 115*9880d681SAndroid Build Coastguard Worker func_regex = LLC_FUNCTION_RE 116*9880d681SAndroid Build Coastguard Worker else: 117*9880d681SAndroid Build Coastguard Worker func_regex = OPT_FUNCTION_RE 118*9880d681SAndroid Build Coastguard Worker for m in func_regex.finditer(raw_tool_output): 119*9880d681SAndroid Build Coastguard Worker if not m: 120*9880d681SAndroid Build Coastguard Worker continue 121*9880d681SAndroid Build Coastguard Worker func = m.group('func') 122*9880d681SAndroid Build Coastguard Worker scrubbed_body = scrub_body(m.group('body'), tool_basename) 123*9880d681SAndroid Build Coastguard Worker if func.startswith('stress'): 124*9880d681SAndroid Build Coastguard Worker # We only use the last line of the function body for stress tests. 125*9880d681SAndroid Build Coastguard Worker scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:]) 126*9880d681SAndroid Build Coastguard Worker if verbose: 127*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'Processing function: ' + func 128*9880d681SAndroid Build Coastguard Worker for l in scrubbed_body.splitlines(): 129*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, ' ' + l 130*9880d681SAndroid Build Coastguard Worker for prefix in prefixes: 131*9880d681SAndroid Build Coastguard Worker if func in func_dict[prefix] and func_dict[prefix][func] != scrubbed_body: 132*9880d681SAndroid Build Coastguard Worker if prefix == prefixes[-1]: 133*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, ('WARNING: Found conflicting asm under the ' 134*9880d681SAndroid Build Coastguard Worker 'same prefix: %r!' % (prefix,)) 135*9880d681SAndroid Build Coastguard Worker else: 136*9880d681SAndroid Build Coastguard Worker func_dict[prefix][func] = None 137*9880d681SAndroid Build Coastguard Worker continue 138*9880d681SAndroid Build Coastguard Worker 139*9880d681SAndroid Build Coastguard Worker func_dict[prefix][func] = scrubbed_body 140*9880d681SAndroid Build Coastguard Worker 141*9880d681SAndroid Build Coastguard Worker 142*9880d681SAndroid Build Coastguard Worker# Create a FileCheck variable name based on an IR name. 143*9880d681SAndroid Build Coastguard Workerdef get_value_name(var): 144*9880d681SAndroid Build Coastguard Worker if var.isdigit(): 145*9880d681SAndroid Build Coastguard Worker var = 'TMP' + var 146*9880d681SAndroid Build Coastguard Worker var = var.replace('.', '_') 147*9880d681SAndroid Build Coastguard Worker return var.upper() 148*9880d681SAndroid Build Coastguard Worker 149*9880d681SAndroid Build Coastguard Worker 150*9880d681SAndroid Build Coastguard Worker# Create a FileCheck variable from regex. 151*9880d681SAndroid Build Coastguard Workerdef get_value_definition(var): 152*9880d681SAndroid Build Coastguard Worker return '[[' + get_value_name(var) + ':%.*]]' 153*9880d681SAndroid Build Coastguard Worker 154*9880d681SAndroid Build Coastguard Worker 155*9880d681SAndroid Build Coastguard Worker# Use a FileCheck variable. 156*9880d681SAndroid Build Coastguard Workerdef get_value_use(var): 157*9880d681SAndroid Build Coastguard Worker return '[[' + get_value_name(var) + ']]' 158*9880d681SAndroid Build Coastguard Worker 159*9880d681SAndroid Build Coastguard Worker 160*9880d681SAndroid Build Coastguard Worker# Replace IR value defs and uses with FileCheck variables. 161*9880d681SAndroid Build Coastguard Workerdef genericize_check_lines(lines): 162*9880d681SAndroid Build Coastguard Worker lines_with_def = [] 163*9880d681SAndroid Build Coastguard Worker vars_seen = [] 164*9880d681SAndroid Build Coastguard Worker for line in lines: 165*9880d681SAndroid Build Coastguard Worker # An IR variable named '%.' matches the FileCheck regex string. 166*9880d681SAndroid Build Coastguard Worker line = line.replace('%.', '%dot') 167*9880d681SAndroid Build Coastguard Worker m = IR_VALUE_DEF_RE.match(line) 168*9880d681SAndroid Build Coastguard Worker if m: 169*9880d681SAndroid Build Coastguard Worker vars_seen.append(m.group(1)) 170*9880d681SAndroid Build Coastguard Worker line = line.replace('%' + m.group(1), get_value_definition(m.group(1))) 171*9880d681SAndroid Build Coastguard Worker 172*9880d681SAndroid Build Coastguard Worker lines_with_def.append(line) 173*9880d681SAndroid Build Coastguard Worker 174*9880d681SAndroid Build Coastguard Worker # A single def isn't worth replacing? 175*9880d681SAndroid Build Coastguard Worker #if len(vars_seen) < 2: 176*9880d681SAndroid Build Coastguard Worker # return lines 177*9880d681SAndroid Build Coastguard Worker 178*9880d681SAndroid Build Coastguard Worker output_lines = [] 179*9880d681SAndroid Build Coastguard Worker vars_seen.sort(key=len, reverse=True) 180*9880d681SAndroid Build Coastguard Worker for line in lines_with_def: 181*9880d681SAndroid Build Coastguard Worker for var in vars_seen: 182*9880d681SAndroid Build Coastguard Worker line = line.replace('%' + var, get_value_use(var)) 183*9880d681SAndroid Build Coastguard Worker output_lines.append(line) 184*9880d681SAndroid Build Coastguard Worker 185*9880d681SAndroid Build Coastguard Worker return output_lines 186*9880d681SAndroid Build Coastguard Worker 187*9880d681SAndroid Build Coastguard Worker 188*9880d681SAndroid Build Coastguard Workerdef add_checks(output_lines, prefix_list, func_dict, func_name, tool_basename): 189*9880d681SAndroid Build Coastguard Worker # Select a label format based on the whether we're checking asm or IR. 190*9880d681SAndroid Build Coastguard Worker if tool_basename == "llc": 191*9880d681SAndroid Build Coastguard Worker check_label_format = "; %s-LABEL: %s:" 192*9880d681SAndroid Build Coastguard Worker else: 193*9880d681SAndroid Build Coastguard Worker check_label_format = "; %s-LABEL: @%s(" 194*9880d681SAndroid Build Coastguard Worker 195*9880d681SAndroid Build Coastguard Worker printed_prefixes = [] 196*9880d681SAndroid Build Coastguard Worker for checkprefixes, _ in prefix_list: 197*9880d681SAndroid Build Coastguard Worker for checkprefix in checkprefixes: 198*9880d681SAndroid Build Coastguard Worker if checkprefix in printed_prefixes: 199*9880d681SAndroid Build Coastguard Worker break 200*9880d681SAndroid Build Coastguard Worker if not func_dict[checkprefix][func_name]: 201*9880d681SAndroid Build Coastguard Worker continue 202*9880d681SAndroid Build Coastguard Worker # Add some space between different check prefixes, but not after the last 203*9880d681SAndroid Build Coastguard Worker # check line (before the test code). 204*9880d681SAndroid Build Coastguard Worker #if len(printed_prefixes) != 0: 205*9880d681SAndroid Build Coastguard Worker # output_lines.append(';') 206*9880d681SAndroid Build Coastguard Worker printed_prefixes.append(checkprefix) 207*9880d681SAndroid Build Coastguard Worker output_lines.append(check_label_format % (checkprefix, func_name)) 208*9880d681SAndroid Build Coastguard Worker func_body = func_dict[checkprefix][func_name].splitlines() 209*9880d681SAndroid Build Coastguard Worker 210*9880d681SAndroid Build Coastguard Worker # For IR output, change all defs to FileCheck variables, so we're immune 211*9880d681SAndroid Build Coastguard Worker # to variable naming fashions. 212*9880d681SAndroid Build Coastguard Worker if tool_basename == "opt": 213*9880d681SAndroid Build Coastguard Worker func_body = genericize_check_lines(func_body) 214*9880d681SAndroid Build Coastguard Worker 215*9880d681SAndroid Build Coastguard Worker # This could be selectively enabled with an optional invocation argument. 216*9880d681SAndroid Build Coastguard Worker # Disabled for now: better to check everything. Be safe rather than sorry. 217*9880d681SAndroid Build Coastguard Worker 218*9880d681SAndroid Build Coastguard Worker # Handle the first line of the function body as a special case because 219*9880d681SAndroid Build Coastguard Worker # it's often just noise (a useless asm comment or entry label). 220*9880d681SAndroid Build Coastguard Worker #if func_body[0].startswith("#") or func_body[0].startswith("entry:"): 221*9880d681SAndroid Build Coastguard Worker # is_blank_line = True 222*9880d681SAndroid Build Coastguard Worker #else: 223*9880d681SAndroid Build Coastguard Worker # output_lines.append('; %s: %s' % (checkprefix, func_body[0])) 224*9880d681SAndroid Build Coastguard Worker # is_blank_line = False 225*9880d681SAndroid Build Coastguard Worker 226*9880d681SAndroid Build Coastguard Worker # For llc tests, there may be asm directives between the label and the 227*9880d681SAndroid Build Coastguard Worker # first checked line (most likely that first checked line is "# BB#0"). 228*9880d681SAndroid Build Coastguard Worker if tool_basename == "opt": 229*9880d681SAndroid Build Coastguard Worker is_blank_line = False 230*9880d681SAndroid Build Coastguard Worker else: 231*9880d681SAndroid Build Coastguard Worker is_blank_line = True; 232*9880d681SAndroid Build Coastguard Worker 233*9880d681SAndroid Build Coastguard Worker for func_line in func_body: 234*9880d681SAndroid Build Coastguard Worker if func_line.strip() == '': 235*9880d681SAndroid Build Coastguard Worker is_blank_line = True 236*9880d681SAndroid Build Coastguard Worker continue 237*9880d681SAndroid Build Coastguard Worker # Do not waste time checking IR comments. 238*9880d681SAndroid Build Coastguard Worker if tool_basename == "opt": 239*9880d681SAndroid Build Coastguard Worker func_line = SCRUB_IR_COMMENT_RE.sub(r'', func_line) 240*9880d681SAndroid Build Coastguard Worker 241*9880d681SAndroid Build Coastguard Worker # Skip blank lines instead of checking them. 242*9880d681SAndroid Build Coastguard Worker if is_blank_line == True: 243*9880d681SAndroid Build Coastguard Worker output_lines.append('; %s: %s' % (checkprefix, func_line)) 244*9880d681SAndroid Build Coastguard Worker else: 245*9880d681SAndroid Build Coastguard Worker output_lines.append('; %s-NEXT: %s' % (checkprefix, func_line)) 246*9880d681SAndroid Build Coastguard Worker is_blank_line = False 247*9880d681SAndroid Build Coastguard Worker 248*9880d681SAndroid Build Coastguard Worker # Add space between different check prefixes and also before the first 249*9880d681SAndroid Build Coastguard Worker # line of code in the test function. 250*9880d681SAndroid Build Coastguard Worker output_lines.append(';') 251*9880d681SAndroid Build Coastguard Worker break 252*9880d681SAndroid Build Coastguard Worker return output_lines 253*9880d681SAndroid Build Coastguard Worker 254*9880d681SAndroid Build Coastguard Worker 255*9880d681SAndroid Build Coastguard Workerdef should_add_line_to_output(input_line, prefix_set): 256*9880d681SAndroid Build Coastguard Worker # Skip any blank comment lines in the IR. 257*9880d681SAndroid Build Coastguard Worker if input_line.strip() == ';': 258*9880d681SAndroid Build Coastguard Worker return False 259*9880d681SAndroid Build Coastguard Worker # Skip any blank lines in the IR. 260*9880d681SAndroid Build Coastguard Worker #if input_line.strip() == '': 261*9880d681SAndroid Build Coastguard Worker # return False 262*9880d681SAndroid Build Coastguard Worker # And skip any CHECK lines. We're building our own. 263*9880d681SAndroid Build Coastguard Worker m = CHECK_RE.match(input_line) 264*9880d681SAndroid Build Coastguard Worker if m and m.group(1) in prefix_set: 265*9880d681SAndroid Build Coastguard Worker return False 266*9880d681SAndroid Build Coastguard Worker 267*9880d681SAndroid Build Coastguard Worker return True 268*9880d681SAndroid Build Coastguard Worker 269*9880d681SAndroid Build Coastguard Worker 270*9880d681SAndroid Build Coastguard Workerdef main(): 271*9880d681SAndroid Build Coastguard Worker from argparse import RawTextHelpFormatter 272*9880d681SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description=__doc__, formatter_class=RawTextHelpFormatter) 273*9880d681SAndroid Build Coastguard Worker parser.add_argument('-v', '--verbose', action='store_true', 274*9880d681SAndroid Build Coastguard Worker help='Show verbose output') 275*9880d681SAndroid Build Coastguard Worker parser.add_argument('--tool-binary', default='llc', 276*9880d681SAndroid Build Coastguard Worker help='The tool used to generate the test case') 277*9880d681SAndroid Build Coastguard Worker parser.add_argument( 278*9880d681SAndroid Build Coastguard Worker '--function', help='The function in the test file to update') 279*9880d681SAndroid Build Coastguard Worker parser.add_argument('tests', nargs='+') 280*9880d681SAndroid Build Coastguard Worker args = parser.parse_args() 281*9880d681SAndroid Build Coastguard Worker 282*9880d681SAndroid Build Coastguard Worker autogenerated_note = (ADVERT + 'utils/' + os.path.basename(__file__)) 283*9880d681SAndroid Build Coastguard Worker 284*9880d681SAndroid Build Coastguard Worker tool_basename = os.path.basename(args.tool_binary) 285*9880d681SAndroid Build Coastguard Worker if (tool_basename != "llc" and tool_basename != "opt"): 286*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'ERROR: Unexpected tool name: ' + tool_basename 287*9880d681SAndroid Build Coastguard Worker sys.exit(1) 288*9880d681SAndroid Build Coastguard Worker 289*9880d681SAndroid Build Coastguard Worker for test in args.tests: 290*9880d681SAndroid Build Coastguard Worker if args.verbose: 291*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'Scanning for RUN lines in test file: %s' % (test,) 292*9880d681SAndroid Build Coastguard Worker with open(test) as f: 293*9880d681SAndroid Build Coastguard Worker input_lines = [l.rstrip() for l in f] 294*9880d681SAndroid Build Coastguard Worker 295*9880d681SAndroid Build Coastguard Worker run_lines = [m.group(1) 296*9880d681SAndroid Build Coastguard Worker for m in [RUN_LINE_RE.match(l) for l in input_lines] if m] 297*9880d681SAndroid Build Coastguard Worker if args.verbose: 298*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'Found %d RUN lines:' % (len(run_lines),) 299*9880d681SAndroid Build Coastguard Worker for l in run_lines: 300*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, ' RUN: ' + l 301*9880d681SAndroid Build Coastguard Worker 302*9880d681SAndroid Build Coastguard Worker prefix_list = [] 303*9880d681SAndroid Build Coastguard Worker for l in run_lines: 304*9880d681SAndroid Build Coastguard Worker (tool_cmd, filecheck_cmd) = tuple([cmd.strip() for cmd in l.split('|', 1)]) 305*9880d681SAndroid Build Coastguard Worker 306*9880d681SAndroid Build Coastguard Worker if not tool_cmd.startswith(tool_basename + ' '): 307*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'WARNING: Skipping non-%s RUN line: %s' % (tool_basename, l) 308*9880d681SAndroid Build Coastguard Worker continue 309*9880d681SAndroid Build Coastguard Worker 310*9880d681SAndroid Build Coastguard Worker if not filecheck_cmd.startswith('FileCheck '): 311*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'WARNING: Skipping non-FileChecked RUN line: ' + l 312*9880d681SAndroid Build Coastguard Worker continue 313*9880d681SAndroid Build Coastguard Worker 314*9880d681SAndroid Build Coastguard Worker tool_cmd_args = tool_cmd[len(tool_basename):].strip() 315*9880d681SAndroid Build Coastguard Worker tool_cmd_args = tool_cmd_args.replace('< %s', '').replace('%s', '').strip() 316*9880d681SAndroid Build Coastguard Worker 317*9880d681SAndroid Build Coastguard Worker check_prefixes = [m.group(1) 318*9880d681SAndroid Build Coastguard Worker for m in CHECK_PREFIX_RE.finditer(filecheck_cmd)] 319*9880d681SAndroid Build Coastguard Worker if not check_prefixes: 320*9880d681SAndroid Build Coastguard Worker check_prefixes = ['CHECK'] 321*9880d681SAndroid Build Coastguard Worker 322*9880d681SAndroid Build Coastguard Worker # FIXME: We should use multiple check prefixes to common check lines. For 323*9880d681SAndroid Build Coastguard Worker # now, we just ignore all but the last. 324*9880d681SAndroid Build Coastguard Worker prefix_list.append((check_prefixes, tool_cmd_args)) 325*9880d681SAndroid Build Coastguard Worker 326*9880d681SAndroid Build Coastguard Worker func_dict = {} 327*9880d681SAndroid Build Coastguard Worker for prefixes, _ in prefix_list: 328*9880d681SAndroid Build Coastguard Worker for prefix in prefixes: 329*9880d681SAndroid Build Coastguard Worker func_dict.update({prefix: dict()}) 330*9880d681SAndroid Build Coastguard Worker for prefixes, tool_args in prefix_list: 331*9880d681SAndroid Build Coastguard Worker if args.verbose: 332*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'Extracted tool cmd: ' + tool_basename + ' ' + tool_args 333*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'Extracted FileCheck prefixes: ' + str(prefixes) 334*9880d681SAndroid Build Coastguard Worker 335*9880d681SAndroid Build Coastguard Worker raw_tool_output = invoke_tool(args, tool_args, test) 336*9880d681SAndroid Build Coastguard Worker build_function_body_dictionary(raw_tool_output, prefixes, func_dict, args.verbose, tool_basename) 337*9880d681SAndroid Build Coastguard Worker 338*9880d681SAndroid Build Coastguard Worker is_in_function = False 339*9880d681SAndroid Build Coastguard Worker is_in_function_start = False 340*9880d681SAndroid Build Coastguard Worker prefix_set = set([prefix for prefixes, _ in prefix_list for prefix in prefixes]) 341*9880d681SAndroid Build Coastguard Worker if args.verbose: 342*9880d681SAndroid Build Coastguard Worker print >>sys.stderr, 'Rewriting FileCheck prefixes: %s' % (prefix_set,) 343*9880d681SAndroid Build Coastguard Worker output_lines = [] 344*9880d681SAndroid Build Coastguard Worker output_lines.append(autogenerated_note) 345*9880d681SAndroid Build Coastguard Worker 346*9880d681SAndroid Build Coastguard Worker for input_line in input_lines: 347*9880d681SAndroid Build Coastguard Worker if is_in_function_start: 348*9880d681SAndroid Build Coastguard Worker if input_line == '': 349*9880d681SAndroid Build Coastguard Worker continue 350*9880d681SAndroid Build Coastguard Worker if input_line.lstrip().startswith(';'): 351*9880d681SAndroid Build Coastguard Worker m = CHECK_RE.match(input_line) 352*9880d681SAndroid Build Coastguard Worker if not m or m.group(1) not in prefix_set: 353*9880d681SAndroid Build Coastguard Worker output_lines.append(input_line) 354*9880d681SAndroid Build Coastguard Worker continue 355*9880d681SAndroid Build Coastguard Worker 356*9880d681SAndroid Build Coastguard Worker # Print out the various check lines here. 357*9880d681SAndroid Build Coastguard Worker output_lines = add_checks(output_lines, prefix_list, func_dict, name, tool_basename) 358*9880d681SAndroid Build Coastguard Worker is_in_function_start = False 359*9880d681SAndroid Build Coastguard Worker 360*9880d681SAndroid Build Coastguard Worker if is_in_function: 361*9880d681SAndroid Build Coastguard Worker if should_add_line_to_output(input_line, prefix_set) == True: 362*9880d681SAndroid Build Coastguard Worker # This input line of the function body will go as-is into the output. 363*9880d681SAndroid Build Coastguard Worker # Except make leading whitespace uniform: 2 spaces. 364*9880d681SAndroid Build Coastguard Worker input_line = SCRUB_LEADING_WHITESPACE_RE.sub(r' ', input_line) 365*9880d681SAndroid Build Coastguard Worker output_lines.append(input_line) 366*9880d681SAndroid Build Coastguard Worker else: 367*9880d681SAndroid Build Coastguard Worker continue 368*9880d681SAndroid Build Coastguard Worker if input_line.strip() == '}': 369*9880d681SAndroid Build Coastguard Worker is_in_function = False 370*9880d681SAndroid Build Coastguard Worker continue 371*9880d681SAndroid Build Coastguard Worker 372*9880d681SAndroid Build Coastguard Worker # Discard any previous script advertising. 373*9880d681SAndroid Build Coastguard Worker if input_line.startswith(ADVERT): 374*9880d681SAndroid Build Coastguard Worker continue 375*9880d681SAndroid Build Coastguard Worker 376*9880d681SAndroid Build Coastguard Worker # If it's outside a function, it just gets copied to the output. 377*9880d681SAndroid Build Coastguard Worker output_lines.append(input_line) 378*9880d681SAndroid Build Coastguard Worker 379*9880d681SAndroid Build Coastguard Worker m = IR_FUNCTION_RE.match(input_line) 380*9880d681SAndroid Build Coastguard Worker if not m: 381*9880d681SAndroid Build Coastguard Worker continue 382*9880d681SAndroid Build Coastguard Worker name = m.group(1) 383*9880d681SAndroid Build Coastguard Worker if args.function is not None and name != args.function: 384*9880d681SAndroid Build Coastguard Worker # When filtering on a specific function, skip all others. 385*9880d681SAndroid Build Coastguard Worker continue 386*9880d681SAndroid Build Coastguard Worker is_in_function = is_in_function_start = True 387*9880d681SAndroid Build Coastguard Worker 388*9880d681SAndroid Build Coastguard Worker if args.verbose: 389*9880d681SAndroid Build Coastguard Worker print>>sys.stderr, 'Writing %d lines to %s...' % (len(output_lines), test) 390*9880d681SAndroid Build Coastguard Worker 391*9880d681SAndroid Build Coastguard Worker with open(test, 'wb') as f: 392*9880d681SAndroid Build Coastguard Worker f.writelines([l + '\n' for l in output_lines]) 393*9880d681SAndroid Build Coastguard Worker 394*9880d681SAndroid Build Coastguard Worker 395*9880d681SAndroid Build Coastguard Workerif __name__ == '__main__': 396*9880d681SAndroid Build Coastguard Worker main() 397*9880d681SAndroid Build Coastguard Worker 398