From 68ce0ec22244726c1b61d91936a6b79ac20ab77a Mon Sep 17 00:00:00 2001 From: Timothy Arceri Date: Tue, 20 Nov 2018 13:45:58 +1100 Subject: [PATCH] nir: calculate trip count for more loops This adds support to loop analysis for loops where the induction variable is compared to the result of min(variable, constant). For example: for (int i = 0; i < imin(x, 4); i++) ... We add a new bool to the loop terminator struct in order to differentiate terminators with this exit condition. Reviewed-by: Ian Romanick --- src/compiler/nir/nir.h | 11 +++++++ src/compiler/nir/nir_loop_analyze.c | 41 ++++++++++++++++++++++---- src/compiler/nir/nir_opt_loop_unroll.c | 3 +- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index aac9ac448b8..19e69c50f8f 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -1912,6 +1912,17 @@ typedef struct { bool continue_from_then; bool induction_rhs; + /* This is true if the terminators exact trip count is unknown. For + * example: + * + * for (int i = 0; i < imin(x, 4); i++) + * ... + * + * Here loop analysis would have set a max_trip_count of 4 however we dont + * know for sure that this is the exact trip count. + */ + bool exact_trip_count_unknown; + struct list_head loop_terminator_link; } nir_loop_terminator; diff --git a/src/compiler/nir/nir_loop_analyze.c b/src/compiler/nir/nir_loop_analyze.c index 9cff670051e..4c8028a666f 100644 --- a/src/compiler/nir/nir_loop_analyze.c +++ b/src/compiler/nir/nir_loop_analyze.c @@ -539,6 +539,35 @@ guess_loop_limit(loop_info_state *state, nir_const_value *limit_val, return false; } +static bool +try_find_limit_of_alu(nir_loop_variable *limit, nir_const_value *limit_val, + nir_loop_terminator *terminator, loop_info_state *state) +{ + if(!is_var_alu(limit)) + return false; + + nir_alu_instr *limit_alu = nir_instr_as_alu(limit->def->parent_instr); + + if (limit_alu->op == nir_op_imin || + limit_alu->op == nir_op_fmin) { + limit = get_loop_var(limit_alu->src[0].src.ssa, state); + + if (!is_var_constant(limit)) + limit = get_loop_var(limit_alu->src[1].src.ssa, state); + + if (!is_var_constant(limit)) + return false; + + *limit_val = nir_instr_as_load_const(limit->def->parent_instr)->value; + + terminator->exact_trip_count_unknown = true; + + return true; + } + + return false; +} + static int32_t get_iteration(nir_op cond_op, nir_const_value *initial, nir_const_value *step, nir_const_value *limit) @@ -770,12 +799,14 @@ find_trip_count(loop_info_state *state) } else { trip_count_known = false; - /* Guess loop limit based on array access */ - if (!guess_loop_limit(state, &limit_val, basic_ind)) { - continue; - } + if (!try_find_limit_of_alu(limit, &limit_val, terminator, state)) { + /* Guess loop limit based on array access */ + if (!guess_loop_limit(state, &limit_val, basic_ind)) { + continue; + } - guessed_trip_count = true; + guessed_trip_count = true; + } } /* We have determined that we have the following constants: diff --git a/src/compiler/nir/nir_opt_loop_unroll.c b/src/compiler/nir/nir_opt_loop_unroll.c index c700e6704da..a5a5ca3deee 100644 --- a/src/compiler/nir/nir_opt_loop_unroll.c +++ b/src/compiler/nir/nir_opt_loop_unroll.c @@ -827,7 +827,8 @@ process_loops(nir_shader *sh, nir_cf_node *cf_node, bool *has_nested_loop_out) } else { /* Attempt to unroll loops with two terminators. */ unsigned num_lt = list_length(&loop->info->loop_terminator_list); - if (num_lt == 2) { + if (num_lt == 2 && + !loop->info->limiting_terminator->exact_trip_count_unknown) { bool limiting_term_second = true; nir_loop_terminator *terminator = list_first_entry(&loop->info->loop_terminator_list, -- 2.30.2