X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fast_to_hir.cpp;h=762f802c2b76ddeb08f56062e7d28fb44a533542;hb=222d2f2ac2c7d93cbc0643082c78278ad2c8cfce;hp=3de754fa818064b8096b896a5ae1e8883cf7070a;hpb=d4d630b72c7b7f38074addda0f1b819608247d93;p=mesa.git diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 3de754fa818..762f802c2b7 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -49,7 +49,7 @@ * parser (and lexer) sources. */ -#include "main/imports.h" +#include "main/core.h" /* for struct gl_extensions */ #include "glsl_symbol_table.h" #include "glsl_parser_extras.h" #include "ast.h" @@ -64,6 +64,21 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) state->current_function = NULL; + /* 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, + * available for user-defined functions and global variables, is nested + * inside the scope containing the built-in functions." + * + * Since built-in functions like ftransform() access built-in variables, + * it follows that those must be in the outer scope as well. + * + * We push scope here to create this nesting effect...but don't pop. + * This way, a shader's globals are still in the symbol table for use + * by the linker. + */ + state->symbols->push_scope(); + foreach_list_typed (ast_node, ast, link, & state->translation_unit) ast->hir(instructions, state); } @@ -82,7 +97,7 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) * If a conversion is possible (or unnecessary), \c true is returned. * Otherwise \c false is returned. */ -static bool +bool apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from, struct _mesa_glsl_parse_state *state) { @@ -282,8 +297,17 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, * means the vector type of a row from A must be the same as the * vector the type of B. */ - if (type_a->row_type() == type_b) - return type_b; + if (type_a->row_type() == type_b) { + /* The resulting vector has a number of elements equal to + * the number of rows of matrix A. */ + const glsl_type *const type = + glsl_type::get_instance(type_a->base_type, + type_a->column_type()->vector_elements, + 1); + assert(type != glsl_type::error_type); + + return type; + } } else { assert(type_b->is_matrix()); @@ -292,8 +316,17 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, * the type of A must be the same as the vector type of a column from * B. */ - if (type_a == type_b->column_type()) - return type_a; + if (type_a == type_b->column_type()) { + /* The resulting vector has a number of elements equal to + * the number of columns of matrix B. */ + const glsl_type *const type = + glsl_type::get_instance(type_a->base_type, + type_b->row_type()->vector_elements, + 1); + assert(type != glsl_type::error_type); + + return type; + } } _mesa_glsl_error(loc, state, "size mismatch for matrix multiplication"); @@ -477,7 +510,6 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, bool error_emitted = (lhs->type->is_error() || rhs->type->is_error()); if (!error_emitted) { - /* FINISHME: This does not handle 'foo.bar.a.b.c[5].d = 5' */ if (!lhs->is_lvalue()) { _mesa_glsl_error(& lhs_loc, state, "non-lvalue in assignment"); error_emitted = true; @@ -511,9 +543,9 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, var->max_array_access); } - var->type = glsl_type::get_array_instance(state, - lhs->type->element_type(), + var->type = glsl_type::get_array_instance(lhs->type->element_type(), rhs->type->array_size()); + d->type = var->type; } } @@ -527,7 +559,8 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, * temporary and return a deref of that temporary. If the rvalue * ends up not being used, the temp will get copy-propagated out. */ - ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp"); + ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp", + 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, @@ -535,42 +568,21 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, NULL)); deref_var = new(ctx) ir_dereference_variable(var); - instructions->push_tail(new(ctx) ir_assignment(lhs, - deref_var, - NULL)); + if (!error_emitted) + instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var, NULL)); return new(ctx) ir_dereference_variable(var); } - -/** - * Generate a new temporary and add its declaration to the instruction stream - */ -static ir_variable * -generate_temporary(const glsl_type *type, exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - void *ctx = state; - char *name = (char *) malloc(sizeof(char) * 13); - - snprintf(name, 13, "tmp_%08X", state->temp_index); - state->temp_index++; - - ir_variable *const var = new(ctx) ir_variable(type, name); - instructions->push_tail(var); - - return var; -} - - static ir_rvalue * get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue) { void *ctx = talloc_parent(lvalue); ir_variable *var; - /* FINISHME: Give unique names to the temporaries. */ - var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp"); + var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp", + ir_var_temporary); + instructions->push_tail(var); var->mode = ir_var_auto; instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var), @@ -657,7 +669,7 @@ ast_expression::hir(exec_list *instructions, -1, /* ast_sequence doesn't convert to ir_expression. */ }; ir_rvalue *result = NULL; - ir_rvalue *op[2]; + ir_rvalue *op[3]; const struct glsl_type *type = glsl_type::error_type; bool error_emitted = false; YYLTYPE loc; @@ -679,9 +691,9 @@ ast_expression::hir(exec_list *instructions, case ast_plus: op[0] = this->subexpressions[0]->hir(instructions, state); - error_emitted = op[0]->type->is_error(); - if (type->is_error()) - op[0]->type = type; + type = unary_arithmetic_result_type(op[0]->type, state, & loc); + + error_emitted = type->is_error(); result = op[0]; break; @@ -790,9 +802,60 @@ ast_expression::hir(exec_list *instructions, case ast_bit_and: case ast_bit_xor: case ast_bit_or: + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + if (state->language_version < 130) { + _mesa_glsl_error(&loc, state, "bit-wise operations require GLSL 1.30"); + error_emitted = true; + } + + if (!op[0]->type->is_integer()) { + _mesa_glsl_error(&loc, state, "LHS of `%s' must be an integer", + operator_string(this->oper)); + error_emitted = true; + } + + if (!op[1]->type->is_integer()) { + _mesa_glsl_error(&loc, state, "RHS of `%s' must be an integer", + operator_string(this->oper)); + error_emitted = true; + } + + if (op[0]->type->base_type != op[1]->type->base_type) { + _mesa_glsl_error(&loc, state, "operands of `%s' must have the same " + "base type", operator_string(this->oper)); + error_emitted = true; + } + + if (op[0]->type->is_vector() && op[1]->type->is_vector() + && op[0]->type->vector_elements != op[1]->type->vector_elements) { + _mesa_glsl_error(&loc, state, "operands of `%s' cannot be vectors of " + "different sizes", operator_string(this->oper)); + error_emitted = true; + } + + type = op[0]->type->is_scalar() ? op[1]->type : op[0]->type; + result = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); + break; + case ast_bit_not: - _mesa_glsl_error(& loc, state, "FINISHME: implement bit-wise operators"); - error_emitted = true; + 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"); + error_emitted = true; + } + + if (!op[0]->type->is_integer()) { + _mesa_glsl_error(&loc, state, "operand of `~' must be an integer"); + error_emitted = true; + } + + type = op[0]->type; + result = new(ctx) ir_expression(ir_unop_bit_not, type, op[0], NULL); break; case ast_logic_and: { @@ -825,6 +888,11 @@ ast_expression::hir(exec_list *instructions, } type = glsl_type::bool_type; } else { + ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type, + "and_tmp", + ir_var_temporary); + instructions->push_tail(tmp); + ir_if *const stmt = new(ctx) ir_if(op[0]); instructions->push_tail(stmt); @@ -839,9 +907,6 @@ ast_expression::hir(exec_list *instructions, error_emitted = true; } - ir_variable *const tmp = generate_temporary(glsl_type::bool_type, - instructions, state); - 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); @@ -888,13 +953,15 @@ ast_expression::hir(exec_list *instructions, } type = glsl_type::bool_type; } else { + ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type, + "or_tmp", + ir_var_temporary); + instructions->push_tail(tmp); + ir_if *const stmt = new(ctx) ir_if(op[0]); instructions->push_tail(stmt); - ir_variable *const tmp = generate_temporary(glsl_type::bool_type, - instructions, state); - - op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state); + op[1] = this->subexpressions[1]->hir(&stmt->else_instructions, state); if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[1]->get_location(); @@ -961,7 +1028,7 @@ ast_expression::hir(exec_list *instructions, op[0], op[1]); result = do_assignment(instructions, state, - op[0]->clone(NULL), temp_rhs, + op[0]->clone(ctx, NULL), temp_rhs, this->subexpressions[0]->get_location()); type = result->type; error_emitted = (op[0]->type->is_error()); @@ -982,12 +1049,12 @@ ast_expression::hir(exec_list *instructions, assert(operations[this->oper] == ir_binop_mod); - struct ir_rvalue *temp_rhs; + ir_rvalue *temp_rhs; temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); result = do_assignment(instructions, state, - op[0]->clone(NULL), temp_rhs, + op[0]->clone(ctx, NULL), temp_rhs, this->subexpressions[0]->get_location()); type = result->type; error_emitted = type->is_error(); @@ -1067,8 +1134,9 @@ ast_expression::hir(exec_list *instructions, && (cond_val != NULL) && (then_val != NULL) && (else_val != NULL)) { result = (cond_val->value.b[0]) ? then_val : else_val; } else { - ir_variable *const tmp = generate_temporary(type, - instructions, state); + ir_variable *const tmp = + new(ctx) ir_variable(type, "conditional_tmp", ir_var_temporary); + instructions->push_tail(tmp); ir_if *const stmt = new(ctx) ir_if(op[0]); instructions->push_tail(stmt); @@ -1102,12 +1170,12 @@ ast_expression::hir(exec_list *instructions, type = arithmetic_result_type(op[0], op[1], false, state, & loc); - struct ir_rvalue *temp_rhs; + ir_rvalue *temp_rhs; temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); result = do_assignment(instructions, state, - op[0]->clone(NULL), temp_rhs, + op[0]->clone(ctx, NULL), temp_rhs, this->subexpressions[0]->get_location()); type = result->type; error_emitted = op[0]->type->is_error(); @@ -1126,17 +1194,17 @@ ast_expression::hir(exec_list *instructions, type = arithmetic_result_type(op[0], op[1], false, state, & loc); - struct ir_rvalue *temp_rhs; + ir_rvalue *temp_rhs; temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); /* Get a temporary of a copy of the lvalue before it's modified. * This may get thrown away later. */ - result = get_lvalue_copy(instructions, op[0]->clone(NULL)); + result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL)); (void)do_assignment(instructions, state, - op[0]->clone(NULL), temp_rhs, + op[0]->clone(ctx, NULL), temp_rhs, this->subexpressions[0]->get_location()); type = result->type; @@ -1251,6 +1319,19 @@ ast_expression::hir(exec_list *instructions, if ((v != NULL) && (unsigned(idx) > v->max_array_access)) v->max_array_access = idx; } + } else if (array->type->array_size() == 0) { + _mesa_glsl_error(&loc, state, "unsized array index must be constant"); + } else { + if (array->type->is_array()) { + /* whole_variable_referenced can return NULL if the array is a + * member of a structure. In this case it is safe to not update + * the max_array_access field because it is never used for fields + * of structures. + */ + ir_variable *v = array->whole_variable_referenced(); + if (v != NULL) + v->max_array_access = array->type->array_size(); + } } if (error_emitted) @@ -1418,7 +1499,7 @@ process_array_type(const glsl_type *base, ast_node *array_size, } } - return glsl_type::get_array_instance(state, base, length); + return glsl_type::get_array_instance(base, length); } @@ -1446,7 +1527,7 @@ ast_type_specifier::glsl_type(const char **name, static void apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, - struct ir_variable *var, + ir_variable *var, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { @@ -1490,6 +1571,9 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, } } + /* If there is no qualifier that changes the mode of the variable, leave + * the setting alone. + */ if (qual->in && qual->out) var->mode = ir_var_inout; else if (qual->attribute || qual->in @@ -1499,33 +1583,6 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->mode = ir_var_out; else if (qual->uniform) var->mode = ir_var_uniform; - else - var->mode = ir_var_auto; - - if (qual->uniform) - var->shader_in = true; - - /* Any 'in' or 'inout' variables at global scope must be marked as being - * shader inputs. Likewise, any 'out' or 'inout' variables at global scope - * must be marked as being shader outputs. - */ - if (state->current_function == NULL) { - switch (var->mode) { - case ir_var_in: - case ir_var_uniform: - var->shader_in = true; - break; - case ir_var_out: - var->shader_out = true; - break; - case ir_var_inout: - var->shader_in = true; - var->shader_out = true; - break; - default: - break; - } - } if (qual->flat) var->interpolation = ir_var_flat; @@ -1534,6 +1591,19 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, else var->interpolation = ir_var_smooth; + var->pixel_center_integer = qual->pixel_center_integer; + var->origin_upper_left = qual->origin_upper_left; + if ((qual->origin_upper_left || qual->pixel_center_integer) + && (strcmp(var->name, "gl_FragCoord") != 0)) { + const char *const qual_string = (qual->origin_upper_left) + ? "origin_upper_left" : "pixel_center_integer"; + + _mesa_glsl_error(loc, state, + "layout qualifier `%s' can only be applied to " + "fragment shader input `gl_FragCoord'", + qual_string); + } + if (var->type->is_array() && (state->language_version >= 120)) { var->array_lvalue = true; } @@ -1624,7 +1694,7 @@ ast_declarator_list::hir(exec_list *instructions, foreach_list_typed (ast_declaration, decl, link, &this->declarations) { const struct glsl_type *var_type; - struct ir_variable *var; + ir_variable *var; /* FINISHME: Emit a warning if a variable declaration shadows a * FINISHME: declaration at a higher scope. @@ -1649,7 +1719,7 @@ ast_declarator_list::hir(exec_list *instructions, var_type = decl_type; } - var = new(ctx) ir_variable(var_type, decl->identifier); + var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto); /* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification; * @@ -1681,11 +1751,19 @@ ast_declarator_list::hir(exec_list *instructions, & loc); if (this->type->qualifier.invariant) { - if ((state->target == vertex_shader) && !var->shader_out) { + 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 + */ _mesa_glsl_error(& loc, state, "`%s' cannot be marked invariant, vertex shader " "outputs only\n", var->name); - } else if ((state->target == fragment_shader) && !var->shader_in) { + } else if ((state->target == fragment_shader) && + !(var->mode == ir_var_in || var->mode == ir_var_inout)) { + /* FINISHME: Note that this doesn't work for invariant on + * a function signature inval + */ _mesa_glsl_error(& loc, state, "`%s' cannot be marked invariant, fragment shader " "inputs only\n", var->name); @@ -1772,8 +1850,13 @@ ast_declarator_list::hir(exec_list *instructions, } } - instructions->push_tail(var); - + /* 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 + * redeclarations) the declaration may not actually be added to the + * instruction stream. + */ + exec_list initializer_instructions; if (decl->initializer != NULL) { YYLTYPE initializer_loc = decl->initializer->get_location(); @@ -1803,23 +1886,42 @@ ast_declarator_list::hir(exec_list *instructions, } ir_dereference *const lhs = new(ctx) ir_dereference_variable(var); - ir_rvalue *rhs = decl->initializer->hir(instructions, state); + ir_rvalue *rhs = decl->initializer->hir(&initializer_instructions, + state); /* Calculate the constant value if this is a const or uniform * declaration. */ if (this->type->qualifier.constant || this->type->qualifier.uniform) { - ir_constant *constant_value = rhs->constant_expression_value(); - if (!constant_value) { - _mesa_glsl_error(& initializer_loc, state, - "initializer of %s variable `%s' must be a " - "constant expression", - (this->type->qualifier.constant) - ? "const" : "uniform", - decl->identifier); + ir_rvalue *new_rhs = validate_assignment(state, var->type, rhs); + if (new_rhs != NULL) { + rhs = new_rhs; + + ir_constant *constant_value = rhs->constant_expression_value(); + if (!constant_value) { + _mesa_glsl_error(& initializer_loc, state, + "initializer of %s variable `%s' must be a " + "constant expression", + (this->type->qualifier.constant) + ? "const" : "uniform", + decl->identifier); + if (var->type->is_numeric()) { + /* Reduce cascading errors. */ + var->constant_value = ir_constant::zero(ctx, var->type); + } + } else { + rhs = constant_value; + var->constant_value = constant_value; + } } else { - rhs = constant_value; - var->constant_value = constant_value; + _mesa_glsl_error(&initializer_loc, state, + "initializer of type %s cannot be assigned to " + "variable of type %s", + rhs->type->name, var->type->name); + if (var->type->is_numeric()) { + /* Reduce cascading errors. */ + var->constant_value = ir_constant::zero(ctx, var->type); + } } } @@ -1831,7 +1933,8 @@ ast_declarator_list::hir(exec_list *instructions, /* Never emit code to initialize a uniform. */ if (!this->type->qualifier.uniform) - result = do_assignment(instructions, state, lhs, rhs, + result = do_assignment(&initializer_instructions, state, + lhs, rhs, this->get_location()); var->read_only = temp; } @@ -1848,22 +1951,23 @@ ast_declarator_list::hir(exec_list *instructions, "const declaration of `%s' must be initialized"); } - /* Attempt to add the variable to the symbol table. If this fails, it - * means the variable has already been declared at this scope. Arrays - * fudge this rule a little bit. - * - * From page 24 (page 30 of the PDF) of the GLSL 1.50 spec, + /* Check if this declaration is actually a re-declaration, either to + * resize an array or add qualifiers to an existing variable. * - * "It is legal to declare an array without a size and then - * later re-declare the same name as an array of the same - * type and specify a size." + * This is allowed for variables in the current scope, or when at + * global scope (for built-ins in the implicit outer scope). */ - if (state->symbols->name_declared_this_scope(decl->identifier)) { - ir_variable *const earlier = - state->symbols->get_variable(decl->identifier); + ir_variable *earlier = state->symbols->get_variable(decl->identifier); + if (earlier != NULL && (state->current_function == NULL || + state->symbols->name_declared_this_scope(decl->identifier))) { - if ((earlier != NULL) - && (earlier->type->array_size() == 0) + /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec, + * + * "It is legal to declare an array without a size and then + * later re-declare the same name as an array of the same + * type and specify a size." + */ + if ((earlier->type->array_size() == 0) && var->type->is_array() && (var->type->element_type() == earlier->type->element_type())) { /* FINISHME: This doesn't match the qualifiers on the two @@ -1895,32 +1999,41 @@ ast_declarator_list::hir(exec_list *instructions, earlier->type = var->type; delete var; var = NULL; + } else if (state->extensions->ARB_fragment_coord_conventions + && strcmp(var->name, "gl_FragCoord") == 0 + && earlier->type == var->type + && earlier->mode == var->mode) { + /* Allow redeclaration of gl_FragCoord for ARB_fcc layout + * qualifiers. + */ + earlier->origin_upper_left = var->origin_upper_left; + earlier->pixel_center_integer = var->pixel_center_integer; } else { YYLTYPE loc = this->get_location(); - - _mesa_glsl_error(& loc, state, "`%s' redeclared", - decl->identifier); + _mesa_glsl_error(&loc, state, "`%s' redeclared", decl->identifier); } continue; } - /* From page 15 (page 21 of the PDF) of the GLSL 1.10 spec, + /* By now, we know it's a new variable declaration (we didn't hit the + * above "continue"). + * + * From page 15 (page 21 of the PDF) of the GLSL 1.10 spec, * * "Identifiers starting with "gl_" are reserved for use by * OpenGL, and may not be declared in a shader as either a * variable or a function." */ - if (strncmp(decl->identifier, "gl_", 3) == 0) { - /* FINISHME: This should only trigger if we're not redefining - * FINISHME: a builtin (to add a qualifier, for example). - */ + if (strncmp(decl->identifier, "gl_", 3) == 0) _mesa_glsl_error(& loc, state, "identifier `%s' uses reserved `gl_' prefix", decl->identifier); - } - /* Add the variable to the symbol table after processing the initializer. + /* Add the variable to the symbol table. Note that the initializer's + * IR was already processed earlier (though it hasn't been emitted yet), + * without the variable in scope. + * * This differs from most C-like languages, but it follows the GLSL * specification. From page 28 (page 34 of the PDF) of the GLSL 1.50 * spec: @@ -1929,9 +2042,22 @@ ast_declarator_list::hir(exec_list *instructions, * after the initializer if present or immediately after the name * being declared if not." */ - const bool added_variable = - state->symbols->add_variable(var->name, var); - assert(added_variable); + if (!state->symbols->add_variable(var->name, var)) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, "name `%s' already taken in the " + "current scope", decl->identifier); + continue; + } + + /* Push the variable declaration to the top. It means that all + * the variable declarations will appear in a funny + * last-to-first order, but otherwise we run into trouble if a + * function is prototyped, a global var is decled, then the + * function is defined with usage of the global var. See + * glslparsertest's CorrectModule.frag. + */ + instructions->push_head(var); + instructions->append_list(&initializer_instructions); } @@ -1999,19 +2125,26 @@ ast_parameter_declarator::hir(exec_list *instructions, return NULL; } - is_void = false; - ir_variable *var = new(ctx) ir_variable(type, this->identifier); - - /* FINISHME: Handle array declarations. Note that this requires - * FINISHME: complete handling of constant expressions. + /* This only handles "vec4 foo[..]". The earlier specifier->glsl_type(...) + * call already handled the "vec4[..] foo" case. */ + if (this->is_array) { + type = process_array_type(type, this->array_size, state); + } + + if (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); /* 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); - if (var->mode == ir_var_auto) - var->mode = ir_var_in; instructions->push_tail(var); @@ -2060,6 +2193,37 @@ ast_function::hir(exec_list *instructions, const char *const name = identifier; + /* From page 21 (page 27 of the PDF) of the GLSL 1.20 spec, + * + * "Function declarations (prototypes) cannot occur inside of functions; + * they must be at global scope, or for the built-in functions, outside + * the global scope." + * + * From page 27 (page 33 of the PDF) of the GLSL ES 1.00.16 spec, + * + * "User defined functions may only be defined within the global scope." + * + * Note that this language does not appear in GLSL 1.10. + */ + if ((state->current_function != NULL) && (state->language_version != 110)) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, + "declaration of function `%s' not allowed within " + "function body", name); + } + + /* From page 15 (page 21 of the PDF) of the GLSL 1.10 spec, + * + * "Identifiers starting with "gl_" are reserved for use by + * OpenGL, and may not be declared in a shader as either a + * variable or a function." + */ + if (strncmp(name, "gl_", 3) == 0) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, + "identifier `%s' uses reserved `gl_' prefix", name); + } + /* Convert the list of function parameters to HIR now so that they can be * used below to compare this function's signature with previously seen * signatures for functions with the same name. @@ -2072,7 +2236,13 @@ ast_function::hir(exec_list *instructions, const glsl_type *return_type = this->return_type->specifier->glsl_type(& return_type_name, state); - assert(return_type != NULL); + if (!return_type) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, + "function `%s' has undeclared return type `%s'", + name, return_type_name); + return_type = glsl_type::error_type; + } /* From page 56 (page 62 of the PDF) of the GLSL 1.30 spec: * "No qualifier is allowed on the return type of a function." @@ -2088,8 +2258,8 @@ ast_function::hir(exec_list *instructions, * that the previously seen signature does not have an associated definition. */ f = state->symbols->get_function(name); - if (f != NULL) { - ir_function_signature *sig = f->exact_matching_signature(&hir_parameters); + if (f != NULL && !f->is_builtin) { + sig = f->exact_matching_signature(&hir_parameters); if (sig != NULL) { const char *badvar = sig->qualifiers_match(&hir_parameters); if (badvar != NULL) { @@ -2110,23 +2280,37 @@ ast_function::hir(exec_list *instructions, YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "function `%s' redefined", name); - sig = NULL; } } - } else if (state->symbols->name_declared_this_scope(name)) { - /* This function name shadows a non-function use of the same name. - */ - YYLTYPE loc = this->get_location(); - - _mesa_glsl_error(& loc, state, "function name `%s' conflicts with " - "non-function", name); - sig = NULL; } else { f = new(ctx) ir_function(name); - state->symbols->add_function(f->name, f); + if (!state->symbols->add_function(f->name, f)) { + /* This function name shadows a non-function use of the same name. */ + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(&loc, state, "function name `%s' conflicts with " + "non-function", name); + return NULL; + } /* Emit the new function header */ - instructions->push_tail(f); + 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. + * + * This can only happen in a GLSL 1.10 shader. In all other GLSL + * versions this nesting is disallowed. There is a check for this at + * the top of this function. + */ + ir_function *const curr = + const_cast(state->current_function->function()); + + curr->insert_before(f); + } } /* Verify the return type of main() */ @@ -2168,6 +2352,8 @@ ast_function_definition::hir(exec_list *instructions, prototype->hir(instructions, state); ir_function_signature *signature = prototype->signature; + if (signature == NULL) + return NULL; assert(state->current_function == NULL); state->current_function = signature; @@ -2302,6 +2488,16 @@ ast_jump_statement::hir(exec_list *instructions, } else { ir_loop *const loop = state->loop_or_switch_nesting->as_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 (loop != NULL) { ir_loop_jump *const jump = new(ctx) ir_loop_jump((mode == ast_break) @@ -2346,11 +2542,17 @@ ast_selection_statement::hir(exec_list *instructions, ir_if *const stmt = new(ctx) ir_if(condition); - if (then_statement != NULL) + if (then_statement != NULL) { + state->symbols->push_scope(); then_statement->hir(& stmt->then_instructions, state); + state->symbols->pop_scope(); + } - if (else_statement != NULL) + if (else_statement != NULL) { + state->symbols->push_scope(); else_statement->hir(& stmt->else_instructions, state); + state->symbols->pop_scope(); + } instructions->push_tail(stmt); @@ -2416,7 +2618,10 @@ ast_iteration_statement::hir(exec_list *instructions, /* 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; + state->loop_or_switch_nesting = stmt; + state->loop_or_switch_nesting_ast = this; if (mode != ast_do_while) condition_to_hir(stmt, state); @@ -2436,6 +2641,7 @@ ast_iteration_statement::hir(exec_list *instructions, /* Restore previous nesting before returning. */ state->loop_or_switch_nesting = nesting; + state->loop_or_switch_nesting_ast = nesting_ast; /* Loops do not have r-values. */ @@ -2478,8 +2684,8 @@ ast_struct_specifier::hir(exec_list *instructions, * the types to HIR. This ensures that structure definitions embedded in * other structure definitions are processed. */ - glsl_struct_field *const fields = (glsl_struct_field *) - malloc(sizeof(*fields) * decl_count); + glsl_struct_field *const fields = talloc_array(state, glsl_struct_field, + decl_count); unsigned i = 0; foreach_list_typed (ast_declarator_list, decl_list, link, @@ -2527,15 +2733,6 @@ ast_struct_specifier::hir(exec_list *instructions, if (!state->symbols->add_type(name, t)) { _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name); } else { - /* This logic is a bit tricky. It is an error to declare a structure at - * global scope if there is also a function with the same name. - */ - if ((state->current_function == NULL) - && (state->symbols->get_function(name) != NULL)) { - _mesa_glsl_error(& loc, state, "name `%s' previously defined", name); - } else { - t->generate_constructor(state->symbols); - } const glsl_type **s = (const glsl_type **) realloc(state->user_structures,