On Sun, Apr 8, 2018 at 11:15 AM, Bas Nieuwenhuizen <b...@basnieuwenhuizen.nl> wrote: > On Sun, Apr 8, 2018 at 3:29 PM, Rob Clark <robdcl...@gmail.com> wrote: >> On Sun, Apr 8, 2018 at 8:58 AM, Bas Nieuwenhuizen >> <b...@basnieuwenhuizen.nl> wrote: >>> On Sun, Apr 8, 2018 at 1:38 PM, Rob Clark <robdcl...@gmail.com> wrote: >>>> On Tue, Apr 3, 2018 at 2:32 PM, Jason Ekstrand <ja...@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; >>>> >>>> In fact, it seems like deref->mode is unused outside of nir_print and >>>> nir_validate.. for logical addressing we can get the mode from the >>>> deref_var->var at the start of the chain, and deref->mode has no >>>> meaning for physical addressing (where the mode comes from the >>>> pointer). >>>> >>>> So maybe just drop deref->mode? >>> >>> Isn't it still useful with logical addressing in case a var is not >>> immediately available? (think VK_KHR_variable_pointers) >> >> not sure, maybe this should just also use fat-pointers like physical >> addressing does?? >> >>> Also I could see this being useful in physical addressing too to avoid >>> all passes working with derefs needing to do the constant folding? >> >> The problem is that you don't necessarily know the type at compile >> time (and in the case where you do, you need to do constant folding to >> figure it out) > > So I have two considerations here > > 1) for vulkan you always know the mode, even when you don't know the var. > 2) In CL the mode can still get annotated in the source program (CL C > non-generic pointers) in cases in which we cannot reasonably figure it > out with just constant folding. In those cases the mode is extra > information that you really lose.
so, even in cl 1.x, you could do things like 'somefxn(foo ? global_ptr : local_ptr)'.. depending on how much we inline all the things, that might not get CF'd away. I think I'm leaning towards using fat ptrs for the vk case, since I guess that is a case where you could always expect nir_src_as_const_value() to work, to get the variable mode. If for no other reason than I guess these deref's, if the var is not known, start w/ deref_cast, and it would be ugly for deref_cast to have to work differently for compute vs vk. But maybe Jason already has some thoughts about it? BR, -R >> >> The plan was, in lower_io, to lower load/store_deref with a ptr src to: >> >> if (fatptr.y == nir_var_global_mem) >> result = load_global fatptr.x >> else if (fatptr.y == nir_var_shared) >> result = load_shared fatptr.x >> else if ... >> >> And then let constant-folding and DCE hopefully clean that up. >> >> (I think for __constant address space, I'm leaning towards turning >> this into a ubo.. we could turn it in to normal uniform, but adreno >> has uniforms similar to how (iirc) radeon works where they are just >> special read-only 32b registers, so I can't easily do byte addressing >> without generating shifts/masks..) >> >> BR, >> -R >> >>> - Bas >>> >>> >>>> >>>> BR, >>>> -R >>>> >>>>> + /** 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); >>>>> + >>>>> + 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@lists.freedesktop.org >>>>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev >>>> _______________________________________________ >>>> mesa-dev mailing list >>>> mesa-dev@lists.freedesktop.org >>>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev