* 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"
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);
}
* 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());
* 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");
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;
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;
}
}
* 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,
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),
-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;
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;
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: {
}
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);
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);
}
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();
op[0], op[1]);
result = do_assignment(instructions, state,
- (ir_rvalue *)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());
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,
- (ir_rvalue *)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();
&& (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);
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,
- (ir_rvalue *)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();
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, (ir_rvalue *)op[0]->clone(NULL));
+ result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL));
(void)do_assignment(instructions, state,
- (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
+ op[0]->clone(ctx, NULL), temp_rhs,
this->subexpressions[0]->get_location());
type = result->type;
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)
}
}
- return glsl_type::get_array_instance(state, base, length);
+ return glsl_type::get_array_instance(base, length);
}
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)
{
}
}
+ /* 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
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;
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;
}
ir_rvalue *result = NULL;
YYLTYPE loc = this->get_location();
+ /* From page 46 (page 52 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "To ensure that a particular output variable is invariant, it is
+ * necessary to use the invariant qualifier. It can either be used to
+ * qualify a previously declared variable as being invariant
+ *
+ * invariant gl_Position; // make existing gl_Position be invariant"
+ *
+ * In these cases the parser will set the 'invariant' flag in the declarator
+ * list, and the type will be NULL.
+ */
+ if (this->invariant) {
+ assert(this->type == NULL);
+
+ if (state->current_function != NULL) {
+ _mesa_glsl_error(& loc, state,
+ "All uses of `invariant' keyword must be at global "
+ "scope\n");
+ }
+
+ foreach_list_typed (ast_declaration, decl, link, &this->declarations) {
+ assert(!decl->is_array);
+ assert(decl->array_size == NULL);
+ assert(decl->initializer == NULL);
+
+ ir_variable *const earlier =
+ state->symbols->get_variable(decl->identifier);
+ if (earlier == NULL) {
+ _mesa_glsl_error(& loc, state,
+ "Undeclared variable `%s' cannot be marked "
+ "invariant\n", decl->identifier);
+ } else if ((state->target == vertex_shader)
+ && (earlier->mode != ir_var_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)) {
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, fragment shader "
+ "inputs only\n", decl->identifier);
+ } else {
+ earlier->invariant = true;
+ }
+ }
+
+ /* Invariant redeclarations do not have r-values.
+ */
+ return NULL;
+ }
+
+ assert(this->type != NULL);
+ assert(!this->invariant);
+
/* The type specifier may contain a structure definition. Process that
* before any of the variable declarations.
*/
(void) this->type->specifier->hir(instructions, state);
- /* FINISHME: Handle vertex shader "invariant" declarations that do not
- * FINISHME: include a type. These re-declare built-in variables to be
- * FINISHME: invariant.
- */
-
decl_type = this->type->specifier->glsl_type(& type_name, state);
if (this->declarations.is_empty()) {
- /* There are only two valid cases where the declaration list can be
- * empty.
- *
- * 1. The declaration is setting the default precision of a built-in
- * type (e.g., 'precision highp vec4;').
- *
- * 2. Adding 'invariant' to an existing vertex shader output.
+ /* The only valid case where the declaration list can be empty is when
+ * the declaration is setting the default precision of a built-in type
+ * (e.g., 'precision highp vec4;').
*/
- if (this->type->qualifier.invariant) {
- } else if (decl_type != NULL) {
+ if (decl_type != NULL) {
} else {
_mesa_glsl_error(& loc, state, "incomplete declaration");
}
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.
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;
*
apply_type_qualifier_to_variable(& this->type->qualifier, var, state,
& loc);
- /* 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,
- *
- * "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 (state->symbols->name_declared_this_scope(decl->identifier)) {
- ir_variable *const earlier =
- state->symbols->get_variable(decl->identifier);
-
- if ((earlier != NULL)
- && (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
- * FINISHME: declarations. It's not 100% clear whether this is
- * FINISHME: required or not.
+ if (this->type->qualifier.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 (var->type->array_size() <= (int)earlier->max_array_access) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state, "array size must be > %u due to "
- "previous access",
- earlier->max_array_access);
- }
-
- earlier->type = var->type;
- delete var;
- var = NULL;
- } else {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state, "`%s' redeclared",
- decl->identifier);
+ _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)) {
+ /* 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);
}
-
- 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).
- */
- _mesa_glsl_error(& loc, state,
- "identifier `%s' uses reserved `gl_' prefix",
- decl->identifier);
- }
-
- instructions->push_tail(var);
-
if (state->current_function != NULL) {
const char *mode = NULL;
const char *extra = "";
}
}
+ /* 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();
}
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);
+ }
}
}
/* 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;
}
"const declaration of `%s' must be initialized");
}
- /* Add the variable to the symbol table after processing the initializer.
+ /* Check if this declaration is actually a re-declaration, either to
+ * resize an array or add qualifiers to an existing variable.
+ *
+ * This is allowed for variables in the current scope, or when at
+ * global scope (for built-ins in the implicit outer scope).
+ */
+ ir_variable *earlier = state->symbols->get_variable(decl->identifier);
+ if (earlier != NULL && (state->current_function == NULL ||
+ state->symbols->name_declared_this_scope(decl->identifier))) {
+
+ /* 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
+ * FINISHME: declarations. It's not 100% clear whether this is
+ * 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)) {
+ YYLTYPE loc = this->get_location();
+
+ _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)) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state, "array size must be > %u due to "
+ "previous access",
+ earlier->max_array_access);
+ }
+
+ 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);
+ }
+
+ continue;
+ }
+
+ /* 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)
+ _mesa_glsl_error(& loc, state,
+ "identifier `%s' uses reserved `gl_' prefix",
+ 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 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:
* 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);
}
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);
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.
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."
* 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) {
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<ir_function *>(state->current_function->function());
+
+ curr->insert_before(f);
+ }
}
/* Verify the return type of main() */
prototype->hir(instructions, state);
ir_function_signature *signature = prototype->signature;
+ if (signature == NULL)
+ return NULL;
assert(state->current_function == NULL);
state->current_function = signature;
}
case ast_discard:
- /* FINISHME: discard support */
if (state->target != fragment_shader) {
YYLTYPE loc = this->get_location();
_mesa_glsl_error(& loc, state,
"`discard' may only appear in a fragment shader");
}
+ instructions->push_tail(new(ctx) ir_discard);
break;
case ast_break:
} 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)
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);
/* 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);
/* 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.
*/
* 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,
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,