xref: /aosp_15_r20/external/llvm/utils/update_test_checks.py (revision 9880d6810fe72a1726cb53787c6711e909410d58)
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