nir/loop_analyze: store nir_loop_induction_variable hash table in loop_info

No need to create a separate array.

Reviewed-by: Rhys Perry <pendingchaos02@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33131>
This commit is contained in:
Daniel Schürmann 2025-01-17 17:12:06 +01:00 committed by Marge Bot
parent f327ece9bf
commit fbaabcfb0a
5 changed files with 213 additions and 250 deletions

View file

@ -3214,13 +3214,16 @@ typedef struct {
} nir_loop_terminator;
typedef struct {
/* Induction variable. */
/* SSA def of the phi-node associated with this induction variable. */
nir_def *basis;
/* SSA def of the increment of the induction variable. */
nir_def *def;
/* Init statement with only uniform. */
/* Init statement */
nir_src *init_src;
/* Update statement with only uniform. */
/* Update statement */
nir_alu_src *update_src;
} nir_loop_induction_variable;
@ -3254,9 +3257,8 @@ typedef struct {
/* A list of loop_terminators terminating this loop. */
struct list_head loop_terminator_list;
/* array of induction variables for this loop */
nir_loop_induction_variable *induction_vars;
unsigned num_induction_vars;
/* hash table of induction variables for this loop */
struct hash_table *induction_vars;
} nir_loop_info;
typedef enum {

View file

@ -40,6 +40,7 @@
* (uniforms must be lowered to load_ubo before calling this)
*/
#include "util/hash_table.h"
#include "nir_builder.h"
#include "nir_loop_analyze.h"
@ -182,42 +183,40 @@ is_induction_variable(const nir_src *src, int component, nir_loop_info *info,
assert(component < src->ssa->num_components);
/* Return true for induction variable (ie. i in for loop) */
for (int i = 0; i < info->num_induction_vars; i++) {
nir_loop_induction_variable *var = info->induction_vars + i;
if (var->def == src->ssa) {
/* Induction variable should have constant initial value (ie. i = 0),
* constant update value (ie. i++) and constant end condition
* (ie. i < 10), so that we know the exact loop count for unrolling
* the loop.
*
* Add uniforms need to be inlined for this induction variable's
* initial and update value to be constant, for example:
*
* for (i = init; i < count; i += step)
*
* We collect uniform "init" and "step" here.
*/
if (var->init_src) {
if (!nir_collect_src_uniforms(var->init_src, component,
uni_offsets, num_offsets,
max_num_bo, max_offset))
return false;
}
struct hash_entry *entry = _mesa_hash_table_search(info->induction_vars, src->ssa);
if (!entry)
return false;
if (var->update_src) {
nir_alu_src *alu_src = var->update_src;
if (!nir_collect_src_uniforms(&alu_src->src,
alu_src->swizzle[component],
uni_offsets, num_offsets,
max_num_bo, max_offset))
return false;
}
return true;
}
nir_loop_induction_variable *var = entry->data;
/* Induction variable should have constant initial value (ie. i = 0),
* constant update value (ie. i++) and constant end condition
* (ie. i < 10), so that we know the exact loop count for unrolling
* the loop.
*
* Add uniforms need to be inlined for this induction variable's
* initial and update value to be constant, for example:
*
* for (i = init; i < count; i += step)
*
* We collect uniform "init" and "step" here.
*/
if (var->init_src) {
if (!nir_collect_src_uniforms(var->init_src, component,
uni_offsets, num_offsets,
max_num_bo, max_offset))
return false;
}
return false;
if (var->update_src) {
nir_alu_src *alu_src = var->update_src;
if (!nir_collect_src_uniforms(&alu_src->src,
alu_src->swizzle[component],
uni_offsets, num_offsets,
max_num_bo, max_offset))
return false;
}
return true;
}
void

View file

@ -27,41 +27,19 @@
#include "nir.h"
#include "nir_constant_expressions.h"
typedef struct nir_loop_variable {
/* The ssa_def associated with this info */
nir_def *def;
/* Could be a basic_induction if following uniforms are inlined */
nir_src *init_src;
nir_alu_src *update_src;
/**
* SSA def of the phi-node associated with this induction variable.
*
* Every loop induction variable has an associated phi node in the loop
* header. This may point to the same SSA def as \c def. If, however, \c def
* is the increment of the induction variable, this will point to the SSA
* def being incremented.
*/
nir_def *basis;
} nir_loop_variable;
typedef struct {
/* The loop we store information for */
nir_loop *loop;
/* Loop_variable for all ssa_defs in function */
struct hash_table *loop_vars;
nir_variable_mode indirect_mask;
bool force_unroll_sampler_indirect;
} loop_info_state;
static nir_loop_variable *
static nir_loop_induction_variable *
get_loop_var(nir_def *value, loop_info_state *state)
{
struct hash_entry *entry = _mesa_hash_table_search(state->loop_vars, value);
struct hash_entry *entry = _mesa_hash_table_search(state->loop->info->induction_vars, value);
if (entry)
return entry->data;
else
@ -244,6 +222,8 @@ is_only_uniform_src(nir_src *src)
static bool
compute_induction_information(loop_info_state *state)
{
bool progress = false;
/* We are only interested in checking phis for the basic induction
* variable case as its simple to detect. All basic induction variables
* have a phi node
@ -251,19 +231,8 @@ compute_induction_information(loop_info_state *state)
nir_block *header = nir_loop_first_block(state->loop);
nir_block *preheader = nir_block_cf_tree_prev(header);
/* There can be at most 2 induction vars per phi. */
unsigned num_phis = 0;
nir_foreach_phi(phi, header)
num_phis++;
nir_loop_info *info = state->loop->info;
info->induction_vars = reralloc(info, info->induction_vars,
nir_loop_induction_variable,
num_phis * 2);
info->num_induction_vars = 0;
nir_foreach_phi(phi, header) {
nir_loop_variable var = { .basis = &phi->def };
nir_loop_induction_variable var = { .basis = &phi->def };
nir_foreach_phi_src(phi_src, phi) {
nir_def *src = phi_src->src.ssa;
@ -324,28 +293,17 @@ compute_induction_information(loop_info_state *state)
if (var.update_src && var.init_src &&
is_only_uniform_src(var.init_src)) {
/* Insert induction variables into hash table. */
nir_loop_variable *induction_var = ralloc(state, nir_loop_variable);
/* Insert induction variable into hash table. */
struct hash_table *vars = state->loop->info->induction_vars;
nir_loop_induction_variable *induction_var = ralloc(vars, nir_loop_induction_variable);
*induction_var = var;
_mesa_hash_table_insert(state->loop_vars, induction_var->def, induction_var);
_mesa_hash_table_insert(state->loop_vars, induction_var->basis, induction_var);
/* record induction variables into nir_loop_info */
nir_loop_induction_variable *ivar;
ivar = &info->induction_vars[info->num_induction_vars++];
ivar->def = var.basis;
ivar->init_src = var.init_src;
ivar->update_src = var.update_src;
ivar = &info->induction_vars[info->num_induction_vars++];
ivar->def = var.def;
ivar->init_src = var.init_src;
ivar->update_src = var.update_src;
/* don't overflow */
assert(info->num_induction_vars <= num_phis * 2);
_mesa_hash_table_insert(vars, induction_var->def, induction_var);
_mesa_hash_table_insert(vars, induction_var->basis, induction_var);
progress = true;
}
}
return info->num_induction_vars != 0;
return progress;
}
static bool
@ -416,13 +374,13 @@ find_loop_terminators(loop_info_state *state)
static unsigned
find_array_access_via_induction(loop_info_state *state,
nir_deref_instr *deref,
nir_loop_variable **array_index_out)
nir_loop_induction_variable **array_index_out)
{
for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
if (d->deref_type != nir_deref_type_array)
continue;
nir_loop_variable *array_index = get_loop_var(d->arr.index.ssa, state);
nir_loop_induction_variable *array_index = get_loop_var(d->arr.index.ssa, state);
if (!array_index)
continue;
@ -460,7 +418,7 @@ guess_loop_limit(loop_info_state *state)
intrin->intrinsic == nir_intrinsic_store_deref ||
intrin->intrinsic == nir_intrinsic_copy_deref) {
nir_loop_variable *array_idx = NULL;
nir_loop_induction_variable *array_idx = NULL;
unsigned array_size =
find_array_access_via_induction(state,
nir_src_as_deref(intrin->src[0]),
@ -1013,8 +971,8 @@ get_induction_and_limit_vars(nir_scalar cond,
lhs = nir_scalar_chase_alu_src(cond, 0);
rhs = nir_scalar_chase_alu_src(cond, 1);
nir_loop_variable *src0_lv = get_loop_var(lhs.def, state);
nir_loop_variable *src1_lv = get_loop_var(rhs.def, state);
nir_loop_induction_variable *src0_lv = get_loop_var(lhs.def, state);
nir_loop_induction_variable *src1_lv = get_loop_var(rhs.def, state);
if (src0_lv) {
*ind = lhs;
@ -1199,7 +1157,7 @@ find_trip_count(loop_info_state *state, unsigned execution_mode,
* Thats all thats needed to calculate the trip-count
*/
nir_loop_variable *lv = get_loop_var(basic_ind.def, state);
nir_loop_induction_variable *lv = get_loop_var(basic_ind.def, state);
/* The basic induction var might be a vector but, because we guarantee
* earlier that the phi source has a scalar swizzle, we can take the
@ -1414,13 +1372,13 @@ initialize_loop_info_state(nir_loop *loop, void *mem_ctx,
nir_function_impl *impl)
{
loop_info_state *state = rzalloc(mem_ctx, loop_info_state);
state->loop_vars = _mesa_pointer_hash_table_create(mem_ctx);
state->loop = loop;
if (loop->info)
ralloc_free(loop->info);
loop->info = rzalloc(loop, nir_loop_info);
loop->info->induction_vars = _mesa_pointer_hash_table_create(loop->info);
list_inithead(&loop->info->loop_terminator_list);

View file

@ -27,6 +27,7 @@
#include <assert.h>
#include "c11/threads.h"
#include "util/hash_table.h"
#include "util/simple_mtx.h"
#include "nir.h"
#include "nir_xfb_info.h"
@ -1870,13 +1871,19 @@ validate_loop_info(nir_function_impl *impl, validate_state *state)
validate_assert(state, are_loop_terminators_equal(a, b));
}
validate_assert(state, loop->info->num_induction_vars == md->num_induction_vars);
for (unsigned i = 0; i < MIN2(loop->info->num_induction_vars, md->num_induction_vars); i++) {
nir_loop_induction_variable *a = &loop->info->induction_vars[i];
nir_loop_induction_variable *b = &md->induction_vars[i];
validate_assert(state, a->def == b->def);
validate_assert(state, a->init_src == b->init_src);
validate_assert(state, a->update_src == b->update_src);
validate_assert(state, _mesa_hash_table_num_entries(loop->info->induction_vars) ==
_mesa_hash_table_num_entries(md->induction_vars));
hash_table_foreach(loop->info->induction_vars, var) {
struct hash_entry *prev_var = _mesa_hash_table_search(md->induction_vars, var->key);
validate_assert(state, prev_var != NULL);
if (prev_var) {
nir_loop_induction_variable *a = var->data;
nir_loop_induction_variable *b = prev_var->data;
validate_assert(state, a->basis == b->basis);
validate_assert(state, a->def == b->def);
validate_assert(state, a->init_src == b->init_src);
validate_assert(state, a->update_src == b->update_src);
}
}
}

View file

@ -20,6 +20,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "util/hash_table.h"
#include <gtest/gtest.h>
#include "nir.h"
#include "nir_builder.h"
@ -263,20 +264,20 @@ TEST_F(nir_loop_analyze_test, one_iteration_fneu)
EXPECT_TRUE(loop->info->exact_trip_count_known);
/* Loop should have an induction variable for ssa_5 and ssa_4. */
EXPECT_EQ(2, loop->info->num_induction_vars);
ASSERT_NE((void *)0, loop->info->induction_vars);
EXPECT_EQ(2, _mesa_hash_table_num_entries(loop->info->induction_vars));
/* The def field should not be NULL. The init_src field should point to a
* load_const. The update_src field should point to a load_const.
/* The basis and def fields should not be NULL. The init_src field should
* point to a load_const. The update_src field should point to a load_const.
*/
const nir_loop_induction_variable *const ivars = loop->info->induction_vars;
for (unsigned i = 0; i < loop->info->num_induction_vars; i++) {
EXPECT_NE((void *)0, ivars[i].def);
ASSERT_NE((void *)0, ivars[i].init_src);
EXPECT_TRUE(nir_src_is_const(*ivars[i].init_src));
ASSERT_NE((void *)0, ivars[i].update_src);
EXPECT_TRUE(nir_src_is_const(ivars[i].update_src->src));
hash_table_foreach(loop->info->induction_vars, entry) {
nir_loop_induction_variable *ivar = (nir_loop_induction_variable *)entry->data;
EXPECT_NE((void *)0, ivar->basis);
EXPECT_NE((void *)0, ivar->def);
ASSERT_NE((void *)0, ivar->init_src);
EXPECT_TRUE(nir_src_is_const(*ivar->init_src));
ASSERT_NE((void *)0, ivar->update_src);
EXPECT_TRUE(nir_src_is_const(ivar->update_src->src));
}
}
@ -328,112 +329,109 @@ CMP_MIN(ilt, imax)
CMP_MIN_REV(ilt, imin)
INOT_COMPARE(ilt_imin_rev)
#define KNOWN_COUNT_TEST(_init_value, _cond_value, _incr_value, cond, incr, count) \
TEST_F(nir_loop_analyze_test, incr ## _ ## cond ## _known_count_ ## count) \
{ \
nir_loop *loop = \
loop_builder(&b, {.init_value = _init_value, \
.cond_value = _cond_value, \
.incr_value = _incr_value, \
.cond_instr = nir_ ## cond, \
.incr_instr = nir_ ## incr, \
.use_unknown_init_value = false, \
.invert_exit_condition_and_continue_branch = false}); \
\
nir_validate_shader(b.shader, "input"); \
\
nir_loop_analyze_impl(b.impl, nir_var_all, false); \
\
ASSERT_NE((void *)0, loop->info); \
EXPECT_NE((void *)0, loop->info->limiting_terminator); \
EXPECT_EQ(count, loop->info->max_trip_count); \
EXPECT_TRUE(loop->info->exact_trip_count_known); \
\
EXPECT_EQ(2, loop->info->num_induction_vars); \
ASSERT_NE((void *)0, loop->info->induction_vars); \
\
const nir_loop_induction_variable *const ivars = \
loop->info->induction_vars; \
\
for (unsigned i = 0; i < loop->info->num_induction_vars; i++) { \
EXPECT_NE((void *)0, ivars[i].def); \
ASSERT_NE((void *)0, ivars[i].init_src); \
EXPECT_TRUE(nir_src_is_const(*ivars[i].init_src)); \
ASSERT_NE((void *)0, ivars[i].update_src); \
EXPECT_TRUE(nir_src_is_const(ivars[i].update_src->src)); \
} \
#define KNOWN_COUNT_TEST(_init_value, _cond_value, _incr_value, cond, incr, count) \
TEST_F(nir_loop_analyze_test, incr##_##cond##_known_count_##count) \
{ \
nir_loop *loop = \
loop_builder(&b, { .init_value = _init_value, \
.cond_value = _cond_value, \
.incr_value = _incr_value, \
.cond_instr = nir_##cond, \
.incr_instr = nir_##incr, \
.use_unknown_init_value = false, \
.invert_exit_condition_and_continue_branch = false }); \
\
nir_validate_shader(b.shader, "input"); \
\
nir_loop_analyze_impl(b.impl, nir_var_all, false); \
\
ASSERT_NE((void *)0, loop->info); \
EXPECT_NE((void *)0, loop->info->limiting_terminator); \
EXPECT_EQ(count, loop->info->max_trip_count); \
EXPECT_TRUE(loop->info->exact_trip_count_known); \
\
ASSERT_NE((void *)0, loop->info->induction_vars); \
EXPECT_EQ(2, _mesa_hash_table_num_entries(loop->info->induction_vars)); \
\
hash_table_foreach(loop->info->induction_vars, entry) { \
nir_loop_induction_variable *ivar = (nir_loop_induction_variable *)entry->data; \
EXPECT_NE((void *)0, ivar->basis); \
EXPECT_NE((void *)0, ivar->def); \
ASSERT_NE((void *)0, ivar->init_src); \
EXPECT_TRUE(nir_src_is_const(*ivar->init_src)); \
ASSERT_NE((void *)0, ivar->update_src); \
EXPECT_TRUE(nir_src_is_const(ivar->update_src->src)); \
} \
}
#define INEXACT_COUNT_TEST_UNKNOWN_INIT(_cond_value, _incr_value, cond, incr, count, invert) \
TEST_F(nir_loop_analyze_test, incr ## _ ## cond ## _inexact_count_ ## count ## _invert_ ## invert) \
{ \
nir_loop *loop = \
loop_builder(&b, {.init_value = 0, \
.cond_value = _cond_value, \
.incr_value = _incr_value, \
.cond_instr = nir_ ## cond, \
.incr_instr = nir_ ## incr, \
.use_unknown_init_value = true, \
.invert_exit_condition_and_continue_branch = invert }); \
\
nir_validate_shader(b.shader, "input"); \
\
nir_loop_analyze_impl(b.impl, nir_var_all, false); \
\
ASSERT_NE((void *)0, loop->info); \
EXPECT_NE((void *)0, loop->info->limiting_terminator); \
EXPECT_EQ(count, loop->info->max_trip_count); \
EXPECT_FALSE(loop->info->exact_trip_count_known); \
\
EXPECT_EQ(2, loop->info->num_induction_vars); \
ASSERT_NE((void *)0, loop->info->induction_vars); \
\
const nir_loop_induction_variable *const ivars = \
loop->info->induction_vars; \
\
for (unsigned i = 0; i < loop->info->num_induction_vars; i++) { \
EXPECT_NE((void *)0, ivars[i].def); \
ASSERT_NE((void *)0, ivars[i].init_src); \
EXPECT_FALSE(nir_src_is_const(*ivars[i].init_src)); \
ASSERT_NE((void *)0, ivars[i].update_src); \
EXPECT_TRUE(nir_src_is_const(ivars[i].update_src->src)); \
} \
TEST_F(nir_loop_analyze_test, incr##_##cond##_inexact_count_##count##_invert_##invert) \
{ \
nir_loop *loop = \
loop_builder(&b, { .init_value = 0, \
.cond_value = _cond_value, \
.incr_value = _incr_value, \
.cond_instr = nir_##cond, \
.incr_instr = nir_##incr, \
.use_unknown_init_value = true, \
.invert_exit_condition_and_continue_branch = invert }); \
\
nir_validate_shader(b.shader, "input"); \
\
nir_loop_analyze_impl(b.impl, nir_var_all, false); \
\
ASSERT_NE((void *)0, loop->info); \
EXPECT_NE((void *)0, loop->info->limiting_terminator); \
EXPECT_EQ(count, loop->info->max_trip_count); \
EXPECT_FALSE(loop->info->exact_trip_count_known); \
\
ASSERT_NE((void *)0, loop->info->induction_vars); \
EXPECT_EQ(2, _mesa_hash_table_num_entries(loop->info->induction_vars)); \
\
hash_table_foreach(loop->info->induction_vars, entry) { \
nir_loop_induction_variable *ivar = (nir_loop_induction_variable *)entry->data; \
EXPECT_NE((void *)0, ivar->basis); \
EXPECT_NE((void *)0, ivar->def); \
ASSERT_NE((void *)0, ivar->init_src); \
EXPECT_FALSE(nir_src_is_const(*ivar->init_src)); \
ASSERT_NE((void *)0, ivar->update_src); \
EXPECT_TRUE(nir_src_is_const(ivar->update_src->src)); \
} \
}
#define INEXACT_COUNT_TEST(_init_value, _cond_value, _incr_value, cond, incr, count) \
TEST_F(nir_loop_analyze_test, incr ## _ ## cond ## _inexact_count_ ## count) \
{ \
nir_loop *loop = \
loop_builder(&b, {.init_value = _init_value, \
.cond_value = _cond_value, \
.incr_value = _incr_value, \
.cond_instr = nir_ ## cond, \
.incr_instr = nir_ ## incr, \
.use_unknown_init_value = false, \
.invert_exit_condition_and_continue_branch = false}); \
\
nir_validate_shader(b.shader, "input"); \
\
nir_loop_analyze_impl(b.impl, nir_var_all, false); \
\
ASSERT_NE((void *)0, loop->info); \
EXPECT_NE((void *)0, loop->info->limiting_terminator); \
EXPECT_EQ(count, loop->info->max_trip_count); \
EXPECT_FALSE(loop->info->exact_trip_count_known); \
\
EXPECT_EQ(2, loop->info->num_induction_vars); \
ASSERT_NE((void *)0, loop->info->induction_vars); \
\
const nir_loop_induction_variable *const ivars = \
loop->info->induction_vars; \
\
for (unsigned i = 0; i < loop->info->num_induction_vars; i++) { \
EXPECT_NE((void *)0, ivars[i].def); \
ASSERT_NE((void *)0, ivars[i].init_src); \
EXPECT_TRUE(nir_src_is_const(*ivars[i].init_src)); \
ASSERT_NE((void *)0, ivars[i].update_src); \
EXPECT_TRUE(nir_src_is_const(ivars[i].update_src->src)); \
} \
#define INEXACT_COUNT_TEST(_init_value, _cond_value, _incr_value, cond, incr, count) \
TEST_F(nir_loop_analyze_test, incr##_##cond##_inexact_count_##count) \
{ \
nir_loop *loop = \
loop_builder(&b, { .init_value = _init_value, \
.cond_value = _cond_value, \
.incr_value = _incr_value, \
.cond_instr = nir_##cond, \
.incr_instr = nir_##incr, \
.use_unknown_init_value = false, \
.invert_exit_condition_and_continue_branch = false }); \
\
nir_validate_shader(b.shader, "input"); \
\
nir_loop_analyze_impl(b.impl, nir_var_all, false); \
\
ASSERT_NE((void *)0, loop->info); \
EXPECT_NE((void *)0, loop->info->limiting_terminator); \
EXPECT_EQ(count, loop->info->max_trip_count); \
EXPECT_FALSE(loop->info->exact_trip_count_known); \
\
ASSERT_NE((void *)0, loop->info->induction_vars); \
EXPECT_EQ(2, _mesa_hash_table_num_entries(loop->info->induction_vars)); \
\
hash_table_foreach(loop->info->induction_vars, entry) { \
nir_loop_induction_variable *ivar = (nir_loop_induction_variable *)entry->data; \
EXPECT_NE((void *)0, ivar->basis); \
EXPECT_NE((void *)0, ivar->def); \
ASSERT_NE((void *)0, ivar->init_src); \
EXPECT_TRUE(nir_src_is_const(*ivar->init_src)); \
ASSERT_NE((void *)0, ivar->update_src); \
EXPECT_TRUE(nir_src_is_const(ivar->update_src->src)); \
} \
}
#define UNKNOWN_COUNT_TEST(_init_value, _cond_value, _incr_value, cond, incr) \
@ -481,37 +479,36 @@ INOT_COMPARE(ilt_imin_rev)
}
#define KNOWN_COUNT_TEST_INVERT(_init_value, _incr_value, _cond_value, cond, incr, count) \
TEST_F(nir_loop_analyze_test, incr ## _ ## cond ## _known_count_invert_ ## count) \
{ \
nir_loop *loop = \
loop_builder_invert(&b, {.init_value = _init_value, \
.incr_value = _incr_value, \
.cond_value = _cond_value, \
.cond_instr = nir_ ## cond, \
.incr_instr = nir_ ## incr}); \
\
nir_validate_shader(b.shader, "input"); \
\
nir_loop_analyze_impl(b.impl, nir_var_all, false); \
\
ASSERT_NE((void *)0, loop->info); \
EXPECT_NE((void *)0, loop->info->limiting_terminator); \
EXPECT_EQ(count, loop->info->max_trip_count); \
EXPECT_TRUE(loop->info->exact_trip_count_known); \
\
EXPECT_EQ(2, loop->info->num_induction_vars); \
ASSERT_NE((void *)0, loop->info->induction_vars); \
\
const nir_loop_induction_variable *const ivars = \
loop->info->induction_vars; \
\
for (unsigned i = 0; i < loop->info->num_induction_vars; i++) { \
EXPECT_NE((void *)0, ivars[i].def); \
ASSERT_NE((void *)0, ivars[i].init_src); \
EXPECT_TRUE(nir_src_is_const(*ivars[i].init_src)); \
ASSERT_NE((void *)0, ivars[i].update_src); \
EXPECT_TRUE(nir_src_is_const(ivars[i].update_src->src)); \
} \
TEST_F(nir_loop_analyze_test, incr##_##cond##_known_count_invert_##count) \
{ \
nir_loop *loop = \
loop_builder_invert(&b, { .init_value = _init_value, \
.incr_value = _incr_value, \
.cond_value = _cond_value, \
.cond_instr = nir_##cond, \
.incr_instr = nir_##incr }); \
\
nir_validate_shader(b.shader, "input"); \
\
nir_loop_analyze_impl(b.impl, nir_var_all, false); \
\
ASSERT_NE((void *)0, loop->info); \
EXPECT_NE((void *)0, loop->info->limiting_terminator); \
EXPECT_EQ(count, loop->info->max_trip_count); \
EXPECT_TRUE(loop->info->exact_trip_count_known); \
\
ASSERT_NE((void *)0, loop->info->induction_vars); \
EXPECT_EQ(2, _mesa_hash_table_num_entries(loop->info->induction_vars)); \
\
hash_table_foreach(loop->info->induction_vars, entry) { \
nir_loop_induction_variable *ivar = (nir_loop_induction_variable *)entry->data; \
EXPECT_NE((void *)0, ivar->basis); \
EXPECT_NE((void *)0, ivar->def); \
ASSERT_NE((void *)0, ivar->init_src); \
EXPECT_TRUE(nir_src_is_const(*ivar->init_src)); \
ASSERT_NE((void *)0, ivar->update_src); \
EXPECT_TRUE(nir_src_is_const(ivar->update_src->src)); \
} \
}
#define UNKNOWN_COUNT_TEST_INVERT(_init_value, _incr_value, _cond_value, cond, incr) \