diff options
author | Ian Romanick <[email protected]> | 2013-03-15 14:10:12 -0700 |
---|---|---|
committer | Ian Romanick <[email protected]> | 2013-04-08 15:17:05 -0700 |
commit | 46934adb8d855a9505f2231ba3f1ad5449b896a4 (patch) | |
tree | 8b32df284f39e03ab6063d7f1c2c4742e07ae7b1 /src/glsl/ast_array_index.cpp | |
parent | cd39ae73944333690d72c4356ac45675fecef958 (diff) |
glsl: Refactor handling of ast_array_index to a separate function
I love 800+ line switch-statements as much as the next guy... Future
commits will make changes to this part of the AST-to-HIR conversion, and
extracting this code will make that a bit easier.
Signed-off-by: Ian Romanick <[email protected]>
Reviewed-by: Kenneth Graunke <[email protected]>
Diffstat (limited to 'src/glsl/ast_array_index.cpp')
-rw-r--r-- | src/glsl/ast_array_index.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/src/glsl/ast_array_index.cpp b/src/glsl/ast_array_index.cpp new file mode 100644 index 00000000000..fecda4592b6 --- /dev/null +++ b/src/glsl/ast_array_index.cpp @@ -0,0 +1,194 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ast.h" +#include "glsl_types.h" +#include "ir.h" + +ir_rvalue * +_mesa_ast_array_index_to_hir(void *mem_ctx, + struct _mesa_glsl_parse_state *state, + ir_rvalue *array, ir_rvalue *idx, + YYLTYPE &loc, YYLTYPE &idx_loc, + bool error_emitted) +{ + ir_rvalue *result = new(mem_ctx) ir_dereference_array(array, idx); + + if (error_emitted) + return result; + + if (!array->type->is_array() + && !array->type->is_matrix() + && !array->type->is_vector()) { + _mesa_glsl_error(& idx_loc, state, + "cannot dereference non-array / non-matrix / " + "non-vector"); + error_emitted = true; + } + + if (!idx->type->is_integer()) { + _mesa_glsl_error(& idx_loc, state, + "array index must be integer type"); + error_emitted = true; + } else if (!idx->type->is_scalar()) { + _mesa_glsl_error(& idx_loc, state, + "array index must be scalar"); + error_emitted = true; + } + + /* If the array index is a constant expression and the array has a + * declared size, ensure that the access is in-bounds. If the array + * index is not a constant expression, ensure that the array has a + * declared size. + */ + ir_constant *const const_index = idx->constant_expression_value(); + if (const_index != NULL) { + const int idx = const_index->value.i[0]; + const char *type_name; + unsigned bound = 0; + + if (array->type->is_matrix()) { + type_name = "matrix"; + } else if (array->type->is_vector()) { + type_name = "vector"; + } else { + type_name = "array"; + } + + /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec: + * + * "It is illegal to declare an array with a size, and then + * later (in the same shader) index the same array with an + * integral constant expression greater than or equal to the + * declared size. It is also illegal to index an array with a + * negative constant expression." + */ + if (array->type->is_matrix()) { + if (array->type->row_type()->vector_elements <= idx) { + bound = array->type->row_type()->vector_elements; + } + } else if (array->type->is_vector()) { + if (array->type->vector_elements <= idx) { + bound = array->type->vector_elements; + } + } else { + if ((array->type->array_size() > 0) + && (array->type->array_size() <= idx)) { + bound = array->type->array_size(); + } + } + + if (bound > 0) { + _mesa_glsl_error(& loc, state, "%s index must be < %u", + type_name, bound); + error_emitted = true; + } else if (idx < 0) { + _mesa_glsl_error(& loc, state, "%s index must be >= 0", + type_name); + error_emitted = true; + } + + if (array->type->is_array()) { + /* If the array is a variable dereference, it dereferences the + * whole array, by definition. Use this to get the variable. + * + * FINISHME: Should some methods for getting / setting / testing + * FINISHME: array access limits be added to ir_dereference? + */ + ir_variable *const v = array->whole_variable_referenced(); + if ((v != NULL) && (unsigned(idx) > v->max_array_access)) { + v->max_array_access = idx; + + /* Check whether this access will, as a side effect, implicitly + * cause the size of a built-in array to be too large. + */ + if (check_builtin_array_max_size(v->name, idx+1, loc, state)) + error_emitted = true; + } + } + } else if (array->type->array_size() == 0) { + _mesa_glsl_error(&loc, state, "unsized array index must be constant"); + } else if (array->type->is_array() + && array->type->fields.array->is_interface()) { + /* Page 46 in section 4.3.7 of the OpenGL ES 3.00 spec says: + * + * "All indexes used to index a uniform block array must be + * constant integral expressions." + */ + _mesa_glsl_error(&loc, state, + "uniform block array index must be constant"); + } else { + if (array->type->is_array()) { + /* whole_variable_referenced can return NULL if the array is a + * member of a structure. In this case it is safe to not update + * the max_array_access field because it is never used for fields + * of structures. + */ + ir_variable *v = array->whole_variable_referenced(); + if (v != NULL) + v->max_array_access = array->type->array_size() - 1; + } + } + + /* From page 23 (29 of the PDF) of the GLSL 1.30 spec: + * + * "Samplers aggregated into arrays within a shader (using square + * brackets [ ]) can only be indexed with integral constant + * expressions [...]." + * + * This restriction was added in GLSL 1.30. Shaders using earlier version + * of the language should not be rejected by the compiler front-end for + * using this construct. This allows useful things such as using a loop + * counter as the index to an array of samplers. If the loop in unrolled, + * the code should compile correctly. Instead, emit a warning. + */ + if (array->type->is_array() && + array->type->element_type()->is_sampler() && + const_index == NULL) { + + if (!state->is_version(130, 100)) { + if (state->es_shader) { + _mesa_glsl_warning(&loc, state, + "sampler arrays indexed with non-constant " + "expressions is optional in %s", + state->get_version_string()); + } else { + _mesa_glsl_warning(&loc, state, + "sampler arrays indexed with non-constant " + "expressions will be forbidden in GLSL 1.30 and " + "later"); + } + } else { + _mesa_glsl_error(&loc, state, + "sampler arrays indexed with non-constant " + "expressions is forbidden in GLSL 1.30 and " + "later"); + error_emitted = true; + } + } + + if (error_emitted) + result->type = glsl_type::error_type; + + return result; +} |