nir/serialize: Pack deref modes better

With nir_var_image, we've now run out of bits in our packed blob for
deref instructions.  We could revert to an unpacked blob or we could be
a bit more clever about how we encode deref modes and pack them into 5
bits.

Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13386>
This commit is contained in:
Jason Ekstrand 2021-10-15 13:25:50 -05:00 committed by Marge Bot
parent 9272a952c9
commit d343aef942
2 changed files with 48 additions and 5 deletions

View file

@ -136,7 +136,9 @@ typedef enum {
nir_var_mem_ssbo = (1 << 9),
nir_var_mem_constant = (1 << 10),
/* Generic modes intentionally come last. */
/* Generic modes intentionally come last. See encode_dref_modes() in
* nir_serialize.c for more details.
*/
nir_var_shader_temp = (1 << 11),
nir_var_function_temp = (1 << 12),
nir_var_mem_shared = (1 << 13),

View file

@ -627,7 +627,8 @@ union packed_instr {
unsigned instr_type:4;
unsigned deref_type:3;
unsigned cast_type_same_as_last:1;
unsigned modes:15; /* deref_var redefines this */
unsigned modes:5; /* See (de|en)code_deref_modes() */
unsigned _pad:10;
unsigned packed_src_ssa_16bit:1; /* deref_var redefines this */
unsigned dest:8;
} deref;
@ -965,11 +966,51 @@ read_alu(read_ctx *ctx, union packed_instr header)
return alu;
}
#define MODE_ENC_GENERIC_BIT (1 << 4)
static nir_variable_mode
decode_deref_modes(unsigned modes)
{
if (modes & MODE_ENC_GENERIC_BIT) {
modes &= ~MODE_ENC_GENERIC_BIT;
return modes << (ffs(nir_var_mem_generic) - 1);
} else {
return 1 << modes;
}
}
static unsigned
encode_deref_modes(nir_variable_mode modes)
{
/* Mode sets on derefs generally come in two forms. For certain OpenCL
* cases, we can have more than one of the generic modes set. In this
* case, we need the full bitfield. Fortunately, there are only 4 of
* these. For all other modes, we can only have one mode at a time so we
* can compress them by only storing the bit position. This, plus one bit
* to select encoding, lets us pack the entire bitfield in 5 bits.
*/
STATIC_ASSERT((nir_var_all & ~nir_var_mem_generic) <
(1 << MODE_ENC_GENERIC_BIT));
unsigned enc;
if (modes == 0 || (modes & nir_var_mem_generic)) {
assert(!(modes & ~nir_var_mem_generic));
enc = modes >> (ffs(nir_var_mem_generic) - 1);
assert(enc < MODE_ENC_GENERIC_BIT);
enc |= MODE_ENC_GENERIC_BIT;
} else {
assert(util_is_power_of_two_nonzero(modes));
enc = ffs(modes) - 1;
assert(enc < MODE_ENC_GENERIC_BIT);
}
assert(modes == decode_deref_modes(enc));
return enc;
}
static void
write_deref(write_ctx *ctx, const nir_deref_instr *deref)
{
assert(deref->deref_type < 8);
assert(deref->modes < (1 << 15));
union packed_instr header;
header.u32 = 0;
@ -978,7 +1019,7 @@ write_deref(write_ctx *ctx, const nir_deref_instr *deref)
header.deref.deref_type = deref->deref_type;
if (deref->deref_type == nir_deref_type_cast) {
header.deref.modes = deref->modes;
header.deref.modes = encode_deref_modes(deref->modes);
header.deref.cast_type_same_as_last = deref->type == ctx->last_type;
}
@ -1114,7 +1155,7 @@ read_deref(read_ctx *ctx, union packed_instr header)
if (deref_type == nir_deref_type_var) {
deref->modes = deref->var->data.mode;
} else if (deref->deref_type == nir_deref_type_cast) {
deref->modes = header.deref.modes;
deref->modes = decode_deref_modes(header.deref.modes);
} else {
assert(deref->parent.is_ssa);
deref->modes = nir_instr_as_deref(deref->parent.ssa->parent_instr)->modes;