Files
clang-p2996/llvm/test/CodeGen/AArch64/Atomics/generate-tests.py
Tomas Matheson 9e3010ad99 [AArch64] Fix LSE2/LSE128/RCPC3 precedence
D142712 added tests for when both lse2 and lse128 are available, but
in practice there is no way to enable LSE128 without LSE2 from clang:
LSE128 is a v9 only feature and LSE2 has been mandatory since v8.4,
and +/-lse2 can not be specified on the clang command line.

Therefore it makes more sense that lse2+lse128 should emit lse128
instructions, otherwise they will not be emitted at all.

It also makes sense to remove the lse128-only backend tests if that set
of attributes is never set by the frontend.

Differential Revision: https://reviews.llvm.org/D143506
2023-02-13 12:31:38 +00:00

283 lines
8.4 KiB
Python
Executable File

#!/usr/bin/env python3
import textwrap
import enum
import os
"""
Generate the tests in llvm/test/CodeGen/AArch64/Atomics. Run from top level llvm-project.
"""
TRIPLES = [
'aarch64',
'aarch64_be',
]
# Type name size
class Type(enum.Enum):
# Value is the size in bytes
i8 = 1
i16 = 2
i32 = 4
i64 = 8
i128 = 16
def align(self, aligned: bool) -> int:
return self.value if aligned else 1
def __str__(self) -> str:
return self.name
# Is this an aligned or unaligned access?
class Aligned(enum.Enum):
aligned = True
unaligned = False
def __str__(self) -> str:
return self.name
def __bool__(self) -> bool:
return self.value
class AtomicOrder(enum.Enum):
notatomic = 0
unordered = 1
monotonic = 2
acquire = 3
release = 4
acq_rel = 5
seq_cst = 6
def __str__(self) -> str:
return self.name
ATOMICRMW_ORDERS = [
AtomicOrder.monotonic,
AtomicOrder.acquire,
AtomicOrder.release,
AtomicOrder.acq_rel,
AtomicOrder.seq_cst,
]
ATOMIC_LOAD_ORDERS = [
AtomicOrder.unordered,
AtomicOrder.monotonic,
AtomicOrder.acquire,
AtomicOrder.seq_cst,
]
ATOMIC_STORE_ORDERS = [
AtomicOrder.unordered,
AtomicOrder.monotonic,
AtomicOrder.release,
AtomicOrder.seq_cst,
]
ATOMIC_FENCE_ORDERS = [
AtomicOrder.acquire,
AtomicOrder.release,
AtomicOrder.acq_rel,
AtomicOrder.seq_cst,
]
CMPXCHG_SUCCESS_ORDERS = [
AtomicOrder.monotonic,
AtomicOrder.acquire,
AtomicOrder.release,
AtomicOrder.acq_rel,
AtomicOrder.seq_cst,
]
CMPXCHG_FAILURE_ORDERS = [
AtomicOrder.monotonic,
AtomicOrder.acquire,
AtomicOrder.seq_cst,
]
FENCE_ORDERS = [
AtomicOrder.acquire,
AtomicOrder.release,
AtomicOrder.acq_rel,
AtomicOrder.seq_cst,
]
class Feature(enum.Flag):
# Feature names in filenames are determined by the spelling here:
v8a = enum.auto()
v8_1a = enum.auto() # -mattr=+v8.1a, mandatory FEAT_LOR, FEAT_LSE
rcpc = enum.auto() # FEAT_LRCPC
lse2 = enum.auto() # FEAT_LSE2
outline_atomics = enum.auto() # -moutline-atomics
rcpc3 = enum.auto() # FEAT_LSE2 + FEAT_LRCPC3
lse2_lse128 = enum.auto() # FEAT_LSE2 + FEAT_LSE128
@property
def mattr(self):
if self == Feature.outline_atomics:
return '+outline-atomics'
if self == Feature.v8_1a:
return '+v8.1a'
if self == Feature.rcpc3:
return '+lse2,+rcpc3'
if self == Feature.lse2_lse128:
return '+lse2,+lse128'
return '+' + self.name
ATOMICRMW_OPS = [
'xchg',
'add',
'sub',
'and',
'nand',
'or',
'xor',
'max',
'min',
'umax',
'umin',
]
def all_atomicrmw(f):
for op in ATOMICRMW_OPS:
for aligned in Aligned:
for ty in Type:
for ordering in ATOMICRMW_ORDERS:
name = f'atomicrmw_{op}_{ty}_{aligned}_{ordering}'
instr = 'atomicrmw'
f.write(
textwrap.dedent(f'''
define dso_local {ty} @{name}(ptr %ptr, {ty} %value) {{
%r = {instr} {op} ptr %ptr, {ty} %value {ordering}, align {ty.align(aligned)}
ret {ty} %r
}}
'''))
def all_load(f):
for aligned in Aligned:
for ty in Type:
for ordering in ATOMIC_LOAD_ORDERS:
for const in [False, True]:
name = f'load_atomic_{ty}_{aligned}_{ordering}'
instr = 'load atomic'
if const:
name += '_const'
arg = 'ptr readonly %ptr' if const else 'ptr %ptr'
f.write(
textwrap.dedent(f'''
define dso_local {ty} @{name}({arg}) {{
%r = {instr} {ty}, ptr %ptr {ordering}, align {ty.align(aligned)}
ret {ty} %r
}}
'''))
def all_store(f):
for aligned in Aligned:
for ty in Type:
for ordering in ATOMIC_STORE_ORDERS: # FIXME stores
name = f'store_atomic_{ty}_{aligned}_{ordering}'
instr = 'store atomic'
f.write(
textwrap.dedent(f'''
define dso_local void @{name}({ty} %value, ptr %ptr) {{
{instr} {ty} %value, ptr %ptr {ordering}, align {ty.align(aligned)}
ret void
}}
'''))
def all_cmpxchg(f):
for aligned in Aligned:
for ty in Type:
for success_ordering in CMPXCHG_SUCCESS_ORDERS:
for failure_ordering in CMPXCHG_FAILURE_ORDERS:
for weak in [False, True]:
name = f'cmpxchg_{ty}_{aligned}_{success_ordering}_{failure_ordering}'
instr = 'cmpxchg'
if weak:
name += '_weak'
instr += ' weak'
f.write(
textwrap.dedent(f'''
define dso_local {ty} @{name}({ty} %expected, {ty} %new, ptr %ptr) {{
%pair = {instr} ptr %ptr, {ty} %expected, {ty} %new {success_ordering} {failure_ordering}, align {ty.align(aligned)}
%r = extractvalue {{ {ty}, i1 }} %pair, 0
ret {ty} %r
}}
'''))
def all_fence(f):
for ordering in FENCE_ORDERS:
name = f'fence_{ordering}'
f.write(
textwrap.dedent(f'''
define dso_local void @{name}() {{
fence {ordering}
ret void
}}
'''))
def header(f, triple, features, filter_args: str):
f.write('; NOTE: Assertions have been autogenerated by '
'utils/update_llc_test_checks.py UTC_ARGS: ')
f.write(filter_args)
f.write('\n')
f.write(f'; The base test file was generated by {__file__}\n')
for feat in features:
for OptFlag in ['-O0', '-O1']:
f.write(' '.join([
';', 'RUN:', 'llc', '%s', '-o', '-', '-verify-machineinstrs',
f'-mtriple={triple}', f'-mattr={feat.mattr}', OptFlag, '|',
'FileCheck', '%s', f'--check-prefixes=CHECK,{OptFlag}\n'
]))
def write_lit_tests():
os.chdir('llvm/test/CodeGen/AArch64/Atomics/')
for triple in TRIPLES:
# Feature has no effect on fence, so keep it to one file.
with open(f'{triple}-fence.ll', 'w') as f:
filter_args = r'--filter "^\s*(dmb)"'
header(f, triple, Feature, filter_args)
all_fence(f)
for feat in Feature:
with open(f'{triple}-atomicrmw-{feat.name}.ll', 'w') as f:
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)"'
header(f, triple, [feat], filter_args)
all_atomicrmw(f)
with open(f'{triple}-cmpxchg-{feat.name}.ll', 'w') as f:
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)"'
header(f, triple, [feat], filter_args)
all_cmpxchg(f)
with open(f'{triple}-atomic-load-{feat.name}.ll', 'w') as f:
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)"'
header(f, triple, [feat], filter_args)
all_load(f)
with open(f'{triple}-atomic-store-{feat.name}.ll', 'w') as f:
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)"'
header(f, triple, [feat], filter_args)
all_store(f)
if __name__ == '__main__':
write_lit_tests()
print(textwrap.dedent('''
Testcases written. To update checks run:
$ ./llvm/utils/update_llc_test_checks.py -u llvm/test/CodeGen/AArch64/Atomics/*.ll
Or in parallel:
$ parallel ./llvm/utils/update_llc_test_checks.py -u ::: llvm/test/CodeGen/AArch64/Atomics/*.ll
'''))