• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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