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),
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;
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;
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;
}
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;