* parser (and lexer) sources.
*/
-#include "main/imports.h"
-#include "main/extensions.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);
}
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;
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);
}
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",
ir_var_temporary);
instructions->push_tail(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_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: {
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());
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();
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();
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;
}
} 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)
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)
{
else if (qual->uniform)
var->mode = ir_var_uniform;
- 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 if (qual->noperspective)
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.
& 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);
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 {
_mesa_glsl_error(&initializer_loc, state,
"initializer of type %s cannot be assigned to "
"variable of type %s",
rhs->type->name, var->type->name);
- }
-
- 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);
- } else {
- rhs = constant_value;
- var->constant_value = constant_value;
+ if (var->type->is_numeric()) {
+ /* Reduce cascading errors. */
+ var->constant_value = ir_constant::zero(ctx, var->type);
+ }
}
}
"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
earlier->type = var->type;
delete var;
var = NULL;
- } else if (state->extensions->ARB_fragment_coord_conventions &&
- (earlier != NULL) &&
- (strcmp(var->name, "gl_FragCoord") == 0) &&
- earlier->type == var->type &&
- earlier->mode == var->mode) {
+ } 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->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);
- }
- instructions->push_tail(var);
- instructions->append_list(&initializer_instructions);
-
- /* 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:
* 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;
}
+ /* 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);
- /* FINISHME: Handle array declarations. Note that this requires
- * FINISHME: complete handling of constant expressions.
- */
-
/* Apply any specified qualifiers to the parameter declaration. Note that
* for function parameters the default mode is 'in'.
*/
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;
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);
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,