nouveau/mme: Fix while loops pre-Turing

Pre-Turing, we don't have a full condition built into the loop so, for
mme_while(b, ine, x, y) we have to generate the following:

[top]   BR -> [cond]
        /* loop body */
[cond]  XOR tmp, x, y
        BRZ !tmp -> [top]

However, due to an accounting error, we were generating

[top]   BR -> [cond]
        /* loop body */
        XOR tmp, x, y
[cond]  BRZ !tmp -> [top]

which meant that the XOR (or ADD if one is an immediate) was getting
skipped, leading to the loop either never terminating or always
terminating.  The way to fix this accounting error is to close the while
first, then compute the condition value, then do the jump.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>
This commit is contained in:
Faith Ekstrand 2023-03-28 23:34:29 -05:00 committed by Marge Bot
parent ccf004837a
commit 08a200193f
2 changed files with 59 additions and 5 deletions

View file

@ -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();

View file

@ -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<uint32_t> 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);
}
}
}