nir/tests: Port almost all loop_analyze tests to new macro-based infastructure

The one test that remains would have an automatically generated name
that would conflict with another test. This test is also a little
special (per the comment in the test), so it's probably best to leave it
separate anyway.

Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3445>
This commit is contained in:
Ian Romanick 2023-02-17 12:20:09 -08:00 committed by Marge Bot
parent 9427aaeab7
commit 72a9d12c96

View file

@ -185,484 +185,6 @@ loop_builder_invert(nir_builder *b, loop_builder_invert_param p)
return loop;
}
TEST_F(nir_loop_analyze_test, infinite_loop_feq)
{
/* Create IR:
*
* float i = 0.0;
* while (true) {
* if (i == 0.9)
* break;
*
* i = i + 0.2;
* }
*/
nir_loop *loop =
loop_builder(&b, {.init_value = 0x00000000, .cond_value = 0x3e4ccccd,
.incr_value = 0x3f666666,
.cond_instr = nir_feq, .incr_instr = nir_fadd});
/* At this point, we should have:
*
* impl main {
* block block_0:
* // preds:
* vec1 32 ssa_0 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_1 = load_const (0x3e4ccccd = 0.900000)
* vec1 32 ssa_2 = load_const (0x3f666666 = 0.200000)
* // succs: block_1
* loop {
* block block_1:
* // preds: block_0 block_4
* vec1 32 ssa_5 = phi block_0: ssa_0, block_4: ssa_4
* vec1 1 ssa_3 = feq ssa_5, ssa_1
* // succs: block_2 block_3
* if ssa_3 {
* block block_2:
* // preds: block_1
* break
* // succs: block_5
* } else {
* block block_3:
* // preds: block_1
* // succs: block_4
* }
* block block_4:
* // preds: block_3
* vec1 32 ssa_4 = fadd ssa_5, ssa_2
* // succs: block_1
* }
* block block_5:
* // preds: block_2
* // succs: block_6
* block block_6:
* }
*/
nir_validate_shader(b.shader, "input");
nir_loop_analyze_impl(b.impl, nir_var_all, false);
ASSERT_NE((void *)0, loop->info);
EXPECT_FALSE(loop->info->guessed_trip_count);
EXPECT_FALSE(loop->info->exact_trip_count_known);
EXPECT_EQ((void *)0, loop->info->limiting_terminator);
/* 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);
/* 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.
*/
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, zero_iterations_ine)
{
/* Create IR:
*
* uint i = 1;
* while (true) {
* if (i != 0)
* break;
*
* i++;
* }
*
* This loop should have an iteration count of zero. See also
* https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19732#note_1648999
*/
nir_loop *loop =
loop_builder(&b, {.init_value = 0x00000001, .cond_value = 0x00000000,
.incr_value = 0x00000001,
.cond_instr = nir_ine, .incr_instr = nir_iadd});
/* At this point, we should have:
*
* impl main {
* block block_0:
* // preds:
* vec1 32 ssa_0 = load_const (0x00000001 = 0.000000)
* vec1 32 ssa_1 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_2 = load_const (0x00000001 = 0.000000)
* // succs: block_1
* loop {
* block block_1:
* // preds: block_0 block_4
* vec1 32 ssa_5 = phi block_0: ssa_0, block_4: ssa_4
* vec1 1 ssa_3 = ine ssa_5, ssa_1
* // succs: block_2 block_3
* if ssa_3 {
* block block_2:
* // preds: block_1
* break
* // succs: block_5
* } else {
* block block_3:
* // preds: block_1
* // succs: block_4
* }
* block block_4:
* // preds: block_3
* vec1 32 ssa_4 = iadd ssa_5, ssa_2
* // succs: block_1
* }
* block block_5:
* // preds: block_2
* // succs: block_6
* block block_6:
* }
*/
nir_validate_shader(b.shader, "input");
nir_loop_analyze_impl(b.impl, nir_var_all, false);
ASSERT_NE((void *)0, loop->info);
EXPECT_EQ(0, loop->info->max_trip_count);
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);
/* 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.
*/
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, one_iteration_uge)
{
/* Create IR:
*
* uint i = 0;
* while (true) {
* if (i >= 1)
* break;
*
* i++;
* }
*/
nir_loop *loop =
loop_builder(&b, {.init_value = 0x00000000, .cond_value = 0x00000001,
.incr_value = 0x00000001,
.cond_instr = nir_uge, .incr_instr = nir_iadd});
/* At this point, we should have:
*
* impl main {
* block block_0:
* // preds:
* vec1 32 ssa_0 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_1 = load_const (0x00000001 = 0.000000)
* vec1 32 ssa_2 = load_const (0x00000001 = 0.000000)
* // succs: block_1
* loop {
* block block_1:
* // preds: block_0 block_4
* vec1 32 ssa_5 = phi block_0: ssa_0, block_4: ssa_4
* vec1 1 ssa_3 = uge ssa_5, ssa_1
* // succs: block_2 block_3
* if ssa_3 {
* block block_2:
* // preds: block_1
* break
* // succs: block_5
* } else {
* block block_3:
* // preds: block_1
* // succs: block_4
* }
* block block_4:
* // preds: block_3
* vec1 32 ssa_4 = iadd ssa_5, ssa_2
* // succs: block_1
* }
* block block_5:
* // preds: block_2
* // succs: block_6
* block block_6:
* }
*/
nir_validate_shader(b.shader, "input");
nir_loop_analyze_impl(b.impl, nir_var_all, false);
ASSERT_NE((void *)0, loop->info);
EXPECT_EQ(1, loop->info->max_trip_count);
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);
/* 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.
*/
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, one_iteration_ine)
{
/* Create IR:
*
* uint i = 0;
* while (true) {
* if (i != 0)
* break;
*
* i++;
* }
*/
nir_loop *loop =
loop_builder(&b, {.init_value = 0x00000000, .cond_value = 0x00000000,
.incr_value = 0x00000001,
.cond_instr = nir_ine, .incr_instr = nir_iadd});
/* At this point, we should have:
*
* impl main {
* block block_0:
* // preds:
* vec1 32 ssa_0 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_1 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_2 = load_const (0x00000001 = 0.000000)
* // succs: block_1
* loop {
* block block_1:
* // preds: block_0 block_4
* vec1 32 ssa_5 = phi block_0: ssa_0, block_4: ssa_4
* vec1 1 ssa_3 = ine ssa_5, ssa_1
* // succs: block_2 block_3
* if ssa_3 {
* block block_2:
* // preds: block_1
* break
* // succs: block_5
* } else {
* block block_3:
* // preds: block_1
* // succs: block_4
* }
* block block_4:
* // preds: block_3
* vec1 32 ssa_4 = iadd ssa_5, ssa_2
* // succs: block_1
* }
* block block_5:
* // preds: block_2
* // succs: block_6
* block block_6:
* }
*/
nir_validate_shader(b.shader, "input");
nir_loop_analyze_impl(b.impl, nir_var_all, false);
ASSERT_NE((void *)0, loop->info);
EXPECT_EQ(1, loop->info->max_trip_count);
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);
/* 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.
*/
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, one_iteration_ieq)
{
/* Create IR:
*
* uint i = 0;
* while (true) {
* if (i == 1)
* break;
*
* i++;
* }
*/
nir_loop *loop =
loop_builder(&b, {.init_value = 0x00000000, .cond_value = 0x00000001,
.incr_value = 0x00000001,
.cond_instr = nir_ieq, .incr_instr = nir_iadd});
/* At this point, we should have:
*
* impl main {
* block block_0:
* // preds:
* vec1 32 ssa_0 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_1 = load_const (0x00000001 = 0.000000)
* vec1 32 ssa_2 = load_const (0x00000001 = 0.000000)
* // succs: block_1
* loop {
* block block_1:
* // preds: block_0 block_4
* vec1 32 ssa_5 = phi block_0: ssa_0, block_4: ssa_4
* vec1 1 ssa_3 = ieq ssa_5, ssa_1
* // succs: block_2 block_3
* if ssa_3 {
* block block_2:
* // preds: block_1
* break
* // succs: block_5
* } else {
* block block_3:
* // preds: block_1
* // succs: block_4
* }
* block block_4:
* // preds: block_3
* vec1 32 ssa_4 = iadd ssa_5, ssa_2
* // succs: block_1
* }
* block block_5:
* // preds: block_2
* // succs: block_6
* block block_6:
* }
*/
nir_validate_shader(b.shader, "input");
nir_loop_analyze_impl(b.impl, nir_var_all, false);
ASSERT_NE((void *)0, loop->info);
EXPECT_EQ(1, loop->info->max_trip_count);
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);
/* 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.
*/
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, one_iteration_easy_fneu)
{
/* Create IR:
*
* float i = 0.0;
* while (true) {
* if (i != 0.0)
* break;
*
* i = i + 1.0;
* }
*/
nir_loop *loop =
loop_builder(&b, {.init_value = 0x00000000, .cond_value = 0x00000000,
.incr_value = 0x3f800000,
.cond_instr = nir_fneu, .incr_instr = nir_fadd});
/* At this point, we should have:
*
* impl main {
* block block_0:
* // preds:
* vec1 32 ssa_0 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_1 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_2 = load_const (0x3f800000 = 1.000000)
* // succs: block_1
* loop {
* block block_1:
* // preds: block_0 block_4
* vec1 32 ssa_5 = phi block_0: ssa_0, block_4: ssa_4
* vec1 1 ssa_3 = fneu ssa_5, ssa_1
* // succs: block_2 block_3
* if ssa_3 {
* block block_2:
* // preds: block_1
* break
* // succs: block_5
* } else {
* block block_3:
* // preds: block_1
* // succs: block_4
* }
* block block_4:
* // preds: block_3
* vec1 32 ssa_4 = fadd ssa_5, ssa_2
* // succs: block_1
* }
* block block_5:
* // preds: block_2
* // succs: block_6
* block block_6:
* }
*/
nir_validate_shader(b.shader, "input");
nir_loop_analyze_impl(b.impl, nir_var_all, false);
ASSERT_NE((void *)0, loop->info);
EXPECT_EQ(1, loop->info->max_trip_count);
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);
/* 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.
*/
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, one_iteration_fneu)
{
/* Create IR:
@ -747,168 +269,6 @@ TEST_F(nir_loop_analyze_test, one_iteration_fneu)
}
}
TEST_F(nir_loop_analyze_test, zero_iterations_ine_inverted)
{
/* Create IR:
*
* uint i = 0;
* while (true) {
* i++;
*
* if (i != 0)
* break;
* }
*
* This loop should have an iteration count of zero.
*/
nir_loop *loop =
loop_builder_invert(&b, {.init_value = 0x00000000, .incr_value = 0x00000001,
.cond_value = 0x00000000,
.cond_instr = nir_ine, .incr_instr = nir_iadd});
/* At this point, we should have:
*
* impl main {
* block block_0:
* // preds:
* vec1 32 ssa_0 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_1 = load_const (0x00000001 = 0.000000)
* vec1 32 ssa_2 = load_const (0x00000000 = 0.000000)
* // succs: block_1
* loop {
* block block_1:
* // preds: block_0 block_4
* vec1 32 ssa_5 = phi block_0: ssa_0, block_4: ssa_4
* vec1 32 ssa_3 = iadd ssa_5, ssa_1
* vec1 1 ssa_4 = ine ssa_3, ssa_2
* // succs: block_2 block_3
* if ssa_4 {
* block block_2:
* // preds: block_1
* break
* // succs: block_5
* } else {
* block block_3:
* // preds: block_1
* // succs: block_4
* }
* block block_4:
* // preds: block_3
* // succs: block_1
* }
* block block_5:
* // preds: block_2
* // succs: block_6
* block block_6:
* }
*/
nir_validate_shader(b.shader, "input");
nir_loop_analyze_impl(b.impl, nir_var_all, false);
ASSERT_NE((void *)0, loop->info);
EXPECT_EQ(0, loop->info->max_trip_count);
EXPECT_TRUE(loop->info->exact_trip_count_known);
/* Loop should have an induction variable for ssa_5 and ssa_3. */
EXPECT_EQ(2, loop->info->num_induction_vars);
ASSERT_NE((void *)0, 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.
*/
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, five_iterations_ige_inverted)
{
/* Create IR:
*
* int i = 0;
* while (true) {
* i++;
*
* if (i >= 6)
* break;
* }
*
* This loop should have an iteration count of 5.
*/
nir_loop *loop =
loop_builder_invert(&b, {.init_value = 0x00000000, .incr_value = 0x00000001,
.cond_value = 0x00000006,
.cond_instr = nir_ige, .incr_instr = nir_iadd});
/* At this point, we should have:
*
* impl main {
* block block_0:
* // preds:
* vec1 32 ssa_0 = load_const (0x00000000 = 0.000000)
* vec1 32 ssa_1 = load_const (0x00000001 = 0.000000)
* vec1 32 ssa_2 = load_const (0x00000006 = 0.000000)
* // succs: block_1
* loop {
* block block_1:
* // preds: block_0 block_4
* vec1 32 ssa_5 = phi block_0: ssa_0, block_4: ssa_4
* vec1 32 ssa_3 = iadd ssa_5, ssa_1
* vec1 1 ssa_4 = ilt ssa_3, ssa_2
* // succs: block_2 block_3
* if ssa_4 {
* block block_2:
* // preds: block_1
* break
* // succs: block_5
* } else {
* block block_3:
* // preds: block_1
* // succs: block_4
* }
* block block_4:
* // preds: block_3
* // succs: block_1
* }
* block block_5:
* // preds: block_2
* // succs: block_6
* block block_6:
* }
*/
nir_validate_shader(b.shader, "input");
nir_loop_analyze_impl(b.impl, nir_var_all, false);
ASSERT_NE((void *)0, loop->info);
EXPECT_EQ(5, loop->info->max_trip_count);
EXPECT_TRUE(loop->info->exact_trip_count_known);
/* Loop should have an induction variable for ssa_5 and ssa_3. */
EXPECT_EQ(2, loop->info->num_induction_vars);
ASSERT_NE((void *)0, 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.
*/
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 COMPARE_REVERSE(comp) \
static nir_ssa_def * \
nir_ ## comp ## _rev(nir_builder *b, nir_ssa_def *x, nir_ssa_def *y) \
@ -1079,6 +439,89 @@ INOT_COMPARE(ilt_rev)
EXPECT_FALSE(loop->info->exact_trip_count_known); \
}
/* float i = 0.0;
* while (true) {
* if (i == 0.9)
* break;
*
* i = i + 0.2;
* }
*/
INFINITE_LOOP_UNKNOWN_COUNT_TEST(0x00000000, 0x3e4ccccd, 0x3f666666, feq, fadd)
/* uint i = 1;
* while (true) {
* if (i != 0)
* break;
*
* i++;
* }
*
* This loop should have an iteration count of zero. See also
* https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19732#note_1648999
*/
KNOWN_COUNT_TEST(0x00000001, 0x00000000, 0x00000001, ine, iadd, 0)
/* uint i = 0;
* while (true) {
* if (i >= 1)
* break;
*
* i++;
* }
*/
KNOWN_COUNT_TEST(0x00000000, 0x00000001, 0x00000001, uge, iadd, 1)
/* uint i = 0;
* while (true) {
* if (i != 0)
* break;
*
* i++;
* }
*/
KNOWN_COUNT_TEST(0x00000000, 0x00000000, 0x00000001, ine, iadd, 1)
/* uint i = 0;
* while (true) {
* if (i == 1)
* break;
*
* i++;
* }
*/
KNOWN_COUNT_TEST(0x00000000, 0x00000001, 0x00000001, ieq, iadd, 1)
/* float i = 0.0;
* while (true) {
* if (i != 0.0)
* break;
*
* i = i + 1.0;
* }
*/
KNOWN_COUNT_TEST(0x00000000, 0x00000000, 0x3f800000, fneu, fadd, 1)
/* uint i = 0;
* while (true) {
* i++;
*
* if (i != 0)
* break;
* }
*/
KNOWN_COUNT_TEST_INVERT(0x00000000, 0x00000001, 0x00000000, ine, iadd, 0)
/* int i = 0;
* while (true) {
* i++;
*
* if (i >= 6)
* break;
* }
*/
KNOWN_COUNT_TEST_INVERT(0x00000000, 0x00000001, 0x00000006, ige, iadd, 5)
/* uint i = 10;
* while (true) {
* if (!(5 < i))