brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.1 KiB · 01ee0e1 Raw
370 lines · python
1"""MIR test utility functions for UpdateTestChecks scripts."""2 3import re4import sys5from UpdateTestChecks import common6from UpdateTestChecks.common import (7    CHECK_RE,8    warn,9)10 11IR_FUNC_NAME_RE = re.compile(12    r"^\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[A-Za-z0-9_.]+)\s*\("13)14IR_PREFIX_DATA_RE = re.compile(r"^ *(;|$)")15MIR_FUNC_NAME_RE = re.compile(r" *name: *(?P<func>[A-Za-z0-9_.-]+)")16MIR_BODY_BEGIN_RE = re.compile(r" *body: *\|")17MIR_BASIC_BLOCK_RE = re.compile(r" *bb\.[0-9]+.*:$")18MIR_PREFIX_DATA_RE = re.compile(r"^ *(;|bb.[0-9].*: *$|[a-z]+:( |$)|$)")19 20VREG_RE = re.compile(r"(%[0-9]+)(?:\.[a-z0-9_]+)?(?::[a-z0-9_]+)?(?:\([<>a-z0-9 ]+\))?")21MI_FLAGS_STR = (22    r"(frame-setup |frame-destroy |nnan |ninf |nsz |arcp |contract |afn "23    r"|reassoc |nuw |nsw |exact |nofpexcept |nomerge |unpredictable "24    r"|noconvergent |nneg |disjoint |nusw |samesign |inbounds )*"25)26VREG_DEF_FLAGS_STR = r"(?:dead |undef )*"27 28# Pattern to match the defined vregs and the opcode of an instruction that29# defines vregs. Opcodes starting with a lower-case 't' are allowed to match30# ARM's thumb instructions, like tADDi8 and t2ADDri.31VREG_DEF_RE = re.compile(32    r"^ *(?P<vregs>{2}{0}(?:, {2}{0})*) = "33    r"{1}(?P<opcode>[A-Zt][A-Za-z0-9_]+)".format(34        VREG_RE.pattern, MI_FLAGS_STR, VREG_DEF_FLAGS_STR35    )36)37 38MIR_FUNC_RE = re.compile(39    r"^---$"40    r"\n"41    r"^ *name: *(?P<func>[A-Za-z0-9_.-]+)$"42    r".*?"43    r"(?:^ *fixedStack: *(\[\])? *\n"44    r"(?P<fixedStack>.*?)\n?"45    r"^ *stack:"46    r".*?)?"47    r"^ *body: *\|\n"48    r"(?P<body>.*?)\n"49    r"^\.\.\.$",50    flags=(re.M | re.S),51)52 53 54def build_function_info_dictionary(55    test, raw_tool_output, triple, prefixes, func_dict, verbose56):57    for m in MIR_FUNC_RE.finditer(raw_tool_output):58        func = m.group("func")59        fixedStack = m.group("fixedStack")60        body = m.group("body")61        if verbose:62            print("Processing function: {}".format(func), file=sys.stderr)63            for l in body.splitlines():64                print("  {}".format(l), file=sys.stderr)65 66        # Vreg mangling67        mangled = []68        vreg_map = {}69        for func_line in body.splitlines(keepends=True):70            m = VREG_DEF_RE.match(func_line)71            if m:72                for vreg in VREG_RE.finditer(m.group("vregs")):73                    if vreg.group(1) in vreg_map:74                        name = vreg_map[vreg.group(1)]75                    else:76                        name = mangle_vreg(m.group("opcode"), vreg_map.values())77                        vreg_map[vreg.group(1)] = name78                    func_line = func_line.replace(79                        vreg.group(1), "[[{}:%[0-9]+]]".format(name), 180                    )81            for number, name in vreg_map.items():82                func_line = re.sub(83                    r"{}\b".format(number), "[[{}]]".format(name), func_line84                )85            mangled.append(func_line)86        body = "".join(mangled)87 88        for prefix in prefixes:89            info = common.function_body(90                body, fixedStack, None, None, None, None, ginfo=None91            )92            if func in func_dict[prefix]:93                if (94                    not func_dict[prefix][func]95                    or func_dict[prefix][func].scrub != info.scrub96                    or func_dict[prefix][func].extrascrub != info.extrascrub97                ):98                    func_dict[prefix][func] = None99            else:100                func_dict[prefix][func] = info101 102 103def mangle_vreg(opcode, current_names):104    base = opcode105    # Simplify some common prefixes and suffixes106    if opcode.startswith("G_"):107        base = base[len("G_") :]108    if opcode.endswith("_PSEUDO"):109        base = base[: len("_PSEUDO")]110    # Shorten some common opcodes with long-ish names111    base = dict(112        IMPLICIT_DEF="DEF",113        GLOBAL_VALUE="GV",114        CONSTANT="C",115        FCONSTANT="C",116        MERGE_VALUES="MV",117        UNMERGE_VALUES="UV",118        INTRINSIC="INT",119        INTRINSIC_W_SIDE_EFFECTS="INT",120        INSERT_VECTOR_ELT="IVEC",121        EXTRACT_VECTOR_ELT="EVEC",122        SHUFFLE_VECTOR="SHUF",123    ).get(base, base)124    # Avoid ambiguity when opcodes end in numbers125    if len(base.rstrip("0123456789")) < len(base):126        base += "_"127 128    i = 0129    for name in current_names:130        if name.rstrip("0123456789") == base:131            i += 1132    if i:133        return "{}{}".format(base, i)134    return base135 136 137def find_mir_functions_with_one_bb(lines, verbose=False):138    result = []139    cur_func = None140    bbs = 0141    for line in lines:142        m = MIR_FUNC_NAME_RE.match(line)143        if m:144            if bbs == 1:145                result.append(cur_func)146            cur_func = m.group("func")147            bbs = 0148        m = MIR_BASIC_BLOCK_RE.match(line)149        if m:150            bbs += 1151    if bbs == 1:152        result.append(cur_func)153    return result154 155 156def add_mir_checks_for_function(157    test,158    output_lines,159    run_list,160    func_dict,161    func_name,162    single_bb,163    print_fixed_stack,164    first_check_is_next,165    at_the_function_name,166    check_indent=None,167):168    printed_prefixes = set()169    for run in run_list:170        for prefix in run[0]:171            if prefix in printed_prefixes:172                break173            # func_info can be empty if there was a prefix conflict.174            if not func_dict[prefix].get(func_name):175                continue176            if printed_prefixes:177                # Add some space between different check prefixes.178                indent = len(output_lines[-1]) - len(output_lines[-1].lstrip(" "))179                output_lines.append(" " * indent + ";")180            printed_prefixes.add(prefix)181            add_mir_check_lines(182                test,183                output_lines,184                prefix,185                ("@" if at_the_function_name else "") + func_name,186                single_bb,187                func_dict[prefix][func_name],188                print_fixed_stack,189                first_check_is_next,190                check_indent,191            )192            break193        else:194            warn(195                "Found conflicting asm for function: {}".format(func_name),196                test_file=test,197            )198    return output_lines199 200 201def add_mir_check_lines(202    test,203    output_lines,204    prefix,205    func_name,206    single_bb,207    func_info,208    print_fixed_stack,209    first_check_is_next,210    check_indent=None,211):212    func_body = str(func_info).splitlines()213    if single_bb:214        # Don't bother checking the basic block label for a single BB215        func_body.pop(0)216 217    if not func_body:218        warn(219            "Function has no instructions to check: {}".format(func_name),220            test_file=test,221        )222        return223 224    first_line = func_body[0]225    indent = len(first_line) - len(first_line.lstrip(" "))226    # A check comment, indented the appropriate amount227    if check_indent is not None:228        check = "{}; {}".format(check_indent, prefix)229    else:230        check = "{:>{}}; {}".format("", indent, prefix)231 232    output_lines.append("{}-LABEL: name: {}".format(check, func_name))233 234    if print_fixed_stack:235        output_lines.append("{}: fixedStack:".format(check))236        for stack_line in func_info.extrascrub.splitlines():237            filecheck_directive = check + "-NEXT"238            output_lines.append("{}: {}".format(filecheck_directive, stack_line))239 240    first_check = not first_check_is_next241    for func_line in func_body:242        if not func_line.strip():243            # The mir printer prints leading whitespace so we can't use CHECK-EMPTY:244            output_lines.append(check + "-NEXT: {{" + func_line + "$}}")245            continue246        filecheck_directive = check if first_check else check + "-NEXT"247        first_check = False248        check_line = "{}: {}".format(filecheck_directive, func_line[indent:]).rstrip()249        output_lines.append(check_line)250 251 252def should_add_mir_line_to_output(input_line, prefix_set):253    # Skip any check lines that we're handling as well as comments254    m = CHECK_RE.match(input_line)255    if (m and m.group(1) in prefix_set) or input_line.strip() == ";":256        return False257    return True258 259 260def add_mir_checks(261    input_lines,262    prefix_set,263    autogenerated_note,264    test,265    run_list,266    func_dict,267    print_fixed_stack,268    first_check_is_next,269    at_the_function_name,270):271    simple_functions = find_mir_functions_with_one_bb(input_lines)272 273    output_lines = []274    output_lines.append(autogenerated_note)275 276    func_name = None277    state = "toplevel"278    for input_line in input_lines:279        if input_line == autogenerated_note:280            continue281 282        if state == "toplevel":283            m = IR_FUNC_NAME_RE.match(input_line)284            if m:285                state = "ir function prefix"286                func_name = m.group("func")287            if input_line.rstrip("| \r\n") == "---":288                state = "document"289            output_lines.append(input_line)290        elif state == "document":291            m = MIR_FUNC_NAME_RE.match(input_line)292            if m:293                state = "mir function metadata"294                func_name = m.group("func")295            if input_line.strip() == "...":296                state = "toplevel"297                func_name = None298            if should_add_mir_line_to_output(input_line, prefix_set):299                output_lines.append(input_line)300        elif state == "mir function metadata":301            if should_add_mir_line_to_output(input_line, prefix_set):302                output_lines.append(input_line)303            m = MIR_BODY_BEGIN_RE.match(input_line)304            if m:305                if func_name in simple_functions:306                    # If there's only one block, put the checks inside it307                    state = "mir function prefix"308                    continue309                state = "mir function body"310                add_mir_checks_for_function(311                    test,312                    output_lines,313                    run_list,314                    func_dict,315                    func_name,316                    single_bb=False,317                    print_fixed_stack=print_fixed_stack,318                    first_check_is_next=first_check_is_next,319                    at_the_function_name=at_the_function_name,320                )321        elif state == "mir function prefix":322            m = MIR_PREFIX_DATA_RE.match(input_line)323            if not m:324                state = "mir function body"325                add_mir_checks_for_function(326                    test,327                    output_lines,328                    run_list,329                    func_dict,330                    func_name,331                    single_bb=True,332                    print_fixed_stack=print_fixed_stack,333                    first_check_is_next=first_check_is_next,334                    at_the_function_name=at_the_function_name,335                )336 337            if should_add_mir_line_to_output(input_line, prefix_set):338                output_lines.append(input_line)339        elif state == "mir function body":340            if input_line.strip() == "...":341                state = "toplevel"342                func_name = None343            if should_add_mir_line_to_output(input_line, prefix_set):344                output_lines.append(input_line)345        elif state == "ir function prefix":346            m = IR_PREFIX_DATA_RE.match(input_line)347            if not m:348                state = "ir function body"349                add_mir_checks_for_function(350                    test,351                    output_lines,352                    run_list,353                    func_dict,354                    func_name,355                    single_bb=False,356                    print_fixed_stack=print_fixed_stack,357                    first_check_is_next=first_check_is_next,358                    at_the_function_name=at_the_function_name,359                )360 361            if should_add_mir_line_to_output(input_line, prefix_set):362                output_lines.append(input_line)363        elif state == "ir function body":364            if input_line.strip() == "}":365                state = "toplevel"366                func_name = None367            if should_add_mir_line_to_output(input_line, prefix_set):368                output_lines.append(input_line)369    return output_lines370