[Mesa-dev] [PATCH v4 2/7] nir: propagates if condition evaluation down some alu chains

Jason Ekstrand jason at jlekstrand.net
Tue Aug 28 16:05:31 UTC 2018


On Mon, Aug 27, 2018 at 4:09 AM Timothy Arceri <tarceri at itsqueeze.com>
wrote:

> v2:
>  - only allow nir_op_inot or nir_op_b2i when alu input is 1.
>  - use some helpers as suggested by Jason.
>
> shader-db IVB results:
>
> total instructions in shared programs: 9993483 -> 9993472 (-0.00%)
> instructions in affected programs: 1300 -> 1289 (-0.85%)
> helped: 11
> HURT: 0
>
> total cycles in shared programs: 219476091 -> 219476059 (-0.00%)
> cycles in affected programs: 7675 -> 7643 (-0.42%)
> helped: 10
> HURT: 1
> ---
>  src/compiler/nir/nir_opt_if.c | 135 ++++++++++++++++++++++++++++++++--
>  1 file changed, 129 insertions(+), 6 deletions(-)
>
> diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c
> index 11c6693d302..6d81705f6b7 100644
> --- a/src/compiler/nir/nir_opt_if.c
> +++ b/src/compiler/nir/nir_opt_if.c
> @@ -403,9 +403,113 @@ evaluate_if_condition(nir_if *nif, nir_cursor
> cursor, uint32_t *value)
>     }
>  }
>
> +/*
> + * This propagates if condition evaluation down the chain of some alu
> + * instructions. For example by checking the use of some of the following
> alu
> + * instruction we can eventually replace ssa_107 with NIR_TRUE.
> + *
> + *   loop {
> + *      block block_1:
> + *      vec1 32 ssa_85 = load_const (0x00000002)
> + *      vec1 32 ssa_86 = ieq ssa_48, ssa_85
> + *      vec1 32 ssa_87 = load_const (0x00000001)
> + *      vec1 32 ssa_88 = ieq ssa_48, ssa_87
> + *      vec1 32 ssa_89 = ior ssa_86, ssa_88
> + *      vec1 32 ssa_90 = ieq ssa_48, ssa_0
> + *      vec1 32 ssa_91 = ior ssa_89, ssa_90
> + *      if ssa_86 {
> + *         block block_2:
> + *             ...
> + *            break
> + *      } else {
> + *            block block_3:
> + *      }
> + *      block block_4:
> + *      if ssa_88 {
> + *            block block_5:
> + *             ...
> + *            break
> + *      } else {
> + *            block block_6:
> + *      }
> + *      block block_7:
> + *      if ssa_90 {
> + *            block block_8:
> + *             ...
> + *            break
> + *      } else {
> + *            block block_9:
> + *      }
> + *      block block_10:
> + *      vec1 32 ssa_107 = inot ssa_91
> + *      if ssa_107 {
> + *            block block_11:
> + *            break
> + *      } else {
> + *            block block_12:
> + *      }
> + *   }
> + */
>  static bool
> -evaluate_condition_use(nir_if *nif, nir_src *use_src, void *mem_ctx,
> -                       bool is_if_condition)
> +propagate_condition_eval(nir_builder *b, nir_if *nif, nir_src *use_src,
> +                         nir_src *alu_use, nir_alu_instr *alu, void
> *mem_ctx,
> +                         bool is_if_condition)
> +{
> +   bool progress = false;
> +
> +   uint32_t bool_value;
> +   nir_cursor cursor = nir_before_src(alu_use, is_if_condition);
> +   if (nir_op_infos[alu->op].num_inputs == 1) {
>

Howa about just

if (alu->op == nir_op_inot || alu->op == nir_op_b2i) {
   if (evaluate_if_condition()) {
      replace_if_condition_with_const();
      return true;
   }
} else if (alu->op == alu_op_ior || alu_op_iand) {
   if (evaluate_if_condition()) {
      // stuff
      return true;
   }
}

return false;

Or, for that matter, it could be a switch statement.  My point is that
checking the number of sources and then checking the number of inputs seems
kind-of pointless.


> +      if ((alu->op == nir_op_inot || alu->op == nir_op_b2i) &&
> +          evaluate_if_condition(nif, cursor, &bool_value)) {
> +         replace_if_condition_use_with_const(alu_use, mem_ctx, cursor,
> +                                             bool_value, is_if_condition);
>

This isn't correct.  We need to run nir_eval_const_opcode on it before
replacing the ALU destination with it.


> +         progress = true;
> +      }
> +   } else {
> +      assert(alu->op == nir_op_ior || alu->op == nir_op_iand);
> +
> +      if (evaluate_if_condition(nif, cursor, &bool_value)) {
> +         nir_ssa_def *def[2];
> +         for (unsigned i = 0; i < 2; i++) {
> +            if (alu->src[i].src.ssa == use_src->ssa) {
> +               if (is_if_condition) {
> +                  b->cursor =
> +                     nir_before_cf_node(&alu_use->parent_if->cf_node);
> +               } else {
> +                  b->cursor = nir_before_instr(alu_use->parent_instr);
> +               }
>

This should be nir_before_src


> +
> +               nir_const_value const_value;
> +               const_value.u32[0] = bool_value;
> +
> +               def[i] = nir_build_imm(b, 1, 32, const_value);
> +            } else {
> +               def[i] = alu->src[i].src.ssa;
> +            }
> +         }
> +
> +         nir_ssa_def *nalu =
> +            nir_build_alu(b, alu->op, def[0], def[1], NULL, NULL);
> +
> +         /* Rewrite use to use new alu instruction */
> +         nir_src new_src = nir_src_for_ssa(nalu);
> +
> +         if (is_if_condition)
> +            nir_if_rewrite_condition(alu_use->parent_if, new_src);
> +         else
> +            nir_instr_rewrite_src(alu_use->parent_instr, alu_use,
> new_src);
> +
> +         progress = true;
> +      }
> +   }
> +
> +   return progress;
> +}
> +
> +static bool
> +evaluate_condition_use(nir_builder *b, nir_if *nif, nir_src *use_src,
> +                       void *mem_ctx, bool is_if_condition)
>  {
>     bool progress = false;
>
> @@ -417,23 +521,42 @@ evaluate_condition_use(nir_if *nif, nir_src
> *use_src, void *mem_ctx,
>        progress = true;
>     }
>
> +   if (!is_if_condition &&
> +       use_src->parent_instr->type == nir_instr_type_alu &&
> +       (nir_instr_as_alu(use_src->parent_instr)->op == nir_op_ior ||
> +        nir_instr_as_alu(use_src->parent_instr)->op == nir_op_iand ||
> +
> nir_op_infos[nir_instr_as_alu(use_src->parent_instr)->op].num_inputs == 1))
> {
>

So we're checking for exact opcodes for binops  here but leaving the check
for unops to the function we call?  Let's pick one.  How about having a
little can_propagate_through_alu helper and call that here?


> +
> +         nir_alu_instr *alu = nir_instr_as_alu(use_src->parent_instr);
> +
> +         nir_foreach_use_safe(alu_use, &alu->dest.dest.ssa) {
> +            progress |= propagate_condition_eval(b, nif, use_src,
> alu_use, alu,
> +                                                 mem_ctx, false);
> +         }
> +
> +         nir_foreach_if_use_safe(alu_use, &alu->dest.dest.ssa) {
> +            progress |= propagate_condition_eval(b, nif, use_src,
> alu_use, alu,
> +                                                 mem_ctx, true);
> +         }
> +   }
> +
>     return progress;
>  }
>
>  static bool
> -opt_if_evaluate_condition_use(nir_if *nif, void *mem_ctx)
> +opt_if_evaluate_condition_use(nir_builder *b, nir_if *nif, void *mem_ctx)
>  {
>     bool progress = false;
>
>     /* Evaluate any uses of the if condition inside the if branches */
>     assert(nif->condition.is_ssa);
>     nir_foreach_use_safe(use_src, nif->condition.ssa) {
> -      progress |= evaluate_condition_use(nif, use_src, mem_ctx, false);
> +      progress |= evaluate_condition_use(b, nif, use_src, mem_ctx, false);
>     }
>
>     nir_foreach_if_use_safe(use_src, nif->condition.ssa) {
>        if (use_src->parent_if != nif)
> -         progress |= evaluate_condition_use(nif, use_src, mem_ctx, true);
> +         progress |= evaluate_condition_use(b, nif, use_src, mem_ctx,
> true);
>     }
>
>     return progress;
> @@ -489,7 +612,7 @@ opt_if_safe_cf_list(nir_builder *b, struct exec_list
> *cf_list, void *mem_ctx)
>           nir_if *nif = nir_cf_node_as_if(cf_node);
>           progress |= opt_if_safe_cf_list(b, &nif->then_list, mem_ctx);
>           progress |= opt_if_safe_cf_list(b, &nif->else_list, mem_ctx);
> -         progress |= opt_if_evaluate_condition_use(nif, mem_ctx);
> +         progress |= opt_if_evaluate_condition_use(b, nif, mem_ctx);
>           break;
>        }
>
> --
> 2.17.1
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20180828/edf10baf/attachment.html>


More information about the mesa-dev mailing list