brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.9 KiB · 7cffc23 Raw
416 lines · python
1#!/usr/bin/env python32import textwrap3import enum4import os5import re6 7"""8Generate the tests in llvm/test/CodeGen/AArch64/Atomics. Run from top level llvm-project.9"""10 11TRIPLES = [12    "aarch64",13    "aarch64_be",14]15 16 17class ByteSizes:18    def __init__(self, pairs):19        if not isinstance(pairs, list):20            raise ValueError("Must init with a list of key-value pairs")21 22        self._data = pairs[:]23 24    def __iter__(self):25        return iter(self._data)26 27 28# fmt: off29Type = ByteSizes([30   ("i8",   1),31   ("i16",  2),32   ("i32",  4),33   ("i64",  8),34   ("i128", 16)])35 36FPType = ByteSizes([37   ("half",   2),38   ("bfloat", 2),39   ("float",  4),40   ("double", 8)])41# fmt: on42 43 44# Is this an aligned or unaligned access?45class Aligned(enum.Enum):46    aligned = True47    unaligned = False48 49    def __str__(self) -> str:50        return self.name51 52    def __bool__(self) -> bool:53        return self.value54 55 56class AtomicOrder(enum.Enum):57    notatomic = 058    unordered = 159    monotonic = 260    acquire = 361    release = 462    acq_rel = 563    seq_cst = 664 65    def __str__(self) -> str:66        return self.name67 68 69ATOMICRMW_ORDERS = [70    AtomicOrder.monotonic,71    AtomicOrder.acquire,72    AtomicOrder.release,73    AtomicOrder.acq_rel,74    AtomicOrder.seq_cst,75]76 77ATOMIC_LOAD_ORDERS = [78    AtomicOrder.unordered,79    AtomicOrder.monotonic,80    AtomicOrder.acquire,81    AtomicOrder.seq_cst,82]83 84ATOMIC_STORE_ORDERS = [85    AtomicOrder.unordered,86    AtomicOrder.monotonic,87    AtomicOrder.release,88    AtomicOrder.seq_cst,89]90 91ATOMIC_FENCE_ORDERS = [92    AtomicOrder.acquire,93    AtomicOrder.release,94    AtomicOrder.acq_rel,95    AtomicOrder.seq_cst,96]97 98CMPXCHG_SUCCESS_ORDERS = [99    AtomicOrder.monotonic,100    AtomicOrder.acquire,101    AtomicOrder.release,102    AtomicOrder.acq_rel,103    AtomicOrder.seq_cst,104]105 106CMPXCHG_FAILURE_ORDERS = [107    AtomicOrder.monotonic,108    AtomicOrder.acquire,109    AtomicOrder.seq_cst,110]111 112FENCE_ORDERS = [113    AtomicOrder.acquire,114    AtomicOrder.release,115    AtomicOrder.acq_rel,116    AtomicOrder.seq_cst,117]118 119 120class Feature(enum.Flag):121    # Feature names in filenames are determined by the spelling here:122    v8a = enum.auto()123    v8_1a = enum.auto()  # -mattr=+v8.1a, mandatory FEAT_LOR, FEAT_LSE124    rcpc = enum.auto()  # FEAT_LRCPC125    lse2 = enum.auto()  # FEAT_LSE2126    outline_atomics = enum.auto()  # -moutline-atomics127    rcpc3 = enum.auto()  # FEAT_LSE2 + FEAT_LRCPC3128    lse2_lse128 = enum.auto()  # FEAT_LSE2 + FEAT_LSE128129 130    def test_scope():131        return "all"132 133    @property134    def mattr(self):135        if self == Feature.outline_atomics:136            return "+outline-atomics"137        if self == Feature.v8_1a:138            return "+v8.1a"139        if self == Feature.rcpc3:140            return "+lse2,+rcpc3"141        if self == Feature.lse2_lse128:142            return "+lse2,+lse128"143        return "+" + self.name144 145 146class FPFeature(enum.Flag):147    # Feature names in filenames are determined by the spelling here:148    v8a_fp = enum.auto()149    lsfe = enum.auto()  # FEAT_LSFE150 151    def test_scope():152        return "atomicrmw"153 154    @property155    def mattr(self):156        if self == FPFeature.v8a_fp:157            return "+v8a"158        return "+" + self.name159 160 161ATOMICRMW_OPS = [162    "xchg",163    "add",164    "sub",165    "and",166    "nand",167    "or",168    "xor",169    "max",170    "min",171    "umax",172    "umin",173]174 175FP_ATOMICRMW_OPS = [176    "fadd",177    "fsub",178    "fmax",179    "fmin",180    "fmaximum",181    "fminimum",182]183 184 185def relpath():186    # __file__ changed to return absolute path in Python 3.9. Print only187    # up to llvm-project (6 levels higher), to avoid unnecessary diffs and188    # revealing directory structure of people running this script189    top = "../" * 6190    fp = os.path.relpath(__file__, os.path.abspath(os.path.join(__file__, top)))191    return fp192 193 194def generate_unused_res_test(featname, ordering, op, alignval):195    if featname != "lsfe" or op == "fsub" or alignval == 1:196        return False197    if ordering not in [AtomicOrder.monotonic, AtomicOrder.release]:198        return False199    return True200 201 202def align(val, aligned: bool) -> int:203    return val if aligned else 1204 205 206def all_atomicrmw(f, datatype, atomicrmw_ops, featname):207    instr = "atomicrmw"208    generate_unused = False209    tests = []210    for op in atomicrmw_ops:211        for aligned in Aligned:212            for ty, val in datatype:213                alignval = align(val, aligned)214                for ordering in ATOMICRMW_ORDERS:215                    name = f"atomicrmw_{op}_{ty}_{aligned}_{ordering}"216                    tests.append(217                        textwrap.dedent(218                            f"""219                        define dso_local {ty} @{name}(ptr %ptr, {ty} %value) {{220                            %r = {instr} {op} ptr %ptr, {ty} %value {ordering}, align {alignval}221                            ret {ty} %r222                        }}223                    """224                        )225                    )226                    if generate_unused_res_test(featname, ordering, op, alignval):227                        generate_unused = True228                        name = f"atomicrmw_{op}_{ty}_{aligned}_{ordering}_unused"229                        tests.append(230                            textwrap.dedent(231                                f"""232                           define dso_local void @{name}(ptr %ptr, {ty} %value) {{233                               %r = {instr} {op} ptr %ptr, {ty} %value {ordering}, align {alignval}234                               ret void235                           }}236                        """237                            )238                        )239 240    if generate_unused:241        f.write(242            "\n; NOTE: '_unused' tests are added to ensure we do not lower to "243            "ST[F]ADD when the destination register is WZR/XZR.\n"244            "; See discussion on https://github.com/llvm/llvm-project/pull/131174\n"245        )246 247    for test in tests:248        f.write(test)249 250 251def all_load(f):252    for aligned in Aligned:253        for ty, val in Type:254            alignval = align(val, aligned)255            for ordering in ATOMIC_LOAD_ORDERS:256                for const in [False, True]:257                    name = f"load_atomic_{ty}_{aligned}_{ordering}"258                    instr = "load atomic"259                    if const:260                        name += "_const"261                    arg = "ptr readonly %ptr" if const else "ptr %ptr"262                    f.write(263                        textwrap.dedent(264                            f"""265                        define dso_local {ty} @{name}({arg}) {{266                            %r = {instr} {ty}, ptr %ptr {ordering}, align {alignval}267                            ret {ty} %r268                        }}269                    """270                        )271                    )272 273 274def all_store(f):275    for aligned in Aligned:276        for ty, val in Type:277            alignval = align(val, aligned)278            for ordering in ATOMIC_STORE_ORDERS:  # FIXME stores279                name = f"store_atomic_{ty}_{aligned}_{ordering}"280                instr = "store atomic"281                f.write(282                    textwrap.dedent(283                        f"""284                    define dso_local void @{name}({ty} %value, ptr %ptr) {{285                        {instr} {ty} %value, ptr %ptr {ordering}, align {alignval}286                        ret void287                    }}288                """289                    )290                )291 292 293def all_cmpxchg(f):294    for aligned in Aligned:295        for ty, val in Type:296            alignval = align(val, aligned)297            for success_ordering in CMPXCHG_SUCCESS_ORDERS:298                for failure_ordering in CMPXCHG_FAILURE_ORDERS:299                    for weak in [False, True]:300                        name = f"cmpxchg_{ty}_{aligned}_{success_ordering}_{failure_ordering}"301                        instr = "cmpxchg"302                        if weak:303                            name += "_weak"304                            instr += " weak"305                        f.write(306                            textwrap.dedent(307                                f"""308                            define dso_local {ty} @{name}({ty} %expected, {ty} %new, ptr %ptr) {{309                                %pair = {instr} ptr %ptr, {ty} %expected, {ty} %new {success_ordering} {failure_ordering}, align {alignval}310                                %r = extractvalue {{ {ty}, i1 }} %pair, 0311                                ret {ty} %r312                            }}313                        """314                            )315                        )316 317 318def all_fence(f):319    for ordering in FENCE_ORDERS:320        name = f"fence_{ordering}"321        f.write(322            textwrap.dedent(323                f"""324            define dso_local void @{name}() {{325                fence {ordering}326                ret void327            }}328        """329            )330        )331 332 333def header(f, triple, features, filter_args: str):334    f.write(335        "; NOTE: Assertions have been autogenerated by "336        "utils/update_llc_test_checks.py UTC_ARGS: "337    )338    f.write(filter_args)339    f.write("\n")340    f.write(f"; The base test file was generated by ./{relpath()}\n")341 342    for feat in features:343        for OptFlag in ["-O0", "-O1"]:344            f.write(345                " ".join(346                    [347                        ";",348                        "RUN:",349                        "llc",350                        "%s",351                        "-o",352                        "-",353                        "-verify-machineinstrs",354                        f"-mtriple={triple}",355                        f"-mattr={feat.mattr}",356                        OptFlag,357                        "|",358                        "FileCheck",359                        "%s",360                        f"--check-prefixes=CHECK,{OptFlag}\n",361                    ]362                )363            )364 365 366def write_lit_tests(feature, datatypes, ops):367    for triple in TRIPLES:368        # Feature has no effect on fence, so keep it to one file.369        with open(f"{triple}-fence.ll", "w") as f:370            filter_args = r'--filter "^\s*(dmb)"'371            header(f, triple, Feature, filter_args)372            all_fence(f)373 374        for feat in feature:375            with open(f"{triple}-atomicrmw-{feat.name}.ll", "w") as f:376                filter_args = r'--filter-out "\b(sp)\b" --filter "^\s*(ld[^r]|st[^r]|swp|cas|bl|add|and|eor|orn|orr|sub|mvn|sxt|cmp|ccmp|csel|dmb)"'377                header(f, triple, [feat], filter_args)378                all_atomicrmw(f, datatypes, ops, feat.name)379 380            # Floating point atomics only supported for atomicrmw currently381            if feature.test_scope() == "atomicrmw":382                continue383 384            with open(f"{triple}-cmpxchg-{feat.name}.ll", "w") as f:385                filter_args = r'--filter-out "\b(sp)\b" --filter "^\s*(ld[^r]|st[^r]|swp|cas|bl|add|and|eor|orn|orr|sub|mvn|sxt|cmp|ccmp|csel|dmb)"'386                header(f, triple, [feat], filter_args)387                all_cmpxchg(f)388 389            with open(f"{triple}-atomic-load-{feat.name}.ll", "w") as f:390                filter_args = r'--filter-out "\b(sp)\b" --filter "^\s*(ld|st[^r]|swp|cas|bl|add|and|eor|orn|orr|sub|mvn|sxt|cmp|ccmp|csel|dmb)"'391                header(f, triple, [feat], filter_args)392                all_load(f)393 394            with open(f"{triple}-atomic-store-{feat.name}.ll", "w") as f:395                filter_args = r'--filter-out "\b(sp)\b" --filter "^\s*(ld[^r]|st|swp|cas|bl|add|and|eor|orn|orr|sub|mvn|sxt|cmp|ccmp|csel|dmb)"'396                header(f, triple, [feat], filter_args)397                all_store(f)398 399 400if __name__ == "__main__":401    os.chdir("llvm/test/CodeGen/AArch64/Atomics/")402    write_lit_tests(Feature, Type, ATOMICRMW_OPS)403    write_lit_tests(FPFeature, FPType, FP_ATOMICRMW_OPS)404 405    print(406        textwrap.dedent(407            """408        Testcases written. To update checks run:409            $ ./llvm/utils/update_llc_test_checks.py -u llvm/test/CodeGen/AArch64/Atomics/*.ll410 411        Or in parallel:412            $ parallel ./llvm/utils/update_llc_test_checks.py -u ::: llvm/test/CodeGen/AArch64/Atomics/*.ll413    """414        )415    )416