1bf215546Sopenharmony_ci# 2bf215546Sopenharmony_ci# Copyright (C) 2020 Collabora, Ltd. 3bf215546Sopenharmony_ci# 4bf215546Sopenharmony_ci# Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci# copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci# to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci# the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci# and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci# Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci# 11bf215546Sopenharmony_ci# The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci# paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci# Software. 14bf215546Sopenharmony_ci# 15bf215546Sopenharmony_ci# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci# IN THE SOFTWARE. 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ciimport sys 24bf215546Sopenharmony_cifrom bifrost_isa import * 25bf215546Sopenharmony_cifrom mako.template import Template 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci# Consider pseudo instructions when getting the modifier list 28bf215546Sopenharmony_ciinstructions_with_pseudo = parse_instructions(sys.argv[1], include_pseudo = True) 29bf215546Sopenharmony_ciir_instructions_with_pseudo = partition_mnemonics(instructions_with_pseudo) 30bf215546Sopenharmony_cimodifier_lists = order_modifiers(ir_instructions_with_pseudo) 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci# ...but strip for packing 33bf215546Sopenharmony_ciinstructions = parse_instructions(sys.argv[1]) 34bf215546Sopenharmony_ciir_instructions = partition_mnemonics(instructions) 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci# Packs sources into an argument. Offset argument to work around a quirk of our 37bf215546Sopenharmony_ci# compiler IR when dealing with staging registers (TODO: reorder in the IR to 38bf215546Sopenharmony_ci# fix this) 39bf215546Sopenharmony_cidef pack_sources(sources, body, pack_exprs, offset, is_fma): 40bf215546Sopenharmony_ci for i, src in enumerate(sources): 41bf215546Sopenharmony_ci # FMA first two args are restricted, but that's checked once for all 42bf215546Sopenharmony_ci # FMA so the compiler has less work to do 43bf215546Sopenharmony_ci expected = 0xFB if (is_fma and i < 2) else 0xFF 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci # Validate the source 46bf215546Sopenharmony_ci if src[1] != expected: 47bf215546Sopenharmony_ci assert((src[1] & expected) == src[1]) 48bf215546Sopenharmony_ci body.append('assert((1 << src{}) & {});'.format(i, hex(src[1]))) 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci # Sources are state-invariant 51bf215546Sopenharmony_ci for state in pack_exprs: 52bf215546Sopenharmony_ci state.append('(src{} << {})'.format(i, src[0])) 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci# Try to map from a modifier list `domain` to the list `target` 55bf215546Sopenharmony_cidef map_modifier(body, prefix, mod, domain, target): 56bf215546Sopenharmony_ci # We don't want to map reserveds, that's invalid IR anyway 57bf215546Sopenharmony_ci def reserved_to_none(arr): 58bf215546Sopenharmony_ci return [None if x == 'reserved' else x for x in arr] 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci # Trim out reserveds at the end 61bf215546Sopenharmony_ci noned_domain = reserved_to_none(domain) 62bf215546Sopenharmony_ci noned_target = reserved_to_none(target) 63bf215546Sopenharmony_ci none_indices = [i for i, x in enumerate(noned_target) if x != None] 64bf215546Sopenharmony_ci trimmed = noned_target[0: none_indices[-1] + 1] 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci if trimmed == noned_domain[0:len(trimmed)]: 67bf215546Sopenharmony_ci # Identity map, possibly on the left subset 68bf215546Sopenharmony_ci return mod 69bf215546Sopenharmony_ci else: 70bf215546Sopenharmony_ci # Generate a table as a fallback 71bf215546Sopenharmony_ci table = ", ".join([str(target.index(x)) if x in target else "~0" for x in domain]) 72bf215546Sopenharmony_ci body.append("static uint8_t {}_table[] = {{ {} }};".format(prefix, table)) 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci if len(domain) > 2: 75bf215546Sopenharmony_ci # no need to validate bools 76bf215546Sopenharmony_ci body.append("assert({} < {});".format(mod, len(domain))) 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci return "{}_table[{}]".format(prefix, mod) 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_cidef pick_from_bucket(opts, bucket): 81bf215546Sopenharmony_ci intersection = set(opts) & bucket 82bf215546Sopenharmony_ci assert(len(intersection) <= 1) 83bf215546Sopenharmony_ci return intersection.pop() if len(intersection) == 1 else None 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_cidef pack_modifier(mod, width, default, opts, body, pack_exprs): 86bf215546Sopenharmony_ci # Destructure the modifier name 87bf215546Sopenharmony_ci (raw, arg) = (mod[0:-1], mod[-1]) if mod[-1] in "0123" else (mod, 0) 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci SWIZZLES = ["lane", "lanes", "replicate", "swz", "widen", "swap"] 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci ir_value = "bytes2" if mod == "bytes2" else "{}[{}]".format(raw, arg) if mod[-1] in "0123" else mod 92bf215546Sopenharmony_ci lists = modifier_lists[raw] 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci # Swizzles need to be packed "specially" 95bf215546Sopenharmony_ci SWIZZLE_BUCKETS = [ 96bf215546Sopenharmony_ci set(['h00', 'h0']), 97bf215546Sopenharmony_ci set(['h01', 'none', 'b0123', 'w0']), # Identity 98bf215546Sopenharmony_ci set(['h10']), 99bf215546Sopenharmony_ci set(['h11', 'h1']), 100bf215546Sopenharmony_ci set(['b0000', 'b00', 'b0']), 101bf215546Sopenharmony_ci set(['b1111', 'b11', 'b1']), 102bf215546Sopenharmony_ci set(['b2222', 'b22', 'b2']), 103bf215546Sopenharmony_ci set(['b3333', 'b33', 'b3']), 104bf215546Sopenharmony_ci set(['b0011', 'b01']), 105bf215546Sopenharmony_ci set(['b2233', 'b23']), 106bf215546Sopenharmony_ci set(['b1032']), 107bf215546Sopenharmony_ci set(['b3210']), 108bf215546Sopenharmony_ci set(['b0022', 'b02']) 109bf215546Sopenharmony_ci ] 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci if raw in SWIZZLES: 112bf215546Sopenharmony_ci # Construct a list 113bf215546Sopenharmony_ci lists = [pick_from_bucket(opts, bucket) for bucket in SWIZZLE_BUCKETS] 114bf215546Sopenharmony_ci ir_value = "src[{}].swizzle".format(arg) 115bf215546Sopenharmony_ci elif raw == "lane_dest": 116bf215546Sopenharmony_ci lists = [pick_from_bucket(opts, bucket) for bucket in SWIZZLE_BUCKETS] 117bf215546Sopenharmony_ci ir_value = "dest->swizzle" 118bf215546Sopenharmony_ci elif raw in ["abs", "sign"]: 119bf215546Sopenharmony_ci ir_value = "src[{}].abs".format(arg) 120bf215546Sopenharmony_ci elif raw in ["neg", "not"]: 121bf215546Sopenharmony_ci ir_value = "src[{}].neg".format(arg) 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci ir_value = "I->{}".format(ir_value) 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci # We need to map from ir_opts to opts 126bf215546Sopenharmony_ci mapped = map_modifier(body, mod, ir_value, lists, opts) 127bf215546Sopenharmony_ci body.append('unsigned {} = {};'.format(mod, mapped)) 128bf215546Sopenharmony_ci body.append('assert({} < {});'.format(mod, 1 << width)) 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci# Compiles an S-expression (and/or/eq/neq, modifiers, `ordering`, immediates) 131bf215546Sopenharmony_ci# into a C boolean expression suitable to stick in an if-statement. Takes an 132bf215546Sopenharmony_ci# imm_map to map modifiers to immediate values, parametrized by the ctx that 133bf215546Sopenharmony_ci# we're looking up in (the first, non-immediate argument of the equality) 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ciSEXPR_BINARY = { 136bf215546Sopenharmony_ci "and": "&&", 137bf215546Sopenharmony_ci "or": "||", 138bf215546Sopenharmony_ci "eq": "==", 139bf215546Sopenharmony_ci "neq": "!=" 140bf215546Sopenharmony_ci} 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_cidef compile_s_expr(expr, imm_map, ctx): 143bf215546Sopenharmony_ci if expr[0] == 'alias': 144bf215546Sopenharmony_ci return compile_s_expr(expr[1], imm_map, ctx) 145bf215546Sopenharmony_ci elif expr == ['eq', 'ordering', '#gt']: 146bf215546Sopenharmony_ci return '(src0 > src1)' 147bf215546Sopenharmony_ci elif expr == ['neq', 'ordering', '#lt']: 148bf215546Sopenharmony_ci return '(src0 >= src1)' 149bf215546Sopenharmony_ci elif expr == ['neq', 'ordering', '#gt']: 150bf215546Sopenharmony_ci return '(src0 <= src1)' 151bf215546Sopenharmony_ci elif expr == ['eq', 'ordering', '#lt']: 152bf215546Sopenharmony_ci return '(src0 < src1)' 153bf215546Sopenharmony_ci elif expr == ['eq', 'ordering', '#eq']: 154bf215546Sopenharmony_ci return '(src0 == src1)' 155bf215546Sopenharmony_ci elif isinstance(expr, list): 156bf215546Sopenharmony_ci sep = " {} ".format(SEXPR_BINARY[expr[0]]) 157bf215546Sopenharmony_ci return "(" + sep.join([compile_s_expr(s, imm_map, expr[1]) for s in expr[1:]]) + ")" 158bf215546Sopenharmony_ci elif expr[0] == '#': 159bf215546Sopenharmony_ci return str(imm_map[ctx][expr[1:]]) 160bf215546Sopenharmony_ci else: 161bf215546Sopenharmony_ci return expr 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci# Packs a derived value. We just iterate through the possible choices and test 164bf215546Sopenharmony_ci# whether the encoding matches, and if so we use it. 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_cidef pack_derived(pos, exprs, imm_map, body, pack_exprs): 167bf215546Sopenharmony_ci body.append('unsigned derived_{} = 0;'.format(pos)) 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci first = True 170bf215546Sopenharmony_ci for i, expr in enumerate(exprs): 171bf215546Sopenharmony_ci if expr is not None: 172bf215546Sopenharmony_ci cond = compile_s_expr(expr, imm_map, None) 173bf215546Sopenharmony_ci body.append('{}if {} derived_{} = {};'.format('' if first else 'else ', cond, pos, i)) 174bf215546Sopenharmony_ci first = False 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci assert (not first) 177bf215546Sopenharmony_ci body.append('else unreachable("No pattern match at pos {}");'.format(pos)) 178bf215546Sopenharmony_ci body.append('') 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci assert(pos is not None) 181bf215546Sopenharmony_ci pack_exprs.append('(derived_{} << {})'.format(pos, pos)) 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci# Generates a routine to pack a single variant of a single- instruction. 184bf215546Sopenharmony_ci# Template applies the needed formatting and combine to OR together all the 185bf215546Sopenharmony_ci# pack_exprs to avoid bit fields. 186bf215546Sopenharmony_ci# 187bf215546Sopenharmony_ci# Argument swapping is sensitive to the order of operations. Dependencies: 188bf215546Sopenharmony_ci# sources (RW), modifiers (RW), derived values (W). Hence we emit sources and 189bf215546Sopenharmony_ci# modifiers first, then perform a swap if necessary overwriting 190bf215546Sopenharmony_ci# sources/modifiers, and last calculate derived values and pack. 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_civariant_template = Template("""static inline unsigned 193bf215546Sopenharmony_cibi_pack_${name}(${", ".join(["bi_instr *I"] + ["enum bifrost_packed_src src{}".format(i) for i in range(srcs)])}) 194bf215546Sopenharmony_ci{ 195bf215546Sopenharmony_ci${"\\n".join([(" " + x) for x in common_body])} 196bf215546Sopenharmony_ci% if single_state: 197bf215546Sopenharmony_ci% for (pack_exprs, s_body, _) in states: 198bf215546Sopenharmony_ci${"\\n".join([" " + x for x in s_body + ["return {};".format( " | ".join(pack_exprs))]])} 199bf215546Sopenharmony_ci% endfor 200bf215546Sopenharmony_ci% else: 201bf215546Sopenharmony_ci% for i, (pack_exprs, s_body, cond) in enumerate(states): 202bf215546Sopenharmony_ci ${'} else ' if i > 0 else ''}if ${cond} { 203bf215546Sopenharmony_ci${"\\n".join([" " + x for x in s_body + ["return {};".format(" | ".join(pack_exprs))]])} 204bf215546Sopenharmony_ci% endfor 205bf215546Sopenharmony_ci } else { 206bf215546Sopenharmony_ci unreachable("No matching state found in ${name}"); 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci% endif 209bf215546Sopenharmony_ci} 210bf215546Sopenharmony_ci""") 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_cidef pack_variant(opname, states): 213bf215546Sopenharmony_ci # Expressions to be ORed together for the final pack, an array per state 214bf215546Sopenharmony_ci pack_exprs = [[hex(state[1]["exact"][1])] for state in states] 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci # Computations which need to be done to encode first, across states 217bf215546Sopenharmony_ci common_body = [] 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci # Map from modifier names to a map from modifier values to encoded values 220bf215546Sopenharmony_ci # String -> { String -> Uint }. This can be shared across states since 221bf215546Sopenharmony_ci # modifiers are (except the pos values) constant across state. 222bf215546Sopenharmony_ci imm_map = {} 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci # Pack sources. Offset over to deal with staging/immediate weirdness in our 225bf215546Sopenharmony_ci # IR (TODO: reorder sources upstream so this goes away). Note sources are 226bf215546Sopenharmony_ci # constant across states. 227bf215546Sopenharmony_ci staging = states[0][1].get("staging", "") 228bf215546Sopenharmony_ci offset = 0 229bf215546Sopenharmony_ci if staging in ["r", "rw"]: 230bf215546Sopenharmony_ci offset += 1 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci pack_sources(states[0][1].get("srcs", []), common_body, pack_exprs, offset, opname[0] == '*') 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci modifiers_handled = [] 235bf215546Sopenharmony_ci for st in states: 236bf215546Sopenharmony_ci for ((mod, _, width), default, opts) in st[1].get("modifiers", []): 237bf215546Sopenharmony_ci if mod in modifiers_handled: 238bf215546Sopenharmony_ci continue 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci modifiers_handled.append(mod) 241bf215546Sopenharmony_ci pack_modifier(mod, width, default, opts, common_body, pack_exprs) 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci imm_map[mod] = { x: y for y, x in enumerate(opts) } 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci for i, st in enumerate(states): 246bf215546Sopenharmony_ci for ((mod, pos, width), default, opts) in st[1].get("modifiers", []): 247bf215546Sopenharmony_ci if pos is not None: 248bf215546Sopenharmony_ci pack_exprs[i].append('({} << {})'.format(mod, pos)) 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci for ((src_a, src_b), cond, remap) in st[1].get("swaps", []): 251bf215546Sopenharmony_ci # Figure out which vars to swap, in order to swap the arguments. This 252bf215546Sopenharmony_ci # always includes the sources themselves, and may include source 253bf215546Sopenharmony_ci # modifiers (with the same source indices). We swap based on which 254bf215546Sopenharmony_ci # matches A, this is arbitrary but if we swapped both nothing would end 255bf215546Sopenharmony_ci # up swapping at all since it would swap back. 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci vars_to_swap = ['src'] 258bf215546Sopenharmony_ci for ((mod, _, width), default, opts) in st[1].get("modifiers", []): 259bf215546Sopenharmony_ci if mod[-1] in str(src_a): 260bf215546Sopenharmony_ci vars_to_swap.append(mod[0:-1]) 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci common_body.append('if {}'.format(compile_s_expr(cond, imm_map, None)) + ' {') 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci # Emit the swaps. We use a temp, and wrap in a block to avoid naming 265bf215546Sopenharmony_ci # collisions with multiple swaps. {{Doubling}} to escape the format. 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci for v in vars_to_swap: 268bf215546Sopenharmony_ci common_body.append(' {{ unsigned temp = {}{}; {}{} = {}{}; {}{} = temp; }}'.format(v, src_a, v, src_a, v, src_b, v, src_b)) 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_ci # Also, remap. Bidrectional swaps are explicit in the XML. 271bf215546Sopenharmony_ci for v in remap: 272bf215546Sopenharmony_ci maps = remap[v] 273bf215546Sopenharmony_ci imm = imm_map[v] 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci for i, l in enumerate(maps): 276bf215546Sopenharmony_ci common_body.append(' {}if ({} == {}) {} = {};'.format('' if i == 0 else 'else ', v, imm[l], v, imm[maps[l]])) 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci common_body.append('}') 279bf215546Sopenharmony_ci common_body.append('') 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci for (name, pos, width) in st[1].get("immediates", []): 282bf215546Sopenharmony_ci common_body.append('unsigned {} = I->{};'.format(name, name)) 283bf215546Sopenharmony_ci common_body.append('assert({} < {});'.format(name, hex(1 << width))) 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci for st in pack_exprs: 286bf215546Sopenharmony_ci st.append('({} << {})'.format(name, pos)) 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci # After this, we have to branch off, since deriveds *do* vary based on state. 289bf215546Sopenharmony_ci state_body = [[] for s in states] 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci for i, (_, st) in enumerate(states): 292bf215546Sopenharmony_ci for ((pos, width), exprs) in st.get("derived", []): 293bf215546Sopenharmony_ci pack_derived(pos, exprs, imm_map, state_body[i], pack_exprs[i]) 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci # How do we pick a state? Accumulate the conditions 296bf215546Sopenharmony_ci state_conds = [compile_s_expr(st[0], imm_map, None) for st in states] if len(states) > 1 else [None] 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci if state_conds == None: 299bf215546Sopenharmony_ci assert (states[0][0] == None) 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci # Finally, we'll collect everything together 302bf215546Sopenharmony_ci return variant_template.render(name = opname_to_c(opname), states = zip(pack_exprs, state_body, state_conds), common_body = common_body, single_state = (len(states) == 1), srcs = 4) 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ciprint(COPYRIGHT + '#include "compiler.h"') 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_cipacks = [pack_variant(e, instructions[e]) for e in instructions] 307bf215546Sopenharmony_cifor p in packs: 308bf215546Sopenharmony_ci print(p) 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_citop_pack = Template("""unsigned 311bf215546Sopenharmony_cibi_pack_${'fma' if unit == '*' else 'add'}(bi_instr *I, 312bf215546Sopenharmony_ci enum bifrost_packed_src src0, 313bf215546Sopenharmony_ci enum bifrost_packed_src src1, 314bf215546Sopenharmony_ci enum bifrost_packed_src src2, 315bf215546Sopenharmony_ci enum bifrost_packed_src src3) 316bf215546Sopenharmony_ci{ 317bf215546Sopenharmony_ci if (!I) 318bf215546Sopenharmony_ci return bi_pack_${opname_to_c(unit + 'NOP')}(I, src0, src1, src2, src3); 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci% if unit == '*': 321bf215546Sopenharmony_ci assert((1 << src0) & 0xfb); 322bf215546Sopenharmony_ci assert((1 << src1) & 0xfb); 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci% endif 325bf215546Sopenharmony_ci switch (I->op) { 326bf215546Sopenharmony_ci% for opcode in ops: 327bf215546Sopenharmony_ci% if unit + opcode in instructions: 328bf215546Sopenharmony_ci case BI_OPCODE_${opcode.replace('.', '_').upper()}: 329bf215546Sopenharmony_ci return bi_pack_${opname_to_c(unit + opcode)}(I, src0, src1, src2, src3); 330bf215546Sopenharmony_ci% endif 331bf215546Sopenharmony_ci% endfor 332bf215546Sopenharmony_ci default: 333bf215546Sopenharmony_ci#ifndef NDEBUG 334bf215546Sopenharmony_ci bi_print_instr(I, stderr); 335bf215546Sopenharmony_ci#endif 336bf215546Sopenharmony_ci unreachable("Cannot pack instruction as ${unit}"); 337bf215546Sopenharmony_ci } 338bf215546Sopenharmony_ci} 339bf215546Sopenharmony_ci""") 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_cifor unit in ['*', '+']: 342bf215546Sopenharmony_ci print(top_pack.render(ops = ir_instructions, instructions = instructions, opname_to_c = opname_to_c, unit = unit)) 343