xref: /openbsd-src/gnu/llvm/clang/utils/convert_arm_neon.py (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick#!/usr/bin/env python3
2e5dd7070Spatrick
3e5dd7070Spatrick# This script was committed on 20/11/2019 and it would probably make sense to remove
4e5dd7070Spatrick# it after the next release branches.
5e5dd7070Spatrick
6e5dd7070Spatrick# This script is pipe based and converts an arm_neon.td (or arm_fp16.td) file
7e5dd7070Spatrick# using the old single-char type modifiers to an equivalent new-style form where
8e5dd7070Spatrick# each modifier is orthogonal and they can be composed.
9e5dd7070Spatrick#
10*12c85518Srobert# It was used to directly generate the .td files on main, so if you have any
11e5dd7070Spatrick# local additions I would suggest implementing any modifiers here, and running
12e5dd7070Spatrick# it over your entire pre-merge .td files rather than trying to resolve any
13e5dd7070Spatrick# conflicts manually.
14e5dd7070Spatrick
15e5dd7070Spatrickimport re, sys
16e5dd7070SpatrickMOD_MAP = {
17e5dd7070Spatrick    'v': 'v',
18e5dd7070Spatrick    'x': 'S',
19e5dd7070Spatrick    'u': 'U',
20e5dd7070Spatrick    'd': '.',
21e5dd7070Spatrick    'g': 'q',
22e5dd7070Spatrick    'j': 'Q',
23e5dd7070Spatrick    'w': '>Q',
24e5dd7070Spatrick    'n': '>',
25e5dd7070Spatrick    'h': '<',
26e5dd7070Spatrick    'q': '<Q',
27e5dd7070Spatrick    'e': '<U',
28e5dd7070Spatrick    'm': '<q',
29e5dd7070Spatrick    'i': 'I',
30e5dd7070Spatrick    'l': 'IU>',
31e5dd7070Spatrick    's': '1',
32e5dd7070Spatrick    'z': '1<',
33e5dd7070Spatrick    'r': '1>',
34e5dd7070Spatrick    'b': '1U',
35e5dd7070Spatrick    '$': '1S',
36e5dd7070Spatrick    'k': 'Q',
37e5dd7070Spatrick    '2': '2',
38e5dd7070Spatrick    '3': '3',
39e5dd7070Spatrick    '4': '4',
40e5dd7070Spatrick    'B': '2Q',
41e5dd7070Spatrick    'C': '3Q',
42e5dd7070Spatrick    'D': '4Q',
43e5dd7070Spatrick    'p': '*',
44e5dd7070Spatrick    'c': 'c*',
45e5dd7070Spatrick    '7': '<<q',
46e5dd7070Spatrick    '8': '<<',
47e5dd7070Spatrick    '9': '<<Q',
48e5dd7070Spatrick    't': 'p'
49e5dd7070Spatrick    }
50e5dd7070Spatrick
51e5dd7070Spatrick
52e5dd7070Spatrickdef typespec_elt_size(typespec):
53e5dd7070Spatrick    if 'c' in typespec:
54e5dd7070Spatrick        return 8
55e5dd7070Spatrick    elif 's' in typespec or 'h' in typespec:
56e5dd7070Spatrick        return 16
57e5dd7070Spatrick    elif 'i' in typespec or 'f' in typespec:
58e5dd7070Spatrick        return 32
59e5dd7070Spatrick    elif 'l' in typespec or 'd' in typespec:
60e5dd7070Spatrick        return 64
61e5dd7070Spatrick    elif 'k' in typespec:
62e5dd7070Spatrick        return 128
63e5dd7070Spatrick
64e5dd7070Spatrickdef get_resize(cur, desired):
65e5dd7070Spatrick    res = ''
66e5dd7070Spatrick    while cur < desired:
67e5dd7070Spatrick        res += '>'
68e5dd7070Spatrick        cur *= 2
69e5dd7070Spatrick    while cur > desired:
70e5dd7070Spatrick        res += '<'
71e5dd7070Spatrick        cur /= 2
72e5dd7070Spatrick    return res
73e5dd7070Spatrick
74e5dd7070Spatrick
75e5dd7070Spatrickdef remap_protocol(proto, typespec, name):
76e5dd7070Spatrick    key_type = 0
77e5dd7070Spatrick
78e5dd7070Spatrick    # Conversions like to see the integer type so they know signedness.
79e5dd7070Spatrick    if 'vcvt' in name and '_f' in name and name != 'vcvt_f32_f64' and name != 'vcvt_f64_f32':
80e5dd7070Spatrick        key_type = 1
81e5dd7070Spatrick    default_width = typespec_elt_size(typespec)
82e5dd7070Spatrick    inconsistent_width = False
83e5dd7070Spatrick    for elt in typespec:
84e5dd7070Spatrick        new_width = typespec_elt_size(elt)
85e5dd7070Spatrick        if new_width and new_width != default_width:
86e5dd7070Spatrick            inconsistent_width = True
87e5dd7070Spatrick
88e5dd7070Spatrick    res = ''
89e5dd7070Spatrick    for i, c in enumerate(proto):
90e5dd7070Spatrick        # void and pointers make for bad discriminators in CGBuiltin.cpp.
91e5dd7070Spatrick        if c in 'vcp':
92e5dd7070Spatrick                key_type += 1
93e5dd7070Spatrick
94e5dd7070Spatrick        if c in MOD_MAP:
95e5dd7070Spatrick            cur_mod = MOD_MAP[c]
96e5dd7070Spatrick        elif inconsistent_width:
97e5dd7070Spatrick            # Otherwise it's a fixed output width modifier.
98e5dd7070Spatrick            sys.stderr.write(f'warning: {name} uses fixed output size but has inconsistent input widths: {proto} {typespec}\n')
99e5dd7070Spatrick
100e5dd7070Spatrick        if c == 'Y':
101e5dd7070Spatrick            # y: scalar of half float
102e5dd7070Spatrick            resize = get_resize(default_width, 16)
103e5dd7070Spatrick            cur_mod = f'1F{resize}'
104e5dd7070Spatrick        elif c == 'y':
105e5dd7070Spatrick            # y: scalar of float
106e5dd7070Spatrick            resize = get_resize(default_width, 32)
107e5dd7070Spatrick            cur_mod = f'1F{resize}'
108e5dd7070Spatrick        elif c == 'o':
109e5dd7070Spatrick            # o: scalar of double
110e5dd7070Spatrick            resize = get_resize(default_width, 64)
111e5dd7070Spatrick            cur_mod = f'1F{resize}'
112e5dd7070Spatrick        elif c == 'I':
113e5dd7070Spatrick            # I: scalar of 32-bit signed
114e5dd7070Spatrick            resize = get_resize(default_width, 32)
115e5dd7070Spatrick            cur_mod = f'1S{resize}'
116e5dd7070Spatrick        elif c == 'L':
117e5dd7070Spatrick            # L: scalar of 64-bit signed
118e5dd7070Spatrick            resize = get_resize(default_width, 64)
119e5dd7070Spatrick            cur_mod = f'1S{resize}'
120e5dd7070Spatrick        elif c == 'U':
121e5dd7070Spatrick            # I: scalar of 32-bit unsigned
122e5dd7070Spatrick            resize = get_resize(default_width, 32)
123e5dd7070Spatrick            cur_mod = f'1U{resize}'
124e5dd7070Spatrick        elif c == 'O':
125e5dd7070Spatrick            # O: scalar of 64-bit unsigned
126e5dd7070Spatrick            resize = get_resize(default_width, 64)
127e5dd7070Spatrick            cur_mod = f'1U{resize}'
128e5dd7070Spatrick        elif c == 'f':
129e5dd7070Spatrick            # f: float (int args)
130e5dd7070Spatrick            resize = get_resize(default_width, 32)
131e5dd7070Spatrick            cur_mod = f'F{resize}'
132e5dd7070Spatrick        elif c == 'F':
133e5dd7070Spatrick            # F: double (int args)
134e5dd7070Spatrick            resize = get_resize(default_width, 64)
135e5dd7070Spatrick            cur_mod = f'F{resize}'
136e5dd7070Spatrick        elif c == 'H':
137e5dd7070Spatrick            # H: half (int args)
138e5dd7070Spatrick            resize = get_resize(default_width, 16)
139e5dd7070Spatrick            cur_mod = f'F{resize}'
140e5dd7070Spatrick        elif c == '0':
141e5dd7070Spatrick            # 0: half (int args), ignore 'Q' size modifier.
142e5dd7070Spatrick            resize = get_resize(default_width, 16)
143e5dd7070Spatrick            cur_mod = f'Fq{resize}'
144e5dd7070Spatrick        elif c == '1':
145e5dd7070Spatrick            # 1: half (int args), force 'Q' size modifier.
146e5dd7070Spatrick            resize = get_resize(default_width, 16)
147e5dd7070Spatrick            cur_mod = f'FQ{resize}'
148e5dd7070Spatrick
149e5dd7070Spatrick        if len(cur_mod) == 0:
150e5dd7070Spatrick            raise Exception(f'WTF: {c} in {name}')
151e5dd7070Spatrick
152e5dd7070Spatrick        if key_type != 0 and key_type == i:
153e5dd7070Spatrick            cur_mod += '!'
154e5dd7070Spatrick
155e5dd7070Spatrick        if len(cur_mod) == 1:
156e5dd7070Spatrick            res += cur_mod
157e5dd7070Spatrick        else:
158e5dd7070Spatrick            res += '(' + cur_mod + ')'
159e5dd7070Spatrick
160e5dd7070Spatrick    return res
161e5dd7070Spatrick
162e5dd7070Spatrickdef replace_insts(m):
163e5dd7070Spatrick    start, end = m.span('proto')
164e5dd7070Spatrick    start -= m.start()
165e5dd7070Spatrick    end -= m.start()
166e5dd7070Spatrick    new_proto = remap_protocol(m['proto'], m['kinds'], m['name'])
167e5dd7070Spatrick    return m.group()[:start] + new_proto + m.group()[end:]
168e5dd7070Spatrick
169e5dd7070SpatrickINST = re.compile(r'Inst<"(?P<name>.*?)",\s*"(?P<proto>.*?)",\s*"(?P<kinds>.*?)"')
170e5dd7070Spatrick
171e5dd7070Spatricknew_td = INST.sub(replace_insts, sys.stdin.read())
172e5dd7070Spatricksys.stdout.write(new_td)
173