pco: initial legalize pass/validation to handle hw restrictions

Signed-off-by: Simon Perretta <simon.perretta@imgtec.com>
Acked-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33998>
This commit is contained in:
Simon Perretta
2024-11-23 18:04:17 +00:00
committed by Marge Bot
parent 4402649b01
commit 05912bcb60
7 changed files with 318 additions and 1 deletions

View File

@@ -12,6 +12,7 @@ libpowervr_compiler_files = files(
'pco_group_instrs.c',
'pco_index.c',
'pco_ir.c',
'pco_legalize.c',
'pco_nir.c',
'pco_nir_pvfio.c',
'pco_opt.c',

View File

@@ -337,6 +337,7 @@ typedef struct _pco_shader {
const char *name; /** Shader name. */
bool is_internal; /** Whether this is an internal shader. */
bool is_grouped; /** Whether the shader uses igrps. */
bool is_legalized; /** Whether the shader has been legalized. */
struct list_head funcs; /** List of functions. */
unsigned next_func; /** Next function index. */
@@ -1112,6 +1113,7 @@ bool pco_dce(pco_shader *shader);
bool pco_end(pco_shader *shader);
bool pco_group_instrs(pco_shader *shader);
bool pco_index(pco_shader *shader, bool skip_ssa);
bool pco_legalize(pco_shader *shader);
bool pco_nir_pfo(nir_shader *nir, pco_fs_data *fs);
bool pco_nir_pvi(nir_shader *nir, pco_vs_data *vs);
bool pco_opt(pco_shader *shader);
@@ -1946,6 +1948,47 @@ static inline bool pco_refs_are_equal(pco_ref ref0, pco_ref ref1)
return true;
}
/**
* \brief Checks a reference has a valid hardware source mapping.
*
* \param[in] ref Reference.
* \param[in] mapped_src Hardware source mapping.
* \param[out] needs_s124 Whether the mapping needs to use S{1,2,4}
* rather than S{0,2,3}.
* \return True if the mapping is valid.
*/
static inline bool
ref_src_map_valid(pco_ref ref, enum pco_io mapped_src, bool *needs_s124)
{
if (needs_s124)
*needs_s124 = false;
/* Restrictions only apply to hardware registers. */
if (!pco_ref_is_idx_reg(ref) && !pco_ref_is_reg(ref))
return true;
switch (pco_ref_get_reg_class(ref)) {
case PCO_REG_CLASS_COEFF:
case PCO_REG_CLASS_SHARED:
case PCO_REG_CLASS_INDEX:
case PCO_REG_CLASS_PIXOUT:
return (mapped_src == PCO_IO_S0) || (mapped_src == PCO_IO_S2) ||
(mapped_src == PCO_IO_S3);
case PCO_REG_CLASS_SPEC:
if (needs_s124)
*needs_s124 = true;
return (mapped_src == PCO_IO_S1) || (mapped_src == PCO_IO_S2) ||
(mapped_src == PCO_IO_S4);
default:
return true;
}
return false;
}
/**
* \brief Returns whether none of the lower/upper sources in an instruction
* group are set.

View File

@@ -60,6 +60,7 @@ void pco_process_ir(pco_ctx *ctx, pco_shader *shader)
* time a drc result is used.
*/
PCO_PASS(_, shader, pco_schedule);
PCO_PASS(_, shader, pco_legalize);
PCO_PASS(_, shader, pco_ra);
PCO_PASS(_, shader, pco_end);
PCO_PASS(_, shader, pco_group_instrs);

View File

@@ -0,0 +1,136 @@
/*
* Copyright © 2025 Imagination Technologies Ltd.
*
* SPDX-License-Identifier: MIT
*/
/**
* \file pco_legalize.c
*
* \brief PCO legalizing pass.
*/
#include "pco.h"
#include "pco_builder.h"
#include "pco_internal.h"
#include "util/macros.h"
#include <stdbool.h>
/**
* \brief Insert a mov to legalize how a hardware register is referenced.
*
* \param[in,out] instr PCO instr.
* \param[in,out] ref Reference to be legalized.
* \param[in] needs_s124 Whether the mapping needs to use S{1,2,4}
* rather than S{0,2,3}.
* \return True if progress was made.
*/
static void insert_mov_ref(pco_instr *instr, pco_ref *ref, bool needs_s124)
{
assert(pco_ref_is_scalar(*ref));
pco_ref new_ref = pco_ref_new_ssa(instr->parent_func,
pco_ref_get_bits(*ref),
pco_ref_get_chans(*ref));
pco_ref_xfer_mods(&new_ref, ref, true);
pco_builder b =
pco_builder_create(instr->parent_func, pco_cursor_before_instr(instr));
if (needs_s124)
pco_movs1(&b, new_ref, *ref);
else
pco_mbyp(&b, new_ref, *ref);
*ref = new_ref;
}
/**
* \brief Try to legalize an instruction's hardware source mappings.
*
* \param[in,out] instr PCO instr.
* \param[in] info PCO op info.
* \return True if progress was made.
*/
static bool try_legalize_src_mappings(pco_instr *instr,
const struct pco_op_info *info)
{
bool progress = false;
bool needs_s124;
/* Check dests. */
pco_foreach_instr_dest (pdest, instr) {
unsigned dest_index = pdest - instr->dest;
if (!info->dest_intrn_map[dest_index])
continue;
enum pco_io mapped_src = PCO_IO_S0 + info->dest_intrn_map[dest_index] - 1;
if (ref_src_map_valid(*pdest, mapped_src, &needs_s124))
continue;
insert_mov_ref(instr, pdest, needs_s124);
progress = true;
}
/* Check srcs. */
pco_foreach_instr_src (psrc, instr) {
unsigned src_index = psrc - instr->src;
if (!info->src_intrn_map[src_index])
continue;
enum pco_io mapped_src = PCO_IO_S0 + info->src_intrn_map[src_index] - 1;
if (ref_src_map_valid(*psrc, mapped_src, &needs_s124))
continue;
insert_mov_ref(instr, psrc, needs_s124);
progress = true;
}
return progress;
}
/**
* \brief Try to legalizes an instruction.
*
* \param[in,out] instr PCO instr.
* \return True if progress was made.
*/
static bool try_legalize(pco_instr *instr)
{
const struct pco_op_info *info = &pco_op_info[instr->op];
bool progress = false;
/* Skip pseudo instructions. */
if (info->type == PCO_OP_TYPE_PSEUDO)
return false;
progress |= try_legalize_src_mappings(instr, info);
return progress;
}
/**
* \brief Legalizes instructions where additional restrictions apply.
*
* \param[in,out] shader PCO shader.
* \return True if the pass made progress.
*/
bool pco_legalize(pco_shader *shader)
{
bool progress = false;
assert(!shader->is_grouped);
assert(!shader->is_legalized);
pco_foreach_func_in_shader (func, shader) {
pco_foreach_instr_in_func_safe (instr, func) {
progress |= try_legalize(instr);
}
}
shader->is_legalized = true;
return progress;
}

View File

@@ -781,6 +781,18 @@ encode_map(O_MOVC,
]
)
encode_map(O_MOVWM,
encodings=[
(I_MOVC_EXT, [
('movw0', ('pco_ref_get_movw01', SRC(0))),
('movw1', 0),
('maskw0', (RM_ELEM, DEST(0))),
('aw', True),
('p2end', OM_PHASE2END)
])
]
)
encode_map(O_ADD64_32,
encodings=[
(I_INT32_64_EXT, [
@@ -1082,6 +1094,52 @@ group_map(O_UNPCK,
dests=[('w[0]', ('0', DEST(0)), 'ft0')]
)
group_map(O_MOVWM,
hdr=(I_IGRP_HDR_MAIN, [
('oporg', 'p0_p2'),
('olchk', OM_OLCHK),
('w1p', False),
('w0p', True),
('cc', OM_EXEC_CND),
('end', OM_END),
('atom', OM_ATOM),
('rpt', OM_RPT)
]),
enc_ops=[
('0', O_MBYP, ['ft0'], [SRC(0)]),
('2_mov', O_MOVWM, [DEST(0)], ['ft0', SRC(1)], [(OM_PHASE2END, OM_PHASE2END)])
],
srcs=[
('s[0]', ('0', SRC(0)), 's0'),
('s[1]', ('2_mov', SRC(1)), 'is4')
],
iss=[
('is[0]', 's1'),
('is[4]', 'fte')
],
dests=[('w[0]', ('2_mov', DEST(0)), 'w0')]
)
group_map(O_MOVS1,
hdr=(I_IGRP_HDR_MAIN, [
('oporg', 'p2'),
('olchk', OM_OLCHK),
('w1p', False),
('w0p', True),
('cc', OM_EXEC_CND),
('end', OM_END),
('atom', OM_ATOM),
('rpt', OM_RPT)
]),
enc_ops=[('2_mov', O_MOVWM, [DEST(0)], [SRC(0), 'is4'], [(OM_PHASE2END, True)])],
srcs=[('s[1]', ('2_mov', SRC(0)), 'fte')],
iss=[
('is[0]', 's1'),
('is[4]', 'fte')
],
dests=[('w[0]', ('2_mov', DEST(0)), 'w0')]
)
group_map(O_ADD64_32,
hdr=(I_IGRP_HDR_MAIN, [
('oporg', 'p0'),

View File

@@ -303,6 +303,9 @@ O_UNPCK = hw_op('unpck', OM_ALU + [OM_PCK_FMT, OM_ROUNDZERO, OM_SCALE], 1, 1, []
O_TST = hw_direct_op('tst', [OM_TST_OP_MAIN, OM_PHASE2END, OM_TST_TYPE_MAIN], 2, 2, [], [[RM_ELEM], [RM_ELEM]])
O_MOVC = hw_direct_op('movc', [OM_PHASE2END], 2, 5, [[RM_ELEM]])
O_MOVWM = hw_op('movwm', OM_ALU + [OM_PHASE2END], 1, 2, [[RM_ELEM]])
O_MOVS1 = hw_op('movs1', OM_ALU, 1, 1)
# TODO
# O_PCK_ELEM = pseudo_op('pck.elem', OM_ALU_RPT1 + [OM_PCK_FMT, OM_ROUNDZERO, OM_SCALE], 1, 2)

View File

@@ -152,12 +152,85 @@ static void pco_validate_ssa(struct val_state *state)
"SSA destination defined to more than once");
BITSET_SET(ssa_writes, pdest->val);
}
state->instr = NULL;
state->cf_node = NULL;
}
ralloc_free(ssa_writes);
state->func = NULL;
state->ref = NULL;
state->ref_cursor = REF_CURSOR_NONE;
}
}
/**
* \brief Validates hardware source mappings.
*
* \param[in,out] state Validation state.
*/
static void pco_validate_src_maps(struct val_state *state)
{
/* Only check after the legalize pass has run. */
if (!state->shader->is_legalized)
return;
bool needs_s124;
pco_foreach_func_in_shader (func, state->shader) {
state->func = func;
pco_foreach_instr_in_func (instr, func) {
const struct pco_op_info *info = &pco_op_info[instr->op];
if (info->type == PCO_OP_TYPE_PSEUDO)
continue;
state->cf_node = &instr->parent_block->cf_node;
state->instr = instr;
state->ref_cursor = REF_CURSOR_INSTR_DEST;
pco_foreach_instr_dest (pdest, instr) {
state->ref = pdest;
unsigned dest_index = pdest - instr->dest;
if (!info->dest_intrn_map[dest_index])
continue;
enum pco_io mapped_src =
PCO_IO_S0 + info->dest_intrn_map[dest_index] - 1;
bool valid = ref_src_map_valid(*pdest, mapped_src, &needs_s124);
PCO_ASSERT(state,
valid,
"HW register reference should be mapped to %s",
needs_s124 ? "S1/S2/S4" : "S0/S2/S3");
}
state->ref_cursor = REF_CURSOR_INSTR_SRC;
pco_foreach_instr_src (psrc, instr) {
state->ref = psrc;
unsigned src_index = psrc - instr->src;
if (!info->src_intrn_map[src_index])
continue;
enum pco_io mapped_src =
PCO_IO_S0 + info->src_intrn_map[src_index] - 1;
bool valid = ref_src_map_valid(*psrc, mapped_src, &needs_s124);
PCO_ASSERT(state,
valid,
"HW register reference should be mapped to %s",
needs_s124 ? "S1/S2/S4" : "S0/S2/S3");
}
state->instr = NULL;
state->cf_node = NULL;
}
state->func = NULL;
state->ref = NULL;
state->ref_cursor = REF_CURSOR_NONE;
}
}
@@ -179,8 +252,10 @@ void pco_validate_shader(UNUSED pco_shader *shader, UNUSED const char *when)
.phase = -1,
};
if (!shader->is_grouped)
if (!shader->is_grouped) {
pco_validate_ssa(&state);
pco_validate_src_maps(&state);
}
puts("finishme: pco_validate_shader");
#endif /* NDEBUG */