[Mesa-dev] [PATCH v3 002/104] nir: Add a deref instruction type
Bas Nieuwenhuizen
bas at basnieuwenhuizen.nl
Sun Apr 8 20:43:00 UTC 2018
On Sun, Apr 8, 2018 at 10:23 PM, Bas Nieuwenhuizen
<bas at basnieuwenhuizen.nl> wrote:
> On Tue, Apr 3, 2018 at 8:32 PM, Jason Ekstrand <jason at jlekstrand.net> wrote:
>> 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.
>> ---
>> 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 | 56 +++++++++++++++++++++
>> src/compiler/nir/nir_serialize.c | 81 ++++++++++++++++++++++++++++++
>> src/compiler/nir/nir_validate.c | 83 +++++++++++++++++++++++++++++++
>> 9 files changed, 506 insertions(+), 11 deletions(-)
>>
>> diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c
>> index 8364197..a538f22 100644
>> --- a/src/compiler/nir/nir.c
>> +++ b/src/compiler/nir/nir.c
>> @@ -470,6 +470,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)
>> {
>> @@ -1199,6 +1219,12 @@ visit_alu_dest(nir_alu_instr *instr, nir_foreach_dest_cb cb, void *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)
>> {
>> @@ -1239,6 +1265,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:
>> @@ -1284,6 +1312,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:
>> @@ -1350,6 +1379,23 @@ visit_alu_src(nir_alu_instr *instr, nir_foreach_src_cb cb, void *state)
>> }
>>
>> 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)
>> {
>> for (unsigned i = 0; i < instr->num_srcs; i++) {
>> @@ -1437,6 +1483,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 cc7c401..db7dc91 100644
>> --- a/src/compiler/nir/nir.h
>> +++ b/src/compiler/nir/nir.h
>> @@ -427,6 +427,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,
>> @@ -894,7 +895,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 {
>> @@ -956,6 +959,56 @@ nir_deref_tail(nir_deref *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;
>> +
>> unsigned num_params;
>> nir_deref_var **params;
>> nir_deref_var *return_deref;
>> @@ -2044,6 +2097,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 bcfdaa7..20eaaff 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 9cb9ed4..939ddcc 100644
>> --- a/src/compiler/nir/nir_instr_set.c
>> +++ b/src/compiler/nir/nir_instr_set.c
>> @@ -79,6 +79,40 @@ hash_alu(uint32_t hash, const nir_alu_instr *instr)
>> }
>>
>> 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)
>> {
>> hash = HASH(hash, instr->def.num_components);
>> @@ -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 c4001fa..594727c 100644
>> --- a/src/compiler/nir/nir_opt_copy_propagate.c
>> +++ b/src/compiler/nir/nir_opt_copy_propagate.c
>> @@ -99,6 +99,22 @@ is_swizzleless_move(nir_alu_instr *instr)
>> }
>>
>> static bool
>> +is_trivial_deref_cast(nir_deref_instr *cast)
>> +{
>> + nir_deref_instr *parent = nir_src_as_deref(cast->parent);
>> + if (!parent)
>> + return false;
>> +
>> + if (cast->deref_type != nir_deref_type_cast)
>> + 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 570e430..c9b3388 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 21f1309..64fdfb2 100644
>> --- a/src/compiler/nir/nir_print.c
>> +++ b/src/compiler/nir/nir_print.c
>> @@ -488,6 +488,58 @@ print_var_decl(nir_variable *var, print_state *state)
>> }
>>
>> static void
>> +print_deref_instr(nir_deref_instr *instr, print_state *state)
>> +{
>> + FILE *fp = state->fp;
>> +
>> + print_dest(&instr->dest, state);
>> +
>> + if (instr->deref_type == nir_deref_type_var) {
>> + fprintf(fp, " = deref %s", get_var_name(instr->var, state));
>> + return;
>> + } else if (instr->deref_type == nir_deref_type_cast) {
>> + fprintf(fp, " = deref (%s) (%s *)&",
>> + get_variable_mode_str(instr->mode),
>> + glsl_get_type_name(instr->type));
>> + print_src(&instr->parent, state);
>> + return;
>> + }
>> +
>> + fprintf(fp, " = deref (%s) &", get_variable_mode_str(instr->mode));
>> + print_src(&instr->parent, state);
>> +
>> + assert(instr->parent.is_ssa);
>> + nir_deref_instr *parent =
>> + nir_instr_as_deref(instr->parent.ssa->parent_instr);
>> +
>> + switch (instr->deref_type) {
>> + case nir_deref_type_struct:
>> + fprintf(fp, "->%s",
>> + 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_var(nir_variable *var, print_state *state)
>> {
>> FILE *fp = state->fp;
>> @@ -924,6 +976,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 00df49c..834a65b 100644
>> --- a/src/compiler/nir/nir_serialize.c
>> +++ b/src/compiler/nir/nir_serialize.c
>> @@ -479,6 +479,81 @@ read_alu(read_ctx *ctx)
>> }
>>
>> 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)
>> {
>> blob_write_uint32(ctx->blob, intrin->intrinsic);
>> @@ -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 d05b982..527abde 100644
>> --- a/src/compiler/nir/nir_validate.c
>> +++ b/src/compiler/nir/nir_validate.c
>> @@ -471,6 +471,85 @@ validate_deref_var(void *parent_mem_ctx, nir_deref_var *deref, validate_state *s
>> }
>>
>> 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);
>
> why no phi or select here? Those don't change anything about the
> pointer, so I'd not expect a cast?
nvm, I see it is useful to convey the type and mode of the resulting
pointer in those kinds of situations.
>
>> +
>> + 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)
>> {
>> unsigned dest_bit_size = 0;
>> @@ -624,6 +703,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.5.0.400.gff86faf
>>
>> _______________________________________________
>> mesa-dev mailing list
>> mesa-dev at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list