From 765e9d837d1615678e9a06fc01e82ed6961093f7 Mon Sep 17 00:00:00 2001 From: Simon Perretta Date: Sun, 1 Dec 2024 21:09:53 +0000 Subject: [PATCH] pco, pygen: validate phases and io allocations for ops Signed-off-by: Simon Perretta Acked-by: Frank Binns Part-of: --- src/imagination/pco/pco_info.c.py | 24 +++- src/imagination/pco/pco_internal.h | 9 ++ src/imagination/pco/pco_map.py | 1 + src/imagination/pco/pco_ops.py | 2 - src/imagination/pco/pco_print.c | 34 ++++- src/imagination/pco/pco_validate.c | 210 +++++++++++++++++++++++++++-- 6 files changed, 262 insertions(+), 18 deletions(-) diff --git a/src/imagination/pco/pco_info.c.py b/src/imagination/pco/pco_info.c.py index a446912cdc9..306d6b019bf 100644 --- a/src/imagination/pco/pco_info.c.py +++ b/src/imagination/pco/pco_info.c.py @@ -58,6 +58,28 @@ const struct pco_op_info pco_op_info[_PCO_OP_COUNT] = { % endfor }, % endif +#ifndef NDEBUG +% if op.bname in encode_maps: + .grp_dest_maps = { + % for phase, dests, _ in encode_maps[op.bname].op_ref_maps: + [${phase}] = { + % for dest in dests: + [${loop.index}] = ${dest}, + % endfor + }, + % endfor + }, + .grp_src_maps = { + % for phase, _, srcs in encode_maps[op.bname].op_ref_maps: + [${phase}] = { + % for src in srcs: + [${loop.index}] = ${src}, + % endfor + }, + % endfor + }, +% endif +#endif /* NDEBUG */ }, % endfor }; @@ -104,7 +126,7 @@ const struct pco_ref_mod_info pco_ref_mod_info[_PCO_REF_MOD_COUNT] = { def main(): try: - print(Template(template).render(BaseType=BaseType, ops=ops, op_mods=op_mods, ref_mods=ref_mods, group_maps=group_maps)) + print(Template(template).render(BaseType=BaseType, ops=ops, op_mods=op_mods, ref_mods=ref_mods, group_maps=group_maps, encode_maps=encode_maps)) except: raise Exception(exceptions.text_error_template().render()) diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index 9e4d22a36c3..8016ef0a031 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -362,8 +362,14 @@ struct pco_op_info { bool has_target_cf_node; /** Set if op has a cf-node as a target. */ uint8_t dest_intrn_map[_PCO_OP_MAX_DESTS]; uint8_t src_intrn_map[_PCO_OP_MAX_SRCS]; +#ifndef NDEBUG + uint32_t grp_dest_maps[_PCO_OP_PHASE_COUNT][_PCO_OP_MAX_DESTS]; + uint32_t grp_src_maps[_PCO_OP_PHASE_COUNT][_PCO_OP_MAX_SRCS]; +#endif /* NDEBUG */ }; extern const struct pco_op_info pco_op_info[_PCO_OP_COUNT]; +static_assert(_PCO_REF_MAP_COUNT <= 32, + "enum pco_ref_map must fit into an uint32_t"); /** Op mod info. */ struct pco_op_mod_info { @@ -2164,5 +2170,8 @@ void pco_print_instr(pco_shader *shader, pco_instr *instr); void pco_print_igrp(pco_shader *shader, pco_igrp *igrp); void pco_print_cf_node_name(pco_shader *shader, pco_cf_node *cf_node); void pco_print_shader_info(pco_shader *shader); +void pco_print_phase(pco_shader *shader, + enum pco_alutype alutype, + enum pco_op_phase phase); #endif /* PCO_INTERNAL_H */ diff --git a/src/imagination/pco/pco_map.py b/src/imagination/pco/pco_map.py index a2b46dc5af6..59a088b8de4 100644 --- a/src/imagination/pco/pco_map.py +++ b/src/imagination/pco/pco_map.py @@ -37,6 +37,7 @@ REF_MAP = enum_type('ref_map', [ ('ftt', 'ftt'), ('p0', 'p0'), + ('pe', 'pe'), ('imm', 'imm'), ('drc', 'drc'), diff --git a/src/imagination/pco/pco_ops.py b/src/imagination/pco/pco_ops.py index 44705a72b7b..1ae7e20372d 100644 --- a/src/imagination/pco/pco_ops.py +++ b/src/imagination/pco/pco_ops.py @@ -95,8 +95,6 @@ IO = enum_type('io', [ ('ftt', 'ftt'), ('cout', 'cout'), - - ('p0', 'p0'), ]) PRED = enum_type('pred', [ diff --git a/src/imagination/pco/pco_print.c b/src/imagination/pco/pco_print.c index aa9bafb0f0c..3dc5005ac1f 100644 --- a/src/imagination/pco/pco_print.c +++ b/src/imagination/pco/pco_print.c @@ -528,9 +528,9 @@ static void _pco_print_instr(pco_print_state *state, pco_instr *instr) * \param[in] alutype ALU type. * \param[in] phase Phase. */ -static void pco_print_phase(pco_print_state *state, - enum pco_alutype alutype, - enum pco_op_phase phase) +static void _pco_print_phase(pco_print_state *state, + enum pco_alutype alutype, + enum pco_op_phase phase) { switch (alutype) { case PCO_ALUTYPE_MAIN: @@ -567,7 +567,7 @@ static void pco_print_igrp_phases(pco_print_state *state, pco_igrp *igrp) if (printed) pco_printf(state, ","); - pco_print_phase(state, igrp->hdr.alutype, phase); + _pco_print_phase(state, igrp->hdr.alutype, phase); printed = true; } @@ -772,13 +772,13 @@ static void _pco_print_igrp(pco_print_state *state, pco_igrp *igrp) else if (printed) pco_printf(state, " "); - pco_print_phase(state, igrp->hdr.alutype, phase); + _pco_print_phase(state, igrp->hdr.alutype, phase); pco_printf(state, ": "); _pco_print_instr(state, igrp->instrs[phase]); if (state->verbose) { pco_printf(state, " /* "); - pco_print_phase(state, igrp->hdr.alutype, phase); + _pco_print_phase(state, igrp->hdr.alutype, phase); pco_printf(state, " bytes: %u */\n", igrp->enc.len.instrs[phase]); } @@ -1233,3 +1233,25 @@ void pco_print_shader_info(pco_shader *shader) }; return _pco_print_shader_info(&state, shader); } + +/** + * \brief Print the name of a phase(wrapper). + * + * \param[in] shader PCO shader. + * \param[in] alutype ALU type. + * \param[in] phase Phase. + */ +void pco_print_phase(pco_shader *shader, + enum pco_alutype alutype, + enum pco_op_phase phase) +{ + pco_print_state state = { + .fp = stdout, + .shader = shader, + .indent = 0, + .is_grouped = shader->is_grouped, + .verbose = false, + }; + + return _pco_print_phase(&state, alutype, phase); +} diff --git a/src/imagination/pco/pco_validate.c b/src/imagination/pco/pco_validate.c index 0f432472798..16aaec044fd 100644 --- a/src/imagination/pco/pco_validate.c +++ b/src/imagination/pco/pco_validate.c @@ -19,6 +19,8 @@ #include #include +#ifndef NDEBUG + enum ref_cursor { REF_CURSOR_NONE, REF_CURSOR_INSTR_DEST, @@ -58,7 +60,12 @@ static void pco_assert(struct val_state *state, if (cond) return; - printf("PCO validation failed with assertion \"%s\" - ", cond_str); + printf("PCO validation failed "); + + if (state->when) + printf("%s ", state->when); + + printf("with assertion \"%s\" - ", cond_str); va_list args; va_start(args, fmt); @@ -77,6 +84,18 @@ static void pco_assert(struct val_state *state, printf(" instr src #%" PRIuPTR, state->ref - state->instr->src); break; + case REF_CURSOR_IGRP_DEST: + printf(" igrp dest #%" PRIuPTR, state->ref - state->igrp->srcs.s); + break; + + case REF_CURSOR_IGRP_ISS: + printf(" igrp iss #%" PRIuPTR, state->ref - state->igrp->iss.is); + break; + + case REF_CURSOR_IGRP_SRC: + printf(" igrp src #%" PRIuPTR, state->ref - state->igrp->srcs.s); + break; + default: unreachable(); } @@ -98,6 +117,14 @@ static void pco_assert(struct val_state *state, if (state->instr) { printf(" instr "); + if (state->shader->is_grouped) { + printf("(phase "); + pco_print_phase(state->shader, + state->instr->parent_igrp->hdr.alutype, + state->instr->phase); + printf(") "); + } + pco_print_instr(state->shader, state->instr); } @@ -108,13 +135,13 @@ static void pco_assert(struct val_state *state, printf(".\n"); - pco_print_shader_info(state->shader); + pco_print_shader(state->shader, stdout, state->when); abort(); } -#define PCO_ASSERT(state, cond, fmt, ...) \ - pco_assert(state, cond, #cond, fmt, ##__VA_ARGS__) +# define PCO_ASSERT(state, cond, fmt, ...) \ + pco_assert(state, cond, #cond, fmt, ##__VA_ARGS__) /** * \brief Validates SSA assignments and uses. @@ -234,15 +261,175 @@ static void pco_validate_src_maps(struct val_state *state) } } +# define CHECK_IO(io, ref) \ + case PCO_REF_MAP_##io: \ + if (pco_ref_is_io(ref) && pco_ref_get_io(ref) == PCO_IO_##io) \ + return true; \ + break; + +/** + * \brief Checks whether a ref type corresponds to a supported mapping. + * + * \param[in] ref Src/dest reference. + * \param[in] ref_maps Supported mappings. + * \return True if the ref type corresponds to a supported mapping. + */ +static inline bool ref_is_in_map(pco_ref ref, enum pco_ref_map ref_maps) +{ + u_foreach_bit (_ref_map, ref_maps) { + enum pco_ref_map ref_map = _ref_map; + switch (ref_map) { + case PCO_REF_MAP__: + if (pco_ref_is_null(ref)) + return true; + break; + + CHECK_IO(S0, ref) + CHECK_IO(S1, ref) + CHECK_IO(S2, ref) + CHECK_IO(S3, ref) + CHECK_IO(S4, ref) + CHECK_IO(S5, ref) + + CHECK_IO(W0, ref) + CHECK_IO(W1, ref) + + CHECK_IO(IS0, ref) + CHECK_IO(IS1, ref) + CHECK_IO(IS2, ref) + CHECK_IO(IS3, ref) + CHECK_IO(IS4, ref) + CHECK_IO(IS5, ref) + + CHECK_IO(FT0, ref) + CHECK_IO(FT1, ref) + CHECK_IO(FT2, ref) + CHECK_IO(FTE, ref) + CHECK_IO(FT3, ref) + CHECK_IO(FT4, ref) + CHECK_IO(FT5, ref) + + CHECK_IO(FTT, ref) + + case PCO_REF_MAP_P0: + if (pco_ref_is_pred(ref) && ref.val == PCO_PRED_P0) + return true; + break; + + case PCO_REF_MAP_PE: + if (pco_ref_is_pred(ref) && ref.val == PCO_PRED_PE) + return true; + break; + + case PCO_REF_MAP_IMM: + if (pco_ref_is_imm(ref)) + return true; + break; + + case PCO_REF_MAP_DRC: + if (pco_ref_is_drc(ref)) + return true; + break; + + case PCO_REF_MAP_TEMP: + if ((pco_ref_is_reg(ref) || pco_ref_is_idx_reg(ref)) && + pco_ref_get_reg_class(ref) == PCO_REG_CLASS_TEMP) + return true; + break; + + case PCO_REF_MAP_COEFF: + if ((pco_ref_is_reg(ref) || pco_ref_is_idx_reg(ref)) && + pco_ref_get_reg_class(ref) == PCO_REG_CLASS_COEFF) + return true; + break; + + default: + unreachable(); + } + } + + return false; +} + +# undef CHECK_IO + +/** + * \brief Validates I/O references for igrps. + * + * \param[in,out] state Validation state. + */ +static void pco_validate_ref_maps(struct val_state *state) +{ + bool needs_s124; + pco_foreach_func_in_shader (func, state->shader) { + state->func = func; + + pco_foreach_igrp_in_func (igrp, func) { + state->cf_node = &igrp->parent_block->cf_node; + state->igrp = igrp; + + /* Igrp source mappings. */ + state->ref_cursor = REF_CURSOR_IGRP_SRC; + for (unsigned s = 0; s < ARRAY_SIZE(igrp->srcs.s); ++s) { + state->ref = &igrp->srcs.s[s]; + pco_ref src = igrp->srcs.s[s]; + + if (pco_ref_is_null(src)) + continue; + + bool valid = ref_src_map_valid(src, PCO_IO_S0 + s, &needs_s124); + PCO_ASSERT(state, + valid, + "HW register reference should be mapped to %s", + needs_s124 ? "S1/S2/S4" : "S0/S2/S3"); + } + + pco_foreach_instr_in_igrp (instr, igrp) { + const struct pco_op_info *info = &pco_op_info[instr->op]; + enum pco_op_phase phase = instr->phase; + state->instr = instr; + + /* Instruction dests. */ + state->ref_cursor = REF_CURSOR_INSTR_DEST; + for (unsigned d = 0; d < instr->num_dests; ++d) { + state->ref = &instr->dest[d]; + PCO_ASSERT(state, + ref_is_in_map(instr->dest[d], + info->grp_dest_maps[phase][d]), + "Invalid dest assignment."); + } + + /* Instruction sources. */ + state->ref_cursor = REF_CURSOR_INSTR_SRC; + for (unsigned s = 0; s < instr->num_srcs; ++s) { + state->ref = &instr->src[s]; + PCO_ASSERT(state, + ref_is_in_map(instr->src[s], + info->grp_src_maps[phase][s]), + "Invalid src assignment."); + } + + state->instr = NULL; + } + + state->igrp = NULL; + state->cf_node = NULL; + } + + state->func = NULL; + state->ref = NULL; + state->ref_cursor = REF_CURSOR_NONE; + } +} + /** * \brief Validates a PCO shader. * * \param[in] shader PCO shader. * \param[in] when When the validation check is being run. */ -void pco_validate_shader(UNUSED pco_shader *shader, UNUSED const char *when) +void pco_validate_shader(pco_shader *shader, const char *when) { -#ifndef NDEBUG if (PCO_DEBUG(VAL_SKIP)) return; @@ -255,8 +442,13 @@ void pco_validate_shader(UNUSED pco_shader *shader, UNUSED const char *when) if (!shader->is_grouped) { pco_validate_ssa(&state); pco_validate_src_maps(&state); + } else { + PCO_ASSERT(&state, + shader->is_legalized, + "Legalize pass should have been run before grouping"); + pco_validate_ref_maps(&state); } - - puts("finishme: pco_validate_shader"); -#endif /* NDEBUG */ } +#else /* NDEBUG */ +void pco_validate_shader(UNUSED pco_shader *shader, UNUSED const char *when) {} +#endif /* NDEBUG */