# Copyright (C) 2020 Collabora, Ltd. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. SKIP = set(["lane", "lane_dest", "lanes", "lanes", "replicate", "swz", "widen", "swap", "neg", "abs", "not", "sign", "extend", "divzero", "clamp", "sem", "not_result", "skip"]) TEMPLATE = """ #ifndef _BI_BUILDER_H_ #define _BI_BUILDER_H_ #include "compiler.h" <% # For <32-bit loads/stores, the default extend `none` with a natural sized # input is not encodeable! To avoid a footgun, swap the default to `zext` which # will work as expected ZEXT_DEFAULT = set(["LOAD.i8", "LOAD.i16", "LOAD.i24", "STORE.i8", "STORE.i16", "STORE.i24"]) def nirtypes(opcode): split = opcode.split('.', 1) if len(split) < 2: split = opcode.split('_') if len(split) <= 1: return None assert len(split) > 1 type = split[1] if type[0] == 'v': type = type[2:] if type[0] == 'f': return ['nir_type_float'] elif type[0] == 's': return ['nir_type_int'] elif type[0] == 'u': return ['nir_type_uint'] elif type[0] == 'i': return ['nir_type_uint', 'nir_type_int'] else: return None def condition(opcode, typecheck, sizecheck): cond = '' if typecheck == True: cond += '(' types = nirtypes(opcode) assert types != None for T in types: cond += "{}type == {}".format(' || ' if cond[-1] != '(' else '', T) cond += ')' if sizecheck == True: cond += "{}bitsize == {}".format(' && ' if cond != '' else '', typesize(opcode)) cmpf_mods = ops[opcode]["modifiers"]["cmpf"] if "cmpf" in ops[opcode]["modifiers"] else None if "cmpf" in ops[opcode]["modifiers"]: cond += "{}(".format(' && ' if cond != '' else '') for cmpf in ops[opcode]["modifiers"]["cmpf"]: if cmpf != 'reserved': cond += "{}cmpf == BI_CMPF_{}".format(' || ' if cond[-1] != '(' else '', cmpf.upper()) cond += ')' return 'true' if cond == '' else cond def to_suffix(op): return "_to" if op["dests"] > 0 else "" %> % for opcode in ops: static inline bi_instr * bi_${opcode.replace('.', '_').lower()}${to_suffix(ops[opcode])}(${signature(ops[opcode], modifiers)}) { bi_instr *I = rzalloc(b->shader, bi_instr); I->op = BI_OPCODE_${opcode.replace('.', '_').upper()}; % for dest in range(ops[opcode]["dests"]): I->dest[${dest}] = dest${dest}; % endfor % for src in range(src_count(ops[opcode])): I->src[${src}] = src${src}; % endfor % for mod in ops[opcode]["modifiers"]: % if mod[0:-1] not in SKIP and mod not in SKIP: I->${mod} = ${mod}; % endif % endfor % for imm in ops[opcode]["immediates"]: I->${imm} = ${imm}; % endfor % if opcode in ZEXT_DEFAULT: I->extend = BI_EXTEND_ZEXT; % endif bi_builder_insert(&b->cursor, I); return I; } % if ops[opcode]["dests"] == 1: static inline bi_index bi_${opcode.replace('.', '_').lower()}(${signature(ops[opcode], modifiers, no_dests=True)}) { return (bi_${opcode.replace('.', '_').lower()}_to(${arguments(ops[opcode])}))->dest[0]; } %endif <% common_op = opcode.split('.')[0] variants = [a for a in ops.keys() if a.split('.')[0] == common_op] signatures = [signature(ops[op], modifiers, no_dests=True) for op in variants] homogenous = all([sig == signatures[0] for sig in signatures]) types = [nirtypes(x) for x in variants] typeful = False for t in types: if t != types[0]: typeful = True sizes = [typesize(x) for x in variants] sized = False for size in sizes: if size != sizes[0]: sized = True last = opcode == variants[-1] %> % if homogenous and len(variants) > 1 and last: % for (suffix, temp, dests, ret) in (('_to', False, 1, 'instr *'), ('', True, 0, 'index')): % if not temp or ops[opcode]["dests"] > 0: static inline bi_${ret} bi_${common_op.replace('.', '_').lower()}${suffix if ops[opcode]['dests'] > 0 else ''}(${signature(ops[opcode], modifiers, typeful=typeful, sized=sized, no_dests=not dests)}) { % for i, variant in enumerate(variants): ${"{}if ({})".format("else " if i > 0 else "", condition(variant, typeful, sized))} return (bi_${variant.replace('.', '_').lower()}${to_suffix(ops[opcode])}(${arguments(ops[opcode], temp_dest = temp)}))${"->dest[0]" if temp else ""}; % endfor else unreachable("Invalid parameters for ${common_op}"); } %endif %endfor %endif %endfor #endif""" import sys from bifrost_isa import * from mako.template import Template instructions = parse_instructions(sys.argv[1], include_pseudo = True) ir_instructions = partition_mnemonics(instructions) modifier_lists = order_modifiers(ir_instructions) # Generate type signature for a builder routine def should_skip(mod): return mod in SKIP or mod[0:-1] in SKIP def modifier_signature(op): return sorted([m for m in op["modifiers"].keys() if not should_skip(m)]) def signature(op, modifiers, typeful = False, sized = False, no_dests = False): return ", ".join( ["bi_builder *b"] + (["nir_alu_type type"] if typeful == True else []) + (["unsigned bitsize"] if sized == True else []) + ["bi_index dest{}".format(i) for i in range(0 if no_dests else op["dests"])] + ["bi_index src{}".format(i) for i in range(src_count(op))] + ["{} {}".format( "bool" if len(modifiers[T[0:-1]] if T[-1] in "0123" else modifiers[T]) == 2 else "enum bi_" + T[0:-1] if T[-1] in "0123" else "enum bi_" + T, T) for T in modifier_signature(op)] + ["uint32_t {}".format(imm) for imm in op["immediates"]]) def arguments(op, temp_dest = True): return ", ".join( ["b"] + ["bi_temp(b->shader)" if temp_dest else 'dest{}'.format(i) for i in range(op["dests"])] + ["src{}".format(i) for i in range(src_count(op))] + modifier_signature(op) + op["immediates"]) print(Template(COPYRIGHT + TEMPLATE).render(ops = ir_instructions, modifiers = modifier_lists, signature = signature, arguments = arguments, src_count = src_count, typesize = typesize, SKIP = SKIP))