|  | #!/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) |