X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fglsl%2Floop_analysis.cpp;h=9429e69c2a7fe4c7176bf60164bcb7e311336425;hb=685e79a64bbd6ead6f21b21ec47f55e06a8ce624;hp=0fb6e9feb743dda471603af491555c7a13926ce6;hpb=6403efbe7458d05cf117adb41c8a152ed6e28bdd;p=mesa.git diff --git a/src/compiler/glsl/loop_analysis.cpp b/src/compiler/glsl/loop_analysis.cpp index 0fb6e9feb74..9429e69c2a7 100644 --- a/src/compiler/glsl/loop_analysis.cpp +++ b/src/compiler/glsl/loop_analysis.cpp @@ -88,7 +88,7 @@ find_initial_value(ir_loop *loop, ir_variable *var) static int calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, enum ir_expression_operation op, bool continue_from_then, - bool swap_compare_operands) + bool swap_compare_operands, bool inc_before_terminator) { if (from == NULL || to == NULL || increment == NULL) return -1; @@ -107,7 +107,7 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, return -1; } - if (!iter->type->is_integer()) { + if (!iter->type->is_integer_32()) { const ir_expression_operation op = iter->type->is_double() ? ir_unop_d2i : ir_unop_f2i; ir_rvalue *cast = @@ -118,6 +118,32 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, int iter_value = iter->get_int_component(0); + /* Code after this block works under assumption that iterator will be + * incremented or decremented until it hits the limit, + * however the loop condition can be false on the first iteration. + * Handle such loops first. + */ + { + ir_rvalue *first_value = from; + if (inc_before_terminator) { + first_value = + new(mem_ctx) ir_expression(ir_binop_add, from->type, from, increment); + } + + ir_expression *cmp = swap_compare_operands + ? new(mem_ctx) ir_expression(op, glsl_type::bool_type, to, first_value) + : new(mem_ctx) ir_expression(op, glsl_type::bool_type, first_value, to); + if (continue_from_then) + cmp = new(mem_ctx) ir_expression(ir_unop_logic_not, cmp); + + ir_constant *const cmp_result = cmp->constant_expression_value(mem_ctx); + assert(cmp_result != NULL); + if (cmp_result->get_bool_component(0)) { + ralloc_free(mem_ctx); + return 0; + } + } + /* Make sure that the calculated number of iterations satisfies the exit * condition. This is needed to catch off-by-one errors and some types of * ill-formed loops. For example, we need to detect that the following @@ -172,6 +198,11 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, } ralloc_free(mem_ctx); + + if (inc_before_terminator) { + iter_value--; + } + return (valid_loop) ? iter_value : -1; } @@ -252,8 +283,7 @@ loop_variable::record_reference(bool in_assignee, loop_state::loop_state() { - this->ht = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); + this->ht = _mesa_pointer_hash_table_create(NULL); this->mem_ctx = ralloc_context(NULL); this->loop_found = false; } @@ -289,6 +319,9 @@ loop_state::get(const ir_loop *ir) loop_variable * loop_variable_state::get(const ir_variable *ir) { + if (ir == NULL) + return NULL; + hash_entry *entry = _mesa_hash_table_search(this->var_hash, ir); return entry ? (loop_variable *) entry->data : NULL; } @@ -609,13 +642,13 @@ loop_analysis::visit_leave(ir_loop *ir) loop_variable *lv = ls->get(var); if (lv != NULL && lv->is_induction_var()) { + bool inc_before_terminator = + incremented_before_terminator(ir, var, t->ir); + t->iterations = calculate_iterations(init, limit, lv->increment, cmp, t->continue_from_then, - swap_compare_operands); - - if (incremented_before_terminator(ir, var, t->ir)) { - t->iterations--; - } + swap_compare_operands, + inc_before_terminator); if (t->iterations >= 0 && (ls->limiting_terminator == NULL ||