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 | 155 ++++++++++++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 6 deletions(-) diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c index b3d5046a76e..c9e50cec1fe 100644 --- a/src/compiler/nir/nir_opt_if.c +++ b/src/compiler/nir/nir_opt_if.c @@ -404,9 +404,134 @@ replace_if_condition_use_with_const(nir_src *use, unsigned nir_boolean, nir_instr_rewrite_src(use->parent_instr, use, new_src); } +/* + * 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 +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 if_condition) +{ + bool progress = false; + + nir_block *use_block; + if (if_condition) { + use_block = + nir_cf_node_as_block(nir_cf_node_prev(&alu_use->parent_if->cf_node)); + } else { + use_block = alu_use->parent_instr->block; + } + + if (nir_op_infos[alu->op].num_inputs == 1) { + if (nir_block_dominates(nir_if_first_then_block(nif), use_block)) { + replace_if_condition_use_with_const(alu_use, NIR_TRUE, mem_ctx, + if_condition); + progress = true; + } else if (nir_block_dominates(nir_if_first_else_block(nif), + use_block)) { + replace_if_condition_use_with_const(alu_use, NIR_FALSE, mem_ctx, + if_condition); + progress = true; + } + } else { + assert(alu->op == nir_op_ior || alu->op == nir_op_iand); + + bool found = false; + unsigned nir_boolean = 0; + if (nir_block_dominates(nir_if_first_then_block(nif), use_block)) { + nir_boolean = NIR_TRUE; + found = true; + } else if (nir_block_dominates(nir_if_first_else_block(nif), + use_block)) { + nir_boolean = NIR_FALSE; + found = true; + } + + if (found) { + nir_ssa_def *def[2]; + for (unsigned i = 0; i < 2; i++) { + if (alu->src[i].src.ssa == use_src->ssa) { + if (if_condition) { + b->cursor = + nir_before_cf_node(&alu_use->parent_if->cf_node); + } else { + b->cursor = nir_before_instr(alu_use->parent_instr); + } + + nir_const_value value; + value.u32[0] = nir_boolean; + + def[i] = nir_build_imm(b, 1, 32, 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 (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_if *nif, nir_src *use_src, void *mem_ctx, - bool if_condition) +evaluate_condition_use(nir_builder *b, nir_if *nif, nir_src *use_src, + void *mem_ctx, bool if_condition) { bool progress = false; @@ -428,23 +553,41 @@ evaluate_condition_use(nir_if *nif, nir_src *use_src, void *mem_ctx, progress = true; } + if (!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)) { + + 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; @@ -500,7 +643,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@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev