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