nouveau/mme: Fix add64 of immediates on Fermi

Fixes: 162269f049 ("nouveau/mme: Add Fermi builder")
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30703>
This commit is contained in:
Faith Ekstrand 2024-08-16 21:32:13 -05:00 committed by Marge Bot
parent f2655b10c7
commit 381be88473
3 changed files with 130 additions and 18 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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<uint32_t> params;
params.push_back(UINT32_MAX);
test_macro(&b, macro, params);
}
TEST_F(mme_fermi_sim_test, sub)
{
mme_builder b;