xref: /llvm-project/llvm/test/CodeGen/AArch64/Atomics/generate-tests.py (revision b71edfaa4ec3c998aadb35255ce2f60bba2940b0)
1#!/usr/bin/env python3
2import textwrap
3import enum
4import os
5
6"""
7Generate the tests in llvm/test/CodeGen/AArch64/Atomics. Run from top level llvm-project.
8"""
9
10TRIPLES = [
11    "aarch64",
12    "aarch64_be",
13]
14
15
16# Type name size
17class Type(enum.Enum):
18    # Value is the size in bytes
19    i8 = 1
20    i16 = 2
21    i32 = 4
22    i64 = 8
23    i128 = 16
24
25    def align(self, aligned: bool) -> int:
26        return self.value if aligned else 1
27
28    def __str__(self) -> str:
29        return self.name
30
31
32# Is this an aligned or unaligned access?
33class Aligned(enum.Enum):
34    aligned = True
35    unaligned = False
36
37    def __str__(self) -> str:
38        return self.name
39
40    def __bool__(self) -> bool:
41        return self.value
42
43
44class AtomicOrder(enum.Enum):
45    notatomic = 0
46    unordered = 1
47    monotonic = 2
48    acquire = 3
49    release = 4
50    acq_rel = 5
51    seq_cst = 6
52
53    def __str__(self) -> str:
54        return self.name
55
56
57ATOMICRMW_ORDERS = [
58    AtomicOrder.monotonic,
59    AtomicOrder.acquire,
60    AtomicOrder.release,
61    AtomicOrder.acq_rel,
62    AtomicOrder.seq_cst,
63]
64
65ATOMIC_LOAD_ORDERS = [
66    AtomicOrder.unordered,
67    AtomicOrder.monotonic,
68    AtomicOrder.acquire,
69    AtomicOrder.seq_cst,
70]
71
72ATOMIC_STORE_ORDERS = [
73    AtomicOrder.unordered,
74    AtomicOrder.monotonic,
75    AtomicOrder.release,
76    AtomicOrder.seq_cst,
77]
78
79ATOMIC_FENCE_ORDERS = [
80    AtomicOrder.acquire,
81    AtomicOrder.release,
82    AtomicOrder.acq_rel,
83    AtomicOrder.seq_cst,
84]
85
86CMPXCHG_SUCCESS_ORDERS = [
87    AtomicOrder.monotonic,
88    AtomicOrder.acquire,
89    AtomicOrder.release,
90    AtomicOrder.acq_rel,
91    AtomicOrder.seq_cst,
92]
93
94CMPXCHG_FAILURE_ORDERS = [
95    AtomicOrder.monotonic,
96    AtomicOrder.acquire,
97    AtomicOrder.seq_cst,
98]
99
100FENCE_ORDERS = [
101    AtomicOrder.acquire,
102    AtomicOrder.release,
103    AtomicOrder.acq_rel,
104    AtomicOrder.seq_cst,
105]
106
107
108class Feature(enum.Flag):
109    # Feature names in filenames are determined by the spelling here:
110    v8a = enum.auto()
111    v8_1a = enum.auto()  # -mattr=+v8.1a, mandatory FEAT_LOR, FEAT_LSE
112    rcpc = enum.auto()  # FEAT_LRCPC
113    lse2 = enum.auto()  # FEAT_LSE2
114    outline_atomics = enum.auto()  # -moutline-atomics
115    rcpc3 = enum.auto()  # FEAT_LSE2 + FEAT_LRCPC3
116    lse2_lse128 = enum.auto()  # FEAT_LSE2 + FEAT_LSE128
117
118    @property
119    def mattr(self):
120        if self == Feature.outline_atomics:
121            return "+outline-atomics"
122        if self == Feature.v8_1a:
123            return "+v8.1a"
124        if self == Feature.rcpc3:
125            return "+lse2,+rcpc3"
126        if self == Feature.lse2_lse128:
127            return "+lse2,+lse128"
128        return "+" + self.name
129
130
131ATOMICRMW_OPS = [
132    "xchg",
133    "add",
134    "sub",
135    "and",
136    "nand",
137    "or",
138    "xor",
139    "max",
140    "min",
141    "umax",
142    "umin",
143]
144
145
146def all_atomicrmw(f):
147    for op in ATOMICRMW_OPS:
148        for aligned in Aligned:
149            for ty in Type:
150                for ordering in ATOMICRMW_ORDERS:
151                    name = f"atomicrmw_{op}_{ty}_{aligned}_{ordering}"
152                    instr = "atomicrmw"
153                    f.write(
154                        textwrap.dedent(
155                            f"""
156                        define dso_local {ty} @{name}(ptr %ptr, {ty} %value) {{
157                            %r = {instr} {op} ptr %ptr, {ty} %value {ordering}, align {ty.align(aligned)}
158                            ret {ty} %r
159                        }}
160                    """
161                        )
162                    )
163
164
165def all_load(f):
166    for aligned in Aligned:
167        for ty in Type:
168            for ordering in ATOMIC_LOAD_ORDERS:
169                for const in [False, True]:
170                    name = f"load_atomic_{ty}_{aligned}_{ordering}"
171                    instr = "load atomic"
172                    if const:
173                        name += "_const"
174                    arg = "ptr readonly %ptr" if const else "ptr %ptr"
175                    f.write(
176                        textwrap.dedent(
177                            f"""
178                        define dso_local {ty} @{name}({arg}) {{
179                            %r = {instr} {ty}, ptr %ptr {ordering}, align {ty.align(aligned)}
180                            ret {ty} %r
181                        }}
182                    """
183                        )
184                    )
185
186
187def all_store(f):
188    for aligned in Aligned:
189        for ty in Type:
190            for ordering in ATOMIC_STORE_ORDERS:  # FIXME stores
191                name = f"store_atomic_{ty}_{aligned}_{ordering}"
192                instr = "store atomic"
193                f.write(
194                    textwrap.dedent(
195                        f"""
196                    define dso_local void @{name}({ty} %value, ptr %ptr) {{
197                        {instr} {ty} %value, ptr %ptr {ordering}, align {ty.align(aligned)}
198                        ret void
199                    }}
200                """
201                    )
202                )
203
204
205def all_cmpxchg(f):
206    for aligned in Aligned:
207        for ty in Type:
208            for success_ordering in CMPXCHG_SUCCESS_ORDERS:
209                for failure_ordering in CMPXCHG_FAILURE_ORDERS:
210                    for weak in [False, True]:
211                        name = f"cmpxchg_{ty}_{aligned}_{success_ordering}_{failure_ordering}"
212                        instr = "cmpxchg"
213                        if weak:
214                            name += "_weak"
215                            instr += " weak"
216                        f.write(
217                            textwrap.dedent(
218                                f"""
219                            define dso_local {ty} @{name}({ty} %expected, {ty} %new, ptr %ptr) {{
220                                %pair = {instr} ptr %ptr, {ty} %expected, {ty} %new {success_ordering} {failure_ordering}, align {ty.align(aligned)}
221                                %r = extractvalue {{ {ty}, i1 }} %pair, 0
222                                ret {ty} %r
223                            }}
224                        """
225                            )
226                        )
227
228
229def all_fence(f):
230    for ordering in FENCE_ORDERS:
231        name = f"fence_{ordering}"
232        f.write(
233            textwrap.dedent(
234                f"""
235            define dso_local void @{name}() {{
236                fence {ordering}
237                ret void
238            }}
239        """
240            )
241        )
242
243
244def header(f, triple, features, filter_args: str):
245    f.write(
246        "; NOTE: Assertions have been autogenerated by "
247        "utils/update_llc_test_checks.py UTC_ARGS: "
248    )
249    f.write(filter_args)
250    f.write("\n")
251    f.write(f"; The base test file was generated by {__file__}\n")
252    for feat in features:
253        for OptFlag in ["-O0", "-O1"]:
254            f.write(
255                " ".join(
256                    [
257                        ";",
258                        "RUN:",
259                        "llc",
260                        "%s",
261                        "-o",
262                        "-",
263                        "-verify-machineinstrs",
264                        f"-mtriple={triple}",
265                        f"-mattr={feat.mattr}",
266                        OptFlag,
267                        "|",
268                        "FileCheck",
269                        "%s",
270                        f"--check-prefixes=CHECK,{OptFlag}\n",
271                    ]
272                )
273            )
274
275
276def write_lit_tests():
277    os.chdir("llvm/test/CodeGen/AArch64/Atomics/")
278    for triple in TRIPLES:
279        # Feature has no effect on fence, so keep it to one file.
280        with open(f"{triple}-fence.ll", "w") as f:
281            filter_args = r'--filter "^\s*(dmb)"'
282            header(f, triple, Feature, filter_args)
283            all_fence(f)
284
285        for feat in Feature:
286            with open(f"{triple}-atomicrmw-{feat.name}.ll", "w") as f:
287                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)"'
288                header(f, triple, [feat], filter_args)
289                all_atomicrmw(f)
290
291            with open(f"{triple}-cmpxchg-{feat.name}.ll", "w") as f:
292                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)"'
293                header(f, triple, [feat], filter_args)
294                all_cmpxchg(f)
295
296            with open(f"{triple}-atomic-load-{feat.name}.ll", "w") as f:
297                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)"'
298                header(f, triple, [feat], filter_args)
299                all_load(f)
300
301            with open(f"{triple}-atomic-store-{feat.name}.ll", "w") as f:
302                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)"'
303                header(f, triple, [feat], filter_args)
304                all_store(f)
305
306
307if __name__ == "__main__":
308    write_lit_tests()
309
310    print(
311        textwrap.dedent(
312            """
313        Testcases written. To update checks run:
314            $ ./llvm/utils/update_llc_test_checks.py -u llvm/test/CodeGen/AArch64/Atomics/*.ll
315
316        Or in parallel:
317            $ parallel ./llvm/utils/update_llc_test_checks.py -u ::: llvm/test/CodeGen/AArch64/Atomics/*.ll
318    """
319        )
320    )
321