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;
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_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 ||
return visit_continue;
}
- if (ls->limiting_terminator != NULL) {
- /* If the limiting terminator has an iteration count of zero, then we've
- * proven that the loop cannot run, so delete it.
- */
- int iterations = ls->limiting_terminator->iterations;
- if (iterations == 0) {
- ir->remove();
- this->progress = true;
- return visit_continue;
- }
- }
+ /* Limiting terminator may have iteration count of zero,
+ * this is a valid case because the loop may break during
+ * the first iteration.
+ */
/* Remove the conditional break statements associated with all terminators
* that are associated with a fixed iteration count, except for the one