X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fast_to_hir.cpp;h=49093d88f8e6f8a215397978364eccb2dad0940a;hb=9add4e803877f97ad7f6d479d81d537426f09b6f;hp=2025911acd35d2f51e262dac7730b8a804a5c4d0;hpb=d4144a123b603d3c33cb356cf3c8e5ae4653594e;p=mesa.git diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 2025911acd3..49093d88f8e 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -54,15 +54,19 @@ #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; @@ -87,6 +91,7 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) ast->hir(instructions, state); detect_recursion_unlinked(state, instructions); + detect_conflicting_assignments(state, instructions); state->toplevel_ir = NULL; } @@ -116,7 +121,7 @@ apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from, /* 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: @@ -385,8 +390,7 @@ bit_logic_result_type(const struct glsl_type *type_a, 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; } @@ -441,10 +445,7 @@ modulus_result_type(const struct glsl_type *type_a, 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; } @@ -548,8 +549,7 @@ shift_result_type(const struct glsl_type *type_a, 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; } @@ -653,32 +653,58 @@ validate_assignment(struct _mesa_glsl_parse_state *state, 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 = @@ -713,6 +739,8 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, 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, @@ -729,13 +757,11 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, 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); } @@ -752,12 +778,7 @@ get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue) 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); } @@ -773,16 +794,6 @@ ast_node::hir(exec_list *instructions, 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) { @@ -846,14 +857,11 @@ 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) @@ -892,6 +900,66 @@ get_scalar_boolean_operand(exec_list *instructions, 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) @@ -965,7 +1033,9 @@ ast_expression::hir(exec_list *instructions, 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; @@ -1023,9 +1093,7 @@ ast_expression::hir(exec_list *instructions, 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; } @@ -1079,10 +1147,9 @@ ast_expression::hir(exec_list *instructions, _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; } @@ -1109,8 +1176,7 @@ ast_expression::hir(exec_list *instructions, 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; } @@ -1119,7 +1185,7 @@ ast_expression::hir(exec_list *instructions, 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; @@ -1130,15 +1196,9 @@ ast_expression::hir(exec_list *instructions, 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", @@ -1151,12 +1211,12 @@ ast_expression::hir(exec_list *instructions, 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); @@ -1172,14 +1232,9 @@ ast_expression::hir(exec_list *instructions, 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", @@ -1191,13 +1246,13 @@ ast_expression::hir(exec_list *instructions, 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); @@ -1245,6 +1300,7 @@ ast_expression::hir(exec_list *instructions, 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()); @@ -1270,6 +1326,7 @@ ast_expression::hir(exec_list *instructions, 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(); @@ -1284,8 +1341,9 @@ ast_expression::hir(exec_list *instructions, &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; @@ -1300,8 +1358,9 @@ ast_expression::hir(exec_list *instructions, 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; @@ -1355,9 +1414,10 @@ ast_expression::hir(exec_list *instructions, * "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; } @@ -1381,14 +1441,14 @@ ast_expression::hir(exec_list *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); 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); @@ -1398,11 +1458,11 @@ ast_expression::hir(exec_list *instructions, 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); @@ -1411,6 +1471,7 @@ ast_expression::hir(exec_list *instructions, 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(); @@ -1419,11 +1480,10 @@ ast_expression::hir(exec_list *instructions, 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(); @@ -1439,6 +1499,7 @@ ast_expression::hir(exec_list *instructions, 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()); @@ -1549,11 +1610,27 @@ ast_expression::hir(exec_list *instructions, * 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 @@ -1583,15 +1660,18 @@ ast_expression::hir(exec_list *instructions, 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 " @@ -1622,14 +1702,14 @@ ast_expression::hir(exec_list *instructions, 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; @@ -1762,7 +1842,17 @@ process_array_type(YYLTYPE *loc, const glsl_type *base, ast_node *array_size, { 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; @@ -1826,11 +1916,61 @@ ast_type_specifier::glsl_type(const char **name, } +/** + * 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) { @@ -1859,64 +1999,106 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, _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; @@ -1944,7 +2126,7 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, */ 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"; } @@ -1957,7 +2139,7 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, 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"; } @@ -1987,14 +2169,36 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, } 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? @@ -2012,6 +2216,7 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, * 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 @@ -2044,9 +2249,11 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, + 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) { @@ -2070,8 +2277,23 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, 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); } } @@ -2120,18 +2342,9 @@ get_variable_being_redeclared(ir_variable *var, ast_declaration *decl, * 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); @@ -2160,7 +2373,7 @@ get_variable_being_redeclared(ir_variable *var, ast_declaration *decl, * * 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 @@ -2172,7 +2385,8 @@ get_variable_being_redeclared(ir_variable *var, ast_declaration *decl, 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) { @@ -2226,10 +2440,9 @@ process_initializer(ir_variable *var, ast_declaration *decl, * 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()) { @@ -2237,7 +2450,7 @@ process_initializer(ir_variable *var, ast_declaration *decl, "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), @@ -2296,12 +2509,16 @@ process_initializer(ir_variable *var, ast_declaration *decl, 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 * @@ -2372,12 +2589,12 @@ ast_declarator_list::hir(exec_list *instructions, "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); @@ -2406,14 +2623,32 @@ ast_declarator_list::hir(exec_list *instructions, decl_type = this->type->specifier->glsl_type(& type_name, state); if (this->declarations.is_empty()) { - if (decl_type != NULL) { - /* Warn if this empty declaration is not for declaring a structure. - */ - if (this->type->specifier->structure == NULL) { + /* 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. + */ + 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); } - } else { - _mesa_glsl_error(& loc, state, "incomplete declaration"); } } @@ -2441,6 +2676,8 @@ ast_declarator_list::hir(exec_list *instructions, 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; } @@ -2455,41 +2692,38 @@ ast_declarator_list::hir(exec_list *instructions, * * 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 */ @@ -2526,7 +2760,7 @@ ast_declarator_list::hir(exec_list *instructions, "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) { @@ -2550,6 +2784,13 @@ ast_declarator_list::hir(exec_list *instructions, * "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; @@ -2559,7 +2800,7 @@ ast_declarator_list::hir(exec_list *instructions, break; case GLSL_TYPE_UINT: case GLSL_TYPE_INT: - if (state->language_version > 120) + if (state->is_version(120, 300)) break; /* FALLTHROUGH */ default: @@ -2571,11 +2812,10 @@ ast_declarator_list::hir(exec_list *instructions, 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; } } @@ -2587,13 +2827,21 @@ ast_declarator_list::hir(exec_list *instructions, * "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'"); @@ -2607,8 +2855,10 @@ ast_declarator_list::hir(exec_list *instructions, * "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) { @@ -2633,8 +2883,14 @@ ast_declarator_list::hir(exec_list *instructions, * "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(); @@ -2663,8 +2919,12 @@ ast_declarator_list::hir(exec_list *instructions, /* 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) { @@ -2676,13 +2936,8 @@ ast_declarator_list::hir(exec_list *instructions, /* 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); } @@ -2766,6 +3021,18 @@ ast_declarator_list::hir(exec_list *instructions, _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 @@ -2870,19 +3137,21 @@ ast_parameter_declarator::hir(exec_list *instructions, 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: * @@ -2890,12 +3159,33 @@ ast_parameter_declarator::hir(exec_list *instructions, * as out or inout function parameters, nor can they be assigned * into." */ - if ((var->mode == ir_var_inout || var->mode == ir_var_out) + 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); /* Parameter declarations do not have r-values. @@ -2957,6 +3247,12 @@ ast_function::hir(exec_list *instructions, 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; @@ -2969,7 +3265,8 @@ ast_function::hir(exec_list *instructions, * * 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 " @@ -3229,34 +3526,47 @@ ast_jump_statement::hir(exec_list *instructions, 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); @@ -3319,6 +3629,256 @@ ast_selection_statement::hir(exec_list *instructions, } +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) @@ -3340,8 +3900,7 @@ ast_iteration_statement::condition_to_hir(ir_loop *stmt, * 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); @@ -3372,13 +3931,16 @@ ast_iteration_statement::hir(exec_list *instructions, 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_nesting_ast = this; - state->loop_or_switch_nesting = stmt; - state->loop_or_switch_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); @@ -3395,10 +3957,9 @@ ast_iteration_statement::hir(exec_list *instructions, 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. */ @@ -3416,11 +3977,7 @@ ast_type_specifier::hir(exec_list *instructions, 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 @@ -3450,8 +4007,8 @@ ast_type_specifier::hir(exec_list *instructions, "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"); @@ -3469,35 +4026,50 @@ ast_type_specifier::hir(exec_list *instructions, } -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); @@ -3506,7 +4078,6 @@ ast_struct_specifier::hir(exec_list *instructions, * 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."); } @@ -3516,25 +4087,88 @@ ast_struct_specifier::hir(exec_list *instructions, 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 { @@ -3552,3 +4186,161 @@ ast_struct_specifier::hir(exec_list *instructions, */ 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); + } +}