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