From 3c51c6ac17c8e037fd89808e8227cd089599dd11 Mon Sep 17 00:00:00 2001 From: Simon Perretta Date: Mon, 13 May 2024 17:38:21 +0100 Subject: [PATCH] pco: NIR translation and PCO IR pass boilerplate Signed-off-by: Simon Perretta Acked-by: Frank Binns Part-of: --- src/imagination/.clang-format | 2 + src/imagination/pco/meson.build | 1 + src/imagination/pco/pco.c | 138 ++++++++++++++++++++++ src/imagination/pco/pco_end.c | 43 +++++++ src/imagination/pco/pco_internal.h | 46 +++++++- src/imagination/pco/pco_ir.c | 22 ++++ src/imagination/pco/pco_ops.py | 7 ++ src/imagination/pco/pco_trans_nir.c | 175 +++++++++++++++++++++++++++- 8 files changed, 427 insertions(+), 7 deletions(-) create mode 100644 src/imagination/pco/pco_end.c diff --git a/src/imagination/.clang-format b/src/imagination/.clang-format index 2021ccfb223..f7203128935 100644 --- a/src/imagination/.clang-format +++ b/src/imagination/.clang-format @@ -199,6 +199,7 @@ MacroBlockEnd: '' ForEachMacros: [ 'foreach_instr', 'foreach_instr_safe', + 'foreach_list_typed', 'hash_table_foreach', 'LIST_FOR_EACH_ENTRY', 'LIST_FOR_EACH_ENTRY_FROM', @@ -220,6 +221,7 @@ ForEachMacros: [ 'nir_foreach_block_safe', 'nir_foreach_block_unstructured', 'nir_foreach_function', + 'nir_foreach_function_with_impl', 'nir_foreach_instr', 'nir_foreach_instr_safe', 'nir_foreach_shader_in_variable', diff --git a/src/imagination/pco/meson.build b/src/imagination/pco/meson.build index 0dcd2c04935..484661cf8f7 100644 --- a/src/imagination/pco/meson.build +++ b/src/imagination/pco/meson.build @@ -7,6 +7,7 @@ libpowervr_compiler_files = files( 'pco.c', 'pco_binary.c', 'pco_debug.c', + 'pco_end.c', 'pco_ir.c', 'pco_nir.c', 'pco_trans_nir.c', diff --git a/src/imagination/pco/pco.c b/src/imagination/pco/pco.c index acdae8492c7..e92a7c27785 100644 --- a/src/imagination/pco/pco.c +++ b/src/imagination/pco/pco.c @@ -12,9 +12,13 @@ #include "pco.h" #include "pco_internal.h" +#include "util/list.h" #include "util/macros.h" #include "util/ralloc.h" +#include +#include + /** * \brief Allocates and sets up a PCO compiler context. * @@ -65,6 +69,140 @@ const nir_shader_compiler_options *pco_nir_options(pco_ctx *ctx) return &ctx->nir_options; } +/** + * \brief Allocates and sets up a PCO shader from a NIR shader. + * + * \param[in] ctx PCO compiler context. + * \param[in] nir The NIR shader. + * \return The PCO shader, or NULL on failure. + */ +pco_shader *pco_shader_create(pco_ctx *ctx, nir_shader *nir, void *mem_ctx) +{ + pco_shader *shader = rzalloc_size(mem_ctx, sizeof(*shader)); + + shader->ctx = ctx; + shader->nir = nir; + shader->stage = nir->info.stage; + shader->name = ralloc_strdup(shader, nir->info.name); + shader->is_internal = nir->info.internal; + shader->is_grouped = false; + list_inithead(&shader->funcs); + + return shader; +} + +/** + * \brief Sets up a PCO cf node. + * + * \param[in,out] cf_node PCO cf node. + * \param[in] type CF node type. + */ +static inline void init_cf_node(pco_cf_node *cf_node, + enum pco_cf_node_type type) +{ + cf_node->type = type; + cf_node->parent = NULL; +} + +/** + * \brief Allocates and sets up a PCO function. + * + * \param[in,out] shader PCO shader. + * \param[in] type The function type. + * \param[in] num_params The number of parameters. + * \return The PCO function, or NULL on failure. + */ +pco_func *pco_func_create(pco_shader *shader, + enum pco_func_type type, + unsigned num_params) +{ + pco_func *func = rzalloc_size(shader, sizeof(*func)); + pco_func *preamble = pco_preamble(shader); + + /* Add the function to the shader; preamble goes first, then entrypoint. + * The rest of the functions will get appended. + */ + if (type == PCO_FUNC_TYPE_PREAMBLE) { + assert(!preamble); + list_add(&func->link, &shader->funcs); + } else if (type == PCO_FUNC_TYPE_ENTRYPOINT) { + assert(!pco_entrypoint(shader)); + list_add(&func->link, !preamble ? &shader->funcs : &preamble->link); + } else { + list_addtail(&func->link, &shader->funcs); + } + + init_cf_node(&func->cf_node, PCO_CF_NODE_TYPE_FUNC); + func->parent_shader = shader; + func->type = type; + func->index = shader->next_func++; + + list_inithead(&func->body); + + func->num_params = num_params; + if (num_params) { + func->params = + rzalloc_array_size(func, sizeof(*func->params), num_params); + } + + return func; +} + +/** + * \brief Allocates and sets up a PCO block. + * + * \param[in,out] func Parent function. + * \return The PCO block, or NULL on failure. + */ +pco_block *pco_block_create(pco_func *func) +{ + pco_block *block = rzalloc_size(func, sizeof(*block)); + + init_cf_node(&block->cf_node, PCO_CF_NODE_TYPE_BLOCK); + block->parent_func = func; + list_inithead(&block->instrs); + block->index = func->next_block++; + + return block; +} + +/** + * \brief Allocates and sets up a PCO if construct. + * + * \param[in,out] func Parent function. + * \return The PCO if construct, or NULL on failure. + */ +pco_if *pco_if_create(pco_func *func) +{ + pco_if *pif = rzalloc_size(func, sizeof(*pif)); + + init_cf_node(&pif->cf_node, PCO_CF_NODE_TYPE_IF); + pif->parent_func = func; + list_inithead(&pif->then_body); + list_inithead(&pif->else_body); + pif->index = func->next_if++; + + return pif; +} + +/** + * \brief Allocates and sets up a PCO loop. + * + * \param[in,out] func Parent function. + * \return The PCO loop, or NULL on failure. + */ +pco_loop *pco_loop_create(pco_func *func) +{ + pco_loop *loop = rzalloc_size(func, sizeof(*loop)); + + init_cf_node(&loop->cf_node, PCO_CF_NODE_TYPE_LOOP); + loop->parent_func = func; + list_inithead(&loop->body); + loop->index = func->next_loop++; + + return loop; +} + /** * \brief Allocates and sets up a PCO instruction. * diff --git a/src/imagination/pco/pco_end.c b/src/imagination/pco/pco_end.c new file mode 100644 index 00000000000..785feb5ec33 --- /dev/null +++ b/src/imagination/pco/pco_end.c @@ -0,0 +1,43 @@ +/* + * Copyright © 2024 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: MIT + */ + +/** + * \file pco_end.c + * + * \brief PCO shader ending pass. + */ + +#include "pco.h" +#include "pco_builder.h" +#include "pco_internal.h" +#include "util/macros.h" + +#include + +/** + * \brief Processes end of shader instruction(s). + * + * \param[in,out] shader PCO shader. + */ +bool pco_end(pco_shader *shader) +{ + /* TODO: Support for multiple end points. */ + pco_func *entry = pco_entrypoint(shader); + pco_block *last_block = pco_last_block(entry); + pco_instr *last_instr = pco_last_instr(last_block); + + pco_builder b = + pco_builder_create(entry, pco_cursor_after_block(last_block)); + + if (last_instr && pco_instr_has_end(last_instr)) { + pco_instr_set_end(last_instr, true); + return true; + } + + pco_nop(&b, .end = true); + + return true; +} diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index 6b6f2a5c273..8bbf9d522c3 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -292,7 +292,7 @@ typedef struct _pco_func { pco_shader *parent_shader; /** Shader containing the function. */ - bool is_entrypoint; + enum pco_func_type type; /** Function type. */ unsigned index; /** Function index. */ const char *name; /** Function name. */ @@ -372,6 +372,13 @@ struct pco_ref_mod_info { }; extern const struct pco_ref_mod_info pco_ref_mod_info[_PCO_REF_MOD_COUNT]; +pco_shader *pco_shader_create(pco_ctx *ctx, nir_shader *nir, void *mem_ctx); +pco_func *pco_func_create(pco_shader *shader, + enum pco_func_type type, + unsigned num_params); +pco_block *pco_block_create(pco_func *func); +pco_if *pco_if_create(pco_func *func); +pco_loop *pco_loop_create(pco_func *func); pco_instr *pco_instr_create(pco_func *func, enum pco_op op, unsigned num_dests, @@ -412,20 +419,46 @@ PCO_DEFINE_CAST(pco_cf_node_as_func, type, PCO_CF_NODE_TYPE_FUNC) +/** + * \brief Returns the preamble function of a PCO shader. + * + * \param[in] shader The PCO shader. + * \return The preamble function, or NULL if the shader has no preamble. + */ +static inline pco_func *pco_preamble(pco_shader *shader) +{ + if (list_is_empty(&shader->funcs)) + return NULL; + + pco_func *func = list_first_entry(&shader->funcs, pco_func, link); + if (func->type == PCO_FUNC_TYPE_PREAMBLE) + return func; + + return NULL; +} + /** * \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. + * \return The entrypoint function, or NULL if the shader has no entrypoint. */ 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; + /* Entrypoint will either be the first or second function in the shader, + * depending on whether or not there is a preamble. + */ + pco_func *preamble = pco_preamble(shader); + pco_func *func = !preamble ? list_first_entry(&shader->funcs, pco_func, link) + : list_entry(preamble->link.next, pco_func, link); + + if (func->type == PCO_FUNC_TYPE_ENTRYPOINT) + return func; + + return NULL; } /* Motions. */ @@ -582,4 +615,7 @@ static inline pco_igrp *pco_prev_igrp(pco_igrp *igrp) return list_entry(igrp->link.prev, pco_igrp, link); } + +/* PCO IR passes. */ +bool pco_end(pco_shader *shader); #endif /* PCO_INTERNAL_H */ diff --git a/src/imagination/pco/pco_ir.c b/src/imagination/pco/pco_ir.c index 73cf24f2ab8..b9ed6181e00 100644 --- a/src/imagination/pco/pco_ir.c +++ b/src/imagination/pco/pco_ir.c @@ -12,9 +12,29 @@ #include "pco.h" #include "pco_internal.h" +#include "util/u_debug.h" +#include #include +static inline bool pco_should_skip_pass(const char *pass) +{ + return comma_separated_list_contains(pco_skip_passes, pass); +} + +#define PCO_PASS(progress, shader, pass, ...) \ + do { \ + if (pco_should_skip_pass(#pass)) { \ + fprintf(stdout, "Skipping pass '%s'\n", #pass); \ + break; \ + } \ + \ + if (pass(shader, ##__VA_ARGS__)) { \ + UNUSED bool _; \ + progress = true; \ + } \ + } while (0) + /** * \brief Runs passes on a PCO shader. * @@ -23,5 +43,7 @@ */ void pco_process_ir(pco_ctx *ctx, pco_shader *shader) { + PCO_PASS(_, shader, pco_end); + puts("finishme: pco_process_ir"); } diff --git a/src/imagination/pco/pco_ops.py b/src/imagination/pco/pco_ops.py index e5217d09dc0..44ec8a059c3 100644 --- a/src/imagination/pco/pco_ops.py +++ b/src/imagination/pco/pco_ops.py @@ -20,6 +20,13 @@ REF_TYPE = enum_type('ref_type', [ 'drc', ]) +FUNC_TYPE = enum_type('func_type', [ + 'callable', + 'preamble', + 'entrypoint', + 'phase_change', +]) + # Ref mods. RM_ONEMINUS = ref_mod('oneminus', BaseType.bool) RM_CLAMP = ref_mod('clamp', BaseType.bool) diff --git a/src/imagination/pco/pco_trans_nir.c b/src/imagination/pco/pco_trans_nir.c index f7f6573458e..44cf6ea02fb 100644 --- a/src/imagination/pco/pco_trans_nir.c +++ b/src/imagination/pco/pco_trans_nir.c @@ -10,12 +10,174 @@ * \brief NIR translation functions. */ +#include "compiler/glsl/list.h" #include "pco.h" #include "pco_builder.h" #include "pco_internal.h" +#include "util/bitset.h" +#include "util/list.h" +#include "util/macros.h" +#include "util/ralloc.h" +#include #include +/** Translation context. */ +typedef struct _trans_ctx { + pco_ctx *pco_ctx; /** PCO compiler context. */ + pco_shader *shader; /** Current shader. */ + pco_func *func; /** Current function. */ + pco_builder b; /** Builder. */ + + BITSET_WORD *float_types; /** NIR SSA float vars. */ + BITSET_WORD *int_types; /** NIR SSA int vars. */ +} trans_ctx; + +/* Forward declarations. */ +static pco_block *trans_cf_nodes(trans_ctx *tctx, + pco_cf_node *parent_cf_node, + struct list_head *cf_node_list, + struct exec_list *nir_cf_node_list); + +/** + * \brief Translates a NIR block into PCO. + * + * \param[in] tctx Translation context. + * \param[in] nblock The nir block. + * \return The PCO block. + */ +static pco_block *trans_block(trans_ctx *tctx, nir_block *nblock) +{ + pco_block *block = pco_block_create(tctx->func); + tctx->b = pco_builder_create(tctx->func, pco_cursor_after_block(block)); + + return block; +} + +/** + * \brief Translates a NIR if into PCO. + * + * \param[in] tctx Translation context. + * \param[in] nif The nir if. + * \return The PCO if. + */ +static pco_if *trans_if(trans_ctx *tctx, nir_if *nif) +{ + pco_if *pif = pco_if_create(tctx->func); + + unreachable("finishme: trans_if"); + + return pif; +} + +/** + * \brief Translates a NIR loop into PCO. + * + * \param[in] tctx Translation context. + * \param[in] nloop The nir loop. + * \return The PCO loop. + */ +static pco_loop *trans_loop(trans_ctx *tctx, nir_loop *nloop) +{ + pco_loop *loop = pco_loop_create(tctx->func); + + unreachable("finishme: trans_loop"); + + return loop; +} + +/** + * \brief Translates a NIR function into PCO. + * + * \param[in] tctx Translation context. + * \param[in] impl The nir function impl. + * \return The PCO function. + */ +static pco_func *trans_func(trans_ctx *tctx, nir_function_impl *impl) +{ + nir_function *nfunc = impl->function; + enum pco_func_type func_type = PCO_FUNC_TYPE_CALLABLE; + + if (nfunc->is_preamble) + func_type = PCO_FUNC_TYPE_PREAMBLE; + else if (nfunc->is_entrypoint) + func_type = PCO_FUNC_TYPE_ENTRYPOINT; + + pco_func *func = pco_func_create(tctx->shader, func_type, nfunc->num_params); + tctx->func = func; + + func->name = ralloc_strdup(func, nfunc->name); + func->next_ssa = impl->ssa_alloc; + + /* TODO: Function parameter support. */ + assert(func->num_params == 0 && func->params == NULL); + + /* Gather types. */ + tctx->float_types = + rzalloc_array(NULL, BITSET_WORD, BITSET_WORDS(impl->ssa_alloc)); + tctx->int_types = + rzalloc_array(NULL, BITSET_WORD, BITSET_WORDS(impl->ssa_alloc)); + nir_gather_types(impl, tctx->float_types, tctx->int_types); + + trans_cf_nodes(tctx, &func->cf_node, &func->body, &impl->body); + + ralloc_free(tctx->float_types); + ralloc_free(tctx->int_types); + + return func; +} + +/** + * \brief Translates NIR control flow nodes into PCO. + * + * \param[in] tctx Translation context. + * \param[in] parent_cf_node The parent cf node. + * \param[in] cf_node_list The PCO cf node list. + * \param[in,out] nir_cf_node_list The NIR cf node list. + * \return The first block from the cf nodes. + */ +static pco_block *trans_cf_nodes(trans_ctx *tctx, + pco_cf_node *parent_cf_node, + struct list_head *cf_node_list, + struct exec_list *nir_cf_node_list) +{ + pco_block *start_block = NULL; + + pco_cf_node *cf_node; + foreach_list_typed (nir_cf_node, ncf_node, node, nir_cf_node_list) { + switch (ncf_node->type) { + case nir_cf_node_block: { + pco_block *block = trans_block(tctx, nir_cf_node_as_block(ncf_node)); + cf_node = &block->cf_node; + + if (!start_block) + start_block = block; + break; + } + + case nir_cf_node_if: { + pco_if *pif = trans_if(tctx, nir_cf_node_as_if(ncf_node)); + cf_node = &pif->cf_node; + break; + } + + case nir_cf_node_loop: { + pco_loop *loop = trans_loop(tctx, nir_cf_node_as_loop(ncf_node)); + cf_node = &loop->cf_node; + break; + } + + default: + unreachable(); + } + + cf_node->parent = parent_cf_node; + list_addtail(&cf_node->link, cf_node_list); + } + + return start_block; +} + /** * \brief Translates a NIR shader into a PCO shader. * @@ -26,6 +188,15 @@ */ pco_shader *pco_trans_nir(pco_ctx *ctx, nir_shader *nir, void *mem_ctx) { - puts("finishme: pco_trans_nir"); - return ralloc_context(mem_ctx); + pco_shader *shader = pco_shader_create(ctx, nir, mem_ctx); + trans_ctx tctx = { + .pco_ctx = ctx, + .shader = shader, + }; + + nir_foreach_function_with_impl (func, impl, nir) { + trans_func(&tctx, impl); + } + + return shader; }