aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compiler/glsl/loop_analysis.cpp43
-rw-r--r--src/compiler/glsl/loop_unroll.cpp15
2 files changed, 41 insertions, 17 deletions
diff --git a/src/compiler/glsl/loop_analysis.cpp b/src/compiler/glsl/loop_analysis.cpp
index aae8fc62cd0..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;
@@ -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;
}
@@ -611,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 ||
diff --git a/src/compiler/glsl/loop_unroll.cpp b/src/compiler/glsl/loop_unroll.cpp
index 7e97c3cddf1..1a9229acc34 100644
--- a/src/compiler/glsl/loop_unroll.cpp
+++ b/src/compiler/glsl/loop_unroll.cpp
@@ -390,17 +390,10 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
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