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:
}
}
-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) \
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))