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