brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.8 KiB · 98864be Raw
383 lines · python
1#!/usr/bin/env python32 3"""A test case update script.4 5This script is a utility to update LLVM 'llc' based test cases with new6FileCheck patterns. It can either update all of the tests in the file or7a single test function.8"""9 10from __future__ import print_function11 12from sys import stderr13from traceback import print_exc14import argparse15import os  # Used to advertise this file's name ("autogenerated_note").16import sys17 18from UpdateTestChecks import common, mir19 20# llc is the only llc-like in the LLVM tree but downstream forks can add21# additional ones here if they have them.22LLC_LIKE_TOOLS = [23    "llc",24]25 26 27def update_test(ti: common.TestInfo):28    triple_in_ir = None29    for l in ti.input_lines:30        m = common.TRIPLE_IR_RE.match(l)31        if m:32            triple_in_ir = m.groups()[0]33            break34 35    run_list = []36    mir_run_list = []37    for l in ti.run_lines:38        if "|" not in l:39            common.warn("Skipping unparsable RUN line: " + l)40            continue41 42        commands = [cmd.strip() for cmd in l.split("|")]43        assert len(commands) >= 244        preprocess_cmd = None45        if len(commands) > 2:46            preprocess_cmd = " | ".join(commands[:-2])47        llc_cmd = commands[-2]48        filecheck_cmd = commands[-1]49        llc_tool = llc_cmd.split(" ")[0]50 51        triple_in_cmd = None52        m = common.TRIPLE_ARG_RE.search(llc_cmd)53        if m:54            triple_in_cmd = m.groups()[0]55 56        march_in_cmd = ti.args.default_march57        m = common.MARCH_ARG_RE.search(llc_cmd)58        if m:59            march_in_cmd = m.groups()[0]60 61        target_list = run_list62        m = common.DEBUG_ONLY_ARG_RE.search(llc_cmd)63        if m and m.groups()[0] == "isel":64            from UpdateTestChecks import isel as output_type65        elif not m and common.STOP_PASS_RE.search(llc_cmd):66            # MIR output mode. If -debug-only is present assume67            # the debug output is the main point of interest.68            target_list = mir_run_list69        else:70            from UpdateTestChecks import asm as output_type71 72        common.verify_filecheck_prefixes(filecheck_cmd)73 74        llc_like_tools = LLC_LIKE_TOOLS[:]75        if ti.args.tool:76            llc_like_tools.append(ti.args.tool)77        if llc_tool not in llc_like_tools:78            common.warn("Skipping non-llc RUN line: " + l)79            continue80 81        if not filecheck_cmd.startswith("FileCheck "):82            common.warn("Skipping non-FileChecked RUN line: " + l)83            continue84 85        llc_cmd_args = llc_cmd[len(llc_tool) :].strip()86        llc_cmd_args = llc_cmd_args.replace("< %s", "").replace("%s", "").strip()87        if ti.path.endswith(".mir"):88            llc_cmd_args += " -x mir"89        check_prefixes = common.get_check_prefixes(filecheck_cmd)90 91        # FIXME: We should use multiple check prefixes to common check lines. For92        # now, we just ignore all but the last.93        target_list.append(94            (95                check_prefixes,96                llc_tool,97                llc_cmd_args,98                preprocess_cmd,99                triple_in_cmd,100                march_in_cmd,101            )102        )103 104    if ti.path.endswith(".mir"):105        check_indent = "  "106    else:107        check_indent = ""108 109    ginfo = common.make_asm_generalizer(version=1)110    builder = common.FunctionTestBuilder(111        run_list=run_list,112        flags=type(113            "",114            (object,),115            {116                "verbose": ti.args.verbose,117                "filters": ti.args.filters,118                "function_signature": False,119                "check_attributes": False,120                "replace_value_regex": [],121            },122        ),123        scrubber_args=[ti.args],124        path=ti.path,125        ginfo=ginfo,126    )127 128    # Dictionary to store MIR function bodies separately129    mir_func_dict = {}130    for run_tuple, is_mir in [(run, False) for run in run_list] + [131        (run, True) for run in mir_run_list132    ]:133        (134            prefixes,135            llc_tool,136            llc_args,137            preprocess_cmd,138            triple_in_cmd,139            march_in_cmd,140        ) = run_tuple141 142        common.debug("Extracted LLC cmd:", llc_tool, llc_args)143        common.debug("Extracted FileCheck prefixes:", str(prefixes))144 145        raw_tool_output = common.invoke_tool(146            ti.args.llc_binary or llc_tool,147            llc_args,148            ti.path,149            preprocess_cmd,150            verbose=ti.args.verbose,151        )152        triple = triple_in_cmd or triple_in_ir153        if not triple:154            triple = common.get_triple_from_march(march_in_cmd)155 156        if is_mir:157            # MIR output mode158            common.debug("Detected MIR output mode for prefixes:", str(prefixes))159            for prefix in prefixes:160                if prefix not in mir_func_dict:161                    mir_func_dict[prefix] = {}162 163            mir.build_function_info_dictionary(164                ti.path,165                raw_tool_output,166                triple,167                prefixes,168                mir_func_dict,169                ti.args.verbose,170            )171        else:172            # ASM output mode173            scrubber, function_re = output_type.get_run_handler(triple)174            if 0 == builder.process_run_line(175                function_re, scrubber, raw_tool_output, prefixes176            ):177                common.warn(178                    "Couldn't match any function. Possibly the wrong target triple has been provided"179                )180            builder.processed_prefixes(prefixes)181 182    func_dict = builder.finish_and_get_func_dict()183 184    # Check for conflicts: same prefix used for both ASM and MIR185    conflicting_prefixes = set(func_dict.keys()) & set(mir_func_dict.keys())186    if conflicting_prefixes:187        common.warn(188            "The following prefixes are used for both ASM and MIR output, which will cause FileCheck failures: {}".format(189                ", ".join(sorted(conflicting_prefixes))190            ),191            test_file=ti.path,192        )193        for prefix in conflicting_prefixes:194            mir_func_dict[prefix] = {}195            func_dict[prefix] = {}196 197    global_vars_seen_dict = {}198 199    is_in_function = False200    is_in_function_start = False201    func_name = None202    prefix_set = set([prefix for p in run_list for prefix in p[0]])203    prefix_set.update([prefix for p in mir_run_list for prefix in p[0]])204    common.debug("Rewriting FileCheck prefixes:", str(prefix_set))205    output_lines = []206 207    include_generated_funcs = common.find_arg_in_test(208        ti,209        lambda args: ti.args.include_generated_funcs,210        "--include-generated-funcs",211        True,212    )213 214    generated_prefixes = []215    if include_generated_funcs:216        # Generate the appropriate checks for each function.  We need to emit217        # these in the order according to the generated output so that CHECK-LABEL218        # works properly.  func_order provides that.219 220        # We can't predict where various passes might insert functions so we can't221        # be sure the input function order is maintained.  Therefore, first spit222        # out all the source lines.223        common.dump_input_lines(output_lines, ti, prefix_set, ";")224 225        # Now generate all the checks.226        generated_prefixes = common.add_checks_at_end(227            output_lines,228            run_list,229            builder.func_order(),230            check_indent + ";",231            lambda my_output_lines, prefixes, func: output_type.add_checks(232                my_output_lines,233                check_indent + ";",234                prefixes,235                func_dict,236                func,237                ginfo,238                global_vars_seen_dict,239                is_filtered=builder.is_filtered(),240            ),241        )242    else:243        for input_info in ti.iterlines(output_lines):244            input_line = input_info.line245            args = input_info.args246            if is_in_function_start:247                if input_line == "":248                    continue249                if input_line.lstrip().startswith(";"):250                    m = common.CHECK_RE.match(input_line)251                    if not m or m.group(1) not in prefix_set:252                        output_lines.append(input_line)253                        continue254 255                # Print out the various check lines here.256                generated_prefixes.extend(257                    output_type.add_checks(258                        output_lines,259                        check_indent + ";",260                        run_list,261                        func_dict,262                        func_name,263                        ginfo,264                        global_vars_seen_dict,265                        is_filtered=builder.is_filtered(),266                    )267                )268 269                # Also add MIR checks if we have them for this function270                if mir_run_list and func_name:271                    mir.add_mir_checks_for_function(272                        ti.path,273                        output_lines,274                        mir_run_list,275                        mir_func_dict,276                        func_name,277                        single_bb=False,  # Don't skip basic block labels.278                        print_fixed_stack=False,  # Don't print fixed stack (ASM tests don't need it).279                        first_check_is_next=False,  # First check is LABEL, not NEXT.280                        at_the_function_name=False,  # Use "name:" not "@name".281                        check_indent="",  # No indentation for IR files (not MIR files).282                    )283 284                is_in_function_start = False285 286            if is_in_function:287                if common.should_add_line_to_output(input_line, prefix_set):288                    # This input line of the function body will go as-is into the output.289                    output_lines.append(input_line)290                else:291                    continue292                if input_line.strip() == "}":293                    is_in_function = False294                continue295 296            # If it's outside a function, it just gets copied to the output.297            output_lines.append(input_line)298 299            m = common.IR_FUNCTION_RE.match(input_line)300            if not m:301                continue302            func_name = m.group(1)303            if args.function is not None and func_name != args.function:304                # When filtering on a specific function, skip all others.305                continue306            is_in_function = is_in_function_start = True307 308    if ti.args.gen_unused_prefix_body:309        output_lines.extend(310            ti.get_checks_for_unused_prefixes(run_list, generated_prefixes)311        )312 313    common.debug("Writing %d lines to %s..." % (len(output_lines), ti.path))314    with open(ti.path, "wb") as f:315        f.writelines(["{}\n".format(l).encode("utf-8") for l in output_lines])316 317 318def main():319    parser = argparse.ArgumentParser(description=__doc__)320    parser.add_argument(321        "--llc-binary",322        default=None,323        help='The "llc" binary to use to generate the test case',324    )325    parser.add_argument("--function", help="The function in the test file to update")326    parser.add_argument(327        "--extra_scrub",328        action="store_true",329        help="Always use additional regex to further reduce diffs between various subtargets",330    )331    parser.add_argument(332        "--x86_scrub_sp",333        action="store_true",334        default=True,335        help="Use regex for x86 sp matching to reduce diffs between various subtargets",336    )337    parser.add_argument("--no_x86_scrub_sp", action="store_false", dest="x86_scrub_sp")338    parser.add_argument(339        "--x86_scrub_rip",340        action="store_true",341        default=False,342        help="Use more regex for x86 rip matching to reduce diffs between various subtargets",343    )344    parser.add_argument(345        "--no_x86_scrub_rip", action="store_false", dest="x86_scrub_rip"346    )347    parser.add_argument(348        "--no_x86_scrub_mem_shuffle",349        action="store_true",350        default=False,351        help="Reduce scrubbing shuffles with memory operands",352    )353    parser.add_argument(354        "--tool",355        default=None,356        help="Treat the given tool name as an llc-like tool for which check lines should be generated",357    )358    parser.add_argument(359        "--default-march",360        default=None,361        help="Set a default -march for when neither triple nor arch are found in a RUN line",362    )363    parser.add_argument("tests", nargs="+")364    initial_args = common.parse_commandline_args(parser)365 366    script_name = os.path.basename(__file__)367 368    returncode = 0369    for ti in common.itertests(370        initial_args.tests, parser, script_name="utils/" + script_name371    ):372        try:373            update_test(ti)374        except Exception as e:375            stderr.write(f"Error: Failed to update test {ti.path}\n")376            print_exc()377            returncode = 1378    return returncode379 380 381if __name__ == "__main__":382    sys.exit(main())383