[Mesa-dev] [PATCH v3] nir: propagates if condition evaluation down some alu chains
Timothy Arceri
tarceri at itsqueeze.com
Thu Aug 30 02:46:40 UTC 2018
On 30/08/18 11:05, Ian Romanick wrote:
> I feel like this would be a good candidate for some unit tests.
>
> As a follow up, you might also consider adding bcsel. I have seen quite
> a few cases of bcsel(bool, bool, bool).
Ah yes that is probably a good one to try. I'll give it a go.
>
> On 08/29/2018 04:48 PM, Timothy Arceri wrote:
>> v2:
>> - only allow nir_op_inot or nir_op_b2i when alu input is 1.
>> - use some helpers as suggested by Jason.
>>
>> v3:
>> - evaluate alu op for single input alu ops
>> - add helper function to decide if to propagate through alu
>> - make use of nir_before_src in another spot
>>
>> 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 | 145 ++++++++++++++++++++++++++++++++--
>> 1 file changed, 139 insertions(+), 6 deletions(-)
>>
>> diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c
>> index 11c6693d302..9e9d8edda21 100644
>> --- a/src/compiler/nir/nir_opt_if.c
>> +++ b/src/compiler/nir/nir_opt_if.c
>> @@ -23,6 +23,7 @@
>>
>> #include "nir.h"
>> #include "nir/nir_builder.h"
>> +#include "nir_constant_expressions.h"
>> #include "nir_control_flow.h"
>> #include "nir_loop_analyze.h"
>>
>> @@ -403,9 +404,127 @@ 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;
>> + b->cursor = nir_before_src(alu_use, is_if_condition);
>> + if (nir_op_infos[alu->op].num_inputs == 1) {
>> + assert(alu->op == nir_op_inot || alu->op == nir_op_b2i);
>> +
>> + if (evaluate_if_condition(nif, b->cursor, &bool_value)) {
>> + nir_const_value bool_src;
>> + bool_src.u32[0] = bool_value;
>> +
>> + unsigned bit_size = nir_src_bit_size(alu->src[0].src);
>> + nir_const_value result =
>> + nir_eval_const_opcode(alu->op, 1, bit_size, &bool_src);
>> +
>> + replace_if_condition_use_with_const(alu_use, mem_ctx, b->cursor,
>> + result.u32[0], is_if_condition);
>> + progress = true;
>> + }
>> + } else {
>> + assert(alu->op == nir_op_ior || alu->op == nir_op_iand);
>> +
>> + if (evaluate_if_condition(nif, b->cursor, &bool_value)) {
>> + nir_ssa_def *def[2];
>> + for (unsigned i = 0; i < 2; i++) {
>> + if (alu->src[i].src.ssa == use_src->ssa) {
>> + 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
>> +can_propagate_through_alu(nir_src *src)
>> +{
>> + if (src->parent_instr->type == nir_instr_type_alu &&
>> + (nir_instr_as_alu(src->parent_instr)->op == nir_op_ior ||
>> + nir_instr_as_alu(src->parent_instr)->op == nir_op_iand ||
>> + nir_instr_as_alu(src->parent_instr)->op == nir_op_inot ||
>> + nir_instr_as_alu(src->parent_instr)->op == nir_op_b2i))
>> + return true;
>> +
>> + return false;
>> +}
>> +
>> +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 +536,37 @@ evaluate_condition_use(nir_if *nif, nir_src *use_src, void *mem_ctx,
>> progress = true;
>> }
>>
>> + if (!is_if_condition && can_propagate_through_alu(use_src)) {
>> + 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 +622,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;
>> }
>>
>>
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
More information about the mesa-dev
mailing list