Mesa (shader-work): glsl: teach loop analysis that array dereferences are bounds on the index
Luca Barbieri
lb at kemper.freedesktop.org
Tue Sep 7 18:16:59 UTC 2010
Module: Mesa
Branch: shader-work
Commit: 2ecf7b5cd5067d80cb6ce74d55b2ed93c974d8dc
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=2ecf7b5cd5067d80cb6ce74d55b2ed93c974d8dc
Author: Luca Barbieri <luca at luca-barbieri.com>
Date: Tue Sep 7 19:29:00 2010 +0200
glsl: teach loop analysis that array dereferences are bounds on the index
Since out-of-bounds dereferences cause undefined behavior, we are allowed
to assume that they terminate the loop.
This allows to find the maximum number of iterations in cases like this:
uniform int texcoords;
float4 gl_TexCoord[8];
for(i = 0; i < texcoords; ++i)
do_something_with(gl_TexCoord[i]);
This is apparently an interesting case since NV_fragment_program2 has
a construct for this.
---
src/glsl/loop_analysis.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++
src/glsl/loop_controls.cpp | 29 ++++++++++++++++--------
2 files changed, 70 insertions(+), 10 deletions(-)
diff --git a/src/glsl/loop_analysis.cpp b/src/glsl/loop_analysis.cpp
index 32e8b8c..87ed7b7 100644
--- a/src/glsl/loop_analysis.cpp
+++ b/src/glsl/loop_analysis.cpp
@@ -105,6 +105,7 @@ public:
virtual ir_visitor_status visit(ir_loop_jump *);
virtual ir_visitor_status visit(ir_dereference_variable *);
+ virtual ir_visitor_status visit_leave(ir_dereference_array *);
virtual ir_visitor_status visit_enter(ir_loop *);
virtual ir_visitor_status visit_leave(ir_loop *);
@@ -164,6 +165,7 @@ loop_analysis::visit(ir_dereference_variable *ir)
if (lv == NULL) {
lv = ls->insert(var);
+ /* FINISHME XXX: seems wrong, what if this is gl_TexCoord[i] =, and this is the deref of i ? */
lv->read_before_write = !this->in_assignee;
}
@@ -191,6 +193,55 @@ loop_analysis::visit(ir_dereference_variable *ir)
}
ir_visitor_status
+loop_analysis::visit_leave(ir_dereference_array *ir)
+{
+ /* If we're not somewhere inside a loop, there's nothing to do.
+ */
+ if (this->state.is_empty())
+ return visit_continue_with_parent;
+
+ loop_variable_state *const ls =
+ (loop_variable_state *) this->state.get_head();
+
+ int max_index;
+ if(ir->array->type->is_array())
+ max_index = ir->array->type->length - 1;
+ else if(ir->array->type->is_vector() || ir->array->type->is_matrix())
+ max_index = ir->array->type->components() - 1;
+ else
+ assert(0);
+
+ ir_constant* max_index_c;
+ ir_constant* zero_c;
+ switch(ir->array_index->type->base_type)
+ {
+ case GLSL_TYPE_INT:
+ max_index_c = new(ir) ir_constant((int)max_index);
+ zero_c = new(ir) ir_constant((int)0);
+ break;
+ case GLSL_TYPE_UINT:
+ max_index_c = new(ir) ir_constant((unsigned)max_index);
+ zero_c = new(ir) ir_constant((unsigned)0);
+ break;
+ default:
+ assert(0);
+ }
+
+ ir_if* bound_if;
+
+ bound_if = new (ir) ir_if(new(ir) ir_expression(ir_binop_greater, ir->array_index->type, ir->array_index, max_index_c));
+ bound_if->self_link();
+ ls->insert(bound_if);
+
+ bound_if = new (ir) ir_if(new(ir) ir_expression(ir_binop_less, ir->array_index->type, ir->array_index, zero_c));
+ bound_if->self_link();
+ ls->insert(bound_if);
+
+ return visit_continue;
+}
+
+
+ir_visitor_status
loop_analysis::visit_enter(ir_loop *ir)
{
loop_variable_state *ls = this->loops->insert(ir);
diff --git a/src/glsl/loop_controls.cpp b/src/glsl/loop_controls.cpp
index 9619d8a..e6e8a5b 100644
--- a/src/glsl/loop_controls.cpp
+++ b/src/glsl/loop_controls.cpp
@@ -253,18 +253,27 @@ loop_control_visitor::visit_leave(ir_loop *ir)
ir->cmp = cmp;
max_iterations = iterations;
- }
-
- /* Remove the conditional break statement. The loop
- * controls are now set such that the exit condition will be
- * satisfied.
- */
- if_stmt->remove();
- assert(ls->num_loop_jumps > 0);
- ls->num_loop_jumps--;
+ this->progress = true;
+ }
- this->progress = true;
+ if(if_stmt->next == if_stmt->prev && if_stmt->next == if_stmt)
+ {
+ /* this is a fake if with self_link() inserted to represent array bounds: ignore it */
+ }
+ else
+ {
+ /* Remove the conditional break statement. The loop
+ * controls are now set such that the exit condition will be
+ * satisfied.
+ */
+ if_stmt->remove();
+
+ assert(ls->num_loop_jumps > 0);
+ ls->num_loop_jumps--;
+
+ this->progress = true;
+ }
}
break;
More information about the mesa-commit
mailing list