diff --git a/src/panfrost/bifrost/bifrost_isa.py b/src/panfrost/bifrost/bifrost_isa.py index 1bb284db693..ca46d663c59 100644 --- a/src/panfrost/bifrost/bifrost_isa.py +++ b/src/panfrost/bifrost/bifrost_isa.py @@ -52,6 +52,8 @@ COPYRIGHT = """/* import xml.etree.ElementTree as ET import copy +import itertools +from collections import OrderedDict def parse_cond(cond, aliased = False): if cond.tag == 'reserved': @@ -226,3 +228,92 @@ def expand_states(instructions): out[name] = (ins, test if test is not None else [], desc) return out + +# Drop keys used for packing to simplify IR representation, so we can check for +# equivalence easier + +def simplify_to_ir(ins): + return { + 'staging': ins['staging'], + 'srcs': len(ins['srcs']), + 'modifiers': [[m[0][0], m[2]] for m in ins['modifiers']], + 'immediates': [m[0] for m in ins['immediates']] + } + + +def combine_ir_variants(instructions, v): + variants = sum([[simplify_to_ir(Q[1]) for Q in instructions[x]] for x in v], []) + + # Accumulate modifiers across variants + modifiers = {} + + for s in variants: + # Check consistency + assert(s['srcs'] == variants[0]['srcs']) + assert(s['immediates'] == variants[0]['immediates']) + assert(s['staging'] == variants[0]['staging']) + + for name, opts in s['modifiers']: + if name not in modifiers: + modifiers[name] = copy.deepcopy(opts) + else: + modifiers[name] += opts + + # Great, we've checked srcs/immediates are consistent and we've summed over + # modifiers + return { + 'srcs': variants[0]['srcs'], + 'staging': variants[0]['staging'], + 'immediates': sorted(variants[0]['immediates']), + 'modifiers': { k: modifiers[k] for k in modifiers } + } + +# Partition instructions to mnemonics, considering units and variants +# equivalent. + +def partition_mnemonics(instructions): + partitions = itertools.groupby(instructions, lambda x: x[1:]) + return { k: combine_ir_variants(instructions, v) for (k, v) in partitions } + +# Generate modifier lists, by accumulating all the possible modifiers, and +# deduplicating thus assigning canonical enum values. We don't try _too_ hard +# to be clever, but by preserving as much of the original orderings as +# possible, later instruction encoding is simplified a bit. Probably a micro +# optimization but we have to pick _some_ ordering, might as well choose the +# most convenient. +# +# THIS MUST BE DETERMINISTIC + +def order_modifiers(ir_instructions): + out = {} + + # modifier name -> (list of option strings) + modifier_lists = {} + + for ins in sorted(ir_instructions): + modifiers = ir_instructions[ins]["modifiers"] + + for name in modifiers: + name_ = name[0:-1] if name[-1] in "0123" else name + + if name_ not in modifier_lists: + modifier_lists[name_] = copy.deepcopy(modifiers[name]) + else: + modifier_lists[name_] += modifiers[name] + + for mod in modifier_lists: + lst = list(OrderedDict.fromkeys(modifier_lists[mod])) + + # Ensure none is false for booleans so the builder makes sense + if len(lst) == 2 and lst[1] == "none": + lst.reverse() + + out[mod] = lst + + return out + +# Count sources for a simplified (IR) instruction, including a source for a +# staging register if necessary +def src_count(op): + staging = 1 if (op["staging"] in ["r", "rw"]) else 0 + return op["srcs"] + staging