On Sun, Apr 8, 2018 at 6:06 PM, Rob Clark <robdcl...@gmail.com> wrote: > 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.
But something like __constant int *ptr_value = ...; store ptr in complex data structure. __constant int* ptr2 = load from complex data structure. Without explicitly annotating ptr2 it is unlikely that constant folding would find that ptr2 is pointing to __constant address space. Hence removing the modes loses valuable information that you cannot get back by constant folding. However, if you have a pointer with unknown mode, we could have a special mode (or mode_all?) and you can use the uvec2 representation in that case? > > 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? I'd like to avoid fat pointers alltogether on AMD since we would not use it even for CL. a generic pointer is just a uint64_t for us, with no bitfield in there for the address space. I think we may need to think a bit more about representation however, as e.g. for AMD a pointer is typically 64-bits (but we can do e.g. 32-bits for known workgroup pointers), the current deref instructions return 32-bit, and you want something like a uvec2 as pointer representation? > > 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