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;
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 =
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
}
ralloc_free(mem_ctx);
+
+ if (inc_before_terminator) {
+ iter_value--;
+ }
+
return (valid_loop) ? iter_value : -1;
}
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;
}
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;
}
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 ||