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