From 08a200193ff3cb2b45bd0d885f961029ddfb6e88 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Tue, 28 Mar 2023 23:34:29 -0500 Subject: [PATCH] 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: --- src/nouveau/mme/mme_fermi_builder.c | 14 +++--- src/nouveau/mme/tests/mme_builder_test.cpp | 50 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) 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); + } + } +}