In nir-to-tgsi, I want to free temps storing SSA values when they go dead,
and NIR liveness has most of the information I need. Hoever, when I reach
the end of a block, I need to free whatever temps were in liveout which
are dead at that point. If liveout is indexed by live_index, then I don't
know the maximum live_index for iterating the live_out bitset, and I also
don't have a way to map that index back to the def->index that my temps
are stored under.
We can use the more typical def->index for these bitsets, which resolves
both of those problems. The only cost is that ssa_undefs don't get merged
into a single bit in the bitfield, but there are generally 1-4 of them in
a shader and we don't track liveness for those anyway so splitting them
apart is fine.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6408>
+ impl->valid_metadata &= ~nir_metadata_live_ssa_defs;
+
nir_foreach_block_unstructured(block, impl) {
nir_foreach_instr(instr, block)
nir_foreach_ssa_def(instr, index_ssa_def_cb, &index);
nir_foreach_block_unstructured(block, impl) {
nir_foreach_instr(instr, block)
nir_foreach_ssa_def(instr, index_ssa_def_cb, &index);
/** generic SSA definition index. */
unsigned index;
/** generic SSA definition index. */
unsigned index;
- /** Index into the live_in and live_out bitfields */
+ /** Ordered SSA definition index used by nir_liveness. */
unsigned live_index;
/** Instruction which produces this SSA value. */
unsigned live_index;
/** Instruction which produces this SSA value. */
*/
int16_t dom_pre_index, dom_post_index;
*/
int16_t dom_pre_index, dom_post_index;
- /* live in and out for this block; used for liveness analysis */
+ /* SSA def live in and out for this block; used for liveness analysis.
+ * Indexed by ssa_def->index
+ */
BITSET_WORD *live_in;
BITSET_WORD *live_out;
} nir_block;
BITSET_WORD *live_in;
BITSET_WORD *live_out;
} nir_block;
if (src->ssa->live_index == 0)
return true; /* undefined variables are never live */
if (src->ssa->live_index == 0)
return true; /* undefined variables are never live */
- BITSET_SET(live, src->ssa->live_index);
+ BITSET_SET(live, src->ssa->index);
{
BITSET_WORD *live = void_live;
{
BITSET_WORD *live = void_live;
- BITSET_CLEAR(live, def->live_index);
+ BITSET_CLEAR(live, def->index);
void
nir_live_ssa_defs_impl(nir_function_impl *impl)
{
void
nir_live_ssa_defs_impl(nir_function_impl *impl)
{
- struct live_ssa_defs_state state;
+ struct live_ssa_defs_state state = {
+ .bitset_words = BITSET_WORDS(impl->ssa_alloc),
+ };
+ state.tmp_live = rzalloc_array(impl, BITSET_WORD, state.bitset_words),
/* We start at 1 because we reserve the index value of 0 for ssa_undef
* instructions. Those are never live, so their liveness information
/* We start at 1 because we reserve the index value of 0 for ssa_undef
* instructions. Those are never live, so their liveness information
nir_block_worklist_init(&state.worklist, impl->num_blocks, NULL);
nir_block_worklist_init(&state.worklist, impl->num_blocks, NULL);
- /* We now know how many unique ssa definitions we have and we can go
- * ahead and allocate live_in and live_out sets and add all of the
- * blocks to the worklist.
+ /* Allocate live_in and live_out sets and add all of the blocks to the
+ * worklist.
- state.bitset_words = BITSET_WORDS(state.num_ssa_defs);
- state.tmp_live = rzalloc_array(impl, BITSET_WORD, state.bitset_words);
nir_foreach_block(block, impl) {
init_liveness_block(block, &state);
}
nir_foreach_block(block, impl) {
init_liveness_block(block, &state);
}
static bool
nir_ssa_def_is_live_at(nir_ssa_def *def, nir_instr *instr)
{
static bool
nir_ssa_def_is_live_at(nir_ssa_def *def, nir_instr *instr)
{
- if (BITSET_TEST(instr->block->live_out, def->live_index)) {
+ if (BITSET_TEST(instr->block->live_out, def->index)) {
/* Since def dominates instr, if def is in the liveout of the block,
* it's live at instr
*/
return true;
} else {
/* Since def dominates instr, if def is in the liveout of the block,
* it's live at instr
*/
return true;
} else {
- if (BITSET_TEST(instr->block->live_in, def->live_index) ||
+ if (BITSET_TEST(instr->block->live_in, def->index) ||
def->parent_instr->block == instr->block) {
/* In this case it is either live coming into instr's block or it
* is defined in the same block. In this case, we simply need to
def->parent_instr->block == instr->block) {
/* In this case it is either live coming into instr's block or it
* is defined in the same block. In this case, we simply need to