[NFC][Py Reformat] Reformat python files in llvm
[llvm-project.git] / llvm / utils / update_llc_test_checks.py
blob1ed0132781e2b59140357ad7d0f157849864cffe
1 #!/usr/bin/env python3
3 """A test case update script.
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 """
10 from __future__ import print_function
12 import argparse
13 import os # Used to advertise this file's name ("autogenerated_note").
15 from UpdateTestChecks import common
17 # llc is the only llc-like in the LLVM tree but downstream forks can add
18 # additional ones here if they have them.
19 LLC_LIKE_TOOLS = ("llc",)
22 def main():
23 parser = argparse.ArgumentParser(description=__doc__)
24 parser.add_argument(
25 "--llc-binary",
26 default=None,
27 help='The "llc" binary to use to generate the test case',
29 parser.add_argument("--function", help="The function in the test file to update")
30 parser.add_argument(
31 "--extra_scrub",
32 action="store_true",
33 help="Always use additional regex to further reduce diffs between various subtargets",
35 parser.add_argument(
36 "--x86_scrub_sp",
37 action="store_true",
38 default=True,
39 help="Use regex for x86 sp matching to reduce diffs between various subtargets",
41 parser.add_argument("--no_x86_scrub_sp", action="store_false", dest="x86_scrub_sp")
42 parser.add_argument(
43 "--x86_scrub_rip",
44 action="store_true",
45 default=False,
46 help="Use more regex for x86 rip matching to reduce diffs between various subtargets",
48 parser.add_argument(
49 "--no_x86_scrub_rip", action="store_false", dest="x86_scrub_rip"
51 parser.add_argument(
52 "--no_x86_scrub_mem_shuffle",
53 action="store_true",
54 default=False,
55 help="Reduce scrubbing shuffles with memory operands",
57 parser.add_argument("tests", nargs="+")
58 initial_args = common.parse_commandline_args(parser)
60 script_name = os.path.basename(__file__)
62 for ti in common.itertests(
63 initial_args.tests, parser, script_name="utils/" + script_name
65 triple_in_ir = None
66 for l in ti.input_lines:
67 m = common.TRIPLE_IR_RE.match(l)
68 if m:
69 triple_in_ir = m.groups()[0]
70 break
72 run_list = []
73 for l in ti.run_lines:
74 if "|" not in l:
75 common.warn("Skipping unparsable RUN line: " + l)
76 continue
78 commands = [cmd.strip() for cmd in l.split("|")]
79 assert len(commands) >= 2
80 preprocess_cmd = None
81 if len(commands) > 2:
82 preprocess_cmd = " | ".join(commands[:-2])
83 llc_cmd = commands[-2]
84 filecheck_cmd = commands[-1]
85 llc_tool = llc_cmd.split(" ")[0]
87 triple_in_cmd = None
88 m = common.TRIPLE_ARG_RE.search(llc_cmd)
89 if m:
90 triple_in_cmd = m.groups()[0]
92 march_in_cmd = None
93 m = common.MARCH_ARG_RE.search(llc_cmd)
94 if m:
95 march_in_cmd = m.groups()[0]
97 m = common.DEBUG_ONLY_ARG_RE.search(llc_cmd)
98 if m and m.groups()[0] == "isel":
99 from UpdateTestChecks import isel as output_type
100 else:
101 from UpdateTestChecks import asm as output_type
103 common.verify_filecheck_prefixes(filecheck_cmd)
104 if llc_tool not in LLC_LIKE_TOOLS:
105 common.warn("Skipping non-llc RUN line: " + l)
106 continue
108 if not filecheck_cmd.startswith("FileCheck "):
109 common.warn("Skipping non-FileChecked RUN line: " + l)
110 continue
112 llc_cmd_args = llc_cmd[len(llc_tool) :].strip()
113 llc_cmd_args = llc_cmd_args.replace("< %s", "").replace("%s", "").strip()
114 if ti.path.endswith(".mir"):
115 llc_cmd_args += " -x mir"
116 check_prefixes = common.get_check_prefixes(filecheck_cmd)
118 # FIXME: We should use multiple check prefixes to common check lines. For
119 # now, we just ignore all but the last.
120 run_list.append(
122 check_prefixes,
123 llc_tool,
124 llc_cmd_args,
125 preprocess_cmd,
126 triple_in_cmd,
127 march_in_cmd,
131 if ti.path.endswith(".mir"):
132 check_indent = " "
133 else:
134 check_indent = ""
136 builder = common.FunctionTestBuilder(
137 run_list=run_list,
138 flags=type(
140 (object,),
142 "verbose": ti.args.verbose,
143 "filters": ti.args.filters,
144 "function_signature": False,
145 "check_attributes": False,
146 "replace_value_regex": [],
149 scrubber_args=[ti.args],
150 path=ti.path,
153 for (
154 prefixes,
155 llc_tool,
156 llc_args,
157 preprocess_cmd,
158 triple_in_cmd,
159 march_in_cmd,
160 ) in run_list:
161 common.debug("Extracted LLC cmd:", llc_tool, llc_args)
162 common.debug("Extracted FileCheck prefixes:", str(prefixes))
164 raw_tool_output = common.invoke_tool(
165 ti.args.llc_binary or llc_tool,
166 llc_args,
167 ti.path,
168 preprocess_cmd,
169 verbose=ti.args.verbose,
171 triple = triple_in_cmd or triple_in_ir
172 if not triple:
173 triple = common.get_triple_from_march(march_in_cmd)
175 scrubber, function_re = output_type.get_run_handler(triple)
176 builder.process_run_line(
177 function_re, scrubber, raw_tool_output, prefixes, True
179 builder.processed_prefixes(prefixes)
181 func_dict = builder.finish_and_get_func_dict()
182 global_vars_seen_dict = {}
184 is_in_function = False
185 is_in_function_start = False
186 func_name = None
187 prefix_set = set([prefix for p in run_list for prefix in p[0]])
188 common.debug("Rewriting FileCheck prefixes:", str(prefix_set))
189 output_lines = []
191 include_generated_funcs = common.find_arg_in_test(
193 lambda args: ti.args.include_generated_funcs,
194 "--include-generated-funcs",
195 True,
198 generated_prefixes = []
199 if include_generated_funcs:
200 # Generate the appropriate checks for each function. We need to emit
201 # these in the order according to the generated output so that CHECK-LABEL
202 # works properly. func_order provides that.
204 # We can't predict where various passes might insert functions so we can't
205 # be sure the input function order is maintained. Therefore, first spit
206 # out all the source lines.
207 common.dump_input_lines(output_lines, ti, prefix_set, ";")
209 # Now generate all the checks.
210 generated_prefixes = common.add_checks_at_end(
211 output_lines,
212 run_list,
213 builder.func_order(),
214 check_indent + ";",
215 lambda my_output_lines, prefixes, func: output_type.add_checks(
216 my_output_lines,
217 check_indent + ";",
218 prefixes,
219 func_dict,
220 func,
221 global_vars_seen_dict,
222 is_filtered=builder.is_filtered(),
225 else:
226 for input_info in ti.iterlines(output_lines):
227 input_line = input_info.line
228 args = input_info.args
229 if is_in_function_start:
230 if input_line == "":
231 continue
232 if input_line.lstrip().startswith(";"):
233 m = common.CHECK_RE.match(input_line)
234 if not m or m.group(1) not in prefix_set:
235 output_lines.append(input_line)
236 continue
238 # Print out the various check lines here.
239 generated_prefixes.extend(
240 output_type.add_checks(
241 output_lines,
242 check_indent + ";",
243 run_list,
244 func_dict,
245 func_name,
246 global_vars_seen_dict,
247 is_filtered=builder.is_filtered(),
250 is_in_function_start = False
252 if is_in_function:
253 if common.should_add_line_to_output(input_line, prefix_set):
254 # This input line of the function body will go as-is into the output.
255 output_lines.append(input_line)
256 else:
257 continue
258 if input_line.strip() == "}":
259 is_in_function = False
260 continue
262 # If it's outside a function, it just gets copied to the output.
263 output_lines.append(input_line)
265 m = common.IR_FUNCTION_RE.match(input_line)
266 if not m:
267 continue
268 func_name = m.group(1)
269 if args.function is not None and func_name != args.function:
270 # When filtering on a specific function, skip all others.
271 continue
272 is_in_function = is_in_function_start = True
274 if ti.args.gen_unused_prefix_body:
275 output_lines.extend(
276 ti.get_checks_for_unused_prefixes(run_list, generated_prefixes)
279 common.debug("Writing %d lines to %s..." % (len(output_lines), ti.path))
280 with open(ti.path, "wb") as f:
281 f.writelines(["{}\n".format(l).encode("utf-8") for l in output_lines])
284 if __name__ == "__main__":
285 main()