OSDN Git Service

gn build: Merge r366361.
[android-x86/external-llvm.git] / utils / update_llc_test_checks.py
1 #!/usr/bin/env python
2
3 """A test case update script.
4
5 This script is a utility to update LLVM 'llc' based test cases with new
6 FileCheck patterns. It can either update all of the tests in the file or
7 a single test function.
8 """
9
10 from __future__ import print_function
11
12 import argparse
13 import glob
14 import os         # Used to advertise this file's name ("autogenerated_note").
15 import string
16 import subprocess
17 import sys
18 import re
19
20 from UpdateTestChecks import asm, common
21
22 ADVERT = '; NOTE: Assertions have been autogenerated by '
23
24
25 def main():
26   parser = argparse.ArgumentParser(description=__doc__)
27   parser.add_argument('-v', '--verbose', action='store_true',
28                       help='Show verbose output')
29   parser.add_argument('--llc-binary', default='llc',
30                       help='The "llc" binary to use to generate the test case')
31   parser.add_argument(
32       '--function', help='The function in the test file to update')
33   parser.add_argument(
34       '--extra_scrub', action='store_true',
35       help='Always use additional regex to further reduce diffs between various subtargets')
36   parser.add_argument(
37       '--x86_scrub_rip', action='store_true', default=True,
38       help='Use more regex for x86 matching to reduce diffs between various subtargets')
39   parser.add_argument(
40       '--no_x86_scrub_rip', action='store_false', dest='x86_scrub_rip')
41   parser.add_argument('tests', nargs='+')
42   args = parser.parse_args()
43
44   autogenerated_note = (ADVERT + 'utils/' + os.path.basename(__file__))
45
46   test_paths = [test for pattern in args.tests for test in glob.glob(pattern)]
47   for test in test_paths:
48     if args.verbose:
49       print('Scanning for RUN lines in test file: %s' % (test,), file=sys.stderr)
50     with open(test) as f:
51       input_lines = [l.rstrip() for l in f]
52
53     triple_in_ir = None
54     for l in input_lines:
55       m = common.TRIPLE_IR_RE.match(l)
56       if m:
57         triple_in_ir = m.groups()[0]
58         break
59
60     raw_lines = [m.group(1)
61                  for m in [common.RUN_LINE_RE.match(l) for l in input_lines] if m]
62     run_lines = [raw_lines[0]] if len(raw_lines) > 0 else []
63     for l in raw_lines[1:]:
64       if run_lines[-1].endswith("\\"):
65         run_lines[-1] = run_lines[-1].rstrip("\\") + " " + l
66       else:
67         run_lines.append(l)
68
69     if args.verbose:
70       print('Found %d RUN lines:' % (len(run_lines),), file=sys.stderr)
71       for l in run_lines:
72         print('  RUN: ' + l, file=sys.stderr)
73
74     run_list = []
75     for l in run_lines:
76       commands = [cmd.strip() for cmd in l.split('|', 1)]
77       llc_cmd = commands[0]
78
79       triple_in_cmd = None
80       m = common.TRIPLE_ARG_RE.search(llc_cmd)
81       if m:
82         triple_in_cmd = m.groups()[0]
83
84       march_in_cmd = None
85       m = common.MARCH_ARG_RE.search(llc_cmd)
86       if m:
87         march_in_cmd = m.groups()[0]
88
89       filecheck_cmd = ''
90       if len(commands) > 1:
91         filecheck_cmd = commands[1]
92       if not llc_cmd.startswith('llc '):
93         print('WARNING: Skipping non-llc RUN line: ' + l, file=sys.stderr)
94         continue
95
96       if not filecheck_cmd.startswith('FileCheck '):
97         print('WARNING: Skipping non-FileChecked RUN line: ' + l, file=sys.stderr)
98         continue
99
100       llc_cmd_args = llc_cmd[len('llc'):].strip()
101       llc_cmd_args = llc_cmd_args.replace('< %s', '').replace('%s', '').strip()
102
103       check_prefixes = [item for m in common.CHECK_PREFIX_RE.finditer(filecheck_cmd)
104                                for item in m.group(1).split(',')]
105       if not check_prefixes:
106         check_prefixes = ['CHECK']
107
108       # FIXME: We should use multiple check prefixes to common check lines. For
109       # now, we just ignore all but the last.
110       run_list.append((check_prefixes, llc_cmd_args, triple_in_cmd, march_in_cmd))
111
112     func_dict = {}
113     for p in run_list:
114       prefixes = p[0]
115       for prefix in prefixes:
116         func_dict.update({prefix: dict()})
117     for prefixes, llc_args, triple_in_cmd, march_in_cmd in run_list:
118       if args.verbose:
119         print('Extracted LLC cmd: llc ' + llc_args, file=sys.stderr)
120         print('Extracted FileCheck prefixes: ' + str(prefixes), file=sys.stderr)
121
122       raw_tool_output = common.invoke_tool(args.llc_binary, llc_args, test)
123       triple = triple_in_cmd or triple_in_ir
124       if not triple:
125         triple = asm.get_triple_from_march(march_in_cmd)
126
127       asm.build_function_body_dictionary_for_triple(args, raw_tool_output,
128           triple, prefixes, func_dict)
129
130     is_in_function = False
131     is_in_function_start = False
132     func_name = None
133     prefix_set = set([prefix for p in run_list for prefix in p[0]])
134     if args.verbose:
135       print('Rewriting FileCheck prefixes: %s' % (prefix_set,), file=sys.stderr)
136     output_lines = []
137     output_lines.append(autogenerated_note)
138
139     for input_line in input_lines:
140       if is_in_function_start:
141         if input_line == '':
142           continue
143         if input_line.lstrip().startswith(';'):
144           m = common.CHECK_RE.match(input_line)
145           if not m or m.group(1) not in prefix_set:
146             output_lines.append(input_line)
147             continue
148
149         # Print out the various check lines here.
150         asm.add_asm_checks(output_lines, ';', run_list, func_dict, func_name)
151         is_in_function_start = False
152
153       if is_in_function:
154         if common.should_add_line_to_output(input_line, prefix_set):
155           # This input line of the function body will go as-is into the output.
156           output_lines.append(input_line)
157         else:
158           continue
159         if input_line.strip() == '}':
160           is_in_function = False
161         continue
162
163       # Discard any previous script advertising.
164       if input_line.startswith(ADVERT):
165         continue
166
167       # If it's outside a function, it just gets copied to the output.
168       output_lines.append(input_line)
169
170       m = common.IR_FUNCTION_RE.match(input_line)
171       if not m:
172         continue
173       func_name = m.group(1)
174       if args.function is not None and func_name != args.function:
175         # When filtering on a specific function, skip all others.
176         continue
177       is_in_function = is_in_function_start = True
178
179     if args.verbose:
180       print('Writing %d lines to %s...' % (len(output_lines), test), file=sys.stderr)
181
182     with open(test, 'wb') as f:
183       f.writelines(['{}\n'.format(l).encode('utf-8') for l in output_lines])
184
185
186 if __name__ == '__main__':
187   main()