1# Copyright (C) 2020 Collabora, Ltd. 2# 3# Permission is hereby granted, free of charge, to any person obtaining a 4# copy of this software and associated documentation files (the "Software"), 5# to deal in the Software without restriction, including without limitation 6# the rights to use, copy, modify, merge, publish, distribute, sublicense, 7# and/or sell copies of the Software, and to permit persons to whom the 8# Software is furnished to do so, subject to the following conditions: 9# 10# The above copyright notice and this permission notice (including the next 11# paragraph) shall be included in all copies or substantial portions of the 12# Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20# IN THE SOFTWARE. 21 22SKIP = set(["lane", "lane_dest", "lanes", "lanes", "replicate", "swz", "widen", 23 "swap", "neg", "abs", "not", "sign", "extend", "divzero", "clamp", "sem", 24 "not_result", "skip", "round", "ftz"]) 25 26TEMPLATE = """ 27#ifndef _BI_BUILDER_H_ 28#define _BI_BUILDER_H_ 29 30#include "compiler.h" 31 32<% 33# For <32-bit loads/stores, the default extend `none` with a natural sized 34# input is not encodeable! To avoid a footgun, swap the default to `zext` which 35# will work as expected 36ZEXT_DEFAULT = set(["LOAD.i8", "LOAD.i16", "LOAD.i24", "STORE.i8", "STORE.i16", "STORE.i24"]) 37 38def nirtypes(opcode): 39 split = opcode.split('.', 1) 40 if len(split) < 2: 41 split = opcode.split('_') 42 43 if len(split) <= 1: 44 return None 45 46 assert len(split) > 1 47 48 type = split[1] 49 if type[0] == 'v': 50 type = type[2:] 51 52 if type[0] == 'f': 53 return ['nir_type_float'] 54 elif type[0] == 's': 55 return ['nir_type_int'] 56 elif type[0] == 'u': 57 return ['nir_type_uint'] 58 elif type[0] == 'i': 59 return ['nir_type_uint', 'nir_type_int'] 60 else: 61 return None 62 63def condition(opcode, typecheck, sizecheck): 64 cond = '' 65 if typecheck == True: 66 cond += '(' 67 types = nirtypes(opcode) 68 assert types != None 69 for T in types: 70 cond += "{}type == {}".format(' || ' if cond[-1] != '(' else '', T) 71 cond += ')' 72 73 if sizecheck == True: 74 cond += "{}bitsize == {}".format(' && ' if cond != '' else '', typesize(opcode)) 75 76 cmpf_mods = ops[opcode]["modifiers"]["cmpf"] if "cmpf" in ops[opcode]["modifiers"] else None 77 if "cmpf" in ops[opcode]["modifiers"]: 78 cond += "{}(".format(' && ' if cond != '' else '') 79 for cmpf in ops[opcode]["modifiers"]["cmpf"]: 80 if cmpf != 'reserved': 81 cond += "{}cmpf == BI_CMPF_{}".format(' || ' if cond[-1] != '(' else '', cmpf.upper()) 82 cond += ')' 83 84 return 'true' if cond == '' else cond 85 86def to_suffix(op): 87 return "_to" if op["dests"] > 0 else "" 88 89%> 90 91% for opcode in ops: 92static inline 93bi_instr * bi_${opcode.replace('.', '_').lower()}${to_suffix(ops[opcode])}(${signature(ops[opcode], modifiers)}) 94{ 95 bi_instr *I = rzalloc(b->shader, bi_instr); 96 I->op = BI_OPCODE_${opcode.replace('.', '_').upper()}; 97% for dest in range(ops[opcode]["dests"]): 98 I->dest[${dest}] = dest${dest}; 99% endfor 100% for src in range(src_count(ops[opcode])): 101 I->src[${src}] = src${src}; 102% endfor 103% for mod in ops[opcode]["modifiers"]: 104% if not should_skip(mod, opcode): 105 I->${mod} = ${mod}; 106% endif 107% endfor 108% if ops[opcode]["rtz"]: 109 I->round = BI_ROUND_RTZ; 110% endif 111% for imm in ops[opcode]["immediates"]: 112 I->${imm} = ${imm}; 113% endfor 114% if opcode in ZEXT_DEFAULT: 115 I->extend = BI_EXTEND_ZEXT; 116% endif 117 bi_builder_insert(&b->cursor, I); 118 return I; 119} 120 121% if ops[opcode]["dests"] == 1: 122static inline 123bi_index bi_${opcode.replace('.', '_').lower()}(${signature(ops[opcode], modifiers, no_dests=True)}) 124{ 125 return (bi_${opcode.replace('.', '_').lower()}_to(${arguments(ops[opcode])}))->dest[0]; 126} 127 128%endif 129<% 130 common_op = opcode.split('.')[0] 131 variants = [a for a in ops.keys() if a.split('.')[0] == common_op] 132 signatures = [signature(ops[op], modifiers, no_dests=True) for op in variants] 133 homogenous = all([sig == signatures[0] for sig in signatures]) 134 types = [nirtypes(x) for x in variants] 135 typeful = False 136 for t in types: 137 if t != types[0]: 138 typeful = True 139 140 sizes = [typesize(x) for x in variants] 141 sized = False 142 for size in sizes: 143 if size != sizes[0]: 144 sized = True 145 146 last = opcode == variants[-1] 147%> 148% if homogenous and len(variants) > 1 and last: 149% for (suffix, temp, dests, ret) in (('_to', False, 1, 'instr *'), ('', True, 0, 'index')): 150% if not temp or ops[opcode]["dests"] > 0: 151static inline 152bi_${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)}) 153{ 154% for i, variant in enumerate(variants): 155 ${"{}if ({})".format("else " if i > 0 else "", condition(variant, typeful, sized))} 156 return (bi_${variant.replace('.', '_').lower()}${to_suffix(ops[opcode])}(${arguments(ops[opcode], temp_dest = temp)}))${"->dest[0]" if temp else ""}; 157% endfor 158 else 159 unreachable("Invalid parameters for ${common_op}"); 160} 161 162%endif 163%endfor 164%endif 165%endfor 166#endif""" 167 168import sys 169from bifrost_isa import * 170from mako.template import Template 171 172instructions = parse_instructions(sys.argv[1], include_pseudo = True) 173ir_instructions = partition_mnemonics(instructions) 174modifier_lists = order_modifiers(ir_instructions) 175 176# Generate type signature for a builder routine 177 178def should_skip(mod, op): 179 # FROUND and HADD only make sense in context of a round mode, so override 180 # the usual skip 181 if mod == "round" and ("FROUND" in op or "HADD" in op): 182 return False 183 184 return mod in SKIP or mod[0:-1] in SKIP 185 186def modifier_signature(op): 187 return sorted([m for m in op["modifiers"].keys() if not should_skip(m, op["key"])]) 188 189def signature(op, modifiers, typeful = False, sized = False, no_dests = False): 190 return ", ".join( 191 ["bi_builder *b"] + 192 (["nir_alu_type type"] if typeful == True else []) + 193 (["unsigned bitsize"] if sized == True else []) + 194 ["bi_index dest{}".format(i) for i in range(0 if no_dests else op["dests"])] + 195 ["bi_index src{}".format(i) for i in range(src_count(op))] + 196 ["{} {}".format( 197 "bool" if len(modifiers[T[0:-1]] if T[-1] in "0123" else modifiers[T]) == 2 else 198 "enum bi_" + T[0:-1] if T[-1] in "0123" else 199 "enum bi_" + T, 200 T) for T in modifier_signature(op)] + 201 ["uint32_t {}".format(imm) for imm in op["immediates"]]) 202 203def arguments(op, temp_dest = True): 204 return ", ".join( 205 ["b"] + 206 ["bi_temp(b->shader)" if temp_dest else 'dest{}'.format(i) for i in range(op["dests"])] + 207 ["src{}".format(i) for i in range(src_count(op))] + 208 modifier_signature(op) + 209 op["immediates"]) 210 211print(Template(COPYRIGHT + TEMPLATE).render(ops = ir_instructions, modifiers = 212 modifier_lists, signature = signature, arguments = arguments, src_count = 213 src_count, typesize = typesize, should_skip = should_skip)) 214