| #!/usr/bin/env python3 |
| |
| # This script was committed on 20/11/2019 and it would probably make sense to remove |
| # it after the next release branches. |
| |
| # This script is pipe based and converts an arm_neon.td (or arm_fp16.td) file |
| # using the old single-char type modifiers to an equivalent new-style form where |
| # each modifier is orthogonal and they can be composed. |
| # |
| # It was used to directly generate the .td files on main, so if you have any |
| # local additions I would suggest implementing any modifiers here, and running |
| # it over your entire pre-merge .td files rather than trying to resolve any |
| # conflicts manually. |
| |
| import re, sys |
| MOD_MAP = { |
| 'v': 'v', |
| 'x': 'S', |
| 'u': 'U', |
| 'd': '.', |
| 'g': 'q', |
| 'j': 'Q', |
| 'w': '>Q', |
| 'n': '>', |
| 'h': '<', |
| 'q': '<Q', |
| 'e': '<U', |
| 'm': '<q', |
| 'i': 'I', |
| 'l': 'IU>', |
| 's': '1', |
| 'z': '1<', |
| 'r': '1>', |
| 'b': '1U', |
| '$': '1S', |
| 'k': 'Q', |
| '2': '2', |
| '3': '3', |
| '4': '4', |
| 'B': '2Q', |
| 'C': '3Q', |
| 'D': '4Q', |
| 'p': '*', |
| 'c': 'c*', |
| '7': '<<q', |
| '8': '<<', |
| '9': '<<Q', |
| 't': 'p' |
| } |
| |
| |
| def typespec_elt_size(typespec): |
| if 'c' in typespec: |
| return 8 |
| elif 's' in typespec or 'h' in typespec: |
| return 16 |
| elif 'i' in typespec or 'f' in typespec: |
| return 32 |
| elif 'l' in typespec or 'd' in typespec: |
| return 64 |
| elif 'k' in typespec: |
| return 128 |
| |
| def get_resize(cur, desired): |
| res = '' |
| while cur < desired: |
| res += '>' |
| cur *= 2 |
| while cur > desired: |
| res += '<' |
| cur /= 2 |
| return res |
| |
| |
| def remap_protocol(proto, typespec, name): |
| key_type = 0 |
| |
| # Conversions like to see the integer type so they know signedness. |
| if 'vcvt' in name and '_f' in name and name != 'vcvt_f32_f64' and name != 'vcvt_f64_f32': |
| key_type = 1 |
| default_width = typespec_elt_size(typespec) |
| inconsistent_width = False |
| for elt in typespec: |
| new_width = typespec_elt_size(elt) |
| if new_width and new_width != default_width: |
| inconsistent_width = True |
| |
| res = '' |
| for i, c in enumerate(proto): |
| # void and pointers make for bad discriminators in CGBuiltin.cpp. |
| if c in 'vcp': |
| key_type += 1 |
| |
| if c in MOD_MAP: |
| cur_mod = MOD_MAP[c] |
| elif inconsistent_width: |
| # Otherwise it's a fixed output width modifier. |
| sys.stderr.write(f'warning: {name} uses fixed output size but has inconsistent input widths: {proto} {typespec}\n') |
| |
| if c == 'Y': |
| # y: scalar of half float |
| resize = get_resize(default_width, 16) |
| cur_mod = f'1F{resize}' |
| elif c == 'y': |
| # y: scalar of float |
| resize = get_resize(default_width, 32) |
| cur_mod = f'1F{resize}' |
| elif c == 'o': |
| # o: scalar of double |
| resize = get_resize(default_width, 64) |
| cur_mod = f'1F{resize}' |
| elif c == 'I': |
| # I: scalar of 32-bit signed |
| resize = get_resize(default_width, 32) |
| cur_mod = f'1S{resize}' |
| elif c == 'L': |
| # L: scalar of 64-bit signed |
| resize = get_resize(default_width, 64) |
| cur_mod = f'1S{resize}' |
| elif c == 'U': |
| # I: scalar of 32-bit unsigned |
| resize = get_resize(default_width, 32) |
| cur_mod = f'1U{resize}' |
| elif c == 'O': |
| # O: scalar of 64-bit unsigned |
| resize = get_resize(default_width, 64) |
| cur_mod = f'1U{resize}' |
| elif c == 'f': |
| # f: float (int args) |
| resize = get_resize(default_width, 32) |
| cur_mod = f'F{resize}' |
| elif c == 'F': |
| # F: double (int args) |
| resize = get_resize(default_width, 64) |
| cur_mod = f'F{resize}' |
| elif c == 'H': |
| # H: half (int args) |
| resize = get_resize(default_width, 16) |
| cur_mod = f'F{resize}' |
| elif c == '0': |
| # 0: half (int args), ignore 'Q' size modifier. |
| resize = get_resize(default_width, 16) |
| cur_mod = f'Fq{resize}' |
| elif c == '1': |
| # 1: half (int args), force 'Q' size modifier. |
| resize = get_resize(default_width, 16) |
| cur_mod = f'FQ{resize}' |
| |
| if len(cur_mod) == 0: |
| raise Exception(f'WTF: {c} in {name}') |
| |
| if key_type != 0 and key_type == i: |
| cur_mod += '!' |
| |
| if len(cur_mod) == 1: |
| res += cur_mod |
| else: |
| res += '(' + cur_mod + ')' |
| |
| return res |
| |
| def replace_insts(m): |
| start, end = m.span('proto') |
| start -= m.start() |
| end -= m.start() |
| new_proto = remap_protocol(m['proto'], m['kinds'], m['name']) |
| return m.group()[:start] + new_proto + m.group()[end:] |
| |
| INST = re.compile(r'Inst<"(?P<name>.*?)",\s*"(?P<proto>.*?)",\s*"(?P<kinds>.*?)"') |
| |
| new_td = INST.sub(replace_insts, sys.stdin.read()) |
| sys.stdout.write(new_td) |