nak: Remove the old barriers pass

Reviewed-by: M Henning <drawoc@darkrefraction.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28300>
This commit is contained in:
Faith Ekstrand
2024-03-19 21:24:21 -05:00
committed by Marge Bot
parent a510e858b1
commit cad080412d
2 changed files with 0 additions and 271 deletions
-1
View File
@@ -34,7 +34,6 @@ dep_syn = dependency('syn',
libnak_c_files = files(
'nak.h',
'nak_nir.c',
'nak_nir_add_barriers.c',
'nak_nir_lower_cf.c',
'nak_nir_lower_scan_reduce.c',
'nak_nir_lower_tex.c',
-270
View File
@@ -1,270 +0,0 @@
/*
* Copyright © 2022 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#include "nak_private.h"
#include "nir_builder.h"
#include "util/u_dynarray.h"
struct barrier {
nir_cf_node *node;
nir_def *bar_set;
nir_def *bar_reg;
};
struct add_barriers_state {
const struct nak_compiler *nak;
nir_builder builder;
struct util_dynarray barriers;
bool progress;
};
static void
add_bar_cf_node(nir_cf_node *node, struct add_barriers_state *state)
{
nir_builder *b = &state->builder;
nir_block *before = nir_cf_node_as_block(nir_cf_node_prev(node));
nir_block *after = nir_cf_node_as_block(nir_cf_node_next(node));
b->cursor = nir_after_block(before);
nir_def *bar = nir_bar_set_nv(b);
nir_def *bar_reg = nir_decl_reg(b, 1, 32, 0);
nir_store_reg(b, bar, bar_reg);
b->cursor = nir_before_block_after_phis(after);
nir_bar_sync_nv(b, nir_load_reg(b, bar_reg), bar);
struct barrier barrier = {
.node = node,
.bar_set = bar,
.bar_reg = bar_reg,
};
util_dynarray_append(&state->barriers, struct barrier, barrier);
state->progress = true;
}
static void
break_loop_bars(nir_block *block, struct add_barriers_state *state)
{
if (exec_list_is_empty(&block->instr_list))
return;
nir_instr *block_last_instr = nir_block_last_instr(block);
if (block_last_instr->type != nir_instr_type_jump)
return;
nir_jump_instr *jump = nir_instr_as_jump(block_last_instr);
assert(jump->type == nir_jump_break ||
jump->type == nir_jump_continue);
nir_builder *b = &state->builder;
b->cursor = nir_before_instr(&jump->instr);
const unsigned num_bars =
util_dynarray_num_elements(&state->barriers, struct barrier);
int idx = (int)num_bars - 1;
for (nir_cf_node *p = block->cf_node.parent;
p->type != nir_cf_node_loop; p = p->parent) {
if (idx < 0)
break;
const struct barrier *bar =
util_dynarray_element(&state->barriers, struct barrier, idx);
if (bar->node == p) {
nir_def *bar_val = nir_load_reg(b, bar->bar_reg);
bar_val = nir_bar_break_nv(b, bar_val, nir_imm_true(b));
nir_store_reg(b, bar_val, bar->bar_reg);
idx--;
}
}
}
static void
pop_bar_cf_node(nir_cf_node *node, struct add_barriers_state *state)
{
if (state->barriers.size == 0)
return;
const struct barrier *top =
util_dynarray_top_ptr(&state->barriers, struct barrier);
if (top->node == node)
(void)util_dynarray_pop(&state->barriers, struct barrier);
}
/* Checks if this CF node's immediate successor has a sync. There's no point
* in adding a sync if the very next thing we do, besides dealing with phis,
* is to sync.
*/
static bool
cf_node_imm_succ_is_sync(nir_cf_node *node)
{
nir_block *block = nir_cf_node_as_block(nir_cf_node_next(node));
nir_foreach_instr(instr, block) {
if (instr->type == nir_instr_type_phi)
continue;
if (instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *sync = nir_instr_as_intrinsic(instr);
if (sync->intrinsic == nir_intrinsic_bar_sync_nv)
return true;
return false;
}
/* We can only get here if the only thing in the block is phis */
/* There's another loop or if following and we didn't find a sync */
if (nir_cf_node_next(&block->cf_node))
return false;
/* No successor in the CF list. Check the parent. */
nir_cf_node *parent = block->cf_node.parent;
switch (parent->type) {
case nir_cf_node_if:
return cf_node_imm_succ_is_sync(parent);
case nir_cf_node_loop:
/* We want to sync before the continue to avoid additional divergence.
* We could possibly avoid the sync in the case where the loop is known
* to be divergent and therefore syncs afterwards but this seems safer
* for now.
*
* Note that this also catches double loops where you have something
* like this:
*
* loop {
* ...
* if (div) {
* loop {
* ...
* }
* }
* }
*
* In this case, we'll place a merge after the if and so we don't need a
* merge around the inner loop.
*/
return false;
case nir_cf_node_function:
/* The end of the function is a natural sync point */
return true;
default:
unreachable("Unknown CF node type");
}
}
static bool
block_is_merge(const nir_block *block)
{
/* If it's unreachable, there is no merge */
if (block->imm_dom == NULL)
return false;
unsigned num_preds = 0;
set_foreach(block->predecessors, entry) {
const nir_block *pred = entry->key;
/* We don't care about unreachable blocks */
if (pred->imm_dom == NULL)
continue;
num_preds++;
}
return num_preds > 1;
}
static void
add_barriers_cf_list(struct exec_list *cf_list,
struct add_barriers_state *state)
{
foreach_list_typed(nir_cf_node, node, node, cf_list) {
switch (node->type) {
case nir_cf_node_block: {
nir_block *block = nir_cf_node_as_block(node);
break_loop_bars(block, state);
break;
}
case nir_cf_node_if: {
nir_if *nif = nir_cf_node_as_if(node);
if (nif->condition.ssa->divergent &&
block_is_merge(nir_cf_node_as_block(nir_cf_node_next(node))) &&
!cf_node_imm_succ_is_sync(&nif->cf_node))
add_bar_cf_node(&nif->cf_node, state);
add_barriers_cf_list(&nif->then_list, state);
add_barriers_cf_list(&nif->else_list, state);
pop_bar_cf_node(&nif->cf_node, state);
break;
}
case nir_cf_node_loop: {
nir_loop *loop = nir_cf_node_as_loop(node);
if (loop->divergent && !cf_node_imm_succ_is_sync(&loop->cf_node))
add_bar_cf_node(&loop->cf_node, state);
add_barriers_cf_list(&loop->body, state);
pop_bar_cf_node(&loop->cf_node, state);
break;
}
default:
unreachable("Unknown CF node type");
}
}
}
static bool
nak_nir_add_barriers_impl(nir_function_impl *impl,
const struct nak_compiler *nak)
{
nir_metadata_require(impl, nir_metadata_dominance);
struct add_barriers_state state = {
.nak = nak,
.builder = nir_builder_create(impl),
};
util_dynarray_init(&state.barriers, NULL);
add_barriers_cf_list(&impl->body, &state);
util_dynarray_fini(&state.barriers);
if (state.progress) {
nir_metadata_preserve(impl, nir_metadata_block_index |
nir_metadata_dominance |
nir_metadata_loop_analysis);
nir_lower_reg_intrinsics_to_ssa_impl(impl);
} else {
nir_metadata_preserve(impl, nir_metadata_all);
}
return state.progress;
}
bool
nak_nir_add_barriers(nir_shader *nir, const struct nak_compiler *nak)
{
if (nak->sm < 70) {
nir_shader_preserve_all_metadata(nir);
return false;
}
bool progress = false;
nir_foreach_function_impl(impl, nir)
progress |= nak_nir_add_barriers_impl(impl, nak);
return progress;
}