1# 2# Copyright (C) 2020 Collabora, Ltd. 3# 4# Permission is hereby granted, free of charge, to any person obtaining a 5# copy of this software and associated documentation files (the "Software"), 6# to deal in the Software without restriction, including without limitation 7# the rights to use, copy, modify, merge, publish, distribute, sublicense, 8# and/or sell copies of the Software, and to permit persons to whom the 9# Software is furnished to do so, subject to the following conditions: 10# 11# The above copyright notice and this permission notice (including the next 12# paragraph) shall be included in all copies or substantial portions of the 13# Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21# IN THE SOFTWARE. 22 23import sys 24from isa_parse import parse_instructions, opname_to_c 25from mako.template import Template 26 27instructions = parse_instructions(sys.argv[1]) 28 29# Packs sources into an argument. Offset argument to work around a quirk of our 30# compiler IR when dealing with staging registers (TODO: reorder in the IR to 31# fix this) 32def pack_sources(sources, body, pack_exprs, offset): 33 for i, src in enumerate(sources): 34 body.append('unsigned src{} = bi_get_src(ins, regs, {});'.format(i, i + offset)) 35 36 # Validate the source 37 if src[1] != 0xFF: 38 body.append('assert((1 << src{}) & {});'.format(i, hex(src[1]))) 39 40 # Sources are state-invariant 41 for state in pack_exprs: 42 state.append('(src{} << {})'.format(i, src[0])) 43 44 body.append('') 45 46# Gets the argument that the source modifier applies to from the name if 47# applicable, otherwise defaults to the first argument 48 49def mod_arg(mod): 50 return int(mod[-1]) if mod[-1] in "0123" else 0 51 52# Widen/lane/swz/swap/replicate modifiers conceptually act as a combined extend 53# + swizzle. We look at the size of the argument to determine if we apply 54# them, and look at the swizzle to pick which one. 55 56def pack_widen(mod, opts, body, pack_exprs): 57 marg = mod_arg(mod) 58 59 body.append('unsigned {}_sz = nir_alu_type_get_type_size(ins->src_types[{}]);'.format(mod, mod_arg(mod))) 60 body.append('unsigned {}_temp = 0;'.format(mod)) 61 62 first = True 63 for i, op in enumerate(opts): 64 if op is None or op == 'reserved': 65 continue 66 67 t_else = 'else ' if not first else '' 68 first = False 69 70 if op in ['none', 'w0']: 71 body.append('{}if ({}_sz == 32) {}_temp = {};'.format(t_else, mod, mod, i)) 72 elif op == 'd0': 73 body.append('{}if ({}_sz == 64) {}_temp = {};'.format(t_else, mod, mod, i)) 74 else: 75 assert(op[0] in ['h', 'b']) 76 sz = 16 if op[0] == 'h' else 8 77 78 # Condition on the swizzle 79 conds = ['ins->swizzle[{}][{}] == {}'.format(marg, idx, lane) for idx, lane in enumerate(op[1:])] 80 cond = " && ".join(conds) 81 82 body.append('{}if ({}_sz == {} && {}) {}_temp = {};'.format(t_else, mod, sz, cond, mod, i)) 83 body.append('else unreachable("Could not pattern match widen");') 84 85 return mod + '_temp' 86 87# abs/neg are stored in ins->src_{abs,neg}[src] arrays 88def pack_absneg(mod, opts, body, pack_exprs): 89 return 'ins->src_{}[{}]'.format(mod[0:-1] if mod[-1] in "0123" else mod, mod_arg(mod)) 90 91# ins->roundmode is the native format (RTE/RTP/RTN/RTZ) for most ops. But there 92# are some others we might encounter that we don't support in the IR at this 93# point, and there are a few that force a subset of round modes. 94 95def pack_round(mod, opts, body, pack_exprs): 96 if opts == ['none', 'rtz']: 97 body.append('assert(ins->roundmode == BIFROST_RTE || ins->roundmode == BIFROST_RTZ);') 98 return '(ins->roundmode == BIFROST_RTZ) ? 1 : 0' 99 elif opts == ['rtn', 'rtp']: 100 body.append('assert(ins->roundmode == BIFROST_RTN || ins->roundmode == BIFROST_RTP);') 101 return '(ins->roundmode == BIFROST_RTP) ? 1 : 0' 102 elif opts[0:4] == ['none', 'rtp', 'rtn', 'rtz']: 103 return 'ins->roundmode' 104 else: 105 assert False 106 107# Likewise, matches our native format 108 109def pack_clamp(mod, opts, body, pack_exprs): 110 if opts == ['none', 'clamp_0_inf', 'clamp_m1_1', 'clamp_0_1']: 111 return 'ins->outmod' 112 elif opts == ['none', 'clamp_0_1']: 113 body.append('assert(ins->outmod == BIFROST_NONE || ins->outmod == BIFROST_SAT);') 114 return '(ins->outmod == BIFROST_SAT) ? 1 : 0' 115 else: 116 assert False 117 118# Our modifiers match up in name, but there is no shortage of orders. So just 119# emit a table on the fly for it, since you won't get something much better. 120# ENUM_BI_COND must be kept synced with `enum bi_cond` in compiler.h 121 122ENUM_BI_COND = [ 123 "al", 124 "lt", 125 "le", 126 "ge", 127 "gt", 128 "eq", 129 "ne", 130] 131 132def pack_cmpf(mod, opts, body, pack_exprs): 133 # Generate a table mapping ENUM_BI_COND to opts, or an invalid 134 # sentintel if not used (which will then be asserted out in a debug build). 135 table = [str(opts.index(x)) if x in opts else '~0' for x in ENUM_BI_COND] 136 137 body.append('unsigned cmpf_table[] = {') 138 body.append(' ' + ', '.join(table)) 139 body.append('};') 140 141 return 'cmpf_table[ins->cond]' 142 143# Since our IR is explicitly typed, we look at the size/sign to determine sign 144# extension behaviour 145def pack_extend(mod, opts, body, pack_exprs): 146 body.append('ASSERTED bool {}_small = nir_alu_type_get_type_size(ins->src_types[{}]) <= 16;'.format(mod, mod_arg(mod))) 147 body.append('bool {}_signed = nir_alu_type_get_base_type(ins->src_types[{}]) == nir_type_int;'.format(mod, mod_arg(mod))) 148 149 if opts == ['none', 'sext', 'zext', 'reserved']: 150 return '{}_small ? ({}_signed ? 1 : 2) : 0'.format(mod, mod) 151 else: 152 assert opts == ['zext', 'sext'] 153 body.append('assert({}_small);'.format(mod)) 154 return '{}_signed ? 1 : 0'.format(mod) 155 156# Packs special varying loads. Our BIFROST_FRAGZ etc defines match the hw in 157# the bottom two bits (TODO drop upper bits) 158def pack_varying_name(mod, opts, body, pack_exprs): 159 assert(opts[0] == 'point' and opts[2] == 'frag_w' and opts[3] == 'frag_z') 160 return 'ins->constant.u64 & 0x3' 161 162def pack_not_src1(mod, opts, body, pack_exprs): 163 return 'ins->bitwise.src1_invert ? {} : {}'.format(opts.index('not'), opts.index('none')) 164 165def pack_not_result(mod, opts, body, pack_exprs): 166 return 'ins->bitwise.dest_invert ? {} : {}'.format(opts.index('not'), opts.index('none')) 167 168REGISTER_FORMATS = { 169 'f64': 'nir_type_float64', 170 'f32': 'nir_type_float32', 171 'f16': 'nir_type_float16', 172 'u64': 'nir_type_uint64', 173 'u32': 'nir_type_uint32', 174 'u16': 'nir_type_uint16', 175 'i64': 'nir_type_int64', 176 's32': 'nir_type_int32', 177 's16': 'nir_type_int16' 178} 179 180def pack_register_format(mod, opts, body, pack_exprs): 181 body.append('unsigned {}_temp = 0;'.format(mod)) 182 183 first = True 184 for i, op in enumerate(opts): 185 if op is None or op == 'reserved': 186 continue 187 188 t_else = 'else ' if not first else '' 189 first = False 190 nir_type = REGISTER_FORMATS.get(op) 191 192 if nir_type: 193 body.append('{}if (ins->format == {}) {}_temp = {};'.format(t_else, nir_type, mod, i)) 194 195 assert not first 196 body.append('else unreachable("Could not pattern match register format");') 197 return mod + '_temp' 198 199def pack_seg(mod, opts, body, pack_exprs): 200 if len(opts) == 8: 201 body.append('assert(ins->segment);') 202 return 'ins->segment' 203 elif opts == ['none', 'wgl']: 204 body.append('assert(ins->segment == BI_SEGMENT_NONE || ins->segment == BI_SEGMENT_WLS);') 205 return 'ins->segment == BI_SEGMENT_WLS ? 1 : 0' 206 else: 207 assert(False) 208 209# TODO: Update modes (perf / slow) For now just force store, except for special 210# varyings for which we force clobber 211def pack_update(mod, opts, body, pack_exprs): 212 if opts == ['store', 'retrieve', 'conditional', 'clobber']: 213 return '(ins->constant.u64 >= 20) ? 3 : 0' 214 else: 215 assert(opts[0] == 'store') 216 return '0' 217 218# Processes modifiers. If used directly, emits a pack. Otherwise, just 219# processes the value (grabbing it from the IR). This must sync with the IR. 220 221modifier_map = { 222 "widen": pack_widen, 223 "widen0": pack_widen, 224 "widen1": pack_widen, 225 "lane": pack_widen, 226 "lane0": pack_widen, 227 "lane1": pack_widen, 228 "lane2": pack_widen, 229 "lane3": pack_widen, 230 "lanes0": pack_widen, 231 "lanes1": pack_widen, 232 "lanes2": pack_widen, 233 "swz": pack_widen, 234 "swz0": pack_widen, 235 "swz1": pack_widen, 236 "swz2": pack_widen, 237 "swap0": pack_widen, 238 "swap1": pack_widen, 239 "swap2": pack_widen, 240 "replicate0": pack_widen, 241 "replicate1": pack_widen, 242 243 "abs": pack_absneg, 244 "abs0": pack_absneg, 245 "abs1": pack_absneg, 246 "abs2": pack_absneg, 247 "neg": pack_absneg, 248 "neg0": pack_absneg, 249 "neg1": pack_absneg, 250 "neg2": pack_absneg, 251 252 "extend": pack_extend, 253 "extend0": pack_extend, 254 "extend1": pack_extend, 255 "extend2": pack_extend, 256 "sign0": pack_extend, 257 "sign1": pack_extend, 258 259 "clamp": pack_clamp, 260 "round": pack_round, 261 "cmpf": pack_cmpf, 262 "varying_name": pack_varying_name, 263 "not1": pack_not_src1, 264 "not_result": pack_not_result, 265 "register_format": pack_register_format, 266 "seg": pack_seg, 267 "update": pack_update, 268 269 # Just a minus one modifier 270 "vecsize": lambda a,b,c,d: 'ins->vector_channels - 1', 271 272 # 0: compute 1: zero 273 "lod_mode": lambda a,b,c,d: '1 - ins->texture.compute_lod', 274 "skip": lambda a,b,c,d: 'ins->skip', 275 276 # Not much choice in the matter... 277 "divzero": lambda a,b,c,d: '0', 278 "sem": lambda a,b,c,d: '0', # IEEE 754 compliant NaN rules 279 280 # For +ZS_EMIT, infer modifiers from specified sources 281 "z": lambda a,b,c,d: '(ins->src[0] != 0)', 282 "stencil": lambda a,b,c,d: '(ins->src[1] != 0)', 283 284 # For +LD_VAR, infer sample from load_vary.interp_mode 285 "sample": lambda a,b,c,d: 'ins->load_vary.interp_mode', 286 287 # We don't support these in the IR yet (TODO) 288 "saturate": lambda a,b,c,d: '0', # clamp to min/max int 289 "mask": lambda a,b,c,d: '0', # clz(~0) = ~0 290 "result_type": lambda a,opts,c,d: str(opts.index('m1')), # #1, #1.0, ~0 for cmp 291 "special": lambda a,b,c,d: '0', # none, which source wins.. 292 "offset": lambda a,b,c,d: '0', # sin/cos thing 293 "adj": lambda a,b,c,d: '0', # sin/cos thing 294 "sqrt": lambda a,b,c,d: '0', # sin/cos thing 295 "log": lambda a,b,c,d: '1', # frexpe mode -- TODO: other transcendentals for g71 296 "scale": lambda a,b,c,d: '0', # sin/cos thing 297 "precision": lambda a,b,c,d: '0', # log thing 298 "mode": lambda a,b,c,d: '0', # log thing 299 "func": lambda a,b,c,d: '0', # pow special case thing 300 "h": lambda a,b,c,d: '0', # VN_ASST1.f16 301 "l": lambda a,b,c,d: '0', # VN_ASST1.f16 302 "function": lambda a,b,c,d: '3', # LD_VAR_FLAT none 303 "preserve_null": lambda a,b,c,d: '0', # SEG_ADD none 304 "bytes2": lambda a,b,c,d: '0', # NIR shifts are in bits 305 "result_word": lambda a,b,c,d: '0', # 32-bit only shifts for now (TODO) 306 "source": lambda a,b,c,d: '7', # cycle_counter for LD_GCLK 307 "lane_op": lambda a,b,c,d: '0', # CLPER none 308 "subgroup": lambda a,b,c,d: '1', # CLPER subgroup4 309 "inactive_result": lambda a,b,c,d: '0', # CLPER zero 310 "threads": lambda a,b,c,d: '0', # IMULD odd 311 "combine": lambda a,b,c,d: '0', # BRANCHC any 312 "format": lambda a,b,c,d: '1', # LEA_TEX_IMM u32 313 "test_mode": lambda a,b,c,d: '0', # JUMP_EX z 314 "stack_mode": lambda a,b,c,d: '2', # JUMP_EX none 315 "atom_opc": lambda a,b,c,d: '2', # ATOM_C aadd 316 "mux": lambda a,b,c,d: '1', # MUX int_zero 317} 318 319def pack_modifier(mod, width, default, opts, body, pack_exprs): 320 # Invoke the specific one 321 fn = modifier_map.get(mod) 322 323 if fn is None: 324 return None 325 326 expr = fn(mod, opts, body, pack_exprs) 327 body.append('unsigned {} = {};'.format(mod, expr)) 328 329 # Validate we don't overflow 330 try: 331 assert(int(expr) < (1 << width)) 332 except: 333 body.append('assert({} < {});'.format(mod, (1 << width))) 334 335 body.append('') 336 337 return True 338 339# Compiles an S-expression (and/or/eq/neq, modifiers, `ordering`, immediates) 340# into a C boolean expression suitable to stick in an if-statement. Takes an 341# imm_map to map modifiers to immediate values, parametrized by the ctx that 342# we're looking up in (the first, non-immediate argument of the equality) 343 344SEXPR_BINARY = { 345 "and": "&&", 346 "or": "||", 347 "eq": "==", 348 "neq": "!=" 349} 350 351def compile_s_expr(expr, imm_map, ctx): 352 if expr[0] == 'alias': 353 return compile_s_expr(expr[1], imm_map, ctx) 354 elif expr == ['eq', 'ordering', '#gt']: 355 return '(src0 > src1)' 356 elif expr == ['neq', 'ordering', '#lt']: 357 return '(src0 >= src1)' 358 elif expr == ['neq', 'ordering', '#gt']: 359 return '(src0 <= src1)' 360 elif expr == ['eq', 'ordering', '#lt']: 361 return '(src0 < src1)' 362 elif expr == ['eq', 'ordering', '#eq']: 363 return '(src0 == src1)' 364 elif isinstance(expr, list): 365 sep = " {} ".format(SEXPR_BINARY[expr[0]]) 366 return "(" + sep.join([compile_s_expr(s, imm_map, expr[1]) for s in expr[1:]]) + ")" 367 elif expr[0] == '#': 368 return str(imm_map[ctx][expr[1:]]) 369 else: 370 return expr 371 372# Packs a derived value. We just iterate through the possible choices and test 373# whether the encoding matches, and if so we use it. 374 375def pack_derived(pos, exprs, imm_map, body, pack_exprs): 376 body.append('unsigned derived_{} = 0;'.format(pos)) 377 378 first = True 379 for i, expr in enumerate(exprs): 380 if expr is not None: 381 cond = compile_s_expr(expr, imm_map, None) 382 body.append('{}if {} derived_{} = {};'.format('' if first else 'else ', cond, pos, i)) 383 first = False 384 385 assert (not first) 386 body.append('else unreachable("No pattern match at pos {}");'.format(pos)) 387 body.append('') 388 389 assert(pos is not None) 390 pack_exprs.append('(derived_{} << {})'.format(pos, pos)) 391 392# Table mapping immediate names in the machine to expressions of `ins` to 393# lookup the value in the IR, performing adjustments as needed 394 395IMMEDIATE_TABLE = { 396 'attribute_index': 'bi_get_immediate(ins, 0)', 397 'varying_index': 'bi_get_immediate(ins, 0)', 398 'index': 'bi_get_immediate(ins, 0)', 399 'texture_index': 'ins->texture.texture_index', 400 'sampler_index': 'ins->texture.sampler_index', 401 'table': '63', # Bindless (flat addressing) mode for DTSEL_IMM 402 403 # Not supported in the IR (TODO) 404 'shift': '0', 405 'fill': '0', # WMASK 406} 407 408# Generates a routine to pack a single variant of a single- instruction. 409# Template applies the needed formatting and combine to OR together all the 410# pack_exprs to avoid bit fields. 411# 412# Argument swapping is sensitive to the order of operations. Dependencies: 413# sources (RW), modifiers (RW), derived values (W). Hence we emit sources and 414# modifiers first, then perform a swap if necessary overwriting 415# sources/modifiers, and last calculate derived values and pack. 416 417variant_template = Template("""static inline unsigned 418pan_pack_${name}(bi_clause *clause, bi_instruction *ins, bi_registers *regs) 419{ 420${"\\n".join([(" " + x) for x in common_body])} 421% if single_state: 422% for (pack_exprs, s_body, _) in states: 423${"\\n".join([" " + x for x in s_body + ["return {};".format( " | ".join(pack_exprs))]])} 424% endfor 425% else: 426% for i, (pack_exprs, s_body, cond) in enumerate(states): 427 ${'} else ' if i > 0 else ''}if ${cond} { 428${"\\n".join([" " + x for x in s_body + ["return {};".format(" | ".join(pack_exprs))]])} 429% endfor 430 } else { 431 unreachable("No matching state found in ${name}"); 432 } 433% endif 434} 435""") 436 437def pack_variant(opname, states): 438 # Expressions to be ORed together for the final pack, an array per state 439 pack_exprs = [[hex(state[1]["exact"][1])] for state in states] 440 441 # Computations which need to be done to encode first, across states 442 common_body = [] 443 444 # Map from modifier names to a map from modifier values to encoded values 445 # String -> { String -> Uint }. This can be shared across states since 446 # modifiers are (except the pos values) constant across state. 447 imm_map = {} 448 449 # Pack sources. Offset over to deal with staging/immediate weirdness in our 450 # IR (TODO: reorder sources upstream so this goes away). Note sources are 451 # constant across states. 452 staging = states[0][1].get("staging", "") 453 offset = 0 454 if staging in ["r", "rw"]: 455 offset += 1 456 457 offset += len(set(["attribute_index", "varying_index", "index"]) & set([x[0] for x in states[0][1].get("immediates", [])])) 458 459 if opname == '+LD_VAR_SPECIAL': 460 offset += 1 461 462 pack_sources(states[0][1].get("srcs", []), common_body, pack_exprs, offset) 463 464 modifiers_handled = [] 465 for st in states: 466 for ((mod, _, width), default, opts) in st[1].get("modifiers", []): 467 if mod in modifiers_handled: 468 continue 469 470 modifiers_handled.append(mod) 471 472 if pack_modifier(mod, width, default, opts, common_body, pack_exprs) is None: 473 return None 474 475 imm_map[mod] = { x: y for y, x in enumerate(opts) } 476 477 for i, st in enumerate(states): 478 for ((mod, pos, width), default, opts) in st[1].get("modifiers", []): 479 if pos is not None: 480 pack_exprs[i].append('({} << {})'.format(mod, pos)) 481 482 for ((src_a, src_b), cond, remap) in st[1].get("swaps", []): 483 # Figure out which vars to swap, in order to swap the arguments. This 484 # always includes the sources themselves, and may include source 485 # modifiers (with the same source indices). We swap based on which 486 # matches A, this is arbitrary but if we swapped both nothing would end 487 # up swapping at all since it would swap back. 488 489 vars_to_swap = ['src'] 490 for ((mod, _, width), default, opts) in st[1].get("modifiers", []): 491 if mod[-1] in str(src_a): 492 vars_to_swap.append(mod[0:-1]) 493 494 common_body.append('if {}'.format(compile_s_expr(cond, imm_map, None)) + ' {') 495 496 # Emit the swaps. We use a temp, and wrap in a block to avoid naming 497 # collisions with multiple swaps. {{Doubling}} to escape the format. 498 499 for v in vars_to_swap: 500 common_body.append(' {{ unsigned temp = {}{}; {}{} = {}{}; {}{} = temp; }}'.format(v, src_a, v, src_a, v, src_b, v, src_b)) 501 502 # Also, remap. Bidrectional swaps are explicit in the XML. 503 for v in remap: 504 maps = remap[v] 505 imm = imm_map[v] 506 507 for i, l in enumerate(maps): 508 common_body.append(' {}if ({} == {}) {} = {};'.format('' if i == 0 else 'else ', v, imm[l], v, imm[maps[l]])) 509 510 common_body.append('}') 511 common_body.append('') 512 513 for (name, pos, width) in st[1].get("immediates", []): 514 if name not in IMMEDIATE_TABLE: 515 return None 516 517 common_body.append('unsigned {} = {};'.format(name, IMMEDIATE_TABLE[name])) 518 519 for st in pack_exprs: 520 st.append('({} << {})'.format(name, pos)) 521 522 if staging == 'r': 523 common_body.append('bi_read_staging_register(clause, ins);') 524 elif staging == 'w': 525 common_body.append('bi_write_staging_register(clause, ins);') 526 elif staging == '': 527 pass 528 else: 529 assert staging == 'rw' 530 # XXX: register allocation requirement (!) 531 common_body.append('bi_read_staging_register(clause, ins);') 532 common_body.append('assert(ins->src[0] == ins->dest);') 533 534 # After this, we have to branch off, since deriveds *do* vary based on state. 535 state_body = [[] for s in states] 536 537 for i, (_, st) in enumerate(states): 538 for ((pos, width), exprs) in st.get("derived", []): 539 pack_derived(pos, exprs, imm_map, state_body[i], pack_exprs[i]) 540 541 # How do we pick a state? Accumulate the conditions 542 state_conds = [compile_s_expr(st[0], imm_map, None) for st in states] if len(states) > 1 else [None] 543 544 if state_conds == None: 545 assert (states[0][0] == None) 546 547 # Finally, we'll collect everything together 548 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)) 549 550HEADER = """/* 551 * Copyright (C) 2020 Collabora, Ltd. 552 * 553 * Permission is hereby granted, free of charge, to any person obtaining a 554 * copy of this software and associated documentation files (the "Software"), 555 * to deal in the Software without restriction, including without limitation 556 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 557 * and/or sell copies of the Software, and to permit persons to whom the 558 * Software is furnished to do so, subject to the following conditions: 559 * 560 * The above copyright notice and this permission notice (including the next 561 * paragraph) shall be included in all copies or substantial portions of the 562 * Software. 563 * 564 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 565 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 566 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 567 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 568 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 569 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 570 * SOFTWARE. 571 */ 572 573/* Autogenerated file, do not edit */ 574 575#ifndef _BI_GENERATED_PACK_H 576#define _BI_GENERATED_PACK_H 577 578#include "compiler.h" 579#include "bi_pack_helpers.h" 580""" 581 582print(HEADER) 583 584packs = [pack_variant(e, instructions[e]) for e in instructions] 585for p in packs: 586 print(p) 587 588print("#endif") 589