Re: [Mesa-dev] [PATCH 5/9] nir: Add a local dead write vars removal pass

2018-08-29 Thread Jason Ekstrand
On Wed, Aug 29, 2018 at 3:19 PM Caio Marcelo de Oliveira Filho <
caio.olive...@intel.com> wrote:

> Jason Ekstrand  writes:
>
> >> >> +static bool
> >> >> +remove_dead_write_vars_local(struct state *state, nir_block *block)
> >> >> +{
> >> >> +   bool progress = false;
> >> >> +
> >> >> +   struct util_dynarray unused_writes;
> >> >> +   util_dynarray_init(_writes, state->mem_ctx);
> >> >> +
> >> >> +   nir_foreach_instr_safe(instr, block) {
> >> >>
> >> >
> >> > It wouldn't hurt to add a case for call instructions which does a
> barrier
> >> > on everything I mentioned below as well as globals and locals.
> >>
> >> Makes sense.  But I don't get locals are affect?  Is this to cover the
> >> parameters being passed to the call?
> >>
> >
> > Because a deref to a local might be passed in as a parameter.  This is
> the
> > way pass-by-reference works for SPIR-V.
>
> Will the parameter appear to the new function as local too?  If so, will
> they be tagged in a way I can identify the derefs?
>

They'll appear as writes to casts whose source is a load_param intrinsic.


> I'm thinking about what to do with unused writes for locals at the end
> of a function.  If it's the main function, we can just remove them, but
> depending on the answer of the question above, it is not so clear for
> non-main functions.
>

Yeah... That's a bit sticky and I'm not sure what the right answer is.  I
guess we could, in theory, have a new "param" mode which is sort-of like a
local only it crosses function boundaries.  I haven't given that much
though.  However, given that functions are always inlined right now, that's
not something we need to deal with just yet.

--Jason
___
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev


Re: [Mesa-dev] [PATCH 5/9] nir: Add a local dead write vars removal pass

2018-08-29 Thread Caio Marcelo de Oliveira Filho
Jason Ekstrand  writes:

>> >> +static bool
>> >> +remove_dead_write_vars_local(struct state *state, nir_block *block)
>> >> +{
>> >> +   bool progress = false;
>> >> +
>> >> +   struct util_dynarray unused_writes;
>> >> +   util_dynarray_init(_writes, state->mem_ctx);
>> >> +
>> >> +   nir_foreach_instr_safe(instr, block) {
>> >>
>> >
>> > It wouldn't hurt to add a case for call instructions which does a barrier
>> > on everything I mentioned below as well as globals and locals.
>>
>> Makes sense.  But I don't get locals are affect?  Is this to cover the
>> parameters being passed to the call?
>>
>
> Because a deref to a local might be passed in as a parameter.  This is the
> way pass-by-reference works for SPIR-V.

Will the parameter appear to the new function as local too?  If so, will
they be tagged in a way I can identify the derefs?

I'm thinking about what to do with unused writes for locals at the end
of a function.  If it's the main function, we can just remove them, but
depending on the answer of the question above, it is not so clear for
non-main functions.


Thanks,
Caio

___
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev


Re: [Mesa-dev] [PATCH 5/9] nir: Add a local dead write vars removal pass

2018-08-28 Thread Jason Ekstrand
On Mon, Aug 27, 2018 at 4:55 PM Caio Marcelo de Oliveira Filho <
caio.olive...@intel.com> wrote:

> (Disregard the incomplete mail, still adapting to notmuch-emacs).
>
> Jason Ekstrand  writes:
>
> >> +static nir_deref_path *
> >> +get_path(struct state *state, nir_deref_instr *deref)
> >> +{
> >> +   struct hash_entry *entry = _mesa_hash_table_search(state->paths,
> >> deref);
> >> +   if (!entry) {
> >> +  nir_deref_path *path = linear_zalloc_child(state->path_lin_ctx,
> >> sizeof(nir_deref_path));
> >> +  nir_deref_path_init(path, deref, state->mem_ctx);
> >> +  _mesa_hash_table_insert(state->paths, deref, path);
> >> +  return path;
> >> +   } else {
> >> +  return entry->data;
> >> +   }
> >> +}
> >>
> >
> > Do you have any proof that this actually helps?  The deref_path stuff was
> > designed to be put on the stack and absolutely as efficient as possible.
> > In the common case of a deref chain with only a couple of elements, I
> would
> > expect to actually be more work to look it up in a hash table.
>
> Storing those makes more sense if you read the next commit (the
> "global").  Since I've created the "local" commit as an aid for
> reviewing (perhaps a failure), I did not wanted to change it too much.
>
> When I wrote there were some savings when measuring executions with
> perf.
>
> (...)
>
> >> +static bool
> >> +remove_dead_write_vars_local(struct state *state, nir_block *block)
> >> +{
> >> +   bool progress = false;
> >> +
> >> +   struct util_dynarray unused_writes;
> >> +   util_dynarray_init(_writes, state->mem_ctx);
> >> +
> >> +   nir_foreach_instr_safe(instr, block) {
> >>
> >
> > It wouldn't hurt to add a case for call instructions which does a barrier
> > on everything I mentioned below as well as globals and locals.
>
> Makes sense.  But I don't get locals are affect?  Is this to cover the
> parameters being passed to the call?
>

Because a deref to a local might be passed in as a parameter.  This is the
way pass-by-reference works for SPIR-V.


> >
> >> +  if (instr->type != nir_instr_type_intrinsic)
> >> + continue;
> >> +
> >> +  nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
> >> +  switch (intrin->intrinsic) {
> >> +  case nir_intrinsic_barrier:
> >> +  case nir_intrinsic_memory_barrier: {
> >> + nir_variable_mode modes = ~(nir_var_local | nir_var_global |
> >> + nir_var_shader_in |
> nir_var_uniform);
> >>
> >
> > The only thing a barrier like this affects is shared, storage, and
> output.
> > Locals and globals can't cross between shader channels so there's no
> reason
> > to do anything with them on a barrier.  For inputs and uniforms, they're
> > never written anyway so there's no point in doing anything with them on a
> > barrier.
>
> This came from previous code, but except for "system values" it seems to
> do the right thing (note the ~).  Is the suggestion to use a "positive"
> enumeration, e.g.
>

Drp... I completely missed the ~.  Ignore my comment.  Yeah, we could throw
in system values. :D
___
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev


Re: [Mesa-dev] [PATCH 5/9] nir: Add a local dead write vars removal pass

2018-08-27 Thread Caio Marcelo de Oliveira Filho
(Disregard the incomplete mail, still adapting to notmuch-emacs).

Jason Ekstrand  writes:

>> +static nir_deref_path *
>> +get_path(struct state *state, nir_deref_instr *deref)
>> +{
>> +   struct hash_entry *entry = _mesa_hash_table_search(state->paths,
>> deref);
>> +   if (!entry) {
>> +  nir_deref_path *path = linear_zalloc_child(state->path_lin_ctx,
>> sizeof(nir_deref_path));
>> +  nir_deref_path_init(path, deref, state->mem_ctx);
>> +  _mesa_hash_table_insert(state->paths, deref, path);
>> +  return path;
>> +   } else {
>> +  return entry->data;
>> +   }
>> +}
>>
>
> Do you have any proof that this actually helps?  The deref_path stuff was
> designed to be put on the stack and absolutely as efficient as possible.
> In the common case of a deref chain with only a couple of elements, I would
> expect to actually be more work to look it up in a hash table.

Storing those makes more sense if you read the next commit (the
"global").  Since I've created the "local" commit as an aid for
reviewing (perhaps a failure), I did not wanted to change it too much.

When I wrote there were some savings when measuring executions with
perf.

(...)

>> +static bool
>> +remove_dead_write_vars_local(struct state *state, nir_block *block)
>> +{
>> +   bool progress = false;
>> +
>> +   struct util_dynarray unused_writes;
>> +   util_dynarray_init(_writes, state->mem_ctx);
>> +
>> +   nir_foreach_instr_safe(instr, block) {
>>
>
> It wouldn't hurt to add a case for call instructions which does a barrier
> on everything I mentioned below as well as globals and locals.

Makes sense.  But I don't get locals are affect?  Is this to cover the
parameters being passed to the call?

>
>> +  if (instr->type != nir_instr_type_intrinsic)
>> + continue;
>> +
>> +  nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
>> +  switch (intrin->intrinsic) {
>> +  case nir_intrinsic_barrier:
>> +  case nir_intrinsic_memory_barrier: {
>> + nir_variable_mode modes = ~(nir_var_local | nir_var_global |
>> + nir_var_shader_in | nir_var_uniform);
>>
>
> The only thing a barrier like this affects is shared, storage, and output.
> Locals and globals can't cross between shader channels so there's no reason
> to do anything with them on a barrier.  For inputs and uniforms, they're
> never written anyway so there's no point in doing anything with them on a
> barrier.

This came from previous code, but except for "system values" it seems to
do the right thing (note the ~).  Is the suggestion to use a "positive"
enumeration, e.g.

clear_unused_for_modes(_writes, nir_var_shader_out |
   nir_var_shader_storage |
   nir_var_shared);



Thanks,
Caio
___
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev


Re: [Mesa-dev] [PATCH 5/9] nir: Add a local dead write vars removal pass

2018-08-27 Thread Caio Marcelo de Oliveira Filho
Jason Ekstrand  writes:

> On Wed, Aug 15, 2018 at 4:57 PM Caio Marcelo de Oliveira Filho <
> caio.olive...@intel.com> wrote:
>
>> Instead of doing this as part of the existing (local) copy prop vars
>> pass.  This is an intermediate step before changing both the dead
>> write and the copy prop vars to act on the whole program instead of on
>> local blocks.  The nature of data we store and the way we iterate is
>> different enough that would be awkward keeping those together.
>> ---
>>  src/compiler/Makefile.sources  |   1 +
>>  src/compiler/nir/meson.build   |   1 +
>>  src/compiler/nir/nir.h |   2 +
>>  src/compiler/nir/nir_opt_dead_write_vars.c | 243 +
>>  4 files changed, 247 insertions(+)
>>  create mode 100644 src/compiler/nir/nir_opt_dead_write_vars.c
>>
>> diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources
>> index 27a54e0be09..fa93ad08a16 100644
>> --- a/src/compiler/Makefile.sources
>> +++ b/src/compiler/Makefile.sources
>> @@ -274,6 +274,7 @@ NIR_FILES = \
>> nir/nir_opt_cse.c \
>> nir/nir_opt_dce.c \
>> nir/nir_opt_dead_cf.c \
>> +   nir/nir_opt_dead_write_vars.c \
>> nir/nir_opt_gcm.c \
>> nir/nir_opt_global_to_local.c \
>> nir/nir_opt_if.c \
>> diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build
>> index 8708f9b069c..1c164a548a7 100644
>> --- a/src/compiler/nir/meson.build
>> +++ b/src/compiler/nir/meson.build
>> @@ -158,6 +158,7 @@ files_libnir = files(
>>'nir_opt_cse.c',
>>'nir_opt_dce.c',
>>'nir_opt_dead_cf.c',
>> +  'nir_opt_dead_write_vars.c',
>>'nir_opt_gcm.c',
>>'nir_opt_global_to_local.c',
>>'nir_opt_if.c',
>> diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
>> index d0fa693884b..becf6e351c3 100644
>> --- a/src/compiler/nir/nir.h
>> +++ b/src/compiler/nir/nir.h
>> @@ -2968,6 +2968,8 @@ bool nir_opt_dce(nir_shader *shader);
>>
>>  bool nir_opt_dead_cf(nir_shader *shader);
>>
>> +bool nir_opt_dead_write_vars(nir_shader *shader);
>> +
>>  bool nir_opt_gcm(nir_shader *shader, bool value_number);
>>
>>  bool nir_opt_if(nir_shader *shader);
>> diff --git a/src/compiler/nir/nir_opt_dead_write_vars.c
>> b/src/compiler/nir/nir_opt_dead_write_vars.c
>> new file mode 100644
>> index 000..822bfa5595d
>> --- /dev/null
>> +++ b/src/compiler/nir/nir_opt_dead_write_vars.c
>> @@ -0,0 +1,243 @@
>> +/*
>> + * Copyright © 2018 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the
>> "Software"),
>> + * to deal in the Software without restriction, including without
>> limitation
>> + * the rights to use, copy, modify, merge, publish, distribute,
>> sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the
>> next
>> + * paragraph) shall be included in all copies or substantial portions of
>> the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>> SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> DEALINGS
>> + * IN THE SOFTWARE.
>> + */
>> +
>> +#include "nir.h"
>> +#include "nir_builder.h"
>> +#include "nir_deref.h"
>> +
>> +#include "util/u_dynarray.h"
>> +
>> +struct state {
>> +   void *mem_ctx;
>> +
>> +   /* Maps nir_deref_instr to a corresponding nir_deref_path.  Avoids
>> +* rebuilding the paths for the same deref. */
>> +   struct hash_table *paths;
>> +   void *path_lin_ctx;
>> +};
>> +
>> +static nir_deref_path *
>> +get_path(struct state *state, nir_deref_instr *deref)
>> +{
>> +   struct hash_entry *entry = _mesa_hash_table_search(state->paths,
>> deref);
>> +   if (!entry) {
>> +  nir_deref_path *path = linear_zalloc_child(state->path_lin_ctx,
>> sizeof(nir_deref_path));
>> +  nir_deref_path_init(path, deref, state->mem_ctx);
>> +  _mesa_hash_table_insert(state->paths, deref, path);
>> +  return path;
>> +   } else {
>> +  return entry->data;
>> +   }
>> +}
>>
>
> Do you have any proof that this actually helps?  The deref_path stuff was
> designed to be put on the stack and absolutely as efficient as possible.
> In the common case of a deref chain with only a couple of elements, I would
> expect to actually be more work to look it up in a hash table.
>
>
>> +
>> +/* Entry for unused_writes arrays. */
>> +struct write_entry {
>> +   /* If NULL indicates the 

Re: [Mesa-dev] [PATCH 5/9] nir: Add a local dead write vars removal pass

2018-08-22 Thread Jason Ekstrand
On Wed, Aug 15, 2018 at 4:57 PM Caio Marcelo de Oliveira Filho <
caio.olive...@intel.com> wrote:

> Instead of doing this as part of the existing (local) copy prop vars
> pass.  This is an intermediate step before changing both the dead
> write and the copy prop vars to act on the whole program instead of on
> local blocks.  The nature of data we store and the way we iterate is
> different enough that would be awkward keeping those together.
> ---
>  src/compiler/Makefile.sources  |   1 +
>  src/compiler/nir/meson.build   |   1 +
>  src/compiler/nir/nir.h |   2 +
>  src/compiler/nir/nir_opt_dead_write_vars.c | 243 +
>  4 files changed, 247 insertions(+)
>  create mode 100644 src/compiler/nir/nir_opt_dead_write_vars.c
>
> diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources
> index 27a54e0be09..fa93ad08a16 100644
> --- a/src/compiler/Makefile.sources
> +++ b/src/compiler/Makefile.sources
> @@ -274,6 +274,7 @@ NIR_FILES = \
> nir/nir_opt_cse.c \
> nir/nir_opt_dce.c \
> nir/nir_opt_dead_cf.c \
> +   nir/nir_opt_dead_write_vars.c \
> nir/nir_opt_gcm.c \
> nir/nir_opt_global_to_local.c \
> nir/nir_opt_if.c \
> diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build
> index 8708f9b069c..1c164a548a7 100644
> --- a/src/compiler/nir/meson.build
> +++ b/src/compiler/nir/meson.build
> @@ -158,6 +158,7 @@ files_libnir = files(
>'nir_opt_cse.c',
>'nir_opt_dce.c',
>'nir_opt_dead_cf.c',
> +  'nir_opt_dead_write_vars.c',
>'nir_opt_gcm.c',
>'nir_opt_global_to_local.c',
>'nir_opt_if.c',
> diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
> index d0fa693884b..becf6e351c3 100644
> --- a/src/compiler/nir/nir.h
> +++ b/src/compiler/nir/nir.h
> @@ -2968,6 +2968,8 @@ bool nir_opt_dce(nir_shader *shader);
>
>  bool nir_opt_dead_cf(nir_shader *shader);
>
> +bool nir_opt_dead_write_vars(nir_shader *shader);
> +
>  bool nir_opt_gcm(nir_shader *shader, bool value_number);
>
>  bool nir_opt_if(nir_shader *shader);
> diff --git a/src/compiler/nir/nir_opt_dead_write_vars.c
> b/src/compiler/nir/nir_opt_dead_write_vars.c
> new file mode 100644
> index 000..822bfa5595d
> --- /dev/null
> +++ b/src/compiler/nir/nir_opt_dead_write_vars.c
> @@ -0,0 +1,243 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> next
> + * paragraph) shall be included in all copies or substantial portions of
> the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
> OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "nir.h"
> +#include "nir_builder.h"
> +#include "nir_deref.h"
> +
> +#include "util/u_dynarray.h"
> +
> +struct state {
> +   void *mem_ctx;
> +
> +   /* Maps nir_deref_instr to a corresponding nir_deref_path.  Avoids
> +* rebuilding the paths for the same deref. */
> +   struct hash_table *paths;
> +   void *path_lin_ctx;
> +};
> +
> +static nir_deref_path *
> +get_path(struct state *state, nir_deref_instr *deref)
> +{
> +   struct hash_entry *entry = _mesa_hash_table_search(state->paths,
> deref);
> +   if (!entry) {
> +  nir_deref_path *path = linear_zalloc_child(state->path_lin_ctx,
> sizeof(nir_deref_path));
> +  nir_deref_path_init(path, deref, state->mem_ctx);
> +  _mesa_hash_table_insert(state->paths, deref, path);
> +  return path;
> +   } else {
> +  return entry->data;
> +   }
> +}
>

Do you have any proof that this actually helps?  The deref_path stuff was
designed to be put on the stack and absolutely as efficient as possible.
In the common case of a deref chain with only a couple of elements, I would
expect to actually be more work to look it up in a hash table.


> +
> +/* Entry for unused_writes arrays. */
> +struct write_entry {
> +   /* If NULL indicates the entry is free to be reused. */
> +   nir_intrinsic_instr *intrin;
> +   uintptr_t mask;
> +   nir_deref_path *path;
> +};
> +
> +static void
> 

[Mesa-dev] [PATCH 5/9] nir: Add a local dead write vars removal pass

2018-08-15 Thread Caio Marcelo de Oliveira Filho
Instead of doing this as part of the existing (local) copy prop vars
pass.  This is an intermediate step before changing both the dead
write and the copy prop vars to act on the whole program instead of on
local blocks.  The nature of data we store and the way we iterate is
different enough that would be awkward keeping those together.
---
 src/compiler/Makefile.sources  |   1 +
 src/compiler/nir/meson.build   |   1 +
 src/compiler/nir/nir.h |   2 +
 src/compiler/nir/nir_opt_dead_write_vars.c | 243 +
 4 files changed, 247 insertions(+)
 create mode 100644 src/compiler/nir/nir_opt_dead_write_vars.c

diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources
index 27a54e0be09..fa93ad08a16 100644
--- a/src/compiler/Makefile.sources
+++ b/src/compiler/Makefile.sources
@@ -274,6 +274,7 @@ NIR_FILES = \
nir/nir_opt_cse.c \
nir/nir_opt_dce.c \
nir/nir_opt_dead_cf.c \
+   nir/nir_opt_dead_write_vars.c \
nir/nir_opt_gcm.c \
nir/nir_opt_global_to_local.c \
nir/nir_opt_if.c \
diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build
index 8708f9b069c..1c164a548a7 100644
--- a/src/compiler/nir/meson.build
+++ b/src/compiler/nir/meson.build
@@ -158,6 +158,7 @@ files_libnir = files(
   'nir_opt_cse.c',
   'nir_opt_dce.c',
   'nir_opt_dead_cf.c',
+  'nir_opt_dead_write_vars.c',
   'nir_opt_gcm.c',
   'nir_opt_global_to_local.c',
   'nir_opt_if.c',
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
index d0fa693884b..becf6e351c3 100644
--- a/src/compiler/nir/nir.h
+++ b/src/compiler/nir/nir.h
@@ -2968,6 +2968,8 @@ bool nir_opt_dce(nir_shader *shader);
 
 bool nir_opt_dead_cf(nir_shader *shader);
 
+bool nir_opt_dead_write_vars(nir_shader *shader);
+
 bool nir_opt_gcm(nir_shader *shader, bool value_number);
 
 bool nir_opt_if(nir_shader *shader);
diff --git a/src/compiler/nir/nir_opt_dead_write_vars.c 
b/src/compiler/nir/nir_opt_dead_write_vars.c
new file mode 100644
index 000..822bfa5595d
--- /dev/null
+++ b/src/compiler/nir/nir_opt_dead_write_vars.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright © 2018 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "nir.h"
+#include "nir_builder.h"
+#include "nir_deref.h"
+
+#include "util/u_dynarray.h"
+
+struct state {
+   void *mem_ctx;
+
+   /* Maps nir_deref_instr to a corresponding nir_deref_path.  Avoids
+* rebuilding the paths for the same deref. */
+   struct hash_table *paths;
+   void *path_lin_ctx;
+};
+
+static nir_deref_path *
+get_path(struct state *state, nir_deref_instr *deref)
+{
+   struct hash_entry *entry = _mesa_hash_table_search(state->paths, deref);
+   if (!entry) {
+  nir_deref_path *path = linear_zalloc_child(state->path_lin_ctx, 
sizeof(nir_deref_path));
+  nir_deref_path_init(path, deref, state->mem_ctx);
+  _mesa_hash_table_insert(state->paths, deref, path);
+  return path;
+   } else {
+  return entry->data;
+   }
+}
+
+/* Entry for unused_writes arrays. */
+struct write_entry {
+   /* If NULL indicates the entry is free to be reused. */
+   nir_intrinsic_instr *intrin;
+   uintptr_t mask;
+   nir_deref_path *path;
+};
+
+static void
+clear_unused_for_modes(struct util_dynarray *unused_writes, nir_variable_mode 
modes)
+{
+   util_dynarray_foreach(unused_writes, struct write_entry, entry) {
+  if (!entry->intrin)
+ continue;
+  nir_variable *var = entry->path->path[0]->var;
+  if (var->data.mode & modes)
+ entry->intrin = NULL;
+   }
+}
+
+static void
+clear_unused_for_src(struct util_dynarray *unused_writes, nir_deref_path 
*src_path)
+{
+   util_dynarray_foreach(unused_writes, struct write_entry, entry) {
+  if (!entry->intrin)
+ continue;
+  if (nir_compare_deref_paths(src_path, entry->path) & 
nir_derefs_may_alias_bit)
+