diff --git a/src/nouveau/mme/mme_fermi_builder.c b/src/nouveau/mme/mme_fermi_builder.c index f5fad851bce..9e716742489 100644 --- a/src/nouveau/mme/mme_fermi_builder.c +++ b/src/nouveau/mme/mme_fermi_builder.c @@ -520,12 +520,14 @@ mme_fermi_start_while(struct mme_builder *b) static void mme_fermi_end_while_zero(struct mme_builder *b, + struct mme_cf cf, struct mme_value cond, bool is_zero) { struct mme_fermi_builder *fb = &b->fermi; - struct mme_cf cf = mme_fermi_end_cf(b, MME_CF_TYPE_WHILE); + if (fb->inst_parts) + mme_fermi_new_inst(fb); int delta = fb->inst_count - cf.start_ip - 2; mme_fermi_branch(fb, mme_value_alu_reg(cond), -delta, !is_zero); @@ -540,13 +542,15 @@ mme_fermi_end_while(struct mme_builder *b, { assert(op == MME_CMP_OP_EQ); + struct mme_cf cf = mme_fermi_end_cf(b, MME_CF_TYPE_WHILE); + if (mme_is_zero(x)) { - mme_fermi_end_while_zero(b, y, if_true); + mme_fermi_end_while_zero(b, cf, y, if_true); } else if (mme_is_zero(y)) { - mme_fermi_end_while_zero(b, x, if_true); + mme_fermi_end_while_zero(b, cf, x, if_true); } else { struct mme_value tmp = mme_fermi_neq(b, x, y); - mme_fermi_end_while_zero(b, tmp, if_true); + mme_fermi_end_while_zero(b, cf, tmp, if_true); mme_free_reg(b, tmp); } } @@ -569,7 +573,7 @@ mme_fermi_end_loop(struct mme_builder *b) struct mme_fermi_builder *fb = &b->fermi; mme_sub_to(b, fb->loop_counter, fb->loop_counter, mme_imm(1)); - mme_fermi_end_while_zero(b, fb->loop_counter, false); + mme_fermi_end_while(b, MME_CMP_OP_EQ, false, fb->loop_counter, mme_zero()); mme_free_reg(b, fb->loop_counter); fb->loop_counter = mme_zero(); diff --git a/src/nouveau/mme/tests/mme_builder_test.cpp b/src/nouveau/mme/tests/mme_builder_test.cpp index 90367d0254b..dbfb9803034 100644 --- a/src/nouveau/mme/tests/mme_builder_test.cpp +++ b/src/nouveau/mme/tests/mme_builder_test.cpp @@ -259,3 +259,53 @@ TEST_F(mme_builder_test, merge) ASSERT_SIM_DATA(sim); } } + +TEST_F(mme_builder_test, while_ine) +{ + static const uint32_t cases[] = { 1, 3, 5, 8 }; + + for (auto sim : sims) { + mme_builder b; + mme_builder_init(&b, sim->devinfo); + + mme_value inc = mme_load(&b); + mme_value bound = mme_load(&b); + + mme_value x = mme_mov(&b, mme_zero()); + mme_value y = mme_mov(&b, mme_zero()); + mme_value z = mme_mov(&b, mme_zero()); + + mme_value i = mme_mov(&b, mme_zero()); + mme_while(&b, ine, i, bound) { + mme_add_to(&b, x, x, mme_imm(1)); + mme_add_to(&b, y, y, mme_imm(2)); + mme_add_to(&b, z, z, mme_imm(3)); + mme_add_to(&b, i, i, inc); + } + + sim->mme_store_data(&b, 0, x); + sim->mme_store_data(&b, 1, y); + sim->mme_store_data(&b, 2, z); + sim->mme_store_data(&b, 3, i); + + auto macro = mme_builder_finish_vec(&b); + + for (unsigned i = 0; i < ARRAY_SIZE(cases); i++) { + const uint32_t inc = cases[i]; + const uint32_t count = cases[ARRAY_SIZE(cases) - i]; + const uint32_t bound = inc * count; + + std::vector params; + params.push_back(inc); + params.push_back(bound); + + expected[0] = count * 1; + expected[1] = count * 2; + expected[2] = count * 3; + expected[3] = count * inc; + + sim->run_macro(macro, params); + ASSERT_SIM_DATA(sim); + } + } +}