nir: use a u_dynarray for block predecessors
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run

A set is large and expensive to iterate.

This is faster (overall fossilize-replay difference):
Difference at 95.0% confidence
        -250 +/- 28.9257
        -2.04849% +/- 0.235211%
        (Student's t, pooled s = 34.1626)

Signed-off-by: Rhys Perry <pendingchaos02@gmail.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@intel.com>
Reviewed-by: Georg Lehmann <dadschoorse@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40242>
This commit is contained in:
Rhys Perry 2026-04-02 13:42:59 +01:00 committed by Marge Bot
parent 99c5f48da9
commit 01516746eb
4 changed files with 48 additions and 31 deletions

View file

@ -31,6 +31,7 @@
#include <math.h>
#include "util/half_float.h"
#include "util/macros.h"
#include "util/ralloc.h"
#include "util/u_math.h"
#include "util/u_printf.h"
#include "util/u_qsort.h"
@ -729,6 +730,13 @@ nir_function_impl_create(nir_function *function)
return impl;
}
static void
nir_block_destructor(void *block_)
{
nir_block *block = block_;
util_dynarray_fini(&block->predecessors);
}
nir_block *
nir_block_create(nir_shader *shader)
{
@ -737,12 +745,15 @@ nir_block_create(nir_shader *shader)
cf_init(&block->cf_node, nir_cf_node_block);
block->successors[0] = block->successors[1] = NULL;
_mesa_pointer_set_init(&block->predecessors, block);
util_dynarray_init_from_stack(
&block->predecessors, block->_preds_storage, sizeof(block->_preds_storage));
block->imm_dom = NULL;
_mesa_pointer_set_init(&block->dom_frontier, block);
exec_list_make_empty(&block->instr_list);
ralloc_set_destructor(block, &nir_block_destructor);
return block;
}

View file

@ -45,6 +45,7 @@
#include "util/set.h"
#include "util/simple_mtx.h"
#include "util/sparse_bitset.h"
#include "util/u_dynarray.h"
#include "util/u_math.h"
#include "nir_defines.h"
#include "nir_shader_compiler_options.h"
@ -3261,7 +3262,8 @@ typedef struct nir_block {
nir_block *successors[2];
/* Set of nir_block predecessors in the CFG */
struct set predecessors;
struct util_dynarray predecessors;
nir_block *_preds_storage[2];
/*
* this node's immediate dominator in the dominance tree - set to NULL for
@ -3311,57 +3313,48 @@ typedef struct nir_block {
struct u_sparse_bitset live_out;
} nir_block;
static ALWAYS_INLINE nir_block *
_nir_pred_iter_begin(const nir_block *block, nir_block **iter)
static ALWAYS_INLINE nir_block **
_nir_pred_iter_begin(const nir_block *block)
{
struct set_entry *entry = _mesa_set_next_entry(&block->predecessors, NULL);
*iter = (nir_block *)entry;
return entry ? (nir_block *)entry->key : NULL;
return (nir_block **)util_dynarray_begin(&block->predecessors);
}
static ALWAYS_INLINE nir_block *
_nir_pred_iter_end(const nir_block *block)
static ALWAYS_INLINE bool
_nir_pred_iter_end(const nir_block *block, nir_block **iter, nir_block **pred)
{
struct set_entry *entry = NULL;
return (nir_block *)entry;
if (iter == (nir_block **)util_dynarray_end(&block->predecessors))
return false;
*pred = *iter;
return true;
}
static ALWAYS_INLINE nir_block *
_nir_pred_iter_advance(const nir_block *block, nir_block **iter)
{
struct set_entry *entry = (struct set_entry *)*iter;
entry = _mesa_set_next_entry(&block->predecessors, entry);
*iter = (nir_block *)entry;
return entry ? (nir_block *)entry->key : NULL;
}
#define nir_foreach_pred(pred, block) \
for (nir_block * pred##_iter, *pred = _nir_pred_iter_begin((block), &pred##_iter); \
pred##_iter != _nir_pred_iter_end((block)); \
pred = _nir_pred_iter_advance((block), &pred##_iter))
#define nir_foreach_pred(pred, block) \
for (nir_block * pred, **pred##_iter = _nir_pred_iter_begin((block)); \
_nir_pred_iter_end((block), pred##_iter, &pred); \
pred##_iter++)
static inline size_t
nir_block_num_preds(const nir_block *block)
{
return block->predecessors.entries;
return util_dynarray_num_elements(&block->predecessors, nir_block *);
}
static inline bool
nir_block_has_pred(const nir_block *block, const nir_block *pred)
{
return _mesa_set_search(&block->predecessors, pred);
return pred->successors[0] == block || pred->successors[1] == block;
}
static inline void
nir_block_add_pred(nir_block *block, nir_block *pred)
{
_mesa_set_add(&block->predecessors, pred);
util_dynarray_append(&block->predecessors, pred);
}
static inline void
nir_block_remove_pred(nir_block *block, nir_block *pred)
{
_mesa_set_remove_key(&block->predecessors, pred);
util_dynarray_delete_unordered(&block->predecessors, nir_block *, pred);
}
static inline bool

View file

@ -162,7 +162,7 @@ replace_pred_succs(nir_block *block, nir_block *new_block, nir_block *exclude)
nir_block_add_pred(new_block, pred);
}
_mesa_set_clear(&block->predecessors, NULL);
util_dynarray_clear(&block->predecessors);
if (found_exclude)
nir_block_add_pred(block, exclude);
}

View file

@ -1472,8 +1472,10 @@ validate_block_predecessors(nir_block *block, validate_state *state)
block->successors[i]));
/* And we have to be in our successor's predecessors set */
validate_assert(state,
nir_block_has_pred(block->successors[i], block));
bool has_pred = false;
nir_foreach_pred(pred, block->successors[i])
has_pred |= pred == block;
validate_assert(state, has_pred);
validate_phi_srcs(block, block->successors[i], state);
}
@ -1482,6 +1484,17 @@ validate_block_predecessors(nir_block *block, validate_state *state)
if (block == nir_start_block(state->impl))
validate_assert(state, nir_block_num_preds(block) == 0);
/* Check for duplicate predecessors. */
nir_foreach_pred(pred, block) {
bool found = false;
nir_foreach_pred(pred2, block) {
if (pred == pred2) {
validate_assert(state, !found);
found = true;
}
}
}
nir_foreach_pred(pred, block) {
validate_assert(state, _mesa_set_search(state->blocks, pred));
validate_assert(state, pred->successors[0] == block ||