mi-builder: add relocated register/memory writes

When you want to write a value to a register or memory but you don't
know just yet that value when you emit the command.

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: José Roberto de Souza <jose.souza@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29571>
This commit is contained in:
Lionel Landwerlin 2024-06-06 13:00:28 +03:00 committed by Marge Bot
parent 775db77baf
commit a623760f82
2 changed files with 154 additions and 0 deletions

View file

@ -1190,6 +1190,106 @@ mi_udiv32_imm(struct mi_builder *b, struct mi_value N, uint32_t D)
/* This assumes addresses of strictly more than 32bits (aka. Gfx8+). */
#if MI_BUILDER_CAN_WRITE_BATCH
struct mi_reloc_imm_token {
enum mi_value_type dst_type;
uint32_t *ptr[2];
};
/* Emits a immediate write to an address/register where the immediate value
* can be updated later.
*/
static inline struct mi_reloc_imm_token
mi_store_relocated_imm(struct mi_builder *b, struct mi_value dst)
{
mi_builder_flush_math(b);
struct mi_reloc_imm_token token = {
.dst_type = dst.type,
};
uint32_t *dw;
switch (dst.type) {
case MI_VALUE_TYPE_MEM32:
dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
GENX(MI_STORE_DATA_IMM_length));
mi_builder_pack(b, GENX(MI_STORE_DATA_IMM), dw, sdm) {
sdm.DWordLength = GENX(MI_STORE_DATA_IMM_length) -
GENX(MI_STORE_DATA_IMM_length_bias);
sdm.Address = dst.addr;
}
token.ptr[0] = dw + GENX(MI_STORE_DATA_IMM_ImmediateData_start) / 32;
break;
case MI_VALUE_TYPE_MEM64:
dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
GENX(MI_STORE_DATA_IMM_length) + 1);
mi_builder_pack(b, GENX(MI_STORE_DATA_IMM), dw, sdm) {
sdm.DWordLength = GENX(MI_STORE_DATA_IMM_length) + 1 -
GENX(MI_STORE_DATA_IMM_length_bias);
sdm.Address = dst.addr;
}
token.ptr[0] = &dw[GENX(MI_STORE_DATA_IMM_ImmediateData_start) / 32];
token.ptr[1] = &dw[GENX(MI_STORE_DATA_IMM_ImmediateData_start) / 32 + 1];
break;
case MI_VALUE_TYPE_REG32:
dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
GENX(MI_LOAD_REGISTER_IMM_length));
mi_builder_pack(b, GENX(MI_LOAD_REGISTER_IMM), dw, lri) {
lri.DWordLength = GENX(MI_LOAD_REGISTER_IMM_length) -
GENX(MI_LOAD_REGISTER_IMM_length_bias);
struct mi_reg_num reg = mi_adjust_reg_num(dst.reg);
#if GFX_VER >= 11
lri.AddCSMMIOStartOffset = reg.cs;
#endif
lri.RegisterOffset = reg.num;
}
token.ptr[0] = &dw[2];
break;
case MI_VALUE_TYPE_REG64: {
dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
GENX(MI_LOAD_REGISTER_IMM_length) + 2);
struct mi_reg_num reg = mi_adjust_reg_num(dst.reg);
mi_builder_pack(b, GENX(MI_LOAD_REGISTER_IMM), dw, lri) {
lri.DWordLength = GENX(MI_LOAD_REGISTER_IMM_length) + 2 -
GENX(MI_LOAD_REGISTER_IMM_length_bias);
#if GFX_VER >= 11
lri.AddCSMMIOStartOffset = reg.cs;
#endif
}
dw[1] = reg.num;
dw[3] = reg.num + 4;
token.ptr[0] = &dw[2];
token.ptr[1] = &dw[4];
break;
}
default:
unreachable("Invalid value type");
}
mi_value_unref(b, dst);
return token;
}
static inline void
mi_relocate_store_imm(struct mi_reloc_imm_token token, uint64_t value)
{
switch (token.dst_type) {
case MI_VALUE_TYPE_MEM64:
case MI_VALUE_TYPE_REG64:
*token.ptr[1] = value >> 32;
FALLTHROUGH;
case MI_VALUE_TYPE_MEM32:
case MI_VALUE_TYPE_REG32:
*token.ptr[0] = value & 0xffffffff;
break;
default:
unreachable("Invalid value type");
}
}
struct mi_address_token {
/* Pointers to address memory fields in the batch. */
uint64_t *ptrs[2];

View file

@ -69,6 +69,8 @@ __gen_address_offset(address addr, uint64_t offset)
#define INPUT_DATA_OFFSET 0
#define OUTPUT_DATA_OFFSET 2048
#define MI_BUILDER_CAN_WRITE_BATCH GFX_VER >= 8
#define __genxml_cmd_length(cmd) cmd ## _length
#define __genxml_cmd_length_bias(cmd) cmd ## _length_bias
#define __genxml_cmd_header(cmd) cmd ## _header
@ -742,6 +744,58 @@ TEST_F(mi_builder_test, iand)
mi_imm(values[1])));
}
#if GFX_VER >= 8
TEST_F(mi_builder_test, imm_mem_relocated)
{
const uint64_t value = 0x0123456789abcdef;
struct mi_reloc_imm_token r0 = mi_store_relocated_imm(&b, out_mem64(0));
struct mi_reloc_imm_token r1 = mi_store_relocated_imm(&b, out_mem32(8));
mi_relocate_store_imm(r0, value);
mi_relocate_store_imm(r1, value);
submit_batch();
// 64 -> 64
EXPECT_EQ(*(uint64_t *)(output + 0), value);
// 64 -> 32
EXPECT_EQ(*(uint32_t *)(output + 8), (uint32_t)value);
EXPECT_EQ(*(uint32_t *)(output + 12), (uint32_t)canary);
}
TEST_F(mi_builder_test, imm_reg_relocated)
{
const uint64_t value = 0x0123456789abcdef;
struct mi_reloc_imm_token r0, r1;
r0 = mi_store_relocated_imm(&b, mi_reg64(RSVD_TEMP_REG));
r1 = mi_store_relocated_imm(&b, mi_reg64(RSVD_TEMP_REG));
mi_store(&b, out_mem64(0), mi_reg64(RSVD_TEMP_REG));
mi_relocate_store_imm(r0, canary);
mi_relocate_store_imm(r1, value);
r0 = mi_store_relocated_imm(&b, mi_reg64(RSVD_TEMP_REG));
r1 = mi_store_relocated_imm(&b, mi_reg32(RSVD_TEMP_REG));
mi_store(&b, out_mem64(8), mi_reg64(RSVD_TEMP_REG));
mi_relocate_store_imm(r0, canary);
mi_relocate_store_imm(r1, value);
submit_batch();
// 64 -> 64
EXPECT_EQ(*(uint64_t *)(output + 0), value);
// 64 -> 32
EXPECT_EQ(*(uint32_t *)(output + 8), (uint32_t)value);
EXPECT_EQ(*(uint32_t *)(output + 12), (uint32_t)canary);
}
#endif // GFX_VER >= 8
#if GFX_VERx10 >= 125
TEST_F(mi_builder_test, ishl)
{