#include "glsl_parser_extras.h"
#include "ast.h"
#include "glsl_types.h"
+#include "program/hash_table.h"
#include "ir.h"
+static void
+detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
+ exec_list *instructions);
+
void
_mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
{
_mesa_glsl_initialize_variables(instructions, state);
- _mesa_glsl_initialize_functions(state);
- state->symbols->language_version = state->language_version;
+ state->symbols->separate_function_namespace = state->language_version == 110;
state->current_function = NULL;
+ state->toplevel_ir = instructions;
+
/* Section 4.2 of the GLSL 1.20 specification states:
* "The built-in functions are scoped in a scope outside the global scope
* users declare global variables in. That is, a shader's global scope,
foreach_list_typed (ast_node, ast, link, & state->translation_unit)
ast->hir(instructions, state);
+
+ detect_recursion_unlinked(state, instructions);
+ detect_conflicting_assignments(state, instructions);
+
+ state->toplevel_ir = NULL;
}
/* This conversion was added in GLSL 1.20. If the compilation mode is
* GLSL 1.10, the conversion is skipped.
*/
- if (state->language_version < 120)
+ if (!state->is_version(120, 0))
return false;
/* From page 27 (page 33 of the PDF) of the GLSL 1.50 spec:
ast_operators op,
struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
{
- if (state->language_version < 130) {
- _mesa_glsl_error(loc, state, "bit operations require GLSL 1.30");
+ if (!state->check_bitwise_operations_allowed(loc)) {
return glsl_type::error_type;
}
const struct glsl_type *type_b,
struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
{
- if (state->language_version < 130) {
- _mesa_glsl_error(loc, state,
- "operator '%%' is reserved in %s",
- state->version_string);
+ if (!state->check_version(130, 300, loc, "operator '%%' is reserved")) {
return glsl_type::error_type;
}
ast_operators op,
struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
{
- if (state->language_version < 130) {
- _mesa_glsl_error(loc, state, "bit operations require GLSL 1.30");
+ if (!state->check_bitwise_operations_allowed(loc)) {
return glsl_type::error_type;
}
return NULL;
}
+static void
+mark_whole_array_access(ir_rvalue *access)
+{
+ ir_dereference_variable *deref = access->as_dereference_variable();
+
+ if (deref && deref->var) {
+ deref->var->max_array_access = deref->type->length - 1;
+ }
+}
+
ir_rvalue *
do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
+ const char *non_lvalue_description,
ir_rvalue *lhs, ir_rvalue *rhs, bool is_initializer,
YYLTYPE lhs_loc)
{
void *ctx = state;
bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
+ ir_variable *lhs_var = lhs->variable_referenced();
+ if (lhs_var)
+ lhs_var->assigned = true;
+
if (!error_emitted) {
- if (lhs->variable_referenced() != NULL
- && lhs->variable_referenced()->read_only) {
+ if (non_lvalue_description != NULL) {
+ _mesa_glsl_error(&lhs_loc, state,
+ "assignment to %s",
+ non_lvalue_description);
+ error_emitted = true;
+ } else if (lhs->variable_referenced() != NULL
+ && lhs->variable_referenced()->read_only) {
_mesa_glsl_error(&lhs_loc, state,
"assignment to read-only variable '%s'",
lhs->variable_referenced()->name);
error_emitted = true;
+ } else if (lhs->type->is_array() &&
+ !state->check_version(120, 300, &lhs_loc,
+ "whole array assignment forbidden")) {
+ /* From page 32 (page 38 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "Other binary or unary expressions, non-dereferenced
+ * arrays, function names, swizzles with repeated fields,
+ * and constants cannot be l-values."
+ *
+ * The restriction on arrays is lifted in GLSL 1.20 and GLSL ES 3.00.
+ */
+ error_emitted = true;
} else if (!lhs->is_lvalue()) {
_mesa_glsl_error(& lhs_loc, state, "non-lvalue in assignment");
error_emitted = true;
}
-
- if (state->es_shader && lhs->type->is_array()) {
- _mesa_glsl_error(&lhs_loc, state, "whole array assignment is not "
- "allowed in GLSL ES 1.00.");
- error_emitted = true;
- }
}
ir_rvalue *new_rhs =
rhs->type->array_size());
d->type = var->type;
}
+ mark_whole_array_access(rhs);
+ mark_whole_array_access(lhs);
}
/* Most callers of do_assignment (assign, add_assign, pre_inc/dec,
ir_var_temporary);
ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var);
instructions->push_tail(var);
- instructions->push_tail(new(ctx) ir_assignment(deref_var,
- rhs,
- NULL));
+ instructions->push_tail(new(ctx) ir_assignment(deref_var, rhs));
deref_var = new(ctx) ir_dereference_variable(var);
if (!error_emitted)
- instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var, NULL));
+ instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var));
return new(ctx) ir_dereference_variable(var);
}
var->mode = ir_var_auto;
instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
- lvalue, NULL));
-
- /* Once we've created this temporary, mark it read only so it's no
- * longer considered an lvalue.
- */
- var->read_only = true;
+ lvalue));
return new(ctx) ir_dereference_variable(var);
}
return NULL;
}
-static void
-mark_whole_array_access(ir_rvalue *access)
-{
- ir_dereference_variable *deref = access->as_dereference_variable();
-
- if (deref) {
- deref->var->max_array_access = deref->type->length - 1;
- }
-}
-
static ir_rvalue *
do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1)
{
case GLSL_TYPE_ERROR:
case GLSL_TYPE_VOID:
case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_INTERFACE:
/* I assume a comparison of a struct containing a sampler just
* ignores the sampler present in the type.
*/
break;
-
- default:
- assert(!"Should not get here.");
- break;
}
if (cmp == NULL)
return new(ctx) ir_constant(true);
}
+/**
+ * If name refers to a builtin array whose maximum allowed size is less than
+ * size, report an error and return true. Otherwise return false.
+ */
+static bool
+check_builtin_array_max_size(const char *name, unsigned size,
+ YYLTYPE loc, struct _mesa_glsl_parse_state *state)
+{
+ if ((strcmp("gl_TexCoord", name) == 0)
+ && (size > state->Const.MaxTextureCoords)) {
+ /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "The size [of gl_TexCoord] can be at most
+ * gl_MaxTextureCoords."
+ */
+ _mesa_glsl_error(&loc, state, "`gl_TexCoord' array size cannot "
+ "be larger than gl_MaxTextureCoords (%u)\n",
+ state->Const.MaxTextureCoords);
+ return true;
+ } else if (strcmp("gl_ClipDistance", name) == 0
+ && size > state->Const.MaxClipPlanes) {
+ /* From section 7.1 (Vertex Shader Special Variables) of the
+ * GLSL 1.30 spec:
+ *
+ * "The gl_ClipDistance array is predeclared as unsized and
+ * must be sized by the shader either redeclaring it with a
+ * size or indexing it only with integral constant
+ * expressions. ... The size can be at most
+ * gl_MaxClipDistances."
+ */
+ _mesa_glsl_error(&loc, state, "`gl_ClipDistance' array size cannot "
+ "be larger than gl_MaxClipDistances (%u)\n",
+ state->Const.MaxClipPlanes);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Create the constant 1, of a which is appropriate for incrementing and
+ * decrementing values of the given GLSL type. For example, if type is vec4,
+ * this creates a constant value of 1.0 having type float.
+ *
+ * If the given type is invalid for increment and decrement operators, return
+ * a floating point 1--the error will be detected later.
+ */
+static ir_rvalue *
+constant_one_for_inc_dec(void *ctx, const glsl_type *type)
+{
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ return new(ctx) ir_constant((unsigned) 1);
+ case GLSL_TYPE_INT:
+ return new(ctx) ir_constant(1);
+ default:
+ case GLSL_TYPE_FLOAT:
+ return new(ctx) ir_constant(1.0f);
+ }
+}
+
ir_rvalue *
ast_expression::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = this->subexpressions[1]->hir(instructions, state);
- result = do_assignment(instructions, state, op[0], op[1], false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0], op[1], false,
this->subexpressions[0]->get_location());
error_emitted = result->type->is_error();
break;
case ast_lshift:
case ast_rshift:
- if (state->language_version < 130) {
- _mesa_glsl_error(&loc, state, "operator %s requires GLSL 1.30",
- operator_string(this->oper));
+ if (!state->check_bitwise_operations_allowed(&loc)) {
error_emitted = true;
}
_mesa_glsl_error(& loc, state, "operands of `%s' must have the same "
"type", (this->oper == ast_equal) ? "==" : "!=");
error_emitted = true;
- } else if ((state->language_version <= 110)
- && (op[0]->type->is_array() || op[1]->type->is_array())) {
- _mesa_glsl_error(& loc, state, "array comparisons forbidden in "
- "GLSL 1.10");
+ } else if ((op[0]->type->is_array() || op[1]->type->is_array()) &&
+ !state->check_version(120, 300, &loc,
+ "array comparisons forbidden")) {
error_emitted = true;
}
case ast_bit_not:
op[0] = this->subexpressions[0]->hir(instructions, state);
- if (state->language_version < 130) {
- _mesa_glsl_error(&loc, state, "bit-wise operations require GLSL 1.30");
+ if (!state->check_bitwise_operations_allowed(&loc)) {
error_emitted = true;
}
error_emitted = true;
}
- type = op[0]->type;
+ type = error_emitted ? glsl_type::error_type : op[0]->type;
result = new(ctx) ir_expression(ir_unop_bit_not, type, op[0], NULL);
break;
op[1] = get_scalar_boolean_operand(&rhs_instructions, state, this, 1,
"RHS", &error_emitted);
- ir_constant *op0_const = op[0]->constant_expression_value();
- if (op0_const) {
- if (op0_const->value.b[0]) {
- instructions->append_list(&rhs_instructions);
- result = op[1];
- } else {
- result = op0_const;
- }
- type = glsl_type::bool_type;
+ if (rhs_instructions.is_empty()) {
+ result = new(ctx) ir_expression(ir_binop_logic_and, op[0], op[1]);
+ type = result->type;
} else {
ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
"and_tmp",
stmt->then_instructions.append_list(&rhs_instructions);
ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, op[1], NULL);
+ new(ctx) ir_assignment(then_deref, op[1]);
stmt->then_instructions.push_tail(then_assign);
ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false), NULL);
+ new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false));
stmt->else_instructions.push_tail(else_assign);
result = new(ctx) ir_dereference_variable(tmp);
op[1] = get_scalar_boolean_operand(&rhs_instructions, state, this, 1,
"RHS", &error_emitted);
- ir_constant *op0_const = op[0]->constant_expression_value();
- if (op0_const) {
- if (op0_const->value.b[0]) {
- result = op0_const;
- } else {
- result = op[1];
- }
- type = glsl_type::bool_type;
+ if (rhs_instructions.is_empty()) {
+ result = new(ctx) ir_expression(ir_binop_logic_or, op[0], op[1]);
+ type = result->type;
} else {
ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
"or_tmp",
ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true), NULL);
+ new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true));
stmt->then_instructions.push_tail(then_assign);
stmt->else_instructions.append_list(&rhs_instructions);
ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, op[1], NULL);
+ new(ctx) ir_assignment(else_deref, op[1]);
stmt->else_instructions.push_tail(else_assign);
result = new(ctx) ir_dereference_variable(tmp);
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = (op[0]->type->is_error());
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = type->is_error();
&loc);
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
- result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
- temp_rhs, false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
break;
state, &loc);
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
- result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
- temp_rhs, false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
break;
* "The second and third expressions must be the same type, but can
* be of any type other than an array."
*/
- if ((state->language_version <= 110) && type->is_array()) {
- _mesa_glsl_error(& loc, state, "Second and third operands of ?: "
- "operator must not be arrays.");
+ if (type->is_array() &&
+ !state->check_version(120, 300, &loc,
+ "Second and third operands of ?: operator "
+ "cannot be arrays")) {
error_emitted = true;
}
ir_dereference *const then_deref =
new(ctx) ir_dereference_variable(tmp);
ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, op[1], NULL);
+ new(ctx) ir_assignment(then_deref, op[1]);
stmt->then_instructions.push_tail(then_assign);
else_instructions.move_nodes_to(& stmt->else_instructions);
ir_dereference *const else_deref =
new(ctx) ir_dereference_variable(tmp);
ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, op[2], NULL);
+ new(ctx) ir_assignment(else_deref, op[2]);
stmt->else_instructions.push_tail(else_assign);
result = new(ctx) ir_dereference_variable(tmp);
case ast_pre_inc:
case ast_pre_dec: {
+ this->non_lvalue_description = (this->oper == ast_pre_inc)
+ ? "pre-increment operation" : "pre-decrement operation";
+
op[0] = this->subexpressions[0]->hir(instructions, state);
- if (op[0]->type->base_type == GLSL_TYPE_FLOAT)
- op[1] = new(ctx) ir_constant(1.0f);
- else
- op[1] = new(ctx) ir_constant(1);
+ op[1] = constant_one_for_inc_dec(ctx, op[0]->type);
type = arithmetic_result_type(op[0], op[1], false, state, & loc);
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error();
case ast_post_inc:
case ast_post_dec: {
+ this->non_lvalue_description = (this->oper == ast_post_inc)
+ ? "post-increment operation" : "post-decrement operation";
op[0] = this->subexpressions[0]->hir(instructions, state);
- if (op[0]->type->base_type == GLSL_TYPE_FLOAT)
- op[1] = new(ctx) ir_constant(1.0f);
- else
- op[1] = new(ctx) ir_constant(1);
+ op[1] = constant_one_for_inc_dec(ctx, op[0]->type);
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL));
(void)do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
* 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))
+ 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
array->type->element_type()->is_sampler() &&
const_index == NULL) {
- if (state->language_version == 100) {
- _mesa_glsl_warning(&loc, state,
- "sampler arrays indexed with non-constant "
- "expressions is optional in GLSL ES 1.00");
- } else if (state->language_version < 130) {
- _mesa_glsl_warning(&loc, state,
- "sampler arrays indexed with non-constant "
- "expressions is forbidden in GLSL 1.30 and "
- "later");
+ 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 "
ir_variable *var =
state->symbols->get_variable(this->primary_expression.identifier);
- result = new(ctx) ir_dereference_variable(var);
-
if (var != NULL) {
var->used = true;
+ result = new(ctx) ir_dereference_variable(var);
} else {
_mesa_glsl_error(& loc, state, "`%s' undeclared",
this->primary_expression.identifier);
+ result = ir_rvalue::error_value(ctx);
error_emitted = true;
}
break;
{
unsigned length = 0;
- /* FINISHME: Reject delcarations of multidimensional arrays. */
+ /* From page 19 (page 25) of the GLSL 1.20 spec:
+ *
+ * "Only one-dimensional arrays may be declared."
+ */
+ if (base->is_array()) {
+ _mesa_glsl_error(loc, state,
+ "invalid array of `%s' (only one-dimensional arrays "
+ "may be declared)",
+ base->name);
+ return glsl_type::error_type;
+ }
if (array_size != NULL) {
exec_list dummy_instructions;
ir_rvalue *const ir = array_size->hir(& dummy_instructions, state);
YYLTYPE loc = array_size->get_location();
- /* FINISHME: Verify that the grammar forbids side-effects in array
- * FINISHME: sizes. i.e., 'vec4 [x = 12] data'
- */
- assert(dummy_instructions.is_empty());
-
if (ir != NULL) {
if (!ir->type->is_integer()) {
_mesa_glsl_error(& loc, state, "array size must be integer type");
} else {
assert(size->type == ir->type);
length = size->value.u[0];
+
+ /* If the array size 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 array size isn't const after all, or
+ * we are emitting unnecessary instructions.
+ */
+ assert(dummy_instructions.is_empty());
}
}
}
}
+/**
+ * Determine whether a toplevel variable declaration declares a varying. This
+ * function operates by examining the variable's mode and the shader target,
+ * so it correctly identifies linkage variables regardless of whether they are
+ * declared using the deprecated "varying" syntax or the new "in/out" syntax.
+ *
+ * Passing a non-toplevel variable declaration (e.g. a function parameter) to
+ * this function will produce undefined results.
+ */
+static bool
+is_varying_var(ir_variable *var, _mesa_glsl_parser_targets target)
+{
+ switch (target) {
+ case vertex_shader:
+ return var->mode == ir_var_shader_out;
+ case fragment_shader:
+ return var->mode == ir_var_shader_in;
+ default:
+ return var->mode == ir_var_shader_out || var->mode == ir_var_shader_in;
+ }
+}
+
+
+/**
+ * Matrix layout qualifiers are only allowed on certain types
+ */
+static void
+validate_matrix_layout_for_type(struct _mesa_glsl_parse_state *state,
+ YYLTYPE *loc,
+ const glsl_type *type)
+{
+ if (!type->is_matrix() && !type->is_record()) {
+ _mesa_glsl_error(loc, state,
+ "uniform block layout qualifiers row_major and "
+ "column_major can only be applied to matrix and "
+ "structure types");
+ } else if (type->is_record()) {
+ /* We allow 'layout(row_major)' on structure types because it's the only
+ * way to get row-major layouts on matrices contained in structures.
+ */
+ _mesa_glsl_warning(loc, state,
+ "uniform block layout qualifiers row_major and "
+ "column_major applied to structure types is not "
+ "strictly conformant and my be rejected by other "
+ "compilers");
+ }
+}
+
static void
apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
ir_variable *var,
struct _mesa_glsl_parse_state *state,
- YYLTYPE *loc)
+ YYLTYPE *loc,
+ bool ubo_qualifiers_valid,
+ bool is_parameter)
{
if (qual->flags.q.invariant) {
if (var->used) {
_mesa_glsl_shader_target_name(state->target));
}
- /* From page 25 (page 31 of the PDF) of the GLSL 1.10 spec:
- *
- * "The varying qualifier can be used only with the data types
- * float, vec2, vec3, vec4, mat2, mat3, and mat4, or arrays of
- * these."
- */
- if (qual->flags.q.varying) {
- const glsl_type *non_array_type;
-
- if (var->type && var->type->is_array())
- non_array_type = var->type->fields.array;
- else
- non_array_type = var->type;
-
- if (non_array_type && non_array_type->base_type != GLSL_TYPE_FLOAT) {
- var->type = glsl_type::error_type;
- _mesa_glsl_error(loc, state,
- "varying variables must be of base type float");
- }
- }
-
/* If there is no qualifier that changes the mode of the variable, leave
* the setting alone.
*/
if (qual->flags.q.in && qual->flags.q.out)
- var->mode = ir_var_inout;
- else if (qual->flags.q.attribute || qual->flags.q.in
+ var->mode = ir_var_function_inout;
+ else if (qual->flags.q.in)
+ var->mode = is_parameter ? ir_var_function_in : ir_var_shader_in;
+ else if (qual->flags.q.attribute
|| (qual->flags.q.varying && (state->target == fragment_shader)))
- var->mode = ir_var_in;
- else if (qual->flags.q.out
- || (qual->flags.q.varying && (state->target == vertex_shader)))
- var->mode = ir_var_out;
+ var->mode = ir_var_shader_in;
+ else if (qual->flags.q.out)
+ var->mode = is_parameter ? ir_var_function_out : ir_var_shader_out;
+ else if (qual->flags.q.varying && (state->target == vertex_shader))
+ var->mode = ir_var_shader_out;
else if (qual->flags.q.uniform)
var->mode = ir_var_uniform;
+ if (!is_parameter && is_varying_var(var, state->target)) {
+ /* This variable is being used to link data between shader stages (in
+ * pre-glsl-1.30 parlance, it's a "varying"). Check that it has a type
+ * that is allowed for such purposes.
+ *
+ * From page 25 (page 31 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "The varying qualifier can be used only with the data types
+ * float, vec2, vec3, vec4, mat2, mat3, and mat4, or arrays of
+ * these."
+ *
+ * This was relaxed in GLSL version 1.30 and GLSL ES version 3.00. From
+ * page 31 (page 37 of the PDF) of the GLSL 1.30 spec:
+ *
+ * "Fragment inputs can only be signed and unsigned integers and
+ * integer vectors, float, floating-point vectors, matrices, or
+ * arrays of these. Structures cannot be input.
+ *
+ * Similar text exists in the section on vertex shader outputs.
+ *
+ * Similar text exists in the GLSL ES 3.00 spec, except that the GLSL ES
+ * 3.00 spec allows structs as well. Varying structs are also allowed
+ * in GLSL 1.50.
+ */
+ switch (var->type->get_scalar_type()->base_type) {
+ case GLSL_TYPE_FLOAT:
+ /* Ok in all GLSL versions */
+ break;
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ if (state->is_version(130, 300))
+ break;
+ _mesa_glsl_error(loc, state,
+ "varying variables must be of base type float in %s",
+ state->get_version_string());
+ break;
+ case GLSL_TYPE_STRUCT:
+ if (state->is_version(150, 300))
+ break;
+ _mesa_glsl_error(loc, state,
+ "varying variables may not be of type struct");
+ break;
+ default:
+ _mesa_glsl_error(loc, state, "illegal type for a varying variable");
+ break;
+ }
+ }
+
if (state->all_invariant && (state->current_function == NULL)) {
switch (state->target) {
case vertex_shader:
- if (var->mode == ir_var_out)
+ if (var->mode == ir_var_shader_out)
var->invariant = true;
break;
case geometry_shader:
- if ((var->mode == ir_var_in) || (var->mode == ir_var_out))
+ if ((var->mode == ir_var_shader_in)
+ || (var->mode == ir_var_shader_out))
var->invariant = true;
break;
case fragment_shader:
- if (var->mode == ir_var_in)
+ if (var->mode == ir_var_shader_in)
var->invariant = true;
break;
}
}
if (qual->flags.q.flat)
- var->interpolation = ir_var_flat;
+ var->interpolation = INTERP_QUALIFIER_FLAT;
else if (qual->flags.q.noperspective)
- var->interpolation = ir_var_noperspective;
+ var->interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
+ else if (qual->flags.q.smooth)
+ var->interpolation = INTERP_QUALIFIER_SMOOTH;
else
- var->interpolation = ir_var_smooth;
+ var->interpolation = INTERP_QUALIFIER_NONE;
+
+ if (var->interpolation != INTERP_QUALIFIER_NONE &&
+ !(state->target == vertex_shader && var->mode == ir_var_shader_out) &&
+ !(state->target == fragment_shader && var->mode == ir_var_shader_in)) {
+ _mesa_glsl_error(loc, state,
+ "interpolation qualifier `%s' can only be applied to "
+ "vertex shader outputs and fragment shader inputs.",
+ var->interpolation_string());
+ }
var->pixel_center_integer = qual->flags.q.pixel_center_integer;
var->origin_upper_left = qual->flags.q.origin_upper_left;
*/
switch (state->target) {
case vertex_shader:
- if (!global_scope || (var->mode != ir_var_in)) {
+ if (!global_scope || (var->mode != ir_var_shader_in)) {
fail = true;
string = "input";
}
break;
case fragment_shader:
- if (!global_scope || (var->mode != ir_var_out)) {
+ if (!global_scope || (var->mode != ir_var_shader_out)) {
fail = true;
string = "output";
}
} else {
var->location = qual->location;
}
+
+ if (qual->flags.q.explicit_index) {
+ /* From the GLSL 4.30 specification, section 4.4.2 (Output
+ * Layout Qualifiers):
+ *
+ * "It is also a compile-time error if a fragment shader
+ * sets a layout index to less than 0 or greater than 1."
+ *
+ * Older specifications don't mandate a behavior; we take
+ * this as a clarification and always generate the error.
+ */
+ if (qual->index < 0 || qual->index > 1) {
+ _mesa_glsl_error(loc, state,
+ "explicit index may only be 0 or 1\n");
+ } else {
+ var->explicit_index = true;
+ var->index = qual->index;
+ }
+ }
}
+ } else if (qual->flags.q.explicit_index) {
+ _mesa_glsl_error(loc, state,
+ "explicit index requires explicit location\n");
}
/* Does the declaration use the 'layout' keyword?
*/
const bool uses_layout = qual->flags.q.pixel_center_integer
|| qual->flags.q.origin_upper_left
- || qual->flags.q.explicit_location;
+ || qual->flags.q.explicit_location; /* no need for index since it relies on location */
/* Does the declaration use the deprecated 'attribute' or 'varying'
* keywords?
* The following extension do not allow the deprecated keywords:
*
* GL_AMD_conservative_depth
+ * GL_ARB_conservative_depth
* GL_ARB_gpu_shader5
* GL_ARB_separate_shader_objects
* GL_ARB_tesselation_shader
+ qual->flags.q.depth_less
+ qual->flags.q.depth_unchanged;
if (depth_layout_count > 0
- && !state->AMD_conservative_depth_enable) {
+ && !state->AMD_conservative_depth_enable
+ && !state->ARB_conservative_depth_enable) {
_mesa_glsl_error(loc, state,
- "extension GL_AMD_conservative_depth must be enabled "
+ "extension GL_AMD_conservative_depth or "
+ "GL_ARB_conservative_depth must be enabled "
"to use depth layout qualifiers");
} else if (depth_layout_count > 0
&& strcmp(var->name, "gl_FragDepth") != 0) {
else
var->depth_layout = ir_depth_layout_none;
- if (var->type->is_array() && state->language_version != 110) {
- var->array_lvalue = true;
+ if (qual->flags.q.std140 ||
+ qual->flags.q.packed ||
+ qual->flags.q.shared) {
+ _mesa_glsl_error(loc, state,
+ "uniform block layout qualifiers std140, packed, and "
+ "shared can only be applied to uniform blocks, not "
+ "members");
+ }
+
+ if (qual->flags.q.row_major || qual->flags.q.column_major) {
+ if (!ubo_qualifiers_valid) {
+ _mesa_glsl_error(loc, state,
+ "uniform block layout qualifiers row_major and "
+ "column_major can only be applied to uniform block "
+ "members");
+ } else
+ validate_matrix_layout_for_type(state, loc, var->type);
}
}
* FINISHME: required or not.
*/
- /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
- *
- * "The size [of gl_TexCoord] can be at most
- * gl_MaxTextureCoords."
- */
const unsigned size = unsigned(var->type->array_size());
- if ((strcmp("gl_TexCoord", var->name) == 0)
- && (size > state->Const.MaxTextureCoords)) {
- _mesa_glsl_error(& loc, state, "`gl_TexCoord' array size cannot "
- "be larger than gl_MaxTextureCoords (%u)\n",
- state->Const.MaxTextureCoords);
- } else if ((size > 0) && (size <= earlier->max_array_access)) {
+ check_builtin_array_max_size(var->name, size, loc, state);
+ if ((size > 0) && (size <= earlier->max_array_access)) {
_mesa_glsl_error(& loc, state, "array size must be > %u due to "
"previous access",
earlier->max_array_access);
* * gl_Color
* * gl_SecondaryColor
*/
- } else if (state->language_version >= 130
+ } else if (state->is_version(130, 0)
&& (strcmp(var->name, "gl_FrontColor") == 0
|| strcmp(var->name, "gl_BackColor") == 0
|| strcmp(var->name, "gl_FrontSecondaryColor") == 0
earlier->interpolation = var->interpolation;
/* Layout qualifiers for gl_FragDepth. */
- } else if (state->AMD_conservative_depth_enable
+ } else if ((state->AMD_conservative_depth_enable ||
+ state->ARB_conservative_depth_enable)
&& strcmp(var->name, "gl_FragDepth") == 0
&& earlier->type == var->type
&& earlier->mode == var->mode) {
* directly by an application via API commands, or indirectly by
* OpenGL."
*/
- if ((state->language_version <= 110)
- && (var->mode == ir_var_uniform)) {
- _mesa_glsl_error(& initializer_loc, state,
- "cannot initialize uniforms in GLSL 1.10");
+ if (var->mode == ir_var_uniform) {
+ state->check_version(120, 0, &initializer_loc,
+ "cannot initialize uniforms");
}
if (var->type->is_sampler()) {
"cannot initialize samplers");
}
- if ((var->mode == ir_var_in) && (state->current_function == NULL)) {
+ if ((var->mode == ir_var_shader_in) && (state->current_function == NULL)) {
_mesa_glsl_error(& initializer_loc, state,
"cannot initialize %s shader input / %s",
_mesa_glsl_shader_target_name(state->target),
const glsl_type *initializer_type;
if (!type->qualifier.flags.q.uniform) {
result = do_assignment(initializer_instructions, state,
+ NULL,
lhs, rhs, true,
type->get_location());
initializer_type = result->type;
} else
initializer_type = rhs->type;
+ var->constant_initializer = rhs->constant_expression_value();
+ var->has_initializer = true;
+
/* If the declared variable is an unsized array, it must inherrit
* its full type from the initializer. A declaration such as
*
"Undeclared variable `%s' cannot be marked "
"invariant\n", decl->identifier);
} else if ((state->target == vertex_shader)
- && (earlier->mode != ir_var_out)) {
+ && (earlier->mode != ir_var_shader_out)) {
_mesa_glsl_error(& loc, state,
"`%s' cannot be marked invariant, vertex shader "
"outputs only\n", decl->identifier);
} else if ((state->target == fragment_shader)
- && (earlier->mode != ir_var_in)) {
+ && (earlier->mode != ir_var_shader_in)) {
_mesa_glsl_error(& loc, state,
"`%s' cannot be marked invariant, fragment shader "
"inputs only\n", decl->identifier);
decl_type = this->type->specifier->glsl_type(& type_name, state);
if (this->declarations.is_empty()) {
- /* The only valid case where the declaration list can be empty is when
- * the declaration is setting the default precision of a built-in type
- * (e.g., 'precision highp vec4;').
+ /* If there is no structure involved in the program text, there are two
+ * possible scenarios:
+ *
+ * - The program text contained something like 'vec4;'. This is an
+ * empty declaration. It is valid but weird. Emit a warning.
+ *
+ * - The program text contained something like 'S;' and 'S' is not the
+ * name of a known structure type. This is both invalid and weird.
+ * Emit an error.
+ *
+ * Note that if decl_type is NULL and there is a structure involved,
+ * there must have been some sort of error with the structure. In this
+ * case we assume that an error was already generated on this line of
+ * code for the structure. There is no need to generate an additional,
+ * confusing error.
*/
-
- if (decl_type != NULL) {
- } else {
- _mesa_glsl_error(& loc, state, "incomplete declaration");
+ assert(this->type->specifier->structure == NULL || decl_type != NULL
+ || state->error);
+ if (this->type->specifier->structure == NULL) {
+ if (decl_type != NULL) {
+ _mesa_glsl_warning(&loc, state, "empty declaration");
+ } else {
+ _mesa_glsl_error(&loc, state,
+ "invalid type `%s' in empty declaration",
+ type_name);
+ }
}
}
if (decl->is_array) {
var_type = process_array_type(&loc, decl_type, decl->array_size,
state);
+ if (var_type->is_error())
+ continue;
} else {
var_type = decl_type;
}
*
* Local variables can only use the qualifier const."
*
- * This is relaxed in GLSL 1.30. It is also relaxed by any extension
- * that adds the 'layout' keyword.
+ * This is relaxed in GLSL 1.30 and GLSL ES 3.00. It is also relaxed by
+ * any extension that adds the 'layout' keyword.
*/
- if ((state->language_version < 130)
+ if (!state->is_version(130, 300)
&& !state->ARB_explicit_attrib_location_enable
&& !state->ARB_fragment_coord_conventions_enable) {
if (this->type->qualifier.flags.q.out) {
_mesa_glsl_error(& loc, state,
"`out' qualifier in declaration of `%s' "
"only valid for function parameters in %s.",
- decl->identifier, state->version_string);
+ decl->identifier, state->get_version_string());
}
if (this->type->qualifier.flags.q.in) {
_mesa_glsl_error(& loc, state,
"`in' qualifier in declaration of `%s' "
"only valid for function parameters in %s.",
- decl->identifier, state->version_string);
+ decl->identifier, state->get_version_string());
}
/* FINISHME: Test for other invalid qualifiers. */
}
apply_type_qualifier_to_variable(& this->type->qualifier, var, state,
- & loc);
+ & loc, this->ubo_qualifiers_valid, false);
if (this->type->qualifier.flags.q.invariant) {
- if ((state->target == vertex_shader) && !(var->mode == ir_var_out ||
- var->mode == ir_var_inout)) {
- /* FINISHME: Note that this doesn't work for invariant on
- * a function signature outval
- */
+ if ((state->target == vertex_shader) &&
+ var->mode != ir_var_shader_out) {
_mesa_glsl_error(& loc, state,
"`%s' cannot be marked invariant, vertex shader "
"outputs only\n", var->name);
} else if ((state->target == fragment_shader) &&
- !(var->mode == ir_var_in || var->mode == ir_var_inout)) {
+ var->mode != ir_var_shader_in) {
/* FINISHME: Note that this doesn't work for invariant on
* a function signature inval
*/
"global scope%s",
mode, var->name, extra);
}
- } else if (var->mode == ir_var_in) {
+ } else if (var->mode == ir_var_shader_in) {
var->read_only = true;
if (state->target == vertex_shader) {
* "The attribute qualifier can be used only with float,
* floating-point vectors, and matrices. Attribute variables
* cannot be declared as arrays or structures."
+ *
+ * From page 33 (page 39 of the PDF) of the GLSL ES 3.00 spec:
+ *
+ * "Vertex shader inputs can only be float, floating-point
+ * vectors, matrices, signed and unsigned integers and integer
+ * vectors. Vertex shader inputs cannot be arrays or
+ * structures."
*/
const glsl_type *check_type = var->type->is_array()
? var->type->fields.array : var->type;
break;
case GLSL_TYPE_UINT:
case GLSL_TYPE_INT:
- if (state->language_version > 120)
+ if (state->is_version(120, 300))
break;
/* FALLTHROUGH */
default:
error_emitted = true;
}
- if (!error_emitted && (state->language_version <= 130)
- && var->type->is_array()) {
- _mesa_glsl_error(& loc, state,
- "vertex shader input / attribute cannot have "
- "array type");
+ if (!error_emitted && var->type->is_array() &&
+ !state->check_version(140, 0, &loc,
+ "vertex shader input / attribute "
+ "cannot have array type")) {
error_emitted = true;
}
}
* "If a vertex output is a signed or unsigned integer or integer
* vector, then it must be qualified with the interpolation qualifier
* flat."
+ *
+ * From section 4.3.4 of the GLSL 3.00 ES spec:
+ * "Fragment shader inputs that are signed or unsigned integers or
+ * integer vectors must be qualified with the interpolation qualifier
+ * flat."
+ *
+ * Since vertex outputs and fragment inputs must have matching
+ * qualifiers, these two requirements are equivalent.
*/
- if (state->language_version >= 130
+ if (state->is_version(130, 300)
&& state->target == vertex_shader
&& state->current_function == NULL
&& var->type->is_integer()
- && var->mode == ir_var_out
- && var->interpolation != ir_var_flat) {
+ && var->mode == ir_var_shader_out
+ && var->interpolation != INTERP_QUALIFIER_FLAT) {
_mesa_glsl_error(&loc, state, "If a vertex output is an integer, "
"then it must be qualified with 'flat'");
* "interpolation qualifiers may only precede the qualifiers in,
* centroid in, out, or centroid out in a declaration. They do not apply
* to the deprecated storage qualifiers varying or centroid varying."
+ *
+ * These deprecated storage qualifiers do not exist in GLSL ES 3.00.
*/
- if (state->language_version >= 130
+ if (state->is_version(130, 0)
&& this->type->qualifier.has_interpolation()
&& this->type->qualifier.flags.q.varying) {
* "Outputs from a vertex shader (out) and inputs to a fragment
* shader (in) can be further qualified with one or more of these
* interpolation qualifiers"
+ *
+ * From page 31 (page 37 of the PDF) of the GLSL ES 3.00 spec:
+ * "These interpolation qualifiers may only precede the qualifiers
+ * in, centroid in, out, or centroid out in a declaration. They do
+ * not apply to inputs into a vertex shader or outputs from a
+ * fragment shader."
*/
- if (state->language_version >= 130
+ if (state->is_version(130, 300)
&& this->type->qualifier.has_interpolation()) {
const char *i = this->type->qualifier.interpolation_string();
/* From section 4.3.4 of the GLSL 1.30 spec:
* "It is an error to use centroid in in a vertex shader."
+ *
+ * From section 4.3.4 of the GLSL ES 3.00 spec:
+ * "It is an error to use centroid in or interpolation qualifiers in
+ * a vertex shader input."
*/
- if (state->language_version >= 130
+ if (state->is_version(130, 300)
&& this->type->qualifier.flags.q.centroid
&& this->type->qualifier.flags.q.in
&& state->target == vertex_shader) {
/* Precision qualifiers exists only in GLSL versions 1.00 and >= 1.30.
*/
- if (this->type->specifier->precision != ast_precision_none
- && state->language_version != 100
- && state->language_version < 130) {
-
- _mesa_glsl_error(&loc, state,
- "precision qualifiers are supported only in GLSL ES "
- "1.00, and GLSL 1.30 and later");
+ if (this->type->specifier->precision != ast_precision_none) {
+ state->check_precision_qualifiers_allowed(&loc);
}
: "and integer");
}
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "[Sampler types] can only be declared as function
+ * parameters or uniform variables (see Section 4.3.5
+ * "Uniform")".
+ */
+ if (var_type->contains_sampler() &&
+ !this->type->qualifier.flags.q.uniform) {
+ _mesa_glsl_error(&loc, state, "samplers must be declared uniform");
+ }
+
/* Process the initializer and add its instructions to a temporary
* list. This list will be added to the instruction stream (below) after
* the declaration is added. This is done because in some cases (such as
_mesa_glsl_error(& loc, state,
"identifier `%s' uses reserved `gl_' prefix",
decl->identifier);
+ else if (strstr(decl->identifier, "__")) {
+ /* From page 14 (page 20 of the PDF) of the GLSL 1.10
+ * spec:
+ *
+ * "In addition, all identifiers containing two
+ * consecutive underscores (__) are reserved as
+ * possible future keywords."
+ */
+ _mesa_glsl_error(& loc, state,
+ "identifier `%s' uses reserved `__' string",
+ decl->identifier);
+ }
/* Add the variable to the symbol table. Note that the initializer's
* IR was already processed earlier (though it hasn't been emitted
type = process_array_type(&loc, type, this->array_size, state);
}
- if (type->array_size() == 0) {
+ if (!type->is_error() && type->array_size() == 0) {
_mesa_glsl_error(&loc, state, "arrays passed as parameters must have "
"a declared size.");
type = glsl_type::error_type;
}
is_void = false;
- ir_variable *var = new(ctx) ir_variable(type, this->identifier, ir_var_in);
+ ir_variable *var = new(ctx)
+ ir_variable(type, this->identifier, ir_var_function_in);
/* Apply any specified qualifiers to the parameter declaration. Note that
* for function parameters the default mode is 'in'.
*/
- apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc);
+ apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc,
+ false, true);
+
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Samplers cannot be treated as l-values; hence cannot be used
+ * as out or inout function parameters, nor can they be assigned
+ * into."
+ */
+ if ((var->mode == ir_var_function_inout || var->mode == ir_var_function_out)
+ && type->contains_sampler()) {
+ _mesa_glsl_error(&loc, state, "out and inout parameters cannot contain samplers");
+ type = glsl_type::error_type;
+ }
+
+ /* From page 39 (page 45 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "When calling a function, expressions that do not evaluate to
+ * l-values cannot be passed to parameters declared as out or inout."
+ *
+ * From page 32 (page 38 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "Other binary or unary expressions, non-dereferenced arrays,
+ * function names, swizzles with repeated fields, and constants
+ * cannot be l-values."
+ *
+ * So for GLSL 1.10, passing an array as an out or inout parameter is not
+ * allowed. This restriction is removed in GLSL 1.20, and in GLSL ES.
+ */
+ if ((var->mode == ir_var_function_inout || var->mode == ir_var_function_out)
+ && type->is_array()
+ && !state->check_version(120, 100, &loc,
+ "Arrays cannot be out or inout parameters")) {
+ type = glsl_type::error_type;
+ }
instructions->push_tail(var);
void
-emit_function(_mesa_glsl_parse_state *state, exec_list *instructions,
- ir_function *f)
+emit_function(_mesa_glsl_parse_state *state, ir_function *f)
{
- /* Emit the new function header */
- if (state->current_function == NULL) {
- instructions->push_tail(f);
- } else {
- /* IR invariants disallow function declarations or definitions nested
- * within other function definitions. Insert the new ir_function
- * block in the instruction sequence before the ir_function block
- * containing the current ir_function_signature.
- */
- ir_function *const curr =
- const_cast<ir_function *>(state->current_function->function());
-
- curr->insert_before(f);
- }
+ /* IR invariants disallow function declarations or definitions
+ * nested within other function definitions. But there is no
+ * requirement about the relative order of function declarations
+ * and definitions with respect to one another. So simply insert
+ * the new ir_function block at the end of the toplevel instruction
+ * list.
+ */
+ state->toplevel_ir->push_tail(f);
}
const char *const name = identifier;
+ /* New functions are always added to the top-level IR instruction stream,
+ * so this instruction list pointer is ignored. See also emit_function
+ * (called below).
+ */
+ (void) instructions;
+
/* From page 21 (page 27 of the PDF) of the GLSL 1.20 spec,
*
* "Function declarations (prototypes) cannot occur inside of functions;
*
* Note that this language does not appear in GLSL 1.10.
*/
- if ((state->current_function != NULL) && (state->language_version != 110)) {
+ if ((state->current_function != NULL) &&
+ state->is_version(120, 100)) {
YYLTYPE loc = this->get_location();
_mesa_glsl_error(&loc, state,
"declaration of function `%s' not allowed within "
"function `%s' return type has qualifiers", name);
}
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "[Sampler types] can only be declared as function parameters
+ * or uniform variables (see Section 4.3.5 "Uniform")".
+ */
+ if (return_type->contains_sampler()) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state,
+ "function `%s' return type can't contain a sampler",
+ name);
+ }
+
/* Verify that this function's signature either doesn't match a previously
* seen signature for a function with the same name, or, if a match is found,
* that the previously seen signature does not have an associated definition.
return NULL;
}
- emit_function(state, instructions, f);
+ emit_function(state, f);
}
/* Verify the return type of main() */
case ast_break:
case ast_continue:
- /* FINISHME: Handle switch-statements. They cannot contain 'continue',
- * FINISHME: and they use a different IR instruction for 'break'.
- */
- /* FINISHME: Correctly handle the nesting. If a switch-statement is
- * FINISHME: inside a loop, a 'continue' is valid and will bind to the
- * FINISHME: loop.
- */
- if (state->loop_or_switch_nesting == NULL) {
+ if (mode == ast_continue &&
+ state->loop_nesting_ast == NULL) {
YYLTYPE loc = this->get_location();
_mesa_glsl_error(& loc, state,
- "`%s' may only appear in a loop",
- (mode == ast_break) ? "break" : "continue");
- } else {
- ir_loop *const loop = state->loop_or_switch_nesting->as_loop();
+ "continue may only appear in a loop");
+ } else if (mode == ast_break &&
+ state->loop_nesting_ast == NULL &&
+ state->switch_state.switch_nesting_ast == NULL) {
+ YYLTYPE loc = this->get_location();
- /* Inline the for loop expression again, since we don't know
- * where near the end of the loop body the normal copy of it
+ _mesa_glsl_error(& loc, state,
+ "break may only appear in a loop or a switch");
+ } else {
+ /* For a loop, inline the for loop expression again,
+ * since we don't know where near the end of
+ * the loop body the normal copy of it
* is going to be placed.
*/
- if (mode == ast_continue &&
- state->loop_or_switch_nesting_ast->rest_expression) {
- state->loop_or_switch_nesting_ast->rest_expression->hir(instructions,
- state);
+ if (state->loop_nesting_ast != NULL &&
+ mode == ast_continue &&
+ state->loop_nesting_ast->rest_expression) {
+ state->loop_nesting_ast->rest_expression->hir(instructions,
+ state);
}
- if (loop != NULL) {
- ir_loop_jump *const jump =
+ if (state->switch_state.is_switch_innermost &&
+ mode == ast_break) {
+ /* Force break out of switch by setting is_break switch state.
+ */
+ ir_variable *const is_break_var = state->switch_state.is_break_var;
+ ir_dereference_variable *const deref_is_break_var =
+ new(ctx) ir_dereference_variable(is_break_var);
+ ir_constant *const true_val = new(ctx) ir_constant(true);
+ ir_assignment *const set_break_var =
+ new(ctx) ir_assignment(deref_is_break_var, true_val);
+
+ instructions->push_tail(set_break_var);
+ }
+ else {
+ ir_loop_jump *const jump =
new(ctx) ir_loop_jump((mode == ast_break)
? ir_loop_jump::jump_break
: ir_loop_jump::jump_continue);
}
+ir_rvalue *
+ast_switch_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ ir_rvalue *const test_expression =
+ this->test_expression->hir(instructions, state);
+
+ /* From page 66 (page 55 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "The type of init-expression in a switch statement must be a
+ * scalar integer."
+ */
+ if (!test_expression->type->is_scalar() ||
+ !test_expression->type->is_integer()) {
+ YYLTYPE loc = this->test_expression->get_location();
+
+ _mesa_glsl_error(& loc,
+ state,
+ "switch-statement expression must be scalar "
+ "integer");
+ }
+
+ /* Track the switch-statement nesting in a stack-like manner.
+ */
+ struct glsl_switch_state saved = state->switch_state;
+
+ state->switch_state.is_switch_innermost = true;
+ state->switch_state.switch_nesting_ast = this;
+ state->switch_state.labels_ht = hash_table_ctor(0, hash_table_pointer_hash,
+ hash_table_pointer_compare);
+ state->switch_state.previous_default = NULL;
+
+ /* Initalize is_fallthru state to false.
+ */
+ ir_rvalue *const is_fallthru_val = new (ctx) ir_constant(false);
+ state->switch_state.is_fallthru_var =
+ new(ctx) ir_variable(glsl_type::bool_type,
+ "switch_is_fallthru_tmp",
+ ir_var_temporary);
+ instructions->push_tail(state->switch_state.is_fallthru_var);
+
+ ir_dereference_variable *deref_is_fallthru_var =
+ new(ctx) ir_dereference_variable(state->switch_state.is_fallthru_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_is_fallthru_var,
+ is_fallthru_val));
+
+ /* Initalize is_break state to false.
+ */
+ ir_rvalue *const is_break_val = new (ctx) ir_constant(false);
+ state->switch_state.is_break_var = new(ctx) ir_variable(glsl_type::bool_type,
+ "switch_is_break_tmp",
+ ir_var_temporary);
+ instructions->push_tail(state->switch_state.is_break_var);
+
+ ir_dereference_variable *deref_is_break_var =
+ new(ctx) ir_dereference_variable(state->switch_state.is_break_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var,
+ is_break_val));
+
+ /* Cache test expression.
+ */
+ test_to_hir(instructions, state);
+
+ /* Emit code for body of switch stmt.
+ */
+ body->hir(instructions, state);
+
+ hash_table_dtor(state->switch_state.labels_ht);
+
+ state->switch_state = saved;
+
+ /* Switch statements do not have r-values. */
+ return NULL;
+}
+
+
+void
+ast_switch_statement::test_to_hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ /* Cache value of test expression. */
+ ir_rvalue *const test_val =
+ test_expression->hir(instructions,
+ state);
+
+ state->switch_state.test_var = new(ctx) ir_variable(test_val->type,
+ "switch_test_tmp",
+ ir_var_temporary);
+ ir_dereference_variable *deref_test_var =
+ new(ctx) ir_dereference_variable(state->switch_state.test_var);
+
+ instructions->push_tail(state->switch_state.test_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_test_var, test_val));
+}
+
+
+ir_rvalue *
+ast_switch_body::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ if (stmts != NULL)
+ stmts->hir(instructions, state);
+
+ /* Switch bodies do not have r-values. */
+ return NULL;
+}
+
+ir_rvalue *
+ast_case_statement_list::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ foreach_list_typed (ast_case_statement, case_stmt, link, & this->cases)
+ case_stmt->hir(instructions, state);
+
+ /* Case statements do not have r-values. */
+ return NULL;
+}
+
+ir_rvalue *
+ast_case_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ labels->hir(instructions, state);
+
+ /* Conditionally set fallthru state based on break state. */
+ ir_constant *const false_val = new(state) ir_constant(false);
+ ir_dereference_variable *const deref_is_fallthru_var =
+ new(state) ir_dereference_variable(state->switch_state.is_fallthru_var);
+ ir_dereference_variable *const deref_is_break_var =
+ new(state) ir_dereference_variable(state->switch_state.is_break_var);
+ ir_assignment *const reset_fallthru_on_break =
+ new(state) ir_assignment(deref_is_fallthru_var,
+ false_val,
+ deref_is_break_var);
+ instructions->push_tail(reset_fallthru_on_break);
+
+ /* Guard case statements depending on fallthru state. */
+ ir_dereference_variable *const deref_fallthru_guard =
+ new(state) ir_dereference_variable(state->switch_state.is_fallthru_var);
+ ir_if *const test_fallthru = new(state) ir_if(deref_fallthru_guard);
+
+ foreach_list_typed (ast_node, stmt, link, & this->stmts)
+ stmt->hir(& test_fallthru->then_instructions, state);
+
+ instructions->push_tail(test_fallthru);
+
+ /* Case statements do not have r-values. */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_label_list::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ foreach_list_typed (ast_case_label, label, link, & this->labels)
+ label->hir(instructions, state);
+
+ /* Case labels do not have r-values. */
+ return NULL;
+}
+
+ir_rvalue *
+ast_case_label::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ ir_dereference_variable *deref_fallthru_var =
+ new(ctx) ir_dereference_variable(state->switch_state.is_fallthru_var);
+
+ ir_rvalue *const true_val = new(ctx) ir_constant(true);
+
+ /* If not default case, ... */
+ if (this->test_value != NULL) {
+ /* Conditionally set fallthru state based on
+ * comparison of cached test expression value to case label.
+ */
+ ir_rvalue *const label_rval = this->test_value->hir(instructions, state);
+ ir_constant *label_const = label_rval->constant_expression_value();
+
+ if (!label_const) {
+ YYLTYPE loc = this->test_value->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "switch statement case label must be a "
+ "constant expression");
+
+ /* Stuff a dummy value in to allow processing to continue. */
+ label_const = new(ctx) ir_constant(0);
+ } else {
+ ast_expression *previous_label = (ast_expression *)
+ hash_table_find(state->switch_state.labels_ht,
+ (void *)(uintptr_t)label_const->value.u[0]);
+
+ if (previous_label) {
+ YYLTYPE loc = this->test_value->get_location();
+ _mesa_glsl_error(& loc, state,
+ "duplicate case value");
+
+ loc = previous_label->get_location();
+ _mesa_glsl_error(& loc, state,
+ "this is the previous case label");
+ } else {
+ hash_table_insert(state->switch_state.labels_ht,
+ this->test_value,
+ (void *)(uintptr_t)label_const->value.u[0]);
+ }
+ }
+
+ ir_dereference_variable *deref_test_var =
+ new(ctx) ir_dereference_variable(state->switch_state.test_var);
+
+ ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal,
+ label_const,
+ deref_test_var);
+
+ ir_assignment *set_fallthru_on_test =
+ new(ctx) ir_assignment(deref_fallthru_var,
+ true_val,
+ test_cond);
+
+ instructions->push_tail(set_fallthru_on_test);
+ } else { /* default case */
+ if (state->switch_state.previous_default) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(& loc, state,
+ "multiple default labels in one switch");
+
+ loc = state->switch_state.previous_default->get_location();
+ _mesa_glsl_error(& loc, state,
+ "this is the first default label");
+ }
+ state->switch_state.previous_default = this;
+
+ /* Set falltrhu state. */
+ ir_assignment *set_fallthru =
+ new(ctx) ir_assignment(deref_fallthru_var, true_val);
+
+ instructions->push_tail(set_fallthru);
+ }
+
+ /* Case statements do not have r-values. */
+ return NULL;
+}
+
void
ast_iteration_statement::condition_to_hir(ir_loop *stmt,
struct _mesa_glsl_parse_state *state)
* like 'if (!condition) break;' as the loop termination condition.
*/
ir_rvalue *const not_cond =
- new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond,
- NULL);
+ new(ctx) ir_expression(ir_unop_logic_not, cond);
ir_if *const if_stmt = new(ctx) ir_if(not_cond);
ir_loop *const stmt = new(ctx) ir_loop();
instructions->push_tail(stmt);
- /* Track the current loop and / or switch-statement nesting.
- */
- ir_instruction *const nesting = state->loop_or_switch_nesting;
- ast_iteration_statement *nesting_ast = state->loop_or_switch_nesting_ast;
+ /* Track the current loop nesting. */
+ ast_iteration_statement *nesting_ast = state->loop_nesting_ast;
- state->loop_or_switch_nesting = stmt;
- state->loop_or_switch_nesting_ast = this;
+ state->loop_nesting_ast = this;
+
+ /* Likewise, indicate that following code is closest to a loop,
+ * NOT closest to a switch.
+ */
+ bool saved_is_switch_innermost = state->switch_state.is_switch_innermost;
+ state->switch_state.is_switch_innermost = false;
if (mode != ast_do_while)
condition_to_hir(stmt, state);
if (mode != ast_do_while)
state->symbols->pop_scope();
- /* Restore previous nesting before returning.
- */
- state->loop_or_switch_nesting = nesting;
- state->loop_or_switch_nesting_ast = nesting_ast;
+ /* Restore previous nesting before returning. */
+ state->loop_nesting_ast = nesting_ast;
+ state->switch_state.is_switch_innermost = saved_is_switch_innermost;
/* Loops do not have r-values.
*/
YYLTYPE loc = this->get_location();
if (this->precision != ast_precision_none
- && state->language_version != 100
- && state->language_version < 130) {
- _mesa_glsl_error(&loc, state,
- "precision qualifiers exist only in "
- "GLSL ES 1.00, and GLSL 1.30 and later");
+ && !state->check_precision_qualifiers_allowed(&loc)) {
return NULL;
}
if (this->precision != ast_precision_none
"arrays");
return NULL;
}
- if (this->type_specifier != ast_float
- && this->type_specifier != ast_int) {
+ if (strcmp(this->type_name, "float") != 0 &&
+ strcmp(this->type_name, "int") != 0) {
_mesa_glsl_error(&loc, state,
"default precision statements apply only to types "
"float and int");
}
-ir_rvalue *
-ast_struct_specifier::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
+/**
+ * Process a structure or interface block tree into an array of structure fields
+ *
+ * After parsing, where there are some syntax differnces, structures and
+ * interface blocks are almost identical. They are similar enough that the
+ * AST for each can be processed the same way into a set of
+ * \c glsl_struct_field to describe the members.
+ *
+ * \return
+ * The number of fields processed. A pointer to the array structure fields is
+ * stored in \c *fields_ret.
+ */
+unsigned
+ast_process_structure_or_interface_block(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state,
+ exec_list *declarations,
+ YYLTYPE &loc,
+ glsl_struct_field **fields_ret,
+ bool is_interface,
+ bool block_row_major)
{
unsigned decl_count = 0;
- /* Make an initial pass over the list of structure fields to determine how
+ /* Make an initial pass over the list of fields to determine how
* many there are. Each element in this list is an ast_declarator_list.
* This means that we actually need to count the number of elements in the
* 'declarations' list in each of the elements.
*/
- foreach_list_typed (ast_declarator_list, decl_list, link,
- &this->declarations) {
+ foreach_list_typed (ast_declarator_list, decl_list, link, declarations) {
foreach_list_const (decl_ptr, & decl_list->declarations) {
decl_count++;
}
}
- /* Allocate storage for the structure fields and process the field
+ /* Allocate storage for the fields and process the field
* declarations. As the declarations are processed, try to also convert
* the types to HIR. This ensures that structure definitions embedded in
- * other structure definitions are processed.
+ * other structure definitions or in interface blocks are processed.
*/
glsl_struct_field *const fields = ralloc_array(state, glsl_struct_field,
decl_count);
unsigned i = 0;
- foreach_list_typed (ast_declarator_list, decl_list, link,
- &this->declarations) {
+ foreach_list_typed (ast_declarator_list, decl_list, link, declarations) {
const char *type_name;
decl_list->type->specifier->hir(instructions, state);
* embedded structure definitions have been removed from the language.
*/
if (state->es_shader && decl_list->type->specifier->structure != NULL) {
- YYLTYPE loc = this->get_location();
_mesa_glsl_error(&loc, state, "Embedded structure definitions are "
"not allowed in GLSL ES 1.00.");
}
foreach_list_typed (ast_declaration, decl, link,
&decl_list->declarations) {
- const struct glsl_type *field_type = decl_type;
+ /* From the GL_ARB_uniform_buffer_object spec:
+ *
+ * "Sampler types are not allowed inside of uniform
+ * blocks. All other types, arrays, and structures
+ * allowed for uniforms are allowed within a uniform
+ * block."
+ */
+ const struct glsl_type *field_type = decl_type;
+
+ if (is_interface && field_type->contains_sampler()) {
+ YYLTYPE loc = decl_list->get_location();
+ _mesa_glsl_error(&loc, state,
+ "Uniform in non-default uniform block contains sampler\n");
+ }
+
+ const struct ast_type_qualifier *const qual =
+ & decl_list->type->qualifier;
+ if (qual->flags.q.std140 ||
+ qual->flags.q.packed ||
+ qual->flags.q.shared) {
+ _mesa_glsl_error(&loc, state,
+ "uniform block layout qualifiers std140, packed, and "
+ "shared can only be applied to uniform blocks, not "
+ "members");
+ }
+
if (decl->is_array) {
- YYLTYPE loc = decl->get_location();
field_type = process_array_type(&loc, decl_type, decl->array_size,
state);
}
fields[i].type = (field_type != NULL)
? field_type : glsl_type::error_type;
fields[i].name = decl->identifier;
+
+ if (qual->flags.q.row_major || qual->flags.q.column_major) {
+ if (!field_type->is_matrix() && !field_type->is_record()) {
+ _mesa_glsl_error(&loc, state,
+ "uniform block layout qualifiers row_major and "
+ "column_major can only be applied to matrix and "
+ "structure types");
+ } else
+ validate_matrix_layout_for_type(state, &loc, field_type);
+ }
+
+ if (field_type->is_matrix() ||
+ (field_type->is_array() && field_type->fields.array->is_matrix())) {
+ fields[i].row_major = block_row_major;
+ if (qual->flags.q.row_major)
+ fields[i].row_major = true;
+ else if (qual->flags.q.column_major)
+ fields[i].row_major = false;
+ }
+
i++;
}
}
assert(i == decl_count);
+ *fields_ret = fields;
+ return decl_count;
+}
+
+
+ir_rvalue *
+ast_struct_specifier::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ YYLTYPE loc = this->get_location();
+ glsl_struct_field *fields;
+ unsigned decl_count =
+ ast_process_structure_or_interface_block(instructions,
+ state,
+ &this->declarations,
+ loc,
+ &fields,
+ false,
+ false);
+
const glsl_type *t =
glsl_type::get_record_instance(fields, decl_count, this->name);
- YYLTYPE loc = this->get_location();
if (!state->symbols->add_type(name, t)) {
_mesa_glsl_error(& loc, state, "struct `%s' previously defined", name);
} else {
*/
return NULL;
}
+
+ir_rvalue *
+ast_uniform_block::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ YYLTYPE loc = this->get_location();
+
+ /* The ast_uniform_block has a list of ast_declarator_lists. We
+ * need to turn those into ir_variables with an association
+ * with this uniform block.
+ */
+ enum glsl_interface_packing packing;
+ if (this->layout.flags.q.shared) {
+ packing = GLSL_INTERFACE_PACKING_SHARED;
+ } else if (this->layout.flags.q.packed) {
+ packing = GLSL_INTERFACE_PACKING_PACKED;
+ } else {
+ /* The default layout is std140.
+ */
+ packing = GLSL_INTERFACE_PACKING_STD140;
+ }
+
+ bool block_row_major = this->layout.flags.q.row_major;
+ exec_list declared_variables;
+ glsl_struct_field *fields;
+ unsigned int num_variables =
+ ast_process_structure_or_interface_block(&declared_variables,
+ state,
+ &this->declarations,
+ loc,
+ &fields,
+ true,
+ block_row_major);
+
+ const glsl_type *block_type =
+ glsl_type::get_interface_instance(fields,
+ num_variables,
+ packing,
+ this->block_name);
+
+ if (!state->symbols->add_type(block_type->name, block_type)) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state, "Uniform block name `%s' already taken in "
+ "the current scope.\n", this->block_name);
+ }
+
+ /* Since interface blocks cannot contain statements, it should be
+ * impossible for the block to generate any instructions.
+ */
+ assert(declared_variables.is_empty());
+
+ /* Page 39 (page 45 of the PDF) of section 4.3.7 in the GLSL ES 3.00 spec
+ * says:
+ *
+ * "If an instance name (instance-name) is used, then it puts all the
+ * members inside a scope within its own name space, accessed with the
+ * field selector ( . ) operator (analogously to structures)."
+ */
+ if (this->instance_name) {
+ ir_variable *var;
+
+ if (this->array_size != NULL) {
+ const glsl_type *block_array_type =
+ process_array_type(&loc, block_type, this->array_size, state);
+
+ var = new(state) ir_variable(block_array_type,
+ this->instance_name,
+ ir_var_uniform);
+ } else {
+ var = new(state) ir_variable(block_type,
+ this->instance_name,
+ ir_var_uniform);
+ }
+
+ var->interface_type = block_type;
+ state->symbols->add_variable(var);
+ instructions->push_tail(var);
+ } else {
+ /* In order to have an array size, the block must also be declared with
+ * an instane name.
+ */
+ assert(this->array_size == NULL);
+
+ for (unsigned i = 0; i < num_variables; i++) {
+ ir_variable *var =
+ new(state) ir_variable(fields[i].type,
+ ralloc_strdup(state, fields[i].name),
+ ir_var_uniform);
+ var->interface_type = block_type;
+
+ state->symbols->add_variable(var);
+ instructions->push_tail(var);
+ }
+ }
+
+ return NULL;
+}
+
+static void
+detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
+ exec_list *instructions)
+{
+ bool gl_FragColor_assigned = false;
+ bool gl_FragData_assigned = false;
+ bool user_defined_fs_output_assigned = false;
+ ir_variable *user_defined_fs_output = NULL;
+
+ /* It would be nice to have proper location information. */
+ YYLTYPE loc;
+ memset(&loc, 0, sizeof(loc));
+
+ foreach_list(node, instructions) {
+ ir_variable *var = ((ir_instruction *)node)->as_variable();
+
+ if (!var || !var->assigned)
+ continue;
+
+ if (strcmp(var->name, "gl_FragColor") == 0)
+ gl_FragColor_assigned = true;
+ else if (strcmp(var->name, "gl_FragData") == 0)
+ gl_FragData_assigned = true;
+ else if (strncmp(var->name, "gl_", 3) != 0) {
+ if (state->target == fragment_shader &&
+ var->mode == ir_var_shader_out) {
+ user_defined_fs_output_assigned = true;
+ user_defined_fs_output = var;
+ }
+ }
+ }
+
+ /* From the GLSL 1.30 spec:
+ *
+ * "If a shader statically assigns a value to gl_FragColor, it
+ * may not assign a value to any element of gl_FragData. If a
+ * shader statically writes a value to any element of
+ * gl_FragData, it may not assign a value to
+ * gl_FragColor. That is, a shader may assign values to either
+ * gl_FragColor or gl_FragData, but not both. Multiple shaders
+ * linked together must also consistently write just one of
+ * these variables. Similarly, if user declared output
+ * variables are in use (statically assigned to), then the
+ * built-in variables gl_FragColor and gl_FragData may not be
+ * assigned to. These incorrect usages all generate compile
+ * time errors."
+ */
+ if (gl_FragColor_assigned && gl_FragData_assigned) {
+ _mesa_glsl_error(&loc, state, "fragment shader writes to both "
+ "`gl_FragColor' and `gl_FragData'\n");
+ } else if (gl_FragColor_assigned && user_defined_fs_output_assigned) {
+ _mesa_glsl_error(&loc, state, "fragment shader writes to both "
+ "`gl_FragColor' and `%s'\n",
+ user_defined_fs_output->name);
+ } else if (gl_FragData_assigned && user_defined_fs_output_assigned) {
+ _mesa_glsl_error(&loc, state, "fragment shader writes to both "
+ "`gl_FragData' and `%s'\n",
+ user_defined_fs_output->name);
+ }
+}