summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ast_to_hir.cpp42
-rw-r--r--ir.cpp2
-rw-r--r--ir.h8
3 files changed, 43 insertions, 9 deletions
diff --git a/ast_to_hir.cpp b/ast_to_hir.cpp
index ff9cbb09d9..ca3c869dd8 100644
--- a/ast_to_hir.cpp
+++ b/ast_to_hir.cpp
@@ -898,13 +898,29 @@ ast_expression::hir(exec_list *instructions,
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
- result = new ir_dereference(op[0], op[1]);
+ ir_dereference *const lhs = op[0]->as_dereference();
+ ir_instruction *array;
+ if ((lhs != NULL)
+ && (lhs->mode == ir_dereference::ir_reference_variable)) {
+ result = new ir_dereference(lhs->var, op[1]);
+
+ delete op[0];
+ array = lhs->var;
+ } else {
+ result = new ir_dereference(op[0], op[1]);
+ array = op[0];
+ }
+
+ /* Do not use op[0] after this point. Use array.
+ */
+ op[0] = NULL;
+
if (error_emitted)
break;
/* FINISHME: Handle vectors and matrices accessed with []. */
- if (!op[0]->type->is_array()) {
+ if (!array->type->is_array()) {
_mesa_glsl_error(& index_loc, state,
"cannot dereference non-array");
error_emitted = true;
@@ -937,11 +953,11 @@ ast_expression::hir(exec_list *instructions,
* declared size. It is also illegal to index an array with a
* negative constant expression."
*/
- if ((op[0]->type->array_size() > 0)
- && (op[0]->type->array_size() <= idx)) {
+ if ((array->type->array_size() > 0)
+ && (array->type->array_size() <= idx)) {
_mesa_glsl_error(& loc, state,
"array index must be < %u",
- op[0]->type->array_size());
+ array->type->array_size());
error_emitted = true;
}
@@ -950,6 +966,10 @@ ast_expression::hir(exec_list *instructions,
"array index must be >= 0");
error_emitted = true;
}
+
+ ir_variable *const v = array->as_variable();
+ if ((v != NULL) && (unsigned(idx) > v->max_array_access))
+ v->max_array_access = idx;
}
if (error_emitted)
@@ -1265,9 +1285,15 @@ ast_declarator_list::hir(exec_list *instructions,
* FINISHME: declarations. It's not 100% clear whether this is
* FINISHME: required or not.
*/
- /* FINISHME: Check that the array hasn't already been accessed
- * FINISHME: beyond the newly defined bounds.
- */
+
+ if (var->type->array_size() <= earlier->max_array_access) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state, "array size must be > %u due to "
+ "previous access",
+ earlier->max_array_access);
+ }
+
earlier->type = var->type;
delete var;
var = NULL;
diff --git a/ir.cpp b/ir.cpp
index 60f34ca9be..3939e5a7b5 100644
--- a/ir.cpp
+++ b/ir.cpp
@@ -246,7 +246,7 @@ ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length)
ir_variable::ir_variable(const struct glsl_type *type, const char *name)
- : ir_instruction(), read_only(false), centroid(false), invariant(false),
+ : max_array_access(0), read_only(false), centroid(false), invariant(false),
mode(ir_var_auto), interpolation(ir_var_smooth)
{
this->type = type;
diff --git a/ir.h b/ir.h
index de6f09318a..8892f1dc1b 100644
--- a/ir.h
+++ b/ir.h
@@ -121,6 +121,7 @@ public:
{
ir_variable *var = new ir_variable(type, name);
+ var->max_array_access = this->max_array_access;
var->read_only = this->read_only;
var->centroid = this->centroid;
var->invariant = this->invariant;
@@ -132,6 +133,13 @@ public:
const char *name;
+ /**
+ * Highest element accessed with a constant expression array index
+ *
+ * Not used for non-array variables.
+ */
+ unsigned max_array_access;
+
unsigned read_only:1;
unsigned centroid:1;
unsigned invariant:1;