From f179e5a220b4faad8583404712c8cd053f750119 Mon Sep 17 00:00:00 2001 From: Simon Perretta Date: Mon, 13 May 2024 02:41:18 +0100 Subject: [PATCH] pco: define data structures and basic builder implementation with ops Signed-off-by: Simon Perretta Acked-by: Frank Binns Part-of: --- src/imagination/pco/meson.build | 10 + src/imagination/pco/pco.c | 36 ++ src/imagination/pco/pco_binary.c | 1 + src/imagination/pco/pco_builder.h | 434 +++++++++++++++++++++ src/imagination/pco/pco_builder_ops.h.py | 122 ++++++ src/imagination/pco/pco_internal.h | 474 +++++++++++++++++++++++ src/imagination/pco/pco_ops.py | 4 + src/imagination/pco/pco_pygen_common.py | 36 +- src/imagination/pco/pco_trans_nir.c | 1 + 9 files changed, 1112 insertions(+), 6 deletions(-) create mode 100644 src/imagination/pco/pco_builder.h create mode 100644 src/imagination/pco/pco_builder_ops.h.py diff --git a/src/imagination/pco/meson.build b/src/imagination/pco/meson.build index d7f0284d79f..0dcd2c04935 100644 --- a/src/imagination/pco/meson.build +++ b/src/imagination/pco/meson.build @@ -14,6 +14,15 @@ libpowervr_compiler_files = files( pco_pygen_dep_files = files('pco_pygen_common.py', 'pco_isa.py', 'pco_ops.py') +pco_builder_ops_h = custom_target( + 'pco_builder_ops.h', + input : ['pco_builder_ops.h.py'], + output : 'pco_builder_ops.h', + command : [prog_python, '@INPUT@'], + capture : true, + depend_files : pco_pygen_dep_files, +) + pco_common_h = custom_target( 'pco_common.h', input : ['pco_common.h.py'], @@ -52,6 +61,7 @@ pco_ops_h = custom_target( idep_pco_pygen = declare_dependency( sources : [ + pco_builder_ops_h, pco_common_h, pco_info_c, pco_isa_h, diff --git a/src/imagination/pco/pco.c b/src/imagination/pco/pco.c index 49596c47f76..acdae8492c7 100644 --- a/src/imagination/pco/pco.c +++ b/src/imagination/pco/pco.c @@ -64,3 +64,39 @@ const nir_shader_compiler_options *pco_nir_options(pco_ctx *ctx) { return &ctx->nir_options; } + +/** + * \brief Allocates and sets up a PCO instruction. + * + * \param[in,out] func Parent function. + * \param[in] op Instruction op. + * \param[in] num_dests Number of destinations. + * \param[in] num_srcs Number of sources. + * \return The PCO instruction, or NULL on failure. + */ +pco_instr *pco_instr_create(pco_func *func, + enum pco_op op, + unsigned num_dests, + unsigned num_srcs) +{ + pco_instr *instr; + unsigned size = sizeof(*instr); + size += num_dests * sizeof(*instr->dest); + size += num_srcs * sizeof(*instr->src); + + instr = rzalloc_size(func, size); + + instr->parent_func = func; + + instr->op = op; + + instr->num_dests = num_dests; + instr->dest = (pco_ref *)(instr + 1); + + instr->num_srcs = num_srcs; + instr->src = instr->dest + num_dests; + + instr->index = func->next_instr++; + + return instr; +} diff --git a/src/imagination/pco/pco_binary.c b/src/imagination/pco/pco_binary.c index 25e142a1461..794abb6d220 100644 --- a/src/imagination/pco/pco_binary.c +++ b/src/imagination/pco/pco_binary.c @@ -12,6 +12,7 @@ #include "pco.h" #include "pco_internal.h" +#include "pco_isa.h" #include diff --git a/src/imagination/pco/pco_builder.h b/src/imagination/pco/pco_builder.h new file mode 100644 index 00000000000..4a3fbd33c12 --- /dev/null +++ b/src/imagination/pco/pco_builder.h @@ -0,0 +1,434 @@ +/* + * Copyright © 2024 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: MIT + */ + +#ifndef PCO_BUILDER_H +#define PCO_BUILDER_H + +/** + * \\file pco_builder.h + * + * \\brief PCO builder header. + */ + +#include "pco.h" +#include "pco_internal.h" +#include "util/list.h" +#include "util/macros.h" + +#include + +/** Cursor pointer. */ +enum pco_cursor_option { + PCO_CURSOR_BEFORE_CF_NODE, + PCO_CURSOR_AFTER_CF_NODE, + + PCO_CURSOR_BEFORE_INSTR, + PCO_CURSOR_AFTER_INSTR, + + PCO_CURSOR_BEFORE_IGRP, + PCO_CURSOR_AFTER_IGRP, +}; + +/** Cursor for PCO instructions/groups and basic blocks. */ +typedef struct pco_cursor { + enum pco_cursor_option option; /** Cursor pointer option. */ + union { + pco_cf_node *cf_node; + pco_instr *instr; + pco_igrp *igrp; + }; +} pco_cursor; + +/** PCO builder context. */ +typedef struct pco_builder { + pco_func *func; /** Target function. */ + pco_cursor cursor; /** Current position in the function. */ +} pco_builder; + +/* Cursor position setters. */ +/** + * \brief Returns a cursor set to before a cf node. + * + * \param[in] cf_node The cf node. + * \return The cursor. + */ +static inline pco_cursor pco_cursor_before_cf_node(pco_cf_node *cf_node) +{ + return (pco_cursor){ + .option = PCO_CURSOR_BEFORE_CF_NODE, + .cf_node = cf_node, + }; +} + +/** + * \brief Returns a cursor set to after a cf node. + * + * \param[in] cf_node The cf node. + * \return The cursor. + */ +static inline pco_cursor pco_cursor_after_cf_node(pco_cf_node *cf_node) +{ + return (pco_cursor){ + .option = PCO_CURSOR_AFTER_CF_NODE, + .cf_node = cf_node, + }; +} + +/** + * \brief Returns a cursor set to before a block. + * + * \param[in] block The block. + * \return The cursor. + */ +static inline pco_cursor pco_cursor_before_block(pco_block *block) +{ + return pco_cursor_before_cf_node(&block->cf_node); +} + +/** + * \brief Returns a cursor set to after a block. + * + * \param[in] block The block. + * \return The cursor. + */ +static inline pco_cursor pco_cursor_after_block(pco_block *block) +{ + return pco_cursor_after_cf_node(&block->cf_node); +} + +/** + * \brief Returns a cursor set to before an instruction. + * + * \param[in] instr The instruction. + * \return The cursor. + */ +static inline pco_cursor pco_cursor_before_instr(pco_instr *instr) +{ + return (pco_cursor){ + .option = PCO_CURSOR_BEFORE_INSTR, + .instr = instr, + }; +} + +/** + * \brief Returns a cursor set to after an instruction. + * + * \param[in] instr The instruction. + * \return The cursor. + */ +static inline pco_cursor pco_cursor_after_instr(pco_instr *instr) +{ + return (pco_cursor){ + .option = PCO_CURSOR_AFTER_INSTR, + .instr = instr, + }; +} + +/** + * \brief Returns a cursor set to before an instruction group. + * + * \param[in] igrp The instruction group. + * \return The cursor. + */ +static inline pco_cursor pco_cursor_before_igrp(pco_igrp *igrp) +{ + return (pco_cursor){ + .option = PCO_CURSOR_BEFORE_IGRP, + .igrp = igrp, + }; +} + +/** + * \brief Returns a cursor set to after an instruction group. + * + * \param[in] igrp The instruction group. + * \return The cursor. + */ +static inline pco_cursor pco_cursor_after_igrp(pco_igrp *igrp) +{ + return (pco_cursor){ + .option = PCO_CURSOR_AFTER_IGRP, + .igrp = igrp, + }; +} + +/** + * \brief Returns whether a cursor is set to before a construct. + * + * \param[in] cursor The cursor. + * \return True if the cursor is set to before a construct. + */ +static inline bool pco_cursor_is_before(pco_cursor cursor) +{ + return cursor.option == PCO_CURSOR_BEFORE_CF_NODE || + cursor.option == PCO_CURSOR_BEFORE_INSTR || + cursor.option == PCO_CURSOR_BEFORE_IGRP; +} + +/* Cursor get functions. */ +/** + * \brief Returns the function being pointed to by the cursor. + * + * \param[in] cursor The cursor. + * \return The function being pointed to. + */ +static inline pco_func *pco_cursor_func(pco_cursor cursor) +{ + switch (cursor.option) { + case PCO_CURSOR_BEFORE_CF_NODE: + case PCO_CURSOR_AFTER_CF_NODE: + switch (cursor.cf_node->type) { + case PCO_CF_NODE_TYPE_BLOCK: + return pco_cf_node_as_block(cursor.cf_node)->parent_func; + + case PCO_CF_NODE_TYPE_IF: + return pco_cf_node_as_if(cursor.cf_node)->parent_func; + + case PCO_CF_NODE_TYPE_LOOP: + return pco_cf_node_as_loop(cursor.cf_node)->parent_func; + + case PCO_CF_NODE_TYPE_FUNC: + return pco_cf_node_as_func(cursor.cf_node); + + default: + break; + } + break; + + case PCO_CURSOR_BEFORE_INSTR: + case PCO_CURSOR_AFTER_INSTR: + return cursor.instr->parent_func; + + case PCO_CURSOR_BEFORE_IGRP: + case PCO_CURSOR_AFTER_IGRP: + return cursor.igrp->parent_func; + + default: + break; + } + + unreachable(); +} + +/** + * \brief Returns the cf node being pointed to by the cursor. + * + * \param[in] cursor The cursor. + * \return The cf node being pointed to. + */ +static inline pco_cf_node *pco_cursor_cf_node(pco_cursor cursor) +{ + switch (cursor.option) { + case PCO_CURSOR_BEFORE_CF_NODE: + case PCO_CURSOR_AFTER_CF_NODE: + return cursor.cf_node; + + case PCO_CURSOR_BEFORE_INSTR: + case PCO_CURSOR_AFTER_INSTR: + return &cursor.instr->parent_block->cf_node; + + case PCO_CURSOR_BEFORE_IGRP: + case PCO_CURSOR_AFTER_IGRP: + return &cursor.igrp->parent_block->cf_node; + + default: + break; + } + + unreachable(); +} + +/** + * \brief Returns the block being pointed to by the cursor. + * + * \param[in] cursor The cursor. + * \return The block being pointed to. + */ +static inline pco_block *pco_cursor_block(pco_cursor cursor) +{ + switch (cursor.option) { + case PCO_CURSOR_BEFORE_CF_NODE: + case PCO_CURSOR_AFTER_CF_NODE: + switch (cursor.cf_node->type) { + case PCO_CF_NODE_TYPE_BLOCK: + return pco_cf_node_as_block(cursor.cf_node); + + /* TODO: other cf node types? */ + default: + break; + } + break; + + case PCO_CURSOR_BEFORE_INSTR: + case PCO_CURSOR_AFTER_INSTR: + return cursor.instr->parent_block; + + case PCO_CURSOR_BEFORE_IGRP: + case PCO_CURSOR_AFTER_IGRP: + return cursor.igrp->parent_block; + + default: + break; + } + + unreachable(); +} + +/** + * \brief Returns the instruction being pointed to by the cursor. + * + * \param[in] cursor The cursor. + * \return The instruction being pointed to. + */ +static inline pco_instr *pco_cursor_instr(pco_cursor cursor) +{ + bool before = pco_cursor_is_before(cursor); + + switch (cursor.option) { + case PCO_CURSOR_BEFORE_CF_NODE: + case PCO_CURSOR_AFTER_CF_NODE: { + pco_block *block = NULL; + + switch (cursor.cf_node->type) { + case PCO_CF_NODE_TYPE_BLOCK: + block = pco_cf_node_as_block(cursor.cf_node); + return before ? pco_first_instr(block) : pco_last_instr(block); + + /* TODO: other cf node types? */ + default: + break; + } + break; + } + + case PCO_CURSOR_BEFORE_INSTR: + case PCO_CURSOR_AFTER_INSTR: + return cursor.instr; + + default: + break; + } + + unreachable(); +} + +/** + * \brief Returns the instruction group being pointed to by the cursor. + * + * \param[in] cursor The cursor. + * \return The instruction group being pointed to. + */ +static inline pco_igrp *pco_cursor_igrp(pco_cursor cursor) +{ + bool before = pco_cursor_is_before(cursor); + + switch (cursor.option) { + case PCO_CURSOR_BEFORE_CF_NODE: + case PCO_CURSOR_AFTER_CF_NODE: { + pco_block *block = NULL; + + switch (cursor.cf_node->type) { + case PCO_CF_NODE_TYPE_BLOCK: + block = pco_cf_node_as_block(cursor.cf_node); + /* Special case: we're in pco_group_instrs and want to go from + * the start. + */ + if (!block->parent_func->parent_shader->is_grouped) + return NULL; + return before ? pco_first_igrp(block) : pco_last_igrp(block); + + /* TODO: other cf node types? */ + default: + break; + } + break; + } + + case PCO_CURSOR_BEFORE_IGRP: + case PCO_CURSOR_AFTER_IGRP: + return cursor.igrp; + + default: + break; + } + + unreachable(); +} + +/* Builder functions. */ +/** + * \brief Creates a builder. + * + * \param[in] func The function being targeted. + * \param[in] cursor The cursor. + * \return The builder. + */ +static pco_builder pco_builder_create(pco_func *func, pco_cursor cursor) +{ + return (pco_builder){ + .func = func, + .cursor = cursor, + }; +} + +/** + * \brief Inserts a block at a position specified by the builder. + * + * \param[in] b The builder. + * \param[in] block The block. + */ +/* TODO: test with multiple blocks. */ +static inline void pco_builder_insert_block(pco_builder *b, pco_block *block) +{ + struct list_head *list = &pco_cursor_cf_node(b->cursor)->link; + bool before = pco_cursor_is_before(b->cursor); + + list_add(&block->cf_node.link, before ? list->prev : list); + b->cursor = pco_cursor_after_block(block); +} + +/** + * \brief Inserts a instruction at a position specified by the builder. + * + * \param[in] b The builder. + * \param[in] instr The instruction. + */ +static inline void pco_builder_insert_instr(pco_builder *b, pco_instr *instr) +{ + pco_instr *cursor_instr = pco_cursor_instr(b->cursor); + bool before = pco_cursor_is_before(b->cursor); + pco_block *block = pco_cursor_block(b->cursor); + struct list_head *list = cursor_instr ? &cursor_instr->link : &block->instrs; + + instr->parent_block = block; + + list_add(&instr->link, (before && cursor_instr) ? list->prev : list); + b->cursor = pco_cursor_after_instr(instr); +} + +/** + * \brief Inserts a instruction group at a position specified by the builder. + * + * \param[in] b The builder. + * \param[in] igrp The instruction group. + */ +static inline void pco_builder_insert_igrp(pco_builder *b, pco_igrp *igrp) +{ + pco_igrp *cursor_igrp = pco_cursor_igrp(b->cursor); + bool before = pco_cursor_is_before(b->cursor); + pco_block *block = pco_cursor_block(b->cursor); + struct list_head *list = cursor_igrp ? &cursor_igrp->link : &block->instrs; + + igrp->parent_block = block; + + list_add(&igrp->link, (before && cursor_igrp) ? list->prev : list); + b->cursor = pco_cursor_after_igrp(igrp); +} + +/* Generated op building functions. */ +#include "pco_builder_ops.h" + +#endif /* PCO_BUILDER_H */ diff --git a/src/imagination/pco/pco_builder_ops.h.py b/src/imagination/pco/pco_builder_ops.h.py new file mode 100644 index 00000000000..63b8bc0456c --- /dev/null +++ b/src/imagination/pco/pco_builder_ops.h.py @@ -0,0 +1,122 @@ +# 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 + */ + +#ifndef PCO_BUILDER_OPS_H +#define PCO_BUILDER_OPS_H + +/** + * \\file pco_builder_ops.h + * + * \\brief PCO op building functions. + */ + +#include "pco_internal.h" +#include "pco_common.h" +#include "pco_ops.h" +#include "util/macros.h" + +#include +#include + +/** Op mod getting/setting. */ +static inline +bool pco_instr_has_mod(const pco_instr *instr, enum pco_op_mod mod) +{ + assert(mod < _PCO_OP_MOD_COUNT); + return (pco_op_info[instr->op].mods & (1ULL << mod)) != 0; +} + +static inline +void pco_instr_set_mod(pco_instr *instr, enum pco_op_mod mod, uint32_t val) +{ + assert(mod < _PCO_OP_MOD_COUNT); + unsigned mod_index = pco_op_info[instr->op].mod_map[mod]; + assert(mod_index > 0); + instr->mod[mod_index - 1] = val; +} + +static inline +uint32_t pco_instr_get_mod(pco_instr *instr, enum pco_op_mod mod) +{ + assert(mod < _PCO_OP_MOD_COUNT); + unsigned mod_index = pco_op_info[instr->op].mod_map[mod]; + assert(mod_index > 0); + return instr->mod[mod_index - 1]; +} + +% for t, cname, ctype in op_mods.values(): +static inline +bool pco_instr_has_${t.tname}(const pco_instr *instr) +{ + return pco_instr_has_mod(instr, ${cname}); +} + +static inline +void pco_instr_set_${t.tname}(pco_instr *instr, ${t.name} val) +{ + return pco_instr_set_mod(instr, ${cname}, val); +} + +static inline +${t.name} pco_instr_get_${t.tname}(pco_instr *instr) +{ + return pco_instr_get_mod(instr, ${cname}); +} + +% endfor +% for op in ops.values(): + % if bool(op.op_mods): +struct ${op.bname}_mods { + % for t, *_ in op.op_mods: + ${t.name} ${t.tname}; + % endfor +}; + % endif +#define ${op.bname}(${op.builder_params[1]}${op.builder_params[2]}) _${op.bname}(${op.builder_params[1]}${op.builder_params[3]}) +static +pco_instr *_${op.bname}(${op.builder_params[0]}) +{ + pco_instr *instr = pco_instr_create(pco_cursor_func(b->cursor), + ${op.cname.upper()}, + ${op.num_dests}, + ${op.num_srcs}); + + % if op.has_target_cf_node: + instr->target_cf_node = target_cf_node; + % endif + % for d in range(op.num_dests): + instr->dest[${d}] = dest${d}; + % endfor + % for s in range(op.num_srcs): + instr->src[${s}] = src${s}; + % endfor + + % for t, *_ in op.op_mods: + % if t.nzdefault is None: + pco_instr_set_${t.tname}(instr, mods.${t.tname}); + % else: + pco_instr_set_${t.tname}(instr, !mods.${t.tname} ? ${t.nzdefault} : mods.${t.tname}); + % endif + % endfor + + pco_builder_insert_instr(b, instr); + return instr; +} + +% endfor +#endif /* PCO_BUILDER_OPS_H */""" + +def main(): + print(Template(template).render(ops=ops, op_mods=op_mods)) + +if __name__ == '__main__': + main() diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index c71b18f8dbf..6b6f2a5c273 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -19,7 +19,10 @@ #include "pco_ops.h" #include "spirv/nir_spirv.h" #include "util/macros.h" +#include "util/list.h" +#include "util/u_dynarray.h" +#include #include #include @@ -71,6 +74,267 @@ extern const char *pco_skip_passes; extern bool pco_color; void pco_debug_init(void); + +typedef struct _pco_cf_node pco_cf_node; +typedef struct _pco_func pco_func; +typedef struct _pco_block pco_block; +typedef struct _pco_instr pco_instr; + +/** PCO reference index. */ +typedef struct PACKED _pco_ref { + /** Reference value. */ + union PACKED { + unsigned val : 32; + + struct PACKED { + unsigned num : 2; /** Index register number. */ + unsigned offset : 8; /** Offset. */ + unsigned _pad : 22; + } idx_reg; + }; + + /** Source/destination modifiers. */ + bool oneminus : 1; + bool clamp : 1; + bool abs : 1; + bool neg : 1; + bool flr : 1; + enum pco_elem elem : 4; /** .e0.e1.e2.e3 */ + + enum pco_dtype dtype : 2; /** Reference data-type. */ + unsigned chans : 10; /** Number of channels (1-1024). */ + enum pco_bits bits : 3; /** Bit width. */ + enum pco_ref_type type : 3; /** Reference type. */ + enum pco_reg_class reg_class : 4; /** Register class. */ + + unsigned _pad : 1; +} pco_ref; +static_assert(sizeof(pco_ref) == 8, "sizeof(pco_ref) != 8"); + +/** PCO phi source. */ +typedef struct _pco_phi_src { + struct list_head link; /** Link in pco_instr::phi_srcs. */ + + pco_block *pred; /** Predecessor block. */ + pco_ref ref; /** Source reference. */ +} pco_phi_src; + +/** PCO instruction group. */ +typedef struct _pco_igrp { + struct list_head link; /** Link in pco_block::instrs. */ + pco_block *parent_block; /** Basic block containing the igrp. */ + pco_func *parent_func; /** Parent function. */ + + pco_instr *instrs[_PCO_OP_PHASE_COUNT]; /** Instruction/group list. */ + + /** Instruction group header. */ + struct { + unsigned da; + unsigned length; + union { + enum pco_oporg oporg; + enum pco_opcnt opcnt; + }; + bool olchk; + bool w1p; + bool w0p; + enum pco_cc cc; + enum pco_alutype alutype; + union { + struct { + bool end; + bool atom; + unsigned rpt; + }; + struct { + unsigned miscctl; + enum pco_ctrlop ctrlop; + }; + }; + } hdr; + + struct { + pco_ref s0; + pco_ref s1; + pco_ref s2; + + pco_ref s3; + pco_ref s4; + pco_ref s5; + } srcs; + + struct { + pco_ref is0; + pco_ref is1; + pco_ref is2; + pco_ref is3; + pco_ref is4; + pco_ref is5; + } iss; + + struct { + pco_ref w0; + pco_ref w1; + } dests; + + struct { + enum pco_igrp_hdr_variant igrp_hdr; + union { + enum pco_main_variant main; + enum pco_backend_variant backend; + enum pco_bitwise_variant bitwise; + enum pco_ctrl_variant ctrl; + } instr[_PCO_OP_PHASE_COUNT]; + enum pco_src_variant lower_src; + enum pco_src_variant upper_src; + enum pco_iss_variant iss; + enum pco_dst_variant dest; + } variant; + + struct { + struct { + unsigned hdr; + unsigned lower_srcs; + unsigned upper_srcs; + unsigned iss; + unsigned dests; + unsigned instrs[_PCO_OP_PHASE_COUNT]; + unsigned word_padding; + unsigned align_padding; + unsigned total; + } len; + + unsigned offset; + } enc; + + unsigned index; /** Igrp index. */ + char *comment; /** Comment string. */ + +} pco_igrp; + +/** PCO instruction. */ +typedef struct _pco_instr { + union { + struct { + struct list_head link; /** Link in pco_block::instrs. */ + pco_block *parent_block; /** Basic block containing the instruction. */ + }; + + pco_igrp *parent_igrp; /** Igrp containing the instruction. */ + }; + + pco_func *parent_func; /** Parent function. */ + + enum pco_op op; + + unsigned num_dests; + pco_ref *dest; + unsigned num_srcs; + pco_ref *src; + + union { + struct list_head phi_srcs; + pco_cf_node *target_cf_node; + }; + + /** Instruction flags/modifiers. */ + uint32_t mod[_PCO_OP_MAX_MODS]; + + unsigned index; /** Instruction index. */ + char *comment; /** Comment string. */ +} pco_instr; + +/** PCO control-flow node type. */ +enum pco_cf_node_type { + PCO_CF_NODE_TYPE_BLOCK, + PCO_CF_NODE_TYPE_IF, + PCO_CF_NODE_TYPE_LOOP, + PCO_CF_NODE_TYPE_FUNC, +}; + +/** PCO control-flow node. */ +typedef struct _pco_cf_node { + struct list_head link; /** Link in lists of pco_cf_nodes. */ + enum pco_cf_node_type type; /** CF node type. */ + struct _pco_cf_node *parent; /** Parent cf node. */ +} pco_cf_node; + +/** PCO basic block. */ +typedef struct _pco_block { + pco_cf_node cf_node; /** Control flow node. */ + pco_func *parent_func; /** Parent function. */ + struct list_head instrs; /** Instruction/group list. */ + unsigned index; /** Block index. */ +} pco_block; + +/** PCO if cf construct. */ +typedef struct _pco_if { + pco_cf_node cf_node; /** CF node. */ + pco_func *parent_func; /** Parent function. */ + pco_ref cond; /** If condition. */ + struct list_head then_body; /** List of pco_cf_nodes for if body. */ + struct list_head else_body; /** List of pco_cf_nodes for else body. */ + unsigned index; /** If index. */ +} pco_if; + +/** PCO loop cf construct. */ +typedef struct _pco_loop { + pco_cf_node cf_node; /** CF node. */ + pco_func *parent_func; /** Parent function. */ + struct list_head body; /** List of pco_cf_nodes for loop body. */ + unsigned index; /** Loop index. */ +} pco_loop; + +/** PCO function. */ +typedef struct _pco_func { + struct list_head link; /** Link in pco_shader::funcs. */ + pco_cf_node cf_node; /** Control flow node. */ + + pco_shader *parent_shader; /** Shader containing the function. */ + + bool is_entrypoint; + unsigned index; /** Function index. */ + const char *name; /** Function name. */ + + struct list_head body; /** List of pco_cf_nodes for function body. */ + + unsigned num_params; + pco_ref *params; + + unsigned next_ssa; /** Next SSA node index. */ + unsigned next_instr; /** Next instruction index. */ + unsigned next_igrp; /** Next igrp index. */ + unsigned next_block; /** Next block index. */ + unsigned next_if; /** Next if index. */ + unsigned next_loop; /** Next loop index. */ + + unsigned temps; /** Number of temps allocated. */ +} pco_func; + +/** PCO shader. */ +typedef struct _pco_shader { + pco_ctx *ctx; /** Compiler context. */ + nir_shader *nir; /** Source NIR shader. */ + + gl_shader_stage stage; /** Shader stage. */ + const char *name; /** Shader name. */ + bool is_internal; /** Whether this is an internal shader. */ + bool is_grouped; /** Whether the shader uses igrps. */ + + struct list_head funcs; /** List of functions. */ + unsigned next_func; /** Next function index. */ + + struct { + struct util_dynarray buf; /** Shader binary. */ + + /** Binary patch info. */ + unsigned num_patches; + struct { + unsigned offset; + } * patch; + } binary; +} pco_shader; + /** Op info. */ struct pco_op_info { const char *str; /** Op name string. */ @@ -108,4 +372,214 @@ struct pco_ref_mod_info { }; extern const struct pco_ref_mod_info pco_ref_mod_info[_PCO_REF_MOD_COUNT]; +pco_instr *pco_instr_create(pco_func *func, + enum pco_op op, + unsigned num_dests, + unsigned num_srcs); + +/* Cast helpers. */ + +/* CF nodes. */ +#define PCO_DEFINE_CAST(name, in_type, out_type, field, type_field, type_value) \ + static inline out_type *name(const in_type *parent) \ + { \ + assert(parent && parent->type_field == type_value); \ + return list_entry(parent, out_type, field); \ + } + +PCO_DEFINE_CAST(pco_cf_node_as_block, + pco_cf_node, + pco_block, + cf_node, + type, + PCO_CF_NODE_TYPE_BLOCK) +PCO_DEFINE_CAST(pco_cf_node_as_if, + pco_cf_node, + pco_if, + cf_node, + type, + PCO_CF_NODE_TYPE_IF) +PCO_DEFINE_CAST(pco_cf_node_as_loop, + pco_cf_node, + pco_loop, + cf_node, + type, + PCO_CF_NODE_TYPE_LOOP) +PCO_DEFINE_CAST(pco_cf_node_as_func, + pco_cf_node, + pco_func, + cf_node, + type, + PCO_CF_NODE_TYPE_FUNC) + +/** + * \brief Returns the entrypoint function of a PCO shader. + * + * \param[in] shader The PCO shader. + * \return The entrypoint function, or NULL if the shader has no functions. + */ +static inline pco_func *pco_entrypoint(pco_shader *shader) +{ + if (list_is_empty(&shader->funcs)) + return NULL; + + pco_func *func = list_first_entry(&shader->funcs, pco_func, link); + assert(func->is_entrypoint); + return func; +} + +/* Motions. */ +/** + * \brief Returns the first block in a function. + * + * \param[in] func The function. + * \return The first block, or NULL if the function body is empty. + */ +static inline pco_block *pco_first_block(pco_func *func) +{ + pco_cf_node *cf_node = list_first_entry(&func->body, pco_cf_node, link); + if (list_is_empty(&func->body)) + return NULL; + + return pco_cf_node_as_block(cf_node); +} + +/** + * \brief Returns the last block in a function. + * + * \param[in] func The function. + * \return The last block, or NULL if the function body is empty. + */ +static inline pco_block *pco_last_block(pco_func *func) +{ + pco_cf_node *cf_node = list_last_entry(&func->body, pco_cf_node, link); + if (list_is_empty(&func->body)) + return NULL; + + return pco_cf_node_as_block(cf_node); +} + +/** + * \brief Returns the first instruction in a block. + * + * \param[in] block The block. + * \return The first instruction, or NULL if the block is empty. + */ +static inline pco_instr *pco_first_instr(pco_block *block) +{ + assert(!block->parent_func->parent_shader->is_grouped); + if (list_is_empty(&block->instrs)) + return NULL; + + return list_first_entry(&block->instrs, pco_instr, link); +} + +/** + * \brief Returns the last instruction in a block. + * + * \param[in] block The block. + * \return The last instruction, or NULL if the block is empty. + */ +static inline pco_instr *pco_last_instr(pco_block *block) +{ + assert(!block->parent_func->parent_shader->is_grouped); + if (list_is_empty(&block->instrs)) + return NULL; + + return list_last_entry(&block->instrs, pco_instr, link); +} + +/** + * \brief Returns the next instruction. + * + * \param[in] instr The current instruction. + * \return The next instruction, or NULL if the end of the block has been + * reached. + */ +static inline pco_instr *pco_next_instr(pco_instr *instr) +{ + assert(!instr->parent_func->parent_shader->is_grouped); + if (!instr || instr == pco_last_instr(instr->parent_block)) + return NULL; + + return list_entry(instr->link.next, pco_instr, link); +} + +/** + * \brief Returns the previous instruction. + * + * \param[in] instr The current instruction. + * \return The previous instruction, or NULL if the start of the block has been + * reached. + */ +static inline pco_instr *pco_prev_instr(pco_instr *instr) +{ + assert(!instr->parent_func->parent_shader->is_grouped); + if (!instr || instr == pco_first_instr(instr->parent_block)) + return NULL; + + return list_entry(instr->link.prev, pco_instr, link); +} + +/** + * \brief Returns the first instruction group in a block. + * + * \param[in] block The block. + * \return The first instruction group, or NULL if the block is empty. + */ +static inline pco_igrp *pco_first_igrp(pco_block *block) +{ + assert(block->parent_func->parent_shader->is_grouped); + if (list_is_empty(&block->instrs)) + return NULL; + + return list_first_entry(&block->instrs, pco_igrp, link); +} + +/** + * \brief Returns the last instruction group in a block. + * + * \param[in] block The block. + * \return The last instruction group, or NULL if the block is empty. + */ +static inline pco_igrp *pco_last_igrp(pco_block *block) +{ + assert(block->parent_func->parent_shader->is_grouped); + if (list_is_empty(&block->instrs)) + return NULL; + + return list_last_entry(&block->instrs, pco_igrp, link); +} + +/** + * \brief Returns the next instruction group. + * + * \param[in] igrp The current instruction group. + * \return The next instruction group, or NULL if the end of the block has been + * reached. + */ +static inline pco_igrp *pco_next_igrp(pco_igrp *igrp) +{ + assert(igrp->parent_func->parent_shader->is_grouped); + if (!igrp || igrp == pco_last_igrp(igrp->parent_block)) + return NULL; + + return list_entry(igrp->link.next, pco_igrp, link); +} + +/** + * \brief Returns the previous instruction group. + * + * \param[in] igrp The current instruction group. + * \return The previous instruction group, or NULL if the start of the block has + * been reached. + */ +static inline pco_igrp *pco_prev_igrp(pco_igrp *igrp) +{ + assert(igrp->parent_func->parent_shader->is_grouped); + if (!igrp || igrp == pco_first_igrp(igrp->parent_block)) + return NULL; + + return list_entry(igrp->link.prev, pco_igrp, link); +} #endif /* PCO_INTERNAL_H */ diff --git a/src/imagination/pco/pco_ops.py b/src/imagination/pco/pco_ops.py index f4ef838dd4c..e5217d09dc0 100644 --- a/src/imagination/pco/pco_ops.py +++ b/src/imagination/pco/pco_ops.py @@ -249,4 +249,8 @@ OM_PHASE2END = op_mod('phase2end', BaseType.bool) # HW ops O_NOP = hw_op('nop', [OM_EXEC_CND, OM_END]) +O_WOP = hw_op('wop') + +O_MBYP0 = hw_op('mbyp0', [OM_OLCHK, OM_EXEC_CND, OM_END, OM_ATOM, OM_RPT], 1, 1, [], [[RM_ABS, RM_NEG]]) + 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 dc5ec9028d7..de95ffe983b 100644 --- a/src/imagination/pco/pco_pygen_common.py +++ b/src/imagination/pco/pco_pygen_common.py @@ -16,8 +16,9 @@ class BaseType(Enum): enum = auto() class Type(object): - def __init__(self, name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum): + def __init__(self, name, tname, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum): self.name = name + self.tname = tname self.base_type = base_type self.num_bits = num_bits self.dec_bits = dec_bits @@ -41,7 +42,7 @@ def type(name, base_type, num_bits=None, dec_bits=None, check=None, encode=None, else: assert False, f'Invalid base type for type {name}.' - t = Type(_name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum) + t = Type(_name, name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum) types[name] = t return t @@ -360,12 +361,11 @@ def bit_struct(name, bit_set, field_mappings, data=None): 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): + def __init__(self, name, cname, bname, 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, builder_params): self.name = name self.cname = cname + self.bname = bname self.is_pseudo = is_pseudo self.op_mods = op_mods self.cop_mods = cop_mods @@ -377,6 +377,7 @@ class Op(object): self.src_mods = src_mods self.csrc_mods = csrc_mods self.has_target_cf_node = has_target_cf_node + self.builder_params = builder_params ops = {} @@ -384,11 +385,34 @@ def op(name, is_pseudo, op_mods, num_dests, num_srcs, dest_mods, src_mods, has_t assert name not in ops.keys(), f'Duplicate op "{name}".' cname = f'{prefix}_op_{name}'.replace('.', '_') + bname = f'{prefix}_{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) + + # Typed and untyped params for builder. + builder_params = ['', '', '', ''] + builder_params[0] += 'pco_builder *b' + builder_params[1] += 'b' + if has_target_cf_node: + builder_params[0] += ', pco_cf_node *target_cf_node' + builder_params[1] += ', target_cf_node' + + for d in range(num_dests): + builder_params[0] += f', pco_ref dest{d}' + builder_params[1] += f', dest{d}' + + for s in range(num_srcs): + builder_params[0] += f', pco_ref src{s}' + builder_params[1] += f', src{s}' + + if bool(op_mods): + builder_params[0] += f', struct {prefix}_{name}_mods mods' + builder_params[2] = ', ...' + builder_params[3] = f', (struct {bname}_mods){{0, ##__VA_ARGS__}}' + + op = Op(name, cname, bname, 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, builder_params) ops[name] = op return op diff --git a/src/imagination/pco/pco_trans_nir.c b/src/imagination/pco/pco_trans_nir.c index b8e93dccd4f..f7f6573458e 100644 --- a/src/imagination/pco/pco_trans_nir.c +++ b/src/imagination/pco/pco_trans_nir.c @@ -11,6 +11,7 @@ */ #include "pco.h" +#include "pco_builder.h" #include "pco_internal.h" #include