From 381be88473ed9864141d16520e62b0a1f476b36d Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Fri, 16 Aug 2024 21:32:13 -0500 Subject: [PATCH] nouveau/mme: Fix add64 of immediates on Fermi Fixes: 162269f04981 ("nouveau/mme: Add Fermi builder") Part-of: --- src/nouveau/mme/mme_fermi_builder.c | 49 +++++++++-- src/nouveau/mme/mme_fermi_builder.h | 11 +-- .../mme/tests/mme_fermi_sim_hw_test.cpp | 88 +++++++++++++++++++ 3 files changed, 130 insertions(+), 18 deletions(-) diff --git a/src/nouveau/mme/mme_fermi_builder.c b/src/nouveau/mme/mme_fermi_builder.c index 2c60785bb8f..a3e726fdd2c 100644 --- a/src/nouveau/mme/mme_fermi_builder.c +++ b/src/nouveau/mme/mme_fermi_builder.c @@ -698,28 +698,35 @@ mme_to_fermi_alu_op(enum mme_alu_op op) } } -void -mme_fermi_alu_to(struct mme_builder *b, - struct mme_value dst, - enum mme_alu_op op, - struct mme_value x, - struct mme_value y) +static bool +is_imm18_nonzero(struct mme_value x) +{ + return x.type == MME_VALUE_TYPE_IMM && x.imm != 0 && is_int18(x.imm); +} + +static void +mme_fermi_build_alu(struct mme_builder *b, + struct mme_value dst, + enum mme_alu_op op, + struct mme_value x, + struct mme_value y, + bool need_carry) { struct mme_fermi_builder *fb = &b->fermi; switch (op) { case MME_ALU_OP_ADD: - if (x.type == MME_VALUE_TYPE_IMM && x.imm != 0 && is_int18(x.imm)) { + if (is_imm18_nonzero(x) && !need_carry) { mme_fermi_add_imm18(fb, dst, y, x.imm); return; } - if (y.type == MME_VALUE_TYPE_IMM && y.imm != 0 && is_int18(y.imm)) { + if (is_imm18_nonzero(y) && !need_carry) { mme_fermi_add_imm18(fb, dst, x, y.imm); return; } break; case MME_ALU_OP_SUB: - if (y.type == MME_VALUE_TYPE_IMM && is_int18(-y.imm)) { + if (y.type == MME_VALUE_TYPE_IMM && is_int18(-y.imm) && !need_carry) { mme_fermi_add_imm18(fb, dst, x, -y.imm); return; } @@ -762,6 +769,30 @@ mme_fermi_alu_to(struct mme_builder *b, mme_free_reg_if_tmp(b, y, y_reg); } +void +mme_fermi_alu_to(struct mme_builder *b, + struct mme_value dst, + enum mme_alu_op op, + struct mme_value x, + struct mme_value y) +{ + mme_fermi_build_alu(b, dst, op, x, y, false); +} + +void +mme_fermi_alu64_to(struct mme_builder *b, + struct mme_value64 dst, + enum mme_alu_op op_lo, + enum mme_alu_op op_hi, + struct mme_value64 x, + struct mme_value64 y) +{ + assert(dst.lo.type == MME_VALUE_TYPE_REG); + assert(dst.hi.type == MME_VALUE_TYPE_REG); + + mme_fermi_build_alu(b, dst.lo, op_lo, x.lo, y.lo, true); + mme_fermi_build_alu(b, dst.hi, op_hi, x.hi, y.hi, true); +} void mme_fermi_state_arr_to(struct mme_builder *b, struct mme_value dst, diff --git a/src/nouveau/mme/mme_fermi_builder.h b/src/nouveau/mme/mme_fermi_builder.h index d0e4ef7e042..37c52a24d72 100644 --- a/src/nouveau/mme/mme_fermi_builder.h +++ b/src/nouveau/mme/mme_fermi_builder.h @@ -90,20 +90,13 @@ mme_fermi_alu_to(struct mme_builder *b, struct mme_value x, struct mme_value y); -static inline void +void mme_fermi_alu64_to(struct mme_builder *b, struct mme_value64 dst, enum mme_alu_op op_lo, enum mme_alu_op op_hi, struct mme_value64 x, - struct mme_value64 y) -{ - assert(dst.lo.type == MME_VALUE_TYPE_REG); - assert(dst.hi.type == MME_VALUE_TYPE_REG); - - mme_fermi_alu_to(b, dst.lo, op_lo, x.lo, y.lo); - mme_fermi_alu_to(b, dst.hi, op_hi, x.hi, y.hi); -} + struct mme_value64 y); void mme_fermi_bfe_to(struct mme_builder *b, struct mme_value dst, diff --git a/src/nouveau/mme/tests/mme_fermi_sim_hw_test.cpp b/src/nouveau/mme/tests/mme_fermi_sim_hw_test.cpp index 747ae89a2f5..1640686a997 100644 --- a/src/nouveau/mme/tests/mme_fermi_sim_hw_test.cpp +++ b/src/nouveau/mme/tests/mme_fermi_sim_hw_test.cpp @@ -291,6 +291,94 @@ TEST_F(mme_fermi_sim_test, addc) test_macro(&b, macro, params); } +TEST_F(mme_fermi_sim_test, add_imm_carry) +{ + mme_builder b; + mme_builder_init(&b, devinfo); + + mme_value max = mme_load(&b); + + mme_value add_res = mme_alloc_reg(&b); + mme_value add_imm_res = mme_alloc_reg(&b); + mme_value carry = mme_alloc_reg(&b); + + /* Dummy add clears the carry register */ + mme_fermi_asm(&b, i) { + i.op = MME_FERMI_OP_ALU_REG; + i.assign_op = MME_FERMI_ASSIGN_OP_MOVE; + i.dst = mme_fermi_value_as_reg(add_res); + i.src[0] = MME_FERMI_REG_ZERO; + i.src[1] = MME_FERMI_REG_ZERO; + i.alu_op = MME_FERMI_ALU_OP_ADD; + } + + /* ADD_IMM should not touch carry */ + mme_fermi_asm(&b, i) { + i.op = MME_FERMI_OP_ADD_IMM; + i.assign_op = MME_FERMI_ASSIGN_OP_MOVE; + i.dst = mme_fermi_value_as_reg(add_imm_res); + i.src[0] = mme_fermi_value_as_reg(max); + i.imm = 1; + } + + /* Grab the carry */ + mme_fermi_asm(&b, i) { + i.op = MME_FERMI_OP_ALU_REG; + i.assign_op = MME_FERMI_ASSIGN_OP_MOVE; + i.dst = mme_fermi_value_as_reg(carry); + i.src[0] = MME_FERMI_REG_ZERO; + i.src[1] = MME_FERMI_REG_ZERO; + i.alu_op = MME_FERMI_ALU_OP_ADDC; + } + + /* Store everything after all that ALU so none of the stores mess up the + * carry behind our back. + */ + mme_store_imm_addr(&b, data_addr + 0, add_res, false); + mme_store_imm_addr(&b, data_addr + 4, add_imm_res, false); + mme_store_imm_addr(&b, data_addr + 8, carry, false); + + /* Set carry to 1 */ + mme_fermi_asm(&b, i) { + i.op = MME_FERMI_OP_ALU_REG; + i.assign_op = MME_FERMI_ASSIGN_OP_MOVE; + i.dst = mme_fermi_value_as_reg(add_res); + i.src[0] = mme_fermi_value_as_reg(max); + i.src[1] = mme_fermi_value_as_reg(max); + i.alu_op = MME_FERMI_ALU_OP_ADD; + } + + /* ADD_IMM should not touch carry */ + mme_fermi_asm(&b, i) { + i.op = MME_FERMI_OP_ADD_IMM; + i.assign_op = MME_FERMI_ASSIGN_OP_MOVE; + i.dst = mme_fermi_value_as_reg(add_imm_res); + i.src[0] = MME_FERMI_REG_ZERO; + i.imm = 1; + } + + /* Grab the carry */ + mme_fermi_asm(&b, i) { + i.op = MME_FERMI_OP_ALU_REG; + i.assign_op = MME_FERMI_ASSIGN_OP_MOVE; + i.dst = mme_fermi_value_as_reg(carry); + i.src[0] = MME_FERMI_REG_ZERO; + i.src[1] = MME_FERMI_REG_ZERO; + i.alu_op = MME_FERMI_ALU_OP_ADDC; + } + + mme_store_imm_addr(&b, data_addr + 12, add_res, true); + mme_store_imm_addr(&b, data_addr + 16, add_imm_res, true); + mme_store_imm_addr(&b, data_addr + 20, carry, true); + + auto macro = mme_builder_finish_vec(&b); + + std::vector params; + params.push_back(UINT32_MAX); + + test_macro(&b, macro, params); +} + TEST_F(mme_fermi_sim_test, sub) { mme_builder b;