summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/glsl/ast.h20
-rw-r--r--src/glsl/ast_type.cpp60
2 files changed, 80 insertions, 0 deletions
diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index ae763424f71..ca493401d7c 100644
--- a/src/glsl/ast.h
+++ b/src/glsl/ast.h
@@ -350,6 +350,26 @@ public:
exec_list array_dimensions;
};
+class ast_layout_expression : public ast_node {
+public:
+ ast_layout_expression(const struct YYLTYPE &locp, ast_expression *expr)
+ {
+ set_location(locp);
+ layout_const_expressions.push_tail(&expr->link);
+ }
+
+ bool process_qualifier_constant(struct _mesa_glsl_parse_state *state,
+ const char *qual_indentifier,
+ unsigned *value, bool can_be_zero);
+
+ void merge_qualifier(ast_layout_expression *l_expr)
+ {
+ layout_const_expressions.append_list(&l_expr->layout_const_expressions);
+ }
+
+ exec_list layout_const_expressions;
+};
+
/**
* C-style aggregate initialization class
*
diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp
index b107051e32c..89ab8eaa7ff 100644
--- a/src/glsl/ast_type.cpp
+++ b/src/glsl/ast_type.cpp
@@ -467,3 +467,63 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
return true;
}
+
+bool
+ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state *state,
+ const char *qual_indentifier,
+ unsigned *value,
+ bool can_be_zero)
+{
+ int min_value = 0;
+ bool first_pass = true;
+ *value = 0;
+
+ if (!can_be_zero)
+ min_value = 1;
+
+ for (exec_node *node = layout_const_expressions.head;
+ !node->is_tail_sentinel(); node = node->next) {
+
+ exec_list dummy_instructions;
+ ast_node *const_expression = exec_node_data(ast_node, node, link);
+
+ ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state);
+
+ ir_constant *const const_int = ir->constant_expression_value();
+ if (const_int == NULL || !const_int->type->is_integer()) {
+ YYLTYPE loc = const_expression->get_location();
+ _mesa_glsl_error(&loc, state, "%s must be an integral constant "
+ "expression", qual_indentifier);
+ return false;
+ }
+
+ if (const_int->value.i[0] < min_value) {
+ YYLTYPE loc = const_expression->get_location();
+ _mesa_glsl_error(&loc, state, "%s layout qualifier is invalid "
+ "(%d < %d)", qual_indentifier,
+ const_int->value.i[0], min_value);
+ return false;
+ }
+
+ if (!first_pass && *value != const_int->value.u[0]) {
+ YYLTYPE loc = const_expression->get_location();
+ _mesa_glsl_error(&loc, state, "%s layout qualifier does not "
+ "match previous declaration (%d vs %d)",
+ qual_indentifier, *value, const_int->value.i[0]);
+ return false;
+ } else {
+ first_pass = false;
+ *value = const_int->value.u[0];
+ }
+
+ /* If the location is const (and we've verified that
+ * it is) then no instructions should have been emitted
+ * when we converted it to HIR. If they were emitted,
+ * then either the location isn't const after all, or
+ * we are emitting unnecessary instructions.
+ */
+ assert(dummy_instructions.is_empty());
+ }
+
+ return true;
+}