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