#!/usr/bin/env python3 # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception """A test case update script. This script is a utility to update LLVM 'llubi' based test cases with new FileCheck patterns. """ from __future__ import print_function from sys import stderr from traceback import print_exc import argparse import os import subprocess import sys from UpdateTestChecks import common # Invoke the tool that is being tested. def invoke_tool(exe, cmd_args, ir, check_rc): with open(ir) as ir_file: substitutions = common.getSubstitutions(ir) stdout = subprocess.run( exe + " " + common.applySubstitutions(cmd_args, substitutions), shell=True, stdin=ir_file, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=check_rc, ).stdout.decode() # Fix line endings to unix CR style. return stdout.replace("\r\n", "\n") def update_test(ti: common.TestInfo): if len(ti.run_lines) == 0: common.warn("No RUN lines found in test: " + ti.path) return if len(ti.run_lines) > 1: common.warn("Multiple RUN lines found in test: " + ti.path) common.warn("Only the first RUN line will be processed.") l = ti.run_lines[0] if "|" not in l: common.warn("Skipping unparsable RUN line: " + l) return commands = [cmd.strip() for cmd in l.split("|")] assert len(commands) == 2 llubi_cmd = commands[-2] filecheck_cmd = commands[-1] args = llubi_cmd.split(" ") llubi_tool = args[0] check_rc = True if len(args) > 1 and args[0] == "not": llubi_tool = args[1] check_rc = False common.verify_filecheck_prefixes(filecheck_cmd) if llubi_tool != "llubi": common.warn("Skipping non-llubi RUN line: " + l) return if not filecheck_cmd.startswith("FileCheck "): common.warn("Skipping non-FileChecked RUN line: " + l) return llubi_args = llubi_cmd[llubi_cmd.index(llubi_tool) + len(llubi_tool) :].strip() llubi_args = llubi_args.replace("< %s", "").replace("%s", "").strip() prefixes = common.get_check_prefixes(filecheck_cmd) common.debug("Extracted llubi cmd:", llubi_tool, llubi_args) common.debug("Extracted FileCheck prefixes:", str(prefixes)) prefix_set = set([prefix for prefix in prefixes]) raw_tool_output = invoke_tool( ti.args.llubi_binary or llubi_tool, llubi_args, ti.path, check_rc=check_rc, ) if ti.args.llubi_binary: raw_tool_output = raw_tool_output.replace(ti.args.llubi_binary, llubi_tool) output_lines = [] common.dump_input_lines(output_lines, ti, prefix_set, ";") tool_output_lines = raw_tool_output.splitlines() if len(tool_output_lines) == 0: common.warn("No output from llubi.") else: output_lines.append("; CHECK: " + tool_output_lines[0]) output_lines.extend(["; CHECK-NEXT: " + line for line in tool_output_lines[1:]]) common.debug("Writing %d lines to %s..." % (len(output_lines), ti.path)) with open(ti.path, "wb") as f: f.writelines(["{}\n".format(l).encode("utf-8") for l in output_lines]) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "--llubi-binary", default=None, help='The "llubi" binary to use to generate the test case', ) parser.add_argument( "--tool", default=None, help="Treat the given tool name as an llubi-like tool for which check lines should be generated", ) parser.add_argument("tests", nargs="+") initial_args = common.parse_commandline_args(parser) script_name = os.path.basename(__file__) returncode = 0 for ti in common.itertests( initial_args.tests, parser, script_name="utils/" + script_name ): try: update_test(ti) except Exception as e: stderr.write(f"Error: Failed to update test {ti.path}\n") print_exc() returncode = 1 return returncode if __name__ == "__main__": sys.exit(main())