Merge branch 'remove-mkvec' into 'main'

pan/bi: add pass to remove uneeded MKVEC post register allocation

See merge request mesa/mesa!39020
This commit is contained in:
Romaric Jodin 2025-12-20 01:47:12 +01:00
commit 3607a10966
4 changed files with 186 additions and 1 deletions

View file

@ -0,0 +1,181 @@
/*
* Copyright (C) 2025 Google LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Authors (Google):
* Romaric Jodin <rjodin@google.com>
*/
#include "util/hash_table.h"
#include "compiler.h"
#define MULTIPLE_USES ((bi_instr *)(uintptr_t)1)
#define INVALID_INSTR MULTIPLE_USES
#define MAX_REG (64)
struct mkvec_state {
bi_instr *writers[2];
};
static bool
is_valid(bi_instr *I)
{
return I != NULL && I != INVALID_INSTR;
}
static enum bi_swizzle
bi_compose_half_swizzle(enum bi_swizzle inner, enum bi_swizzle outer)
{
if (inner == BI_SWIZZLE_H10) {
switch (outer) {
case BI_SWIZZLE_H00:
return BI_SWIZZLE_H11;
case BI_SWIZZLE_H11:
return BI_SWIZZLE_H00;
default:
UNREACHABLE(
"Outer non-replicate swizzle should have been filtered out earlier ");
}
}
return inner;
}
static void
update_mkvec_state(bi_instr *I, bi_index idx, bi_instr *mkvec,
struct hash_table *mkvec_states)
{
if (!is_valid(mkvec) || I->nr_dests != 1)
return;
struct hash_entry *entry = _mesa_hash_table_search(mkvec_states, mkvec);
struct mkvec_state *state = entry ? entry->data : NULL;
if (!state)
return;
bi_foreach_src(mkvec, s) {
bi_foreach_src(I, I_source) {
if (bi_is_equiv(I->src[I_source], mkvec->dest[0])) {
state->writers[s] = INVALID_INSTR;
}
}
if (state->writers[s] == NULL && bi_is_value_equiv(idx, mkvec->src[s]))
state->writers[s] = I;
}
}
static void
handle_dest(bi_instr *I, bi_index idx, bi_instr **reg_to_mkvec,
struct hash_table *mkvec_states)
{
if (idx.type != BI_INDEX_REGISTER)
return;
unsigned reg = idx.value;
assert(reg < MAX_REG);
update_mkvec_state(I, idx, reg_to_mkvec[reg], mkvec_states);
reg_to_mkvec[reg] = NULL;
}
static void
handle_src(bi_instr *mkvec, bi_index idx, bi_instr **reg_to_mkvec)
{
unsigned reg = idx.value;
if (idx.type != BI_INDEX_REGISTER)
return;
assert(reg < MAX_REG);
if (reg_to_mkvec[reg] == NULL) {
reg_to_mkvec[reg] = mkvec;
} else {
reg_to_mkvec[reg] = MULTIPLE_USES;
}
}
static void
handle_instr(bi_instr *I, bi_instr **reg_to_mkvec,
struct hash_table *mkvec_states)
{
bi_foreach_dest(I, d) {
handle_dest(I, I->dest[d], reg_to_mkvec, mkvec_states);
}
switch (I->op) {
case BI_OPCODE_MKVEC_V2I16:
break;
default:
return;
}
bi_foreach_src(I, s) {
if (!bi_swizzle_replicates_16(I->src[s].swizzle)) {
return;
}
handle_src(I, I->src[s], reg_to_mkvec);
}
assert(_mesa_hash_table_search(mkvec_states, I) == NULL);
struct mkvec_state *state = rzalloc(mkvec_states, struct mkvec_state);
_mesa_hash_table_insert(mkvec_states, I, state);
}
static void
remove_mkvec(bi_instr *mkvec, struct mkvec_state *state)
{
switch (mkvec->op) {
case BI_OPCODE_MKVEC_V2I16: {
if (!is_valid(state->writers[0]) || !is_valid(state->writers[1]))
return;
for (unsigned i = 0; i < 2; ++i) {
bi_foreach_src(state->writers[i], s) {
state->writers[i]->src[s].swizzle = bi_compose_half_swizzle(
state->writers[i]->src[s].swizzle, mkvec->src[i].swizzle);
}
state->writers[i]->dest[0] = bi_half(mkvec->dest[0], i == 1);
}
bi_remove_instruction(mkvec);
} break;
default:
break;
}
}
void
bi_opt_remove_mkvec(bi_context *ctx)
{
bi_postra_liveness(ctx);
bi_foreach_block(ctx, block) {
struct hash_table *mkvec_states = _mesa_pointer_hash_table_create(NULL);
bi_instr *reg_to_mkvec[MAX_REG] = {NULL};
for (unsigned i = 0; i < MAX_REG; ++i) {
if ((block->reg_live_out >> i) & 1)
reg_to_mkvec[i] = MULTIPLE_USES;
}
bi_foreach_instr_in_block_rev(block, I) {
handle_instr(I, reg_to_mkvec, mkvec_states);
}
hash_table_foreach(mkvec_states, entry)
{
remove_mkvec((bi_instr *)entry->key,
(struct mkvec_state *)entry->data);
}
_mesa_hash_table_destroy(mkvec_states, NULL);
}
}

View file

@ -6747,8 +6747,10 @@ bi_compile_variant_nir(nir_shader *nir,
bi_register_allocate(ctx);
if (likely(optimize))
if (likely(optimize)) {
bi_opt_post_ra(ctx);
bi_opt_remove_mkvec(ctx);
}
if (bifrost_debug & BIFROST_DBG_SHADERS && !skip_internal)
bi_print_shader(ctx, stdout);

View file

@ -1444,6 +1444,7 @@ void bi_opt_dce_post_ra(bi_context *ctx);
void bi_opt_message_preload(bi_context *ctx);
void bi_opt_push_ubo(bi_context *ctx);
void bi_opt_reorder_push(bi_context *ctx);
void bi_opt_remove_mkvec(bi_context *ctx);
void bi_lower_swizzle(bi_context *ctx);
void bi_lower_fau(bi_context *ctx);
void bi_assign_scoreboard(bi_context *ctx);

View file

@ -21,6 +21,7 @@ libpanfrost_bifrost_files = files(
'bi_opt_push_ubo.c',
'bi_opt_mod_props.c',
'bi_opt_dual_tex.c',
'bi_opt_remove_mkvec.c',
'bi_iterator_schedule.c',
'bi_pressure_schedule.c',
'bi_ra.c',