diff --git a/src/imagination/pco/meson.build b/src/imagination/pco/meson.build index 84e5e6e33a0..d7f0284d79f 100644 --- a/src/imagination/pco/meson.build +++ b/src/imagination/pco/meson.build @@ -23,6 +23,15 @@ pco_common_h = custom_target( depend_files : pco_pygen_dep_files, ) +pco_info_c = custom_target( + 'pco_info.c', + input : ['pco_info.c.py'], + output : 'pco_info.c', + command : [prog_python, '@INPUT@'], + capture : true, + depend_files : pco_pygen_dep_files, +) + pco_isa_h = custom_target( 'pco_isa.h', input : ['pco_isa.h.py'], @@ -44,13 +53,14 @@ pco_ops_h = custom_target( idep_pco_pygen = declare_dependency( sources : [ pco_common_h, + pco_info_c, pco_isa_h, pco_ops_h, ], include_directories : inc_powervr_compiler, ) -pco_pygen_c_files = [] +pco_pygen_c_files = [pco_info_c] libpowervr_compiler = static_library( 'powervr_compiler', diff --git a/src/imagination/pco/pco_common.h.py b/src/imagination/pco/pco_common.h.py index dce8955c420..b8d271a5760 100644 --- a/src/imagination/pco/pco_common.h.py +++ b/src/imagination/pco/pco_common.h.py @@ -49,6 +49,7 @@ static bool ${enum.name}_valid(uint64_t val) % endfor /** Bit set variants. */ % for bit_set in bit_sets.values(): +#define _${bit_set.name.upper()}_VARIANT_COUNT ${len(bit_set.variants) + 1}U enum ${bit_set.name}_variant { ${bit_set.name.upper()}_NONE, % for variant, *_ in bit_set.variants: diff --git a/src/imagination/pco/pco_info.c.py b/src/imagination/pco/pco_info.c.py new file mode 100644 index 00000000000..f51ed99a75f --- /dev/null +++ b/src/imagination/pco/pco_info.c.py @@ -0,0 +1,95 @@ +# Copyright © 2024 Imagination Technologies Ltd. +# SPDX-License-Identifier: MIT + +from mako.template import Template +from pco_ops import * + +template = """/* + * Copyright © 2024 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: MIT + */ + +/** + * \\file pco_info.c + * + * \\brief PCO info structures. + */ + +#include "pco_common.h" +#include "pco_internal.h" +#include "pco_isa.h" +#include "pco_ops.h" + +const struct pco_op_info pco_op_info[_PCO_OP_COUNT] = { +% for op in ops.values(): + [${op.cname.upper()}] = { + .str = "${op.name}", + .num_dests = ${op.num_dests}, + .num_srcs = ${op.num_srcs}, + .mods = ${op.cop_mods}, + .mod_map = { +% for mod, index in op.op_mod_map.items(): + [${mod}] = ${index}, +% endfor + }, + .dest_mods = { +% for index, cdest_mods in op.cdest_mods.items(): + [${index}] = ${cdest_mods}, +% endfor + }, + .src_mods = { +% for index, csrc_mods in op.csrc_mods.items(): + [${index}] = ${csrc_mods}, +% endfor + }, + .is_pseudo = ${str(op.is_pseudo).lower()}, + .has_target_cf_node = ${str(op.has_target_cf_node).lower()}, + }, +% endfor +}; + +const struct pco_op_mod_info pco_op_mod_info[_PCO_OP_MOD_COUNT] = { +% for name, (mod, cname, ctype) in op_mods.items(): + [${cname}] = { + .print_early = ${str(mod.print_early).lower()}, + .type = ${ctype}, + % if mod.base_type == BaseType.enum: + .strs = (const char * []){ + % for enum_cname, value, string in mod.enum.elems.values(): + [${enum_cname}] = "${string}", + % endfor + }, + % else: + .str = "${name}", + % endif + % if mod.nzdefault is not None: + .nzdefault = ${mod.nzdefault}, + % endif + }, +% endfor +}; + +const struct pco_ref_mod_info pco_ref_mod_info[_PCO_REF_MOD_COUNT] = { +% for name, (mod, cname, ctype) in ref_mods.items(): + [${cname}] = { + .type = ${ctype}, + % if mod.base_type == BaseType.enum: + .is_bitset = ${str(mod.enum.is_bitset).lower()}, + .strs = (const char * []){ + % for enum_cname, value, string in mod.enum.elems.values(): + [${enum_cname}] = "${string}", + % endfor + }, + % else: + .str = "${name}", + % endif + }, +% endfor +};""" + +def main(): + print(Template(template).render(BaseType=BaseType, ops=ops, op_mods=op_mods, ref_mods=ref_mods)) + +if __name__ == '__main__': + main() diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index 77525cf876a..c71b18f8dbf 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -16,6 +16,7 @@ #include "compiler/spirv/nir_spirv.h" #include "pco.h" #include "pco_common.h" +#include "pco_ops.h" #include "spirv/nir_spirv.h" #include "util/macros.h" @@ -70,4 +71,41 @@ extern const char *pco_skip_passes; extern bool pco_color; void pco_debug_init(void); +/** Op info. */ +struct pco_op_info { + const char *str; /** Op name string. */ + unsigned num_dests; /** Number of dests. */ + unsigned num_srcs; /** Number of sources. */ + uint64_t mods; /** Supported mods. */ + uint8_t mod_map[_PCO_OP_MOD_COUNT]; /** Index into pco_instr::mod. */ + uint64_t dest_mods[_PCO_OP_MAX_DESTS]; /** Supported dest mods. */ + uint64_t src_mods[_PCO_OP_MAX_SRCS]; /** Supported source mods. */ + bool is_pseudo; /** Set if op is a pseudo-instruction. */ + bool has_target_cf_node; /** Set if op has a cf-node as a target. */ +}; +extern const struct pco_op_info pco_op_info[_PCO_OP_COUNT]; + +/** Op mod info. */ +struct pco_op_mod_info { + bool print_early : 1; /** Set if printed before the op. */ + enum pco_mod_type type; /** Datatype. */ + union { + const char *str; /** Mod name. */ + const char **strs; /** Mod names (enums). */ + }; + uint32_t nzdefault; /** Default value if non-zero. */ +}; +extern const struct pco_op_mod_info pco_op_mod_info[_PCO_OP_MOD_COUNT]; + +/** Reference mod info. */ +struct pco_ref_mod_info { + bool is_bitset : 1; /** Set if type is an enum bitset. */ + enum pco_mod_type type; /** Datatype. */ + union { + const char *str; /** Mod name. */ + const char **strs; /** Mod names (enums). */ + }; +}; +extern const struct pco_ref_mod_info pco_ref_mod_info[_PCO_REF_MOD_COUNT]; + #endif /* PCO_INTERNAL_H */ diff --git a/src/imagination/pco/pco_ops.h.py b/src/imagination/pco/pco_ops.h.py index 1b929591da4..65d9c1cfc4f 100644 --- a/src/imagination/pco/pco_ops.h.py +++ b/src/imagination/pco/pco_ops.h.py @@ -25,10 +25,41 @@ template = """/* #include #include +#define _PCO_OP_MAX_DESTS ${max([op.num_dests for op in ops.values()])}U +#define _PCO_OP_MAX_SRCS ${max([op.num_srcs for op in ops.values()])}U +#define _PCO_OP_MAX_MODS ${max([len(op.op_mods) for op in ops.values()])}U + +/** Ops. */ +#define _PCO_OP_COUNT ${len(ops) + 1}U +enum pco_op { + PCO_OP_NONE, +% for op in ops.values(): + ${op.cname.upper()}, +% endfor +}; + +/** Op mods. */ +#define _PCO_OP_MOD_COUNT ${len(op_mods) + 1}U +enum pco_op_mod { + PCO_OP_MOD_NONE, +% for op_mod, cname, *_ in op_mods.values(): + ${cname}, +% endfor +}; + +/** Ref mods. */ +#define _PCO_REF_MOD_COUNT ${len(ref_mods) + 1}U +enum pco_ref_mod { + PCO_REF_MOD_NONE, +% for ref_mod, cname, *_ in ref_mods.values(): + ${cname}, +% endfor +}; + #endif /* PCO_OPS_H */""" def main(): - print(Template(template).render()) + print(Template(template).render(ops=ops, op_mods=op_mods, ref_mods=ref_mods)) if __name__ == '__main__': main() diff --git a/src/imagination/pco/pco_ops.py b/src/imagination/pco/pco_ops.py index b8abb481d94..f4ef838dd4c 100644 --- a/src/imagination/pco/pco_ops.py +++ b/src/imagination/pco/pco_ops.py @@ -21,27 +21,27 @@ REF_TYPE = enum_type('ref_type', [ ]) # Ref mods. -R_ONEMINUS = ref_mod('oneminus', BaseType.bool) -R_CLAMP = ref_mod('clamp', BaseType.bool) -R_ABS = ref_mod('abs', BaseType.bool) -R_NEG = ref_mod('neg', BaseType.bool) -R_FLR = ref_mod('flr', BaseType.bool) +RM_ONEMINUS = ref_mod('oneminus', BaseType.bool) +RM_CLAMP = ref_mod('clamp', BaseType.bool) +RM_ABS = ref_mod('abs', BaseType.bool) +RM_NEG = ref_mod('neg', BaseType.bool) +RM_FLR = ref_mod('flr', BaseType.bool) -R_ELEM = ref_mod_enum('elem', [ +RM_ELEM = ref_mod_enum('elem', [ 'e0', 'e1', 'e2', 'e3', ], is_bitset=True) -R_DTYPE = ref_mod_enum('dtype', [ +RM_DTYPE = ref_mod_enum('dtype', [ ('any', ''), ('unsigned', 'u'), ('signed', 'i'), ('float', 'f'), ]) -R_BITS = ref_mod_enum('bits', [ +RM_BITS = ref_mod_enum('bits', [ ('any', ''), ('1', '1'), ('8', '8'), @@ -50,7 +50,7 @@ R_BITS = ref_mod_enum('bits', [ ('64', '64'), ]) -R_REG_CLASS = ref_mod_enum('reg_class', [ +RM_REG_CLASS = ref_mod_enum('reg_class', [ ('virt', '$'), ('temp', 'r'), ('vtxin', 'vi'), @@ -65,7 +65,7 @@ R_REG_CLASS = ref_mod_enum('reg_class', [ ('slot', 'sl'), ]) -R_IO = ref_mod_enum('io', [ +RM_IO = ref_mod_enum('io', [ ('s0', 's0'), ('s1', 's1'), ('s2', 's2'), @@ -100,7 +100,7 @@ R_IO = ref_mod_enum('io', [ ('cout', 'cout'), ]) -R_PRED = ref_mod_enum('pred', [ +RM_PRED = ref_mod_enum('pred', [ ('pe', 'pe'), ('p0', 'p0'), @@ -110,29 +110,29 @@ R_PRED = ref_mod_enum('pred', [ ('p0_false', 'if(!p0)'), ]) -R_DRC = ref_mod_enum('drc', [ +RM_DRC = ref_mod_enum('drc', [ ('pending', '?'), ('0', '0'), ('1', '1'), ]) # Op mods. -O_EXEC_CND = op_mod_enum('exec_cnd', [ +OM_EXEC_CND = op_mod_enum('exec_cnd', [ ('e1_zx', ''), ('e1_z1', 'if(p0)'), ('ex_zx', '(ignorepe)'), ('e1_z0', 'if(!p0)'), ], print_early=True) -O_RPT = op_mod('rpt', BaseType.uint, print_early=True, nzdefault=1) -O_ATOM = op_mod('atom', BaseType.bool) -O_END = op_mod('end', BaseType.bool) -O_OLCHK = op_mod('olchk', BaseType.bool) -O_SAT = op_mod('sat', BaseType.bool) -O_LP = op_mod('lp', BaseType.bool) -O_SCALE = op_mod('scale', BaseType.bool) -O_ROUNDZERO = op_mod('roundzero', BaseType.bool) -O_S = op_mod('s', BaseType.bool) -O_TST_OP_MAIN = op_mod_enum('tst_op_main', [ +OM_RPT = op_mod('rpt', BaseType.uint, print_early=True, nzdefault=1) +OM_ATOM = op_mod('atom', BaseType.bool) +OM_END = op_mod('end', BaseType.bool) +OM_OLCHK = op_mod('olchk', BaseType.bool) +OM_SAT = op_mod('sat', BaseType.bool) +OM_LP = op_mod('lp', BaseType.bool) +OM_SCALE = op_mod('scale', BaseType.bool) +OM_ROUNDZERO = op_mod('roundzero', BaseType.bool) +OM_S = op_mod('s', BaseType.bool) +OM_TST_OP_MAIN = op_mod_enum('tst_op_main', [ ('zero', 'z'), ('gzero', 'gz'), ('gezero', 'gez'), @@ -144,52 +144,52 @@ O_TST_OP_MAIN = op_mod_enum('tst_op_main', [ ('less', 'l'), ('lequal', 'le'), ]) -O_TST_OP_BITWISE = op_mod_enum('tst_op_bitwise', [ +OM_TST_OP_BITWISE = op_mod_enum('tst_op_bitwise', [ ('zero', 'z'), ('nonzero', 'nz'), ]) -O_SIGNPOS = op_mod_enum('signpos', [ +OM_SIGNPOS = op_mod_enum('signpos', [ 'twb', 'pwb', 'mtb', 'ftb', ]) -O_DIM = op_mod('dim', BaseType.uint) -O_PROJ = op_mod('proj', BaseType.bool) -O_FCNORM = op_mod('fcnorm', BaseType.bool) -O_NNCOORDS = op_mod('nncoords', BaseType.bool) -O_LOD_MODE = op_mod_enum('lod_mode', [ +OM_DIM = op_mod('dim', BaseType.uint) +OM_PROJ = op_mod('proj', BaseType.bool) +OM_FCNORM = op_mod('fcnorm', BaseType.bool) +OM_NNCOORDS = op_mod('nncoords', BaseType.bool) +OM_LOD_MODE = op_mod_enum('lod_mode', [ ('normal', ''), ('bias', '.bias'), ('replace', '.replace'), ('gradient', '.gradient'), ]) -O_PPLOD = op_mod('pplod', BaseType.bool) -O_TAO = op_mod('tao', BaseType.bool) -O_SOO = op_mod('soo', BaseType.bool) -O_SNO = op_mod('sno', BaseType.bool) -O_WRT = op_mod('wrt', BaseType.bool) -O_SB_MODE = op_mod_enum('sb_mode', [ +OM_PPLOD = op_mod('pplod', BaseType.bool) +OM_TAO = op_mod('tao', BaseType.bool) +OM_SOO = op_mod('soo', BaseType.bool) +OM_SNO = op_mod('sno', BaseType.bool) +OM_WRT = op_mod('wrt', BaseType.bool) +OM_SB_MODE = op_mod_enum('sb_mode', [ ('none', ''), ('data', '.data'), ('info', '.info'), ('both', '.both'), ]) -O_ARRAY = op_mod('array', BaseType.bool) -O_INTEGER = op_mod('integer', BaseType.bool) -O_SCHEDSWAP = op_mod('schedswap', BaseType.bool) -O_F16 = op_mod('f16', BaseType.bool) -O_TILED = op_mod('tiled', BaseType.bool) -O_FREEP = op_mod('freep', BaseType.bool) -O_SM = op_mod('sm', BaseType.bool) -O_SAVMSK_MODE = op_mod_enum('savmsk_mode', [ +OM_ARRAY = op_mod('array', BaseType.bool) +OM_INTEGER = op_mod('integer', BaseType.bool) +OM_SCHEDSWAP = op_mod('schedswap', BaseType.bool) +OM_F16 = op_mod('f16', BaseType.bool) +OM_TILED = op_mod('tiled', BaseType.bool) +OM_FREEP = op_mod('freep', BaseType.bool) +OM_SM = op_mod('sm', BaseType.bool) +OM_SAVMSK_MODE = op_mod_enum('savmsk_mode', [ 'vm', 'icm', 'icmoc', 'icmi', 'caxy', ]) -O_ATOM_OP = op_mod_enum('atom_op', [ +OM_ATOM_OP = op_mod_enum('atom_op', [ 'add', 'sub', 'xchg', @@ -201,23 +201,23 @@ O_ATOM_OP = op_mod_enum('atom_op', [ 'or', 'xor', ]) -O_MCU_CACHE_MODE_LD = op_mod_enum('mcu_cache_mode_ld', [ +OM_MCU_CACHE_MODE_LD = op_mod_enum('mcu_cache_mode_ld', [ ('normal', ''), ('bypass', '.bypass'), ('force_line_fill', '.forcelinefill'), ]) -O_MCU_CACHE_MODE_ST = op_mod_enum('mcu_cache_mode_st', [ +OM_MCU_CACHE_MODE_ST = op_mod_enum('mcu_cache_mode_st', [ ('write_through', '.writethrough'), ('write_back', '.writeback'), ('lazy_write_back', '.lazywriteback'), ]) -O_BRANCH_CND = op_mod_enum('branch_cnd', [ +OM_BRANCH_CND = op_mod_enum('branch_cnd', [ ('exec_cond', ''), ('allinst', '.allinst'), ('anyinst', '.anyinst'), ]) -O_LINK = op_mod('link', BaseType.bool) -O_PCK_FMT = op_mod_enum('pck_fmt', [ +OM_LINK = op_mod('link', BaseType.bool) +OM_PCK_FMT = op_mod_enum('pck_fmt', [ 'u8888', 's8888', 'o8888', @@ -244,4 +244,9 @@ O_PCK_FMT = op_mod_enum('pck_fmt', [ 'zero', 'one', ]) -O_PHASE2END = op_mod('phase2end', BaseType.bool) +OM_PHASE2END = op_mod('phase2end', BaseType.bool) + +# HW ops +O_NOP = hw_op('nop', [OM_EXEC_CND, OM_END]) + +O_FADD = hw_op('fadd', [OM_LP, OM_SAT], 1, 2, [], [[RM_ABS, RM_NEG, RM_FLR], [RM_ABS]]) diff --git a/src/imagination/pco/pco_pygen_common.py b/src/imagination/pco/pco_pygen_common.py index 4a8bd825cf2..dc5ec9028d7 100644 --- a/src/imagination/pco/pco_pygen_common.py +++ b/src/imagination/pco/pco_pygen_common.py @@ -146,34 +146,42 @@ op_mod_enums = {} def op_mod(name, *args, **kwargs): assert name not in op_mods.keys(), f'Duplicate op mod "{name}".' t = type(name, *args, **kwargs) - op_mods[name] = t + cname = f'{prefix}_op_mod_{name}'.upper() + ctype = f'{prefix}_mod_type_{t.base_type.name.upper()}'.upper() + om = op_mods[name] = (t, cname, ctype) assert len(op_mods) <= 64, f'Too many op mods ({len(op_mods)})!' - return t + return om def op_mod_enum(name, *args, **kwargs): assert name not in op_mods.keys() and name not in op_mod_enums.keys(), f'Duplicate op mod enum "{name}".' t = enum_type(name, *args, **kwargs) - op_mods[name] = t + cname = f'{prefix}_op_mod_{name}'.upper() + ctype = f'{prefix}_mod_type_{t.base_type.name.upper()}'.upper() + om = op_mods[name] = (t, cname, ctype) op_mod_enums[name] = enums[name] assert len(op_mods) <= 64, f'Too many op mods ({len(op_mods)})!' - return t + return om ref_mods = {} ref_mod_enums = {} def ref_mod(name, *args, **kwargs): assert name not in ref_mods.keys(), f'Duplicate ref mod "{name}".' t = type(name, *args, **kwargs) - ref_mods[name] = t + cname = f'{prefix}_ref_mod_{name}'.upper() + ctype = f'{prefix}_mod_type_{t.base_type.name.upper()}'.upper() + rm = ref_mods[name] = (t, cname, ctype) assert len(ref_mods) <= 64, f'Too many ref mods ({len(ref_mods)})!' - return t + return rm def ref_mod_enum(name, *args, **kwargs): assert name not in ref_mods.keys() and name not in ref_mod_enums.keys(), f'Duplicate ref mod enum "{name}".' t = enum_type(name, *args, **kwargs) - ref_mods[name] = t + cname = f'{prefix}_ref_mod_{name}'.upper() + ctype = f'{prefix}_mod_type_{t.base_type.name.upper()}'.upper() + rm = ref_mods[name] = (t, cname, ctype) ref_mod_enums[name] = enums[name] assert len(ref_mods) <= 64, f'Too many ref mods ({len(ref_mods)})!' - return t + return rm # Bit encoding definition helpers. @@ -350,3 +358,42 @@ def bit_struct(name, bit_set, field_mappings, data=None): bit_set.variants.append((f'{bit_set.name}_{name}'.upper(), total_bytes)) return bs + +# Op definitions. +VARIABLE = ~0 + +class Op(object): + def __init__(self, name, cname, is_pseudo, op_mods, cop_mods, op_mod_map, num_dests, num_srcs, dest_mods, cdest_mods, src_mods, csrc_mods, has_target_cf_node): + self.name = name + self.cname = cname + self.is_pseudo = is_pseudo + self.op_mods = op_mods + self.cop_mods = cop_mods + self.op_mod_map = op_mod_map + self.num_dests = num_dests + self.num_srcs = num_srcs + self.dest_mods = dest_mods + self.cdest_mods = cdest_mods + self.src_mods = src_mods + self.csrc_mods = csrc_mods + self.has_target_cf_node = has_target_cf_node + +ops = {} + +def op(name, is_pseudo, op_mods, num_dests, num_srcs, dest_mods, src_mods, has_target_cf_node): + assert name not in ops.keys(), f'Duplicate op "{name}".' + + cname = f'{prefix}_op_{name}'.replace('.', '_') + cop_mods = 0 if not op_mods else ' | '.join([f'(1 << {mod[1]})' for mod in op_mods]) + op_mod_map = {mod[1]: index + 1 for index, mod in enumerate(op_mods)} + cdest_mods = {i: 0 if not dest_mods else ' | '.join([f'(1 << {mod[1]})' for mod in destn_mods]) for i, destn_mods in enumerate(dest_mods)} + csrc_mods = {i: 0 if not src_mods else ' | '.join([f'(1 << {mod[1]})' for mod in srcn_mods]) for i, srcn_mods in enumerate(src_mods)} + op = Op(name, cname, is_pseudo, op_mods, cop_mods, op_mod_map, num_dests, num_srcs, dest_mods, cdest_mods, src_mods, csrc_mods, has_target_cf_node) + ops[name] = op + return op + +def pseudo_op(name, op_mods=[], num_dests=0, num_srcs=0, dest_mods=[], src_mods=[], has_target_cf_node=False): + return op(name, True, op_mods, num_dests, num_srcs, dest_mods, src_mods, has_target_cf_node) + +def hw_op(name, op_mods=[], num_dests=0, num_srcs=0, dest_mods=[], src_mods=[], has_target_cf_node=False): + return op(name, False, op_mods, num_dests, num_srcs, dest_mods, src_mods, has_target_cf_node)