<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Mar 15, 2018 at 9:50 AM, Rob Clark <span dir="ltr"><<a href="mailto:robdclark@gmail.com" target="_blank">robdclark@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Thu, Mar 15, 2018 at 11:51 AM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> wrote:<br>
> On Thu, Mar 15, 2018 at 7:46 AM, Rob Clark <<a href="mailto:robdclark@gmail.com">robdclark@gmail.com</a>> wrote:<br>
>><br>
>> On Thu, Mar 15, 2018 at 1:33 AM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
>> wrote:<br>
>> > This commit adds a new instruction type to NIR for handling derefs.<br>
>> > Nothing uses it yet but this adds the data structure as well as all of<br>
>> > the code to validate, print, clone, and [de]serialize them.<br>
>> ><br>
>> > Cc: Rob Clark <<a href="mailto:robdclark@gmail.com">robdclark@gmail.com</a>><br>
>> > Cc: Connor Abbott <<a href="mailto:cwabbott0@gmail.com">cwabbott0@gmail.com</a>><br>
>> ><br>
>> > ---<br>
>> ><br>
>> > This is not tested beyond compile testing. I'm sending it out ahead so<br>
>> > that people can comment on the instruction data structure. I think this<br>
>> > should handle all the SPIR-V use-cases fairly nicely as well as the<br>
>> > use-cases we have today.<br>
>> ><br>
>> > src/compiler/nir/nir.c | 49 +++++++++++++++++++++++<br>
>> > src/compiler/nir/nir.h | 47 +++++++++++++++++++++-<br>
>> > src/compiler/nir/nir_clone.c | 45 +++++++++++++++++++++<br>
>> > src/compiler/nir/nir_print.c | 46 ++++++++++++++++++++++<br>
>> > src/compiler/nir/nir_<wbr>serialize.c | 85<br>
>> > ++++++++++++++++++++++++++++++<wbr>++++++++++<br>
>> > src/compiler/nir/nir_validate.<wbr>c | 67 ++++++++++++++++++++++++++++++<wbr>+<br>
>> > 6 files changed, 338 insertions(+), 1 deletion(-)<br>
>> ><br>
>> > diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c<br>
>> > index a97b119..1023eb9 100644<br>
>> > --- a/src/compiler/nir/nir.c<br>
>> > +++ b/src/compiler/nir/nir.c<br>
>> > @@ -469,6 +469,26 @@ nir_alu_instr_create(nir_<wbr>shader *shader, nir_op op)<br>
>> > return instr;<br>
>> > }<br>
>> ><br>
>> > +nir_deref_instr *<br>
>> > +nir_deref_instr_create(nir_<wbr>shader *shader, nir_deref_type deref_type)<br>
>> > +{<br>
>> > + nir_deref_instr *instr =<br>
>> > + rzalloc_size(shader, sizeof(nir_deref_instr));<br>
>> > +<br>
>> > + instr_init(&instr->instr, nir_instr_type_deref);<br>
>> > +<br>
>> > + instr->deref_type = deref_type;<br>
>> > + if (deref_type != nir_deref_type_var)<br>
>> > + src_init(&instr->parent);<br>
>> > +<br>
>> > + if (deref_type == nir_deref_type_array_indirect)<br>
>> > + src_init(&instr->arr.indirect)<wbr>;<br>
>> > +<br>
>> > + dest_init(&instr->dest);<br>
>> > +<br>
>> > + return instr;<br>
>> > +}<br>
>> > +<br>
>> > nir_jump_instr *<br>
>> > nir_jump_instr_create(nir_<wbr>shader *shader, nir_jump_type type)<br>
>> > {<br>
>> > @@ -1198,6 +1218,12 @@ visit_alu_dest(nir_alu_instr *instr,<br>
>> > nir_foreach_dest_cb cb, void *state)<br>
>> > }<br>
>> ><br>
>> > static bool<br>
>> > +visit_deref_dest(nir_deref_<wbr>instr *instr, nir_foreach_dest_cb cb, void<br>
>> > *state)<br>
>> > +{<br>
>> > + return cb(&instr->dest, state);<br>
>> > +}<br>
>> > +<br>
>> > +static bool<br>
>> > visit_intrinsic_dest(nir_<wbr>intrinsic_instr *instr, nir_foreach_dest_cb<br>
>> > cb,<br>
>> > void *state)<br>
>> > {<br>
>> > @@ -1238,6 +1264,8 @@ nir_foreach_dest(nir_instr *instr,<br>
>> > nir_foreach_dest_cb cb, void *state)<br>
>> > switch (instr->type) {<br>
>> > case nir_instr_type_alu:<br>
>> > return visit_alu_dest(nir_instr_as_<wbr>alu(instr), cb, state);<br>
>> > + case nir_instr_type_deref:<br>
>> > + return visit_deref_dest(nir_instr_as_<wbr>deref(instr), cb, state);<br>
>> > case nir_instr_type_intrinsic:<br>
>> > return visit_intrinsic_dest(nir_<wbr>instr_as_intrinsic(instr), cb,<br>
>> > state);<br>
>> > case nir_instr_type_tex:<br>
>> > @@ -1349,6 +1377,23 @@ visit_alu_src(nir_alu_instr *instr,<br>
>> > nir_foreach_src_cb cb, void *state)<br>
>> > }<br>
>> ><br>
>> > static bool<br>
>> > +visit_deref_instr_src(nir_<wbr>deref_instr *instr,<br>
>> > + nir_foreach_src_cb cb, void *state)<br>
>> > +{<br>
>> > + if (instr->deref_type != nir_deref_type_var) {<br>
>> > + if (!visit_src(&instr->parent, cb, state))<br>
>> > + return false;<br>
>> > + }<br>
>> > +<br>
>> > + if (instr->deref_type == nir_deref_type_array_indirect) {<br>
>> > + if (!visit_src(&instr->arr.<wbr>indirect, cb, state))<br>
>> > + return false;<br>
>> > + }<br>
>> > +<br>
>> > + return true;<br>
>> > +}<br>
>> > +<br>
>> > +static bool<br>
>> > visit_tex_src(nir_tex_instr *instr, nir_foreach_src_cb cb, void *state)<br>
>> > {<br>
>> > for (unsigned i = 0; i < instr->num_srcs; i++) {<br>
>> > @@ -1436,6 +1481,10 @@ nir_foreach_src(nir_instr *instr,<br>
>> > nir_foreach_src_cb cb, void *state)<br>
>> > if (!visit_alu_src(nir_instr_as_<wbr>alu(instr), cb, state))<br>
>> > return false;<br>
>> > break;<br>
>> > + case nir_instr_type_deref:<br>
>> > + if (!visit_deref_instr_src(nir_<wbr>instr_as_deref(instr), cb, state))<br>
>> > + return false;<br>
>> > + break;<br>
>> > case nir_instr_type_intrinsic:<br>
>> > if (!visit_intrinsic_src(nir_<wbr>instr_as_intrinsic(instr), cb,<br>
>> > state))<br>
>> > return false;<br>
>> > diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
>> > index 839d403..a40a3a0 100644<br>
>> > --- a/src/compiler/nir/nir.h<br>
>> > +++ b/src/compiler/nir/nir.h<br>
>> > @@ -421,6 +421,7 @@ typedef struct nir_register {<br>
>> ><br>
>> > typedef enum {<br>
>> > nir_instr_type_alu,<br>
>> > + nir_instr_type_deref,<br>
>> > nir_instr_type_call,<br>
>> > nir_instr_type_tex,<br>
>> > nir_instr_type_intrinsic,<br>
>> > @@ -888,7 +889,10 @@ bool nir_alu_srcs_equal(const nir_alu_instr *alu1,<br>
>> > const nir_alu_instr *alu2,<br>
>> > typedef enum {<br>
>> > nir_deref_type_var,<br>
>> > nir_deref_type_array,<br>
>> > - nir_deref_type_struct<br>
>> > + nir_deref_type_struct,<br>
>> > + nir_deref_type_array_direct,<br>
>><br>
>> slightly off topic, but when going thru deref-chain stuff earlier, I<br>
>> kinda wondered if there was a point to having the 'direct' case for<br>
>> array's. I mean, there is nir_src_as_const_value().. I guess just<br>
>> needed when you come out of ssa?<br>
><br>
><br>
> It's useful for alias analysis to just be able to look at he deref type.<br>
> Honestly, I'm not sure how useful so maybe we can drop it.<br>
><br>
<br>
</div></div>I hadn't thought too much about opt passes.. although not having<br>
special _direct case would get rid of a bit of if/else in vtn and<br>
maybe elsewhere.<br></blockquote><div><br></div><div>I'm going to try not having separate _direct and _indirect array dereference types and we'll see how it goes. I'm also going to drop the base_offset while we're at it.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Actually, one option would be do it like spirv and not even bother w/<br>
different struct vs array deref instructions, but just have a common<br>
one that had a nir_src which was interpreted according to the<br>
glsl_type. (Ie. nir_validate would require if the glsl_type was a<br>
struct that the src must be _as_const_value())<br><div><div class="h5"></div></div></blockquote><div><br></div><div>I think I'd like to keep structs separate for now as they have somewhat different rules.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
>><br>
>> > + nir_deref_type_array_indirect,<br>
>> > + nir_deref_type_array_wildcard,<br>
>> > } nir_deref_type;<br>
>> ><br>
>> > typedef struct nir_deref {<br>
>> > @@ -950,6 +954,42 @@ nir_deref_tail(nir_deref *deref)<br>
>> > typedef struct {<br>
>> > nir_instr instr;<br>
>> ><br>
>> > + /** The type of this deref instruction */<br>
>> > + nir_deref_type deref_type;<br>
>> > +<br>
>> > + /** The mode of the underlying variable */<br>
>> > + nir_variable_mode mode;<br>
>> > +<br>
>> > + /** The dereferenced type of the resulting pointer value */<br>
>> > + const struct glsl_type *type;<br>
>> > +<br>
>> > + union {<br>
>> > + /** Variable being dereferenced if deref_type is a deref_var */<br>
>> > + nir_variable *var;<br>
>> > +<br>
>> > + /** Parent deref if deref_type is not deref_var */<br>
>> > + nir_src parent;<br>
>><br>
>> maybe just 'nir_ssa_def *parent' directly? I'm not sure the !ssa case<br>
>> makes sense for deref instructions. (And same for the instruction<br>
>> dest)<br>
><br>
><br>
> I thought about that. However, if you want to see these in the back-end<br>
> after out-of-SSA for raw pointiers in CL, you'll want registers. Also,<br>
> having a pure-SSA source is actually kind-of painful in NIR because things<br>
> like nir_foreach_src don't work.<br>
<br>
</div></div>I think for pointers, we will lower to load/store_global or<br>
load/store_shared before coming out of SSA.. which take an address or<br>
offset as nir_src (respectively).<br>
<br>
Actually probably the nir equiv of OpLoad/OpStore return/take a vec2<br>
w/ one component that is the type (global/local (aka shared)/const)<br>
and that gets lowered into if/else ladder of load/store_global/shared<br>
(maybe map const to a ubo).. although I think in most/all cases type<br>
is same for all code paths so if/else ladder should get optimized<br>
out..<br></blockquote><div><br></div><div>I've intentionally made it so that deref values can be any size so that a back-end compiler can come along and make them whatever it wants.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Although the nir_foreach_src() argument is valid. I initially hadn't<br>
paid much attention yet to the validate code but I notice you are<br>
asserting that parent is in ssa form, so I guess that makes it clear<br>
enough that this is always ssa.<br>
<span class=""><br>
><br>
>><br>
>> > + };<br>
>> > +<br>
>> > + /** Additional deref parameters */<br>
>> > + union {<br>
>> > + struct {<br>
>> > + unsigned base_offset;<br>
>> > + nir_src indirect;<br>
>> > + } arr;<br>
>> > +<br>
>> > + struct {<br>
>> > + unsigned index;<br>
>> > + } strct;<br>
>> > + };<br>
>><br>
>> Any particular reason not to have a parent nir_deref_instr, with<br>
>> multiple subclasses (ie.<br>
>> nir_deref_array_instr/nir_<wbr>deref_var_instr/etc) vs unions? That would<br>
>> be more in keeping with how the rest of nir is structured, and avoid<br>
>> having to use names like "strct" :-P<br>
><br>
><br>
> Because all of the casting you have to do with derefs is painful. Honestly,<br>
> one of the most annoying bits of dealing with NIR derefs is all of the<br>
> nir_deref_as_foo() casts. They do provide some safety since, once you do<br>
> the cast, you can't access struct union members of an array deref. I'm not<br>
> sure; things may change as I try to make other changes.<br>
<br>
</span>it's more of a bikeshed thing anyways, I guess, but I guess I'm used<br>
to nir_abc_as_xyz() casts<br></blockquote><div><br></div><div>I think it'll be even cleaner once we drop the separate direct and indirect dereference types.<br><br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
BR,<br>
-R<br>
<div class="HOEnZb"><div class="h5"><br>
><br>
>><br>
>> Otherwise, this is more or less what I had in mind too.<br>
>><br>
>> BR,<br>
>> -R<br>
>><br>
>> > +<br>
>> > + /** Destination to store the resulting "pointer" */<br>
>> > + nir_dest dest;<br>
>> > +} nir_deref_instr;<br>
>> > +<br>
>> > +typedef struct {<br>
>> > + nir_instr instr;<br>
>> > +<br>
>> > unsigned num_params;<br>
>> > nir_deref_var **params;<br>
>> > nir_deref_var *return_deref;<br>
>> > @@ -1521,6 +1561,8 @@ typedef struct {<br>
>> ><br>
>> > NIR_DEFINE_CAST(nir_instr_as_<wbr>alu, nir_instr, nir_alu_instr, instr,<br>
>> > type, nir_instr_type_alu)<br>
>> > +NIR_DEFINE_CAST(nir_instr_as_<wbr>deref, nir_instr, nir_deref_instr, instr,<br>
>> > + type, nir_instr_type_deref)<br>
>> > NIR_DEFINE_CAST(nir_instr_as_<wbr>call, nir_instr, nir_call_instr, instr,<br>
>> > type, nir_instr_type_call)<br>
>> > NIR_DEFINE_CAST(nir_instr_as_<wbr>jump, nir_instr, nir_jump_instr, instr,<br>
>> > @@ -2047,6 +2089,9 @@ void nir_metadata_preserve(nir_<wbr>function_impl<br>
>> > *impl, nir_metadata preserved);<br>
>> > /** creates an instruction with default swizzle/writemask/etc. with<br>
>> > NULL registers */<br>
>> > nir_alu_instr *nir_alu_instr_create(nir_<wbr>shader *shader, nir_op op);<br>
>> ><br>
>> > +nir_deref_instr *nir_deref_instr_create(nir_<wbr>shader *shader,<br>
>> > + nir_deref_type deref_type);<br>
>> > +<br>
>> > nir_jump_instr *nir_jump_instr_create(nir_<wbr>shader *shader, nir_jump_type<br>
>> > type);<br>
>> ><br>
>> > nir_load_const_instr *nir_load_const_instr_create(<wbr>nir_shader *shader,<br>
>> > diff --git a/src/compiler/nir/nir_clone.c b/src/compiler/nir/nir_clone.c<br>
>> > index bcfdaa7..98b3f98 100644<br>
>> > --- a/src/compiler/nir/nir_clone.c<br>
>> > +++ b/src/compiler/nir/nir_clone.c<br>
>> > @@ -346,6 +346,49 @@ clone_alu(clone_state *state, const nir_alu_instr<br>
>> > *alu)<br>
>> > return nalu;<br>
>> > }<br>
>> ><br>
>> > +static nir_deref_instr *<br>
>> > +clone_deref_instr(clone_state *state, const nir_deref_instr *deref)<br>
>> > +{<br>
>> > + nir_deref_instr *nderef =<br>
>> > + nir_deref_instr_create(state-><wbr>ns, deref->deref_type);<br>
>> > +<br>
>> > + __clone_dst(state, &nderef->instr, &nderef->dest, &deref->dest);<br>
>> > +<br>
>> > + nderef->mode = deref->mode;<br>
>> > + nderef->type = deref->type;<br>
>> > +<br>
>> > + if (deref->deref_type == nir_deref_type_var) {<br>
>> > + nderef->var = remap_var(state, deref->var);<br>
>> > + } else {<br>
>> > + __clone_src(state, &nderef->instr, &nderef->parent,<br>
>> > &deref->parent);<br>
>> > + }<br>
>> > +<br>
>> > + switch (deref->deref_type) {<br>
>> > + case nir_deref_type_struct:<br>
>> > + nderef->strct.index = deref->strct.index;<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_array_indirect:<br>
>> > + __clone_src(state, &nderef->instr,<br>
>> > + &nderef->arr.indirect, &deref->arr.indirect);<br>
>> > + /* fall through */<br>
>> > +<br>
>> > + case nir_deref_type_array_direct:<br>
>> > + nderef->arr.base_offset = deref->arr.base_offset;<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_var:<br>
>> > + case nir_deref_type_array_wildcard:<br>
>> > + /* Nothing to do */<br>
>> > + break;<br>
>> > +<br>
>> > + default:<br>
>> > + unreachable("Invalid instruction deref type");<br>
>> > + }<br>
>> > +<br>
>> > + return nderef;<br>
>> > +}<br>
>> > +<br>
>> > static nir_intrinsic_instr *<br>
>> > clone_intrinsic(clone_state *state, const nir_intrinsic_instr *itr)<br>
>> > {<br>
>> > @@ -502,6 +545,8 @@ clone_instr(clone_state *state, const nir_instr<br>
>> > *instr)<br>
>> > switch (instr->type) {<br>
>> > case nir_instr_type_alu:<br>
>> > return &clone_alu(state, nir_instr_as_alu(instr))-><wbr>instr;<br>
>> > + case nir_instr_type_deref:<br>
>> > + return &clone_deref_instr(state,<br>
>> > nir_instr_as_deref(instr))-><wbr>instr;<br>
>> > case nir_instr_type_intrinsic:<br>
>> > return &clone_intrinsic(state,<br>
>> > nir_instr_as_intrinsic(instr))<wbr>->instr;<br>
>> > case nir_instr_type_load_const:<br>
>> > diff --git a/src/compiler/nir/nir_print.c b/src/compiler/nir/nir_print.c<br>
>> > index 7888dbd..32aa3fc 100644<br>
>> > --- a/src/compiler/nir/nir_print.c<br>
>> > +++ b/src/compiler/nir/nir_print.c<br>
>> > @@ -486,6 +486,48 @@ print_var_decl(nir_variable *var, print_state<br>
>> > *state)<br>
>> > }<br>
>> ><br>
>> > static void<br>
>> > +print_deref_instr(nir_deref_<wbr>instr *instr, print_state *state)<br>
>> > +{<br>
>> > + FILE *fp = state->fp;<br>
>> > +<br>
>> > + print_dest(&instr->dest, state);<br>
>> > +<br>
>> > + if (instr->deref_type == nir_deref_type_var) {<br>
>> > + fprintf(fp, " = %s", get_var_name(instr->var, state));<br>
>> > + return;<br>
>> > + }<br>
>> > +<br>
>> > + fprintf(fp, " = &");<br>
>> > + print_src(&instr->parent, state);<br>
>> > +<br>
>> > + assert(instr->parent.is_ssa);<br>
>> > + nir_deref_instr *parent =<br>
>> > + nir_instr_as_deref(instr-><wbr>parent.ssa->parent_instr);<br>
>> > +<br>
>> > + switch (instr->deref_type) {<br>
>> > + case nir_deref_type_struct:<br>
>> > + fprintf(fp, "->%s",<br>
>> > + glsl_get_struct_elem_name(<wbr>parent->type,<br>
>> > instr->strct.index));<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_array_direct:<br>
>> > + fprintf(fp, "[%u]", instr->arr.base_offset);<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_array_indirect:<br>
>> > + fprintf(fp, "[");<br>
>> > + if (instr->arr.base_offset)<br>
>> > + fprintf(fp, "%u + ", instr->arr.base_offset);<br>
>> > + print_src(&instr->arr.<wbr>indirect, state);<br>
>> > + fprintf(fp, "]");<br>
>> > + break;<br>
>> > +<br>
>> > + default:<br>
>> > + unreachable("Invalid deref instruction type");<br>
>> > + }<br>
>> > +}<br>
>> > +<br>
>> > +static void<br>
>> > print_var(nir_variable *var, print_state *state)<br>
>> > {<br>
>> > FILE *fp = state->fp;<br>
>> > @@ -922,6 +964,10 @@ print_instr(const nir_instr *instr, print_state<br>
>> > *state, unsigned tabs)<br>
>> > print_alu_instr(nir_instr_as_<wbr>alu(instr), state);<br>
>> > break;<br>
>> ><br>
>> > + case nir_instr_type_deref:<br>
>> > + print_deref_instr(nir_instr_<wbr>as_deref(instr), state);<br>
>> > + break;<br>
>> > +<br>
>> > case nir_instr_type_call:<br>
>> > print_call_instr(nir_instr_as_<wbr>call(instr), state);<br>
>> > break;<br>
>> > diff --git a/src/compiler/nir/nir_<wbr>serialize.c<br>
>> > b/src/compiler/nir/nir_<wbr>serialize.c<br>
>> > index 00df49c..87e40d9 100644<br>
>> > --- a/src/compiler/nir/nir_<wbr>serialize.c<br>
>> > +++ b/src/compiler/nir/nir_<wbr>serialize.c<br>
>> > @@ -479,6 +479,85 @@ read_alu(read_ctx *ctx)<br>
>> > }<br>
>> ><br>
>> > static void<br>
>> > +write_deref(write_ctx *ctx, const nir_deref_instr *deref)<br>
>> > +{<br>
>> > + blob_write_uint32(ctx->blob, deref->deref_type);<br>
>> > +<br>
>> > + blob_write_uint32(ctx->blob, deref->mode);<br>
>> > + encode_type_to_blob(ctx->blob, deref->type);<br>
>> > +<br>
>> > + write_dest(ctx, &deref->dest);<br>
>> > +<br>
>> > + if (deref->deref_type == nir_deref_type_var) {<br>
>> > + write_object(ctx, deref->var);<br>
>> > + return;<br>
>> > + }<br>
>> > +<br>
>> > + write_src(ctx, &deref->parent);<br>
>> > +<br>
>> > + switch (deref->deref_type) {<br>
>> > + case nir_deref_type_struct:<br>
>> > + blob_write_uint32(ctx->blob, deref->strct.index);<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_array_indirect:<br>
>> > + write_src(ctx, &deref->arr.indirect);<br>
>> > + /* fall through */<br>
>> > + case nir_deref_type_array_direct:<br>
>> > + blob_write_uint32(ctx->blob, deref->arr.base_offset);<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_array_wildcard:<br>
>> > + /* Nothing to do */<br>
>> > + break;<br>
>> > +<br>
>> > + default:<br>
>> > + unreachable("Invalid deref type");<br>
>> > + }<br>
>> > +}<br>
>> > +<br>
>> > +static nir_deref_instr *<br>
>> > +read_deref(read_ctx *ctx)<br>
>> > +{<br>
>> > + nir_deref_type deref_type = blob_read_uint32(ctx->blob);<br>
>> > + nir_deref_instr *deref = nir_deref_instr_create(ctx-><wbr>nir,<br>
>> > deref_type);<br>
>> > +<br>
>> > + deref->mode = blob_read_uint32(ctx->blob);<br>
>> > + deref->type = decode_type_from_blob(ctx-><wbr>blob);<br>
>> > +<br>
>> > + read_dest(ctx, &deref->dest, &deref->instr);<br>
>> > +<br>
>> > + if (deref_type == nir_deref_type_var) {<br>
>> > + deref->var = read_object(ctx);<br>
>> > + return deref;<br>
>> > + }<br>
>> > +<br>
>> > + read_src(ctx, &deref->parent, &deref->instr);<br>
>> > +<br>
>> > + switch (deref->deref_type) {<br>
>> > + case nir_deref_type_struct:<br>
>> > + deref->strct.index = blob_read_uint32(ctx->blob);<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_array_indirect:<br>
>> > + read_src(ctx, &deref->arr.indirect, &deref->instr);<br>
>> > + /* fall through */<br>
>> > + case nir_deref_type_array_direct:<br>
>> > + deref->arr.base_offset = blob_read_uint32(ctx->blob);<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_array_wildcard:<br>
>> > + /* Nothing to do */<br>
>> > + break;<br>
>> > +<br>
>> > + default:<br>
>> > + unreachable("Invalid deref type");<br>
>> > + }<br>
>> > +<br>
>> > + return deref;<br>
>> > +}<br>
>> > +<br>
>> > +static void<br>
>> > write_intrinsic(write_ctx *ctx, const nir_intrinsic_instr *intrin)<br>
>> > {<br>
>> > blob_write_uint32(ctx->blob, intrin->intrinsic);<br>
>> > @@ -803,6 +882,9 @@ write_instr(write_ctx *ctx, const nir_instr *instr)<br>
>> > case nir_instr_type_alu:<br>
>> > write_alu(ctx, nir_instr_as_alu(instr));<br>
>> > break;<br>
>> > + case nir_instr_type_deref:<br>
>> > + write_deref(ctx, nir_instr_as_deref(instr));<br>
>> > + break;<br>
>> > case nir_instr_type_intrinsic:<br>
>> > write_intrinsic(ctx, nir_instr_as_intrinsic(instr))<wbr>;<br>
>> > break;<br>
>> > @@ -840,6 +922,9 @@ read_instr(read_ctx *ctx, nir_block *block)<br>
>> > case nir_instr_type_alu:<br>
>> > instr = &read_alu(ctx)->instr;<br>
>> > break;<br>
>> > + case nir_instr_type_deref:<br>
>> > + instr = &read_deref(ctx)->instr;<br>
>> > + break;<br>
>> > case nir_instr_type_intrinsic:<br>
>> > instr = &read_intrinsic(ctx)->instr;<br>
>> > break;<br>
>> > diff --git a/src/compiler/nir/nir_<wbr>validate.c<br>
>> > b/src/compiler/nir/nir_<wbr>validate.c<br>
>> > index a49948f..354b32b 100644<br>
>> > --- a/src/compiler/nir/nir_<wbr>validate.c<br>
>> > +++ b/src/compiler/nir/nir_<wbr>validate.c<br>
>> > @@ -397,6 +397,69 @@ validate_alu_instr(nir_alu_<wbr>instr *instr,<br>
>> > validate_state *state)<br>
>> > }<br>
>> ><br>
>> > static void<br>
>> > +validate_deref_instr(nir_<wbr>deref_instr *instr, validate_state *state)<br>
>> > +{<br>
>> > + if (instr->deref_type == nir_deref_type_var) {<br>
>> > + /* Variable dereferences are stupid simple. */<br>
>> > + validate_assert(state, instr->mode == instr->var->data.mode);<br>
>> > + validate_assert(state, instr->type == instr->var->type);<br>
>> > + } else {<br>
>> > + /* We require the parent to be SSA. This may be lifted in the<br>
>> > future */<br>
>> > + validate_assert(state, instr->parent.is_ssa);<br>
>> > +<br>
>> > + /* The parent pointer value must have the same number of<br>
>> > components<br>
>> > + * as the destination.<br>
>> > + */<br>
>> > + validate_src(&instr->parent, state,<br>
>> > nir_dest_bit_size(instr->dest)<wbr>,<br>
>> > + nir_dest_num_components(instr-<wbr>>dest));<br>
>> > +<br>
>> > + nir_instr *parent_instr = instr->parent.ssa->parent_<wbr>instr;<br>
>> > +<br>
>> > + /* The parent must come from another deref instruction */<br>
>> > + validate_assert(state, parent_instr->type ==<br>
>> > nir_instr_type_deref);<br>
>> > +<br>
>> > + nir_deref_instr *parent = nir_instr_as_deref(parent_<wbr>instr);<br>
>> > +<br>
>> > + validate_assert(state, instr->mode == parent->mode);<br>
>> > +<br>
>> > + switch (instr->deref_type) {<br>
>> > + case nir_deref_type_struct:<br>
>> > + validate_assert(state, glsl_type_is_struct(parent-><wbr>type));<br>
>> > + validate_assert(state,<br>
>> > + instr->strct.index < glsl_get_length(parent->type))<wbr>;<br>
>> > + validate_assert(state, instr->type ==<br>
>> > + glsl_get_struct_field(parent-><wbr>type, instr->strct.index));<br>
>> > + break;<br>
>> > +<br>
>> > + case nir_deref_type_array_direct:<br>
>> > + case nir_deref_type_array_indirect:<br>
>> > + case nir_deref_type_array_wildcard:<br>
>> > + validate_assert(state, glsl_type_is_array(parent-><wbr>type));<br>
>> > + validate_assert(state,<br>
>> > + instr->type == glsl_get_array_element(parent-<wbr>>type));<br>
>> > +<br>
>> > + if (instr->deref_type != nir_deref_type_array_wildcard) {<br>
>> > + validate_assert(state,<br>
>> > + instr->arr.base_offset < glsl_get_length(parent->type))<wbr>;<br>
>> > + }<br>
>> > +<br>
>> > + if (instr->deref_type == nir_deref_type_array_indirect)<br>
>> > + validate_src(&instr->arr.<wbr>indirect, state, 32, 1);<br>
>> > + break;<br>
>> > +<br>
>> > + default:<br>
>> > + unreachable("Invalid deref instruction type");<br>
>> > + }<br>
>> > + }<br>
>> > +<br>
>> > + /* We intentionally don't validate the size of the destination<br>
>> > because we<br>
>> > + * want to let other compiler components such as SPIR-V decide how<br>
>> > big<br>
>> > + * pointers should be.<br>
>> > + */<br>
>> > + validate_dest(&instr->dest, state, 0, 0);<br>
>> > +}<br>
>> > +<br>
>> > +static void<br>
>> > validate_deref_chain(nir_deref *deref, nir_variable_mode mode,<br>
>> > validate_state *state)<br>
>> > {<br>
>> > @@ -622,6 +685,10 @@ validate_instr(nir_instr *instr, validate_state<br>
>> > *state)<br>
>> > validate_alu_instr(nir_instr_<wbr>as_alu(instr), state);<br>
>> > break;<br>
>> ><br>
>> > + case nir_instr_type_deref:<br>
>> > + validate_deref_instr(nir_<wbr>instr_as_deref(instr), state);<br>
>> > + break;<br>
>> > +<br>
>> > case nir_instr_type_call:<br>
>> > validate_call_instr(nir_instr_<wbr>as_call(instr), state);<br>
>> > break;<br>
>> > --<br>
>> > 2.5.0.400.gff86faf<br>
>> ><br>
><br>
><br>
</div></div></blockquote></div><br></div></div>