101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2016 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2101e04c3fSmrg * DEALINGS IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg#include "nir.h"
2501e04c3fSmrg
2601e04c3fSmrgstatic void
2701e04c3fSmrgadd_src(nir_src *src, struct set *invariants)
2801e04c3fSmrg{
2901e04c3fSmrg   if (src->is_ssa) {
3001e04c3fSmrg      _mesa_set_add(invariants, src->ssa);
3101e04c3fSmrg   } else {
3201e04c3fSmrg      _mesa_set_add(invariants, src->reg.reg);
3301e04c3fSmrg   }
3401e04c3fSmrg}
3501e04c3fSmrg
3601e04c3fSmrgstatic bool
3701e04c3fSmrgadd_src_cb(nir_src *src, void *state)
3801e04c3fSmrg{
3901e04c3fSmrg   add_src(src, state);
4001e04c3fSmrg   return true;
4101e04c3fSmrg}
4201e04c3fSmrg
4301e04c3fSmrgstatic bool
4401e04c3fSmrgdest_is_invariant(nir_dest *dest, struct set *invariants)
4501e04c3fSmrg{
4601e04c3fSmrg   if (dest->is_ssa) {
4701e04c3fSmrg      return _mesa_set_search(invariants, &dest->ssa);
4801e04c3fSmrg   } else {
4901e04c3fSmrg      return _mesa_set_search(invariants, dest->reg.reg);
5001e04c3fSmrg   }
5101e04c3fSmrg}
5201e04c3fSmrg
5301e04c3fSmrgstatic void
5401e04c3fSmrgadd_cf_node(nir_cf_node *cf, struct set *invariants)
5501e04c3fSmrg{
5601e04c3fSmrg   if (cf->type == nir_cf_node_if) {
5701e04c3fSmrg      nir_if *if_stmt = nir_cf_node_as_if(cf);
5801e04c3fSmrg      add_src(&if_stmt->condition, invariants);
5901e04c3fSmrg   }
6001e04c3fSmrg
6101e04c3fSmrg   if (cf->parent)
6201e04c3fSmrg      add_cf_node(cf->parent, invariants);
6301e04c3fSmrg}
6401e04c3fSmrg
6501e04c3fSmrgstatic void
6601e04c3fSmrgadd_var(nir_variable *var, struct set *invariants)
6701e04c3fSmrg{
687e102996Smaya   /* Because we pass the result of nir_intrinsic_get_var directly to this
697e102996Smaya    * function, it's possible for var to be NULL if, for instance, there's a
707e102996Smaya    * cast somewhere in the chain.
717e102996Smaya    */
727e102996Smaya   if (var != NULL)
737e102996Smaya      _mesa_set_add(invariants, var);
7401e04c3fSmrg}
7501e04c3fSmrg
7601e04c3fSmrgstatic bool
7701e04c3fSmrgvar_is_invariant(nir_variable *var, struct set * invariants)
7801e04c3fSmrg{
797e102996Smaya   /* Because we pass the result of nir_intrinsic_get_var directly to this
807e102996Smaya    * function, it's possible for var to be NULL if, for instance, there's a
817e102996Smaya    * cast somewhere in the chain.
827e102996Smaya    */
837e102996Smaya   return var && (var->data.invariant || _mesa_set_search(invariants, var));
8401e04c3fSmrg}
8501e04c3fSmrg
8601e04c3fSmrgstatic void
8701e04c3fSmrgpropagate_invariant_instr(nir_instr *instr, struct set *invariants)
8801e04c3fSmrg{
8901e04c3fSmrg   switch (instr->type) {
9001e04c3fSmrg   case nir_instr_type_alu: {
9101e04c3fSmrg      nir_alu_instr *alu = nir_instr_as_alu(instr);
9201e04c3fSmrg      if (!dest_is_invariant(&alu->dest.dest, invariants))
9301e04c3fSmrg         break;
9401e04c3fSmrg
9501e04c3fSmrg      alu->exact = true;
9601e04c3fSmrg      nir_foreach_src(instr, add_src_cb, invariants);
9701e04c3fSmrg      break;
9801e04c3fSmrg   }
9901e04c3fSmrg
10001e04c3fSmrg   case nir_instr_type_tex: {
10101e04c3fSmrg      nir_tex_instr *tex = nir_instr_as_tex(instr);
10201e04c3fSmrg      if (dest_is_invariant(&tex->dest, invariants))
10301e04c3fSmrg         nir_foreach_src(instr, add_src_cb, invariants);
10401e04c3fSmrg      break;
10501e04c3fSmrg   }
10601e04c3fSmrg
10701e04c3fSmrg   case nir_instr_type_intrinsic: {
10801e04c3fSmrg      nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
10901e04c3fSmrg      switch (intrin->intrinsic) {
11001e04c3fSmrg      case nir_intrinsic_copy_deref:
11101e04c3fSmrg         /* If the destination is invariant then so is the source */
11201e04c3fSmrg         if (var_is_invariant(nir_intrinsic_get_var(intrin, 0), invariants))
11301e04c3fSmrg            add_var(nir_intrinsic_get_var(intrin, 1), invariants);
11401e04c3fSmrg         break;
11501e04c3fSmrg
11601e04c3fSmrg      case nir_intrinsic_load_deref:
11701e04c3fSmrg         if (dest_is_invariant(&intrin->dest, invariants))
11801e04c3fSmrg            add_var(nir_intrinsic_get_var(intrin, 0), invariants);
11901e04c3fSmrg         break;
12001e04c3fSmrg
12101e04c3fSmrg      case nir_intrinsic_store_deref:
12201e04c3fSmrg         if (var_is_invariant(nir_intrinsic_get_var(intrin, 0), invariants))
12301e04c3fSmrg            add_src(&intrin->src[1], invariants);
12401e04c3fSmrg         break;
12501e04c3fSmrg
12601e04c3fSmrg      default:
12701e04c3fSmrg         /* Nothing to do */
12801e04c3fSmrg         break;
12901e04c3fSmrg      }
1307ec681f3Smrg      FALLTHROUGH;
13101e04c3fSmrg   }
13201e04c3fSmrg
13301e04c3fSmrg   case nir_instr_type_deref:
13401e04c3fSmrg   case nir_instr_type_jump:
13501e04c3fSmrg   case nir_instr_type_ssa_undef:
13601e04c3fSmrg   case nir_instr_type_load_const:
13701e04c3fSmrg      break; /* Nothing to do */
13801e04c3fSmrg
13901e04c3fSmrg   case nir_instr_type_phi: {
14001e04c3fSmrg      nir_phi_instr *phi = nir_instr_as_phi(instr);
14101e04c3fSmrg      if (!dest_is_invariant(&phi->dest, invariants))
14201e04c3fSmrg         break;
14301e04c3fSmrg
14401e04c3fSmrg      nir_foreach_phi_src(src, phi) {
14501e04c3fSmrg         add_src(&src->src, invariants);
14601e04c3fSmrg         add_cf_node(&src->pred->cf_node, invariants);
14701e04c3fSmrg      }
14801e04c3fSmrg      break;
14901e04c3fSmrg   }
15001e04c3fSmrg
15101e04c3fSmrg   case nir_instr_type_call:
15201e04c3fSmrg      unreachable("This pass must be run after function inlining");
15301e04c3fSmrg
15401e04c3fSmrg   case nir_instr_type_parallel_copy:
15501e04c3fSmrg   default:
15601e04c3fSmrg      unreachable("Cannot have this instruction type");
15701e04c3fSmrg   }
15801e04c3fSmrg}
15901e04c3fSmrg
16001e04c3fSmrgstatic bool
16101e04c3fSmrgpropagate_invariant_impl(nir_function_impl *impl, struct set *invariants)
16201e04c3fSmrg{
16301e04c3fSmrg   bool progress = false;
16401e04c3fSmrg
16501e04c3fSmrg   while (true) {
16601e04c3fSmrg      uint32_t prev_entries = invariants->entries;
16701e04c3fSmrg
16801e04c3fSmrg      nir_foreach_block_reverse(block, impl) {
16901e04c3fSmrg         nir_foreach_instr_reverse(instr, block)
17001e04c3fSmrg            propagate_invariant_instr(instr, invariants);
17101e04c3fSmrg      }
17201e04c3fSmrg
17301e04c3fSmrg      /* Keep running until we make no more progress. */
17401e04c3fSmrg      if (invariants->entries > prev_entries) {
17501e04c3fSmrg         progress = true;
17601e04c3fSmrg         continue;
17701e04c3fSmrg      } else {
17801e04c3fSmrg         break;
17901e04c3fSmrg      }
18001e04c3fSmrg   }
18101e04c3fSmrg
18201e04c3fSmrg   if (progress) {
18301e04c3fSmrg      nir_metadata_preserve(impl, nir_metadata_block_index |
18401e04c3fSmrg                                  nir_metadata_dominance |
18501e04c3fSmrg                                  nir_metadata_live_ssa_defs);
1867ec681f3Smrg   } else {
1877ec681f3Smrg      nir_metadata_preserve(impl, nir_metadata_all);
18801e04c3fSmrg   }
18901e04c3fSmrg
19001e04c3fSmrg   return progress;
19101e04c3fSmrg}
19201e04c3fSmrg
1937ec681f3Smrg/* If invariant_prim=true, this pass considers all geometry-affecting
1947ec681f3Smrg * outputs as invariant. Doing this works around a common class of application
1957ec681f3Smrg * bugs appearing as flickering.
1967ec681f3Smrg */
19701e04c3fSmrgbool
1987ec681f3Smrgnir_propagate_invariant(nir_shader *shader, bool invariant_prim)
19901e04c3fSmrg{
20001e04c3fSmrg   /* Hash set of invariant things */
2017e102996Smaya   struct set *invariants = _mesa_pointer_set_create(NULL);
20201e04c3fSmrg
2037ec681f3Smrg   if (shader->info.stage != MESA_SHADER_FRAGMENT && invariant_prim) {
2047ec681f3Smrg      nir_foreach_shader_out_variable(var, shader) {
2057ec681f3Smrg         switch (var->data.location) {
2067ec681f3Smrg         case VARYING_SLOT_POS:
2077ec681f3Smrg         case VARYING_SLOT_PSIZ:
2087ec681f3Smrg         case VARYING_SLOT_CLIP_DIST0:
2097ec681f3Smrg         case VARYING_SLOT_CLIP_DIST1:
2107ec681f3Smrg         case VARYING_SLOT_CULL_DIST0:
2117ec681f3Smrg         case VARYING_SLOT_CULL_DIST1:
2127ec681f3Smrg         case VARYING_SLOT_TESS_LEVEL_OUTER:
2137ec681f3Smrg         case VARYING_SLOT_TESS_LEVEL_INNER:
2147ec681f3Smrg            if (!var->data.invariant)
2157ec681f3Smrg               _mesa_set_add(invariants, var);
2167ec681f3Smrg            break;
2177ec681f3Smrg         default:
2187ec681f3Smrg            break;
2197ec681f3Smrg         }
2207ec681f3Smrg      }
2217ec681f3Smrg   }
2227ec681f3Smrg
22301e04c3fSmrg   bool progress = false;
22401e04c3fSmrg   nir_foreach_function(function, shader) {
22501e04c3fSmrg      if (function->impl && propagate_invariant_impl(function->impl, invariants))
22601e04c3fSmrg         progress = true;
22701e04c3fSmrg   }
22801e04c3fSmrg
22901e04c3fSmrg   _mesa_set_destroy(invariants, NULL);
23001e04c3fSmrg
23101e04c3fSmrg   return progress;
23201e04c3fSmrg}
233