From 19a4662a540a8c940310a75f19bc8cd75be651e0 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 14 Mar 2018 21:45:38 -0700 Subject: [PATCH] nir: Add a deref instruction type This commit adds a new instruction type to NIR for handling derefs. Nothing uses it yet but this adds the data structure as well as all of the code to validate, print, clone, and [de]serialize them. Reviewed-by: Caio Marcelo de Oliveira Filho Acked-by: Rob Clark Acked-by: Bas Nieuwenhuizen Acked-by: Dave Airlie Reviewed-by: Kenneth Graunke --- src/compiler/nir/nir.c | 50 ++++++++ src/compiler/nir/nir.h | 58 +++++++++- src/compiler/nir/nir_clone.c | 42 +++++++ src/compiler/nir/nir_instr_set.c | 78 +++++++++++++ src/compiler/nir/nir_opt_copy_propagate.c | 62 ++++++++-- src/compiler/nir/nir_opt_dce.c | 7 ++ src/compiler/nir/nir_print.c | 132 +++++++++++++++++++++- src/compiler/nir/nir_serialize.c | 81 +++++++++++++ src/compiler/nir/nir_validate.c | 83 ++++++++++++++ 9 files changed, 580 insertions(+), 13 deletions(-) diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c index 36a79f57ee5..40bf940ef38 100644 --- a/src/compiler/nir/nir.c +++ b/src/compiler/nir/nir.c @@ -473,6 +473,26 @@ nir_alu_instr_create(nir_shader *shader, nir_op op) return instr; } +nir_deref_instr * +nir_deref_instr_create(nir_shader *shader, nir_deref_type deref_type) +{ + nir_deref_instr *instr = + rzalloc_size(shader, sizeof(nir_deref_instr)); + + instr_init(&instr->instr, nir_instr_type_deref); + + instr->deref_type = deref_type; + if (deref_type != nir_deref_type_var) + src_init(&instr->parent); + + if (deref_type == nir_deref_type_array) + src_init(&instr->arr.index); + + dest_init(&instr->dest); + + return instr; +} + nir_jump_instr * nir_jump_instr_create(nir_shader *shader, nir_jump_type type) { @@ -1201,6 +1221,12 @@ visit_alu_dest(nir_alu_instr *instr, nir_foreach_dest_cb cb, void *state) return cb(&instr->dest.dest, state); } +static bool +visit_deref_dest(nir_deref_instr *instr, nir_foreach_dest_cb cb, void *state) +{ + return cb(&instr->dest, state); +} + static bool visit_intrinsic_dest(nir_intrinsic_instr *instr, nir_foreach_dest_cb cb, void *state) @@ -1242,6 +1268,8 @@ nir_foreach_dest(nir_instr *instr, nir_foreach_dest_cb cb, void *state) switch (instr->type) { case nir_instr_type_alu: return visit_alu_dest(nir_instr_as_alu(instr), cb, state); + case nir_instr_type_deref: + return visit_deref_dest(nir_instr_as_deref(instr), cb, state); case nir_instr_type_intrinsic: return visit_intrinsic_dest(nir_instr_as_intrinsic(instr), cb, state); case nir_instr_type_tex: @@ -1287,6 +1315,7 @@ nir_foreach_ssa_def(nir_instr *instr, nir_foreach_ssa_def_cb cb, void *state) { switch (instr->type) { case nir_instr_type_alu: + case nir_instr_type_deref: case nir_instr_type_tex: case nir_instr_type_intrinsic: case nir_instr_type_phi: @@ -1352,6 +1381,23 @@ visit_alu_src(nir_alu_instr *instr, nir_foreach_src_cb cb, void *state) return true; } +static bool +visit_deref_instr_src(nir_deref_instr *instr, + nir_foreach_src_cb cb, void *state) +{ + if (instr->deref_type != nir_deref_type_var) { + if (!visit_src(&instr->parent, cb, state)) + return false; + } + + if (instr->deref_type == nir_deref_type_array) { + if (!visit_src(&instr->arr.index, cb, state)) + return false; + } + + return true; +} + static bool visit_tex_src(nir_tex_instr *instr, nir_foreach_src_cb cb, void *state) { @@ -1440,6 +1486,10 @@ nir_foreach_src(nir_instr *instr, nir_foreach_src_cb cb, void *state) if (!visit_alu_src(nir_instr_as_alu(instr), cb, state)) return false; break; + case nir_instr_type_deref: + if (!visit_deref_instr_src(nir_instr_as_deref(instr), cb, state)) + return false; + break; case nir_instr_type_intrinsic: if (!visit_intrinsic_src(nir_instr_as_intrinsic(instr), cb, state)) return false; diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 7e9f3968f63..da0b179263f 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -429,6 +429,7 @@ typedef struct nir_register { typedef enum { nir_instr_type_alu, + nir_instr_type_deref, nir_instr_type_call, nir_instr_type_tex, nir_instr_type_intrinsic, @@ -898,7 +899,9 @@ bool nir_alu_srcs_equal(const nir_alu_instr *alu1, const nir_alu_instr *alu2, typedef enum { nir_deref_type_var, nir_deref_type_array, - nir_deref_type_struct + nir_deref_type_array_wildcard, + nir_deref_type_struct, + nir_deref_type_cast, } nir_deref_type; typedef struct nir_deref { @@ -957,6 +960,56 @@ nir_deref_tail(nir_deref *deref) return deref; } +typedef struct { + nir_instr instr; + + /** The type of this deref instruction */ + nir_deref_type deref_type; + + /** The mode of the underlying variable */ + nir_variable_mode mode; + + /** The dereferenced type of the resulting pointer value */ + const struct glsl_type *type; + + union { + /** Variable being dereferenced if deref_type is a deref_var */ + nir_variable *var; + + /** Parent deref if deref_type is not deref_var */ + nir_src parent; + }; + + /** Additional deref parameters */ + union { + struct { + nir_src index; + } arr; + + struct { + unsigned index; + } strct; + }; + + /** Destination to store the resulting "pointer" */ + nir_dest dest; +} nir_deref_instr; + +NIR_DEFINE_CAST(nir_instr_as_deref, nir_instr, nir_deref_instr, instr, + type, nir_instr_type_deref) + +static inline nir_deref_instr * +nir_src_as_deref(nir_src src) +{ + if (!src.is_ssa) + return NULL; + + if (src.ssa->parent_instr->type != nir_instr_type_deref) + return NULL; + + return nir_instr_as_deref(src.ssa->parent_instr); +} + typedef struct { nir_instr instr; @@ -2121,6 +2174,9 @@ void nir_metadata_preserve(nir_function_impl *impl, nir_metadata preserved); /** creates an instruction with default swizzle/writemask/etc. with NULL registers */ nir_alu_instr *nir_alu_instr_create(nir_shader *shader, nir_op op); +nir_deref_instr *nir_deref_instr_create(nir_shader *shader, + nir_deref_type deref_type); + nir_jump_instr *nir_jump_instr_create(nir_shader *shader, nir_jump_type type); nir_load_const_instr *nir_load_const_instr_create(nir_shader *shader, diff --git a/src/compiler/nir/nir_clone.c b/src/compiler/nir/nir_clone.c index bcfdaa75942..20eaaff3bee 100644 --- a/src/compiler/nir/nir_clone.c +++ b/src/compiler/nir/nir_clone.c @@ -346,6 +346,46 @@ clone_alu(clone_state *state, const nir_alu_instr *alu) return nalu; } +static nir_deref_instr * +clone_deref_instr(clone_state *state, const nir_deref_instr *deref) +{ + nir_deref_instr *nderef = + nir_deref_instr_create(state->ns, deref->deref_type); + + __clone_dst(state, &nderef->instr, &nderef->dest, &deref->dest); + + nderef->mode = deref->mode; + nderef->type = deref->type; + + if (deref->deref_type == nir_deref_type_var) { + nderef->var = remap_var(state, deref->var); + return nderef; + } + + __clone_src(state, &nderef->instr, &nderef->parent, &deref->parent); + + switch (deref->deref_type) { + case nir_deref_type_struct: + nderef->strct.index = deref->strct.index; + break; + + case nir_deref_type_array: + __clone_src(state, &nderef->instr, + &nderef->arr.index, &deref->arr.index); + break; + + case nir_deref_type_array_wildcard: + case nir_deref_type_cast: + /* Nothing to do */ + break; + + default: + unreachable("Invalid instruction deref type"); + } + + return nderef; +} + static nir_intrinsic_instr * clone_intrinsic(clone_state *state, const nir_intrinsic_instr *itr) { @@ -502,6 +542,8 @@ clone_instr(clone_state *state, const nir_instr *instr) switch (instr->type) { case nir_instr_type_alu: return &clone_alu(state, nir_instr_as_alu(instr))->instr; + case nir_instr_type_deref: + return &clone_deref_instr(state, nir_instr_as_deref(instr))->instr; case nir_instr_type_intrinsic: return &clone_intrinsic(state, nir_instr_as_intrinsic(instr))->instr; case nir_instr_type_load_const: diff --git a/src/compiler/nir/nir_instr_set.c b/src/compiler/nir/nir_instr_set.c index 9cb9ed43e8b..939ddcc38e3 100644 --- a/src/compiler/nir/nir_instr_set.c +++ b/src/compiler/nir/nir_instr_set.c @@ -78,6 +78,40 @@ hash_alu(uint32_t hash, const nir_alu_instr *instr) return hash; } +static uint32_t +hash_deref(uint32_t hash, const nir_deref_instr *instr) +{ + hash = HASH(hash, instr->deref_type); + hash = HASH(hash, instr->mode); + hash = HASH(hash, instr->type); + + if (instr->deref_type == nir_deref_type_var) + return HASH(hash, instr->var); + + hash = hash_src(hash, &instr->parent); + + switch (instr->deref_type) { + case nir_deref_type_struct: + hash = HASH(hash, instr->strct.index); + break; + + case nir_deref_type_array: + hash = hash_src(hash, &instr->arr.index); + break; + + case nir_deref_type_var: + case nir_deref_type_array_wildcard: + case nir_deref_type_cast: + /* Nothing to do */ + break; + + default: + unreachable("Invalid instruction deref type"); + } + + return hash; +} + static uint32_t hash_load_const(uint32_t hash, const nir_load_const_instr *instr) { @@ -182,6 +216,9 @@ hash_instr(const void *data) case nir_instr_type_alu: hash = hash_alu(hash, nir_instr_as_alu(instr)); break; + case nir_instr_type_deref: + hash = hash_deref(hash, nir_instr_as_deref(instr)); + break; case nir_instr_type_load_const: hash = hash_load_const(hash, nir_instr_as_load_const(instr)); break; @@ -289,6 +326,43 @@ nir_instrs_equal(const nir_instr *instr1, const nir_instr *instr2) } return true; } + case nir_instr_type_deref: { + nir_deref_instr *deref1 = nir_instr_as_deref(instr1); + nir_deref_instr *deref2 = nir_instr_as_deref(instr2); + + if (deref1->deref_type != deref2->deref_type || + deref1->mode != deref2->mode || + deref1->type != deref2->type) + return false; + + if (deref1->deref_type == nir_deref_type_var) + return deref1->var == deref2->var; + + if (!nir_srcs_equal(deref1->parent, deref2->parent)) + return false; + + switch (deref1->deref_type) { + case nir_deref_type_struct: + if (deref1->strct.index != deref2->strct.index) + return false; + break; + + case nir_deref_type_array: + if (!nir_srcs_equal(deref1->arr.index, deref2->arr.index)) + return false; + break; + + case nir_deref_type_var: + case nir_deref_type_array_wildcard: + case nir_deref_type_cast: + /* Nothing to do */ + break; + + default: + unreachable("Invalid instruction deref type"); + } + break; + } case nir_instr_type_tex: { nir_tex_instr *tex1 = nir_instr_as_tex(instr1); nir_tex_instr *tex2 = nir_instr_as_tex(instr2); @@ -430,6 +504,7 @@ instr_can_rewrite(nir_instr *instr) switch (instr->type) { case nir_instr_type_alu: + case nir_instr_type_deref: case nir_instr_type_load_const: case nir_instr_type_phi: return true; @@ -468,6 +543,9 @@ nir_instr_get_dest_ssa_def(nir_instr *instr) case nir_instr_type_alu: assert(nir_instr_as_alu(instr)->dest.dest.is_ssa); return &nir_instr_as_alu(instr)->dest.dest.ssa; + case nir_instr_type_deref: + assert(nir_instr_as_deref(instr)->dest.is_ssa); + return &nir_instr_as_deref(instr)->dest.ssa; case nir_instr_type_load_const: return &nir_instr_as_load_const(instr)->def; case nir_instr_type_phi: diff --git a/src/compiler/nir/nir_opt_copy_propagate.c b/src/compiler/nir/nir_opt_copy_propagate.c index 3cd476a1b97..c8821c39e17 100644 --- a/src/compiler/nir/nir_opt_copy_propagate.c +++ b/src/compiler/nir/nir_opt_copy_propagate.c @@ -98,6 +98,22 @@ is_swizzleless_move(nir_alu_instr *instr) } } +static bool +is_trivial_deref_cast(nir_deref_instr *cast) +{ + if (cast->deref_type != nir_deref_type_cast) + return false; + + nir_deref_instr *parent = nir_src_as_deref(cast->parent); + if (!parent) + return false; + + return cast->mode == parent->mode && + cast->type == parent->type && + cast->dest.ssa.num_components == parent->dest.ssa.num_components && + cast->dest.ssa.bit_size == parent->dest.ssa.bit_size; +} + static bool copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if, unsigned num_components) @@ -109,23 +125,31 @@ copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if, } nir_instr *src_instr = src->ssa->parent_instr; - if (src_instr->type != nir_instr_type_alu) - return false; + nir_ssa_def *copy_def; + if (src_instr->type == nir_instr_type_alu) { + nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr); + if (!is_swizzleless_move(alu_instr)) + return false; - nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr); - if (!is_swizzleless_move(alu_instr)) - return false; + if (alu_instr->src[0].src.ssa->num_components != num_components) + return false; - if (alu_instr->src[0].src.ssa->num_components != num_components) + copy_def= alu_instr->src[0].src.ssa; + } else if (src_instr->type == nir_instr_type_deref) { + nir_deref_instr *deref_instr = nir_instr_as_deref(src_instr); + if (!is_trivial_deref_cast(deref_instr)) + return false; + + copy_def = deref_instr->parent.ssa; + } else { return false; + } if (parent_instr) { - nir_instr_rewrite_src(parent_instr, src, - nir_src_for_ssa(alu_instr->src[0].src.ssa)); + nir_instr_rewrite_src(parent_instr, src, nir_src_for_ssa(copy_def)); } else { assert(src == &parent_if->condition); - nir_if_rewrite_condition(parent_if, - nir_src_for_ssa(alu_instr->src[0].src.ssa)); + nir_if_rewrite_condition(parent_if, nir_src_for_ssa(copy_def)); } return true; @@ -234,6 +258,24 @@ copy_prop_instr(nir_instr *instr) return progress; } + case nir_instr_type_deref: { + nir_deref_instr *deref = nir_instr_as_deref(instr); + + if (deref->deref_type != nir_deref_type_var) { + assert(deref->dest.is_ssa); + const unsigned comps = deref->dest.ssa.num_components; + while (copy_prop_src(&deref->parent, instr, NULL, comps)) + progress = true; + } + + if (deref->deref_type == nir_deref_type_array) { + while (copy_prop_src(&deref->arr.index, instr, NULL, 1)) + progress = true; + } + + return progress; + } + case nir_instr_type_tex: { nir_tex_instr *tex = nir_instr_as_tex(instr); for (unsigned i = 0; i < tex->num_srcs; i++) { diff --git a/src/compiler/nir/nir_opt_dce.c b/src/compiler/nir/nir_opt_dce.c index 570e43000c0..c9b338862e6 100644 --- a/src/compiler/nir/nir_opt_dce.c +++ b/src/compiler/nir/nir_opt_dce.c @@ -52,6 +52,7 @@ static void init_instr(nir_instr *instr, nir_instr_worklist *worklist) { nir_alu_instr *alu_instr; + nir_deref_instr *deref_instr; nir_intrinsic_instr *intrin_instr; nir_tex_instr *tex_instr; @@ -73,6 +74,12 @@ init_instr(nir_instr *instr, nir_instr_worklist *worklist) mark_and_push(worklist, instr); break; + case nir_instr_type_deref: + deref_instr = nir_instr_as_deref(instr); + if (!deref_instr->dest.is_ssa) + mark_and_push(worklist, instr); + break; + case nir_instr_type_intrinsic: intrin_instr = nir_instr_as_intrinsic(instr); if (nir_intrinsic_infos[intrin_instr->intrinsic].flags & diff --git a/src/compiler/nir/nir_print.c b/src/compiler/nir/nir_print.c index 7c3e93eb82a..90d865fe950 100644 --- a/src/compiler/nir/nir_print.c +++ b/src/compiler/nir/nir_print.c @@ -393,7 +393,7 @@ print_constant(nir_constant *c, const struct glsl_type *type, print_state *state } static const char * -get_variable_mode_str(nir_variable_mode mode) +get_variable_mode_str(nir_variable_mode mode, bool want_local_global_mode) { switch (mode) { case nir_var_shader_in: @@ -410,7 +410,9 @@ get_variable_mode_str(nir_variable_mode mode) return "shared"; case nir_var_param: case nir_var_global: + return want_local_global_mode ? "global" : ""; case nir_var_local: + return want_local_global_mode ? "local" : ""; default: return ""; } @@ -428,7 +430,7 @@ print_var_decl(nir_variable *var, print_state *state) const char *const patch = (var->data.patch) ? "patch " : ""; const char *const inv = (var->data.invariant) ? "invariant " : ""; fprintf(fp, "%s%s%s%s%s %s ", - cent, samp, patch, inv, get_variable_mode_str(var->data.mode), + cent, samp, patch, inv, get_variable_mode_str(var->data.mode, false), glsl_interp_mode_name(var->data.interpolation)); const char *const coher = (var->data.image.coherent) ? "coherent " : ""; @@ -517,6 +519,128 @@ print_var_decl(nir_variable *var, print_state *state) print_annotation(state, var); } +static void +print_deref_link(nir_deref_instr *instr, bool whole_chain, print_state *state) +{ + FILE *fp = state->fp; + + if (instr->deref_type == nir_deref_type_var) { + fprintf(fp, "%s", get_var_name(instr->var, state)); + return; + } else if (instr->deref_type == nir_deref_type_cast) { + fprintf(fp, "(%s *)", glsl_get_type_name(instr->type)); + print_src(&instr->parent, state); + return; + } + + assert(instr->parent.is_ssa); + nir_deref_instr *parent = + nir_instr_as_deref(instr->parent.ssa->parent_instr); + + /* Is the parent we're going to print a bare cast? */ + const bool is_parent_cast = + whole_chain && parent->deref_type == nir_deref_type_cast; + + /* If we're not printing the whole chain, the parent we print will be a SSA + * value that represents a pointer. The only deref type that naturally + * gives a pointer is a cast. + */ + const bool is_parent_pointer = + !whole_chain || parent->deref_type == nir_deref_type_cast; + + /* Struct derefs have a nice syntax that works on pointers, arrays derefs + * do not. + */ + const bool need_deref = + is_parent_pointer && instr->deref_type != nir_deref_type_struct; + + /* Cast need extra parens and so * dereferences */ + if (is_parent_cast || need_deref) + fprintf(fp, "("); + + if (need_deref) + fprintf(fp, "*"); + + if (whole_chain) { + print_deref_link(parent, whole_chain, state); + } else { + print_src(&instr->parent, state); + } + + if (is_parent_cast || need_deref) + fprintf(fp, ")"); + + switch (instr->deref_type) { + case nir_deref_type_struct: + fprintf(fp, "%s%s", is_parent_pointer ? "->" : ".", + glsl_get_struct_elem_name(parent->type, instr->strct.index)); + break; + + case nir_deref_type_array: { + nir_const_value *const_index = nir_src_as_const_value(instr->arr.index); + if (const_index) { + fprintf(fp, "[%u]", const_index->u32[0]); + } else { + fprintf(fp, "["); + print_src(&instr->arr.index, state); + fprintf(fp, "]"); + } + break; + } + + case nir_deref_type_array_wildcard: + fprintf(fp, "[*]"); + break; + + default: + unreachable("Invalid deref instruction type"); + } +} + +static void +print_deref_instr(nir_deref_instr *instr, print_state *state) +{ + FILE *fp = state->fp; + + print_dest(&instr->dest, state); + + switch (instr->deref_type) { + case nir_deref_type_var: + fprintf(fp, " = deref_var "); + break; + case nir_deref_type_array: + case nir_deref_type_array_wildcard: + fprintf(fp, " = deref_array "); + break; + case nir_deref_type_struct: + fprintf(fp, " = deref_struct "); + break; + case nir_deref_type_cast: + fprintf(fp, " = deref_cast "); + break; + default: + unreachable("Invalid deref instruction type"); + } + + /* Only casts naturally return a pointer type */ + if (instr->deref_type != nir_deref_type_cast) + fprintf(fp, "&"); + + print_deref_link(instr, false, state); + + fprintf(fp, " (%s %s) ", + get_variable_mode_str(instr->mode, true), + glsl_get_type_name(instr->type)); + + if (instr->deref_type != nir_deref_type_var && + instr->deref_type != nir_deref_type_cast) { + /* Print the entire chain as a comment */ + fprintf(fp, "/* &"); + print_deref_link(instr, true, state); + fprintf(fp, " */"); + } +} + static void print_var(nir_variable *var, print_state *state) { @@ -965,6 +1089,10 @@ print_instr(const nir_instr *instr, print_state *state, unsigned tabs) print_alu_instr(nir_instr_as_alu(instr), state); break; + case nir_instr_type_deref: + print_deref_instr(nir_instr_as_deref(instr), state); + break; + case nir_instr_type_call: print_call_instr(nir_instr_as_call(instr), state); break; diff --git a/src/compiler/nir/nir_serialize.c b/src/compiler/nir/nir_serialize.c index 00df49c2ef3..834a65b07e8 100644 --- a/src/compiler/nir/nir_serialize.c +++ b/src/compiler/nir/nir_serialize.c @@ -478,6 +478,81 @@ read_alu(read_ctx *ctx) return alu; } +static void +write_deref(write_ctx *ctx, const nir_deref_instr *deref) +{ + blob_write_uint32(ctx->blob, deref->deref_type); + + blob_write_uint32(ctx->blob, deref->mode); + encode_type_to_blob(ctx->blob, deref->type); + + write_dest(ctx, &deref->dest); + + if (deref->deref_type == nir_deref_type_var) { + write_object(ctx, deref->var); + return; + } + + write_src(ctx, &deref->parent); + + switch (deref->deref_type) { + case nir_deref_type_struct: + blob_write_uint32(ctx->blob, deref->strct.index); + break; + + case nir_deref_type_array: + write_src(ctx, &deref->arr.index); + break; + + case nir_deref_type_array_wildcard: + case nir_deref_type_cast: + /* Nothing to do */ + break; + + default: + unreachable("Invalid deref type"); + } +} + +static nir_deref_instr * +read_deref(read_ctx *ctx) +{ + nir_deref_type deref_type = blob_read_uint32(ctx->blob); + nir_deref_instr *deref = nir_deref_instr_create(ctx->nir, deref_type); + + deref->mode = blob_read_uint32(ctx->blob); + deref->type = decode_type_from_blob(ctx->blob); + + read_dest(ctx, &deref->dest, &deref->instr); + + if (deref_type == nir_deref_type_var) { + deref->var = read_object(ctx); + return deref; + } + + read_src(ctx, &deref->parent, &deref->instr); + + switch (deref->deref_type) { + case nir_deref_type_struct: + deref->strct.index = blob_read_uint32(ctx->blob); + break; + + case nir_deref_type_array: + read_src(ctx, &deref->arr.index, &deref->instr); + break; + + case nir_deref_type_array_wildcard: + case nir_deref_type_cast: + /* Nothing to do */ + break; + + default: + unreachable("Invalid deref type"); + } + + return deref; +} + static void write_intrinsic(write_ctx *ctx, const nir_intrinsic_instr *intrin) { @@ -803,6 +878,9 @@ write_instr(write_ctx *ctx, const nir_instr *instr) case nir_instr_type_alu: write_alu(ctx, nir_instr_as_alu(instr)); break; + case nir_instr_type_deref: + write_deref(ctx, nir_instr_as_deref(instr)); + break; case nir_instr_type_intrinsic: write_intrinsic(ctx, nir_instr_as_intrinsic(instr)); break; @@ -840,6 +918,9 @@ read_instr(read_ctx *ctx, nir_block *block) case nir_instr_type_alu: instr = &read_alu(ctx)->instr; break; + case nir_instr_type_deref: + instr = &read_deref(ctx)->instr; + break; case nir_instr_type_intrinsic: instr = &read_intrinsic(ctx)->instr; break; diff --git a/src/compiler/nir/nir_validate.c b/src/compiler/nir/nir_validate.c index 4a4d8a651a2..2d6f287f722 100644 --- a/src/compiler/nir/nir_validate.c +++ b/src/compiler/nir/nir_validate.c @@ -462,6 +462,85 @@ validate_deref_var(void *parent_mem_ctx, nir_deref_var *deref, validate_state *s validate_deref_chain(&deref->deref, deref->var->data.mode, state); } +static void +validate_deref_instr(nir_deref_instr *instr, validate_state *state) +{ + if (instr->deref_type == nir_deref_type_var) { + /* Variable dereferences are stupid simple. */ + validate_assert(state, instr->mode == instr->var->data.mode); + validate_assert(state, instr->type == instr->var->type); + validate_var_use(instr->var, state); + } else if (instr->deref_type == nir_deref_type_cast) { + /* For cast, we simply have to trust the instruction. It's up to + * lowering passes and front/back-ends to make them sane. + */ + validate_src(&instr->parent, state, 0, 0); + + /* We just validate that the type and mode are there */ + validate_assert(state, instr->mode); + validate_assert(state, instr->type); + } else { + /* We require the parent to be SSA. This may be lifted in the future */ + validate_assert(state, instr->parent.is_ssa); + + /* The parent pointer value must have the same number of components + * as the destination. + */ + validate_src(&instr->parent, state, nir_dest_bit_size(instr->dest), + nir_dest_num_components(instr->dest)); + + nir_instr *parent_instr = instr->parent.ssa->parent_instr; + + /* The parent must come from another deref instruction */ + validate_assert(state, parent_instr->type == nir_instr_type_deref); + + nir_deref_instr *parent = nir_instr_as_deref(parent_instr); + + validate_assert(state, instr->mode == parent->mode); + + switch (instr->deref_type) { + case nir_deref_type_struct: + validate_assert(state, glsl_type_is_struct(parent->type)); + validate_assert(state, + instr->strct.index < glsl_get_length(parent->type)); + validate_assert(state, instr->type == + glsl_get_struct_field(parent->type, instr->strct.index)); + break; + + case nir_deref_type_array: + case nir_deref_type_array_wildcard: + if (instr->mode == nir_var_shared) { + /* Shared variables have a bit more relaxed rules because we need + * to be able to handle array derefs on vectors. Fortunately, + * nir_lower_io handles these just fine. + */ + validate_assert(state, glsl_type_is_array(parent->type) || + glsl_type_is_matrix(parent->type) || + glsl_type_is_vector(parent->type)); + } else { + /* Most of NIR cannot handle array derefs on vectors */ + validate_assert(state, glsl_type_is_array(parent->type) || + glsl_type_is_matrix(parent->type)); + } + validate_assert(state, + instr->type == glsl_get_array_element(parent->type)); + + if (instr->deref_type == nir_deref_type_array) + validate_src(&instr->arr.index, state, 32, 1); + break; + + default: + unreachable("Invalid deref instruction type"); + } + } + + /* We intentionally don't validate the size of the destination because we + * want to let other compiler components such as SPIR-V decide how big + * pointers should be. + */ + validate_dest(&instr->dest, state, 0, 0); +} + static void validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state) { @@ -610,6 +689,10 @@ validate_instr(nir_instr *instr, validate_state *state) validate_alu_instr(nir_instr_as_alu(instr), state); break; + case nir_instr_type_deref: + validate_deref_instr(nir_instr_as_deref(instr), state); + break; + case nir_instr_type_call: validate_call_instr(nir_instr_as_call(instr), state); break; -- 2.30.2