From d343aef94233d0064fada98ae93bec0a420a0baa Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 15 Oct 2021 13:25:50 -0500 Subject: [PATCH] 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 Part-of: --- src/compiler/nir/nir.h | 4 +++- src/compiler/nir/nir_serialize.c | 49 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 939b07e..e8bb760 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -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), diff --git a/src/compiler/nir/nir_serialize.c b/src/compiler/nir/nir_serialize.c index b6108ef..d13d18f 100644 --- a/src/compiler/nir/nir_serialize.c +++ b/src/compiler/nir/nir_serialize.c @@ -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; -- 2.7.4