* As a result, my preference is to put as little C code as possible in the
* parser (and lexer) sources.
*/
-#include <stdio.h>
+
#include "main/imports.h"
#include "glsl_symbol_table.h"
#include "glsl_parser_extras.h"
void
_mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
{
- struct simple_node *ptr;
-
_mesa_glsl_initialize_variables(instructions, state);
_mesa_glsl_initialize_constructors(instructions, state);
_mesa_glsl_initialize_functions(instructions, state);
state->current_function = NULL;
- foreach (ptr, & state->translation_unit) {
- ((ast_node *)ptr)->hir(instructions, state);
- }
+ foreach_list_typed (ast_node, ast, link, & state->translation_unit)
+ ast->hir(instructions, state);
}
bool multiply,
struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
{
- const glsl_type *const type_a = value_a->type;
- const glsl_type *const type_b = value_b->type;
+ const glsl_type *type_a = value_a->type;
+ const glsl_type *type_b = value_b->type;
/* From GLSL 1.50 spec, page 56:
*
"arithmetic operator");
return glsl_type::error_type;
}
-
+ type_a = value_a->type;
+ type_b = value_b->type;
+
/* "If the operands are integer types, they must both be signed or
* both be unsigned."
*
relational_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b,
struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
{
- const glsl_type *const type_a = value_a->type;
- const glsl_type *const type_b = value_b->type;
+ const glsl_type *type_a = value_a->type;
+ const glsl_type *type_b = value_b->type;
/* From GLSL 1.50 spec, page 56:
* "The relational operators greater than (>), less than (<), greater
"relational operator");
return glsl_type::error_type;
}
+ type_a = value_a->type;
+ type_b = value_b->type;
if (type_a->base_type != type_b->base_type) {
_mesa_glsl_error(loc, state, "base type mismatch");
* type-check return values.
*/
ir_rvalue *
-validate_assignment(const glsl_type *lhs_type, ir_rvalue *rhs)
+validate_assignment(struct _mesa_glsl_parse_state *state,
+ const glsl_type *lhs_type, ir_rvalue *rhs)
{
- const glsl_type *const rhs_type = rhs->type;
+ const glsl_type *rhs_type = rhs->type;
/* If there is already some error in the RHS, just return it. Anything
* else will lead to an avalanche of error message back to the user.
return rhs;
}
- /* FINISHME: Check for and apply automatic conversions. */
+ /* Check for implicit conversion in GLSL 1.20 */
+ if (apply_implicit_conversion(lhs_type, rhs, state)) {
+ rhs_type = rhs->type;
+ if (rhs_type == lhs_type)
+ return rhs;
+ }
+
return NULL;
}
}
}
- ir_rvalue *new_rhs = validate_assignment(lhs->type, rhs);
+ ir_rvalue *new_rhs = validate_assignment(state, lhs->type, rhs);
if (new_rhs == NULL) {
_mesa_glsl_error(& lhs_loc, state, "type mismatch");
} else {
assert(d != NULL);
- ir_variable *const var = d->var->as_variable();
+ ir_variable *const var = d->variable_referenced();
assert(var != NULL);
}
}
- ir_instruction *tmp = new ir_assignment(lhs, rhs, NULL);
- instructions->push_tail(tmp);
+ /* Most callers of do_assignment (assign, add_assign, pre_inc/dec,
+ * but not post_inc) need the converted assigned value as an rvalue
+ * to handle things like:
+ *
+ * i = j += 1;
+ *
+ * So we always just store the computed value being assigned to a
+ * 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 ir_variable(rhs->type, "assignment_tmp");
+ instructions->push_tail(var);
+ instructions->push_tail(new ir_assignment(new ir_dereference_variable(var),
+ rhs,
+ NULL));
- return rhs;
+ instructions->push_tail(new ir_assignment(lhs,
+ new ir_dereference_variable(var),
+ NULL));
+
+ return new ir_dereference_variable(var);
}
static ir_rvalue *
-get_lvalue_copy(exec_list *instructions, struct _mesa_glsl_parse_state *state,
- ir_rvalue *lvalue, YYLTYPE loc)
+get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue)
{
ir_variable *var;
- ir_rvalue *var_deref;
/* FINISHME: Give unique names to the temporaries. */
- var = new ir_variable(lvalue->type, "_internal_tmp");
+ var = new ir_variable(lvalue->type, "_post_incdec_tmp");
var->mode = ir_var_auto;
- var_deref = new ir_dereference(var);
- do_assignment(instructions, state, var_deref, lvalue, loc);
+ instructions->push_tail(new ir_assignment(new 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;
- return var_deref;
+ return new ir_dereference_variable(var);
}
};
ir_rvalue *result = NULL;
ir_rvalue *op[2];
- struct simple_node op_list;
const struct glsl_type *type = glsl_type::error_type;
bool error_emitted = false;
YYLTYPE loc;
loc = this->get_location();
- make_empty_list(& op_list);
switch (this->oper) {
case ast_assign: {
ir_variable *const tmp = generate_temporary(glsl_type::bool_type,
instructions, state);
- ir_dereference *const then_deref = new ir_dereference(tmp);
+ ir_dereference *const then_deref = new ir_dereference_variable(tmp);
ir_assignment *const then_assign =
new ir_assignment(then_deref, op[1], NULL);
stmt->then_instructions.push_tail(then_assign);
- ir_dereference *const else_deref = new ir_dereference(tmp);
+ ir_dereference *const else_deref = new ir_dereference_variable(tmp);
ir_assignment *const else_assign =
new ir_assignment(else_deref, new ir_constant(false), NULL);
stmt->else_instructions.push_tail(else_assign);
- result = new ir_dereference(tmp);
+ result = new ir_dereference_variable(tmp);
type = tmp->type;
}
break;
error_emitted = true;
}
- ir_dereference *const then_deref = new ir_dereference(tmp);
+ ir_dereference *const then_deref = new ir_dereference_variable(tmp);
ir_assignment *const then_assign =
new ir_assignment(then_deref, new ir_constant(true), NULL);
stmt->then_instructions.push_tail(then_assign);
- ir_dereference *const else_deref = new ir_dereference(tmp);
+ ir_dereference *const else_deref = new ir_dereference_variable(tmp);
ir_assignment *const else_assign =
new ir_assignment(else_deref, op[1], NULL);
stmt->else_instructions.push_tail(else_assign);
- result = new ir_dereference(tmp);
+ result = new ir_dereference_variable(tmp);
type = tmp->type;
}
break;
ir_rvalue *temp_rhs = new ir_expression(operations[this->oper], type,
op[0], op[1]);
- result = do_assignment(instructions, state, op[0], temp_rhs,
+ result = do_assignment(instructions, state,
+ (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
this->subexpressions[0]->get_location());
type = result->type;
error_emitted = (op[0]->type->is_error());
temp_rhs = new ir_expression(operations[this->oper], type,
op[0], op[1]);
- result = do_assignment(instructions, state, op[0], temp_rhs,
+ result = do_assignment(instructions, state,
+ (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
this->subexpressions[0]->get_location());
type = result->type;
error_emitted = type->is_error();
* the if-statement assigns a value to the anonymous temporary. This
* temporary is the r-value of the expression.
*/
- ir_variable *const tmp = generate_temporary(glsl_type::error_type,
- instructions, state);
-
- ir_if *const stmt = new ir_if(op[0]);
- instructions->push_tail(stmt);
-
- op[1] = this->subexpressions[1]->hir(& stmt->then_instructions, state);
- ir_dereference *const then_deref = new ir_dereference(tmp);
- ir_assignment *const then_assign =
- new ir_assignment(then_deref, op[1], NULL);
- stmt->then_instructions.push_tail(then_assign);
+ exec_list then_instructions;
+ exec_list else_instructions;
- op[2] = this->subexpressions[2]->hir(& stmt->else_instructions, state);
- ir_dereference *const else_deref = new ir_dereference(tmp);
- ir_assignment *const else_assign =
- new ir_assignment(else_deref, op[2], NULL);
- stmt->else_instructions.push_tail(else_assign);
+ op[1] = this->subexpressions[1]->hir(&then_instructions, state);
+ op[2] = this->subexpressions[2]->hir(&else_instructions, state);
/* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec:
*
_mesa_glsl_error(& loc, state, "Second and third operands of ?: "
"operator must have matching types.");
error_emitted = true;
+ type = glsl_type::error_type;
} else {
- tmp->type = op[1]->type;
+ type = op[1]->type;
}
- result = new ir_dereference(tmp);
- type = tmp->type;
+ ir_constant *cond_val = op[0]->constant_expression_value();
+ ir_constant *then_val = op[1]->constant_expression_value();
+ ir_constant *else_val = op[2]->constant_expression_value();
+
+ if (then_instructions.is_empty()
+ && else_instructions.is_empty()
+ && (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_if *const stmt = new ir_if(op[0]);
+ instructions->push_tail(stmt);
+
+ then_instructions.move_nodes_to(& stmt->then_instructions);
+ ir_dereference *const then_deref = new ir_dereference_variable(tmp);
+ ir_assignment *const then_assign =
+ new ir_assignment(then_deref, op[1], NULL);
+ stmt->then_instructions.push_tail(then_assign);
+
+ else_instructions.move_nodes_to(& stmt->else_instructions);
+ ir_dereference *const else_deref = new ir_dereference_variable(tmp);
+ ir_assignment *const else_assign =
+ new ir_assignment(else_deref, op[2], NULL);
+ stmt->else_instructions.push_tail(else_assign);
+
+ result = new ir_dereference_variable(tmp);
+ }
break;
}
temp_rhs = new ir_expression(operations[this->oper], type,
op[0], op[1]);
- result = do_assignment(instructions, state, op[0], temp_rhs,
+ result = do_assignment(instructions, state,
+ (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
this->subexpressions[0]->get_location());
type = result->type;
error_emitted = op[0]->type->is_error();
/* Get a temporary of a copy of the lvalue before it's modified.
* This may get thrown away later.
*/
- result = get_lvalue_copy(instructions, state, op[0],
- this->subexpressions[0]->get_location());
+ result = get_lvalue_copy(instructions, (ir_rvalue *)op[0]->clone(NULL));
- (void)do_assignment(instructions, state, op[0], temp_rhs,
+ (void)do_assignment(instructions, state,
+ (ir_rvalue *)op[0]->clone(NULL), temp_rhs,
this->subexpressions[0]->get_location());
type = result->type;
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
- ir_dereference *const lhs = op[0]->as_dereference();
- ir_instruction *array;
- if ((lhs != NULL)
- && (lhs->mode == ir_dereference::ir_reference_variable)) {
- result = new ir_dereference(lhs->var, op[1]);
+ ir_rvalue *const array = op[0];
- delete op[0];
- array = lhs->var;
- } else {
- result = new ir_dereference(op[0], op[1]);
- array = op[0];
- }
+ result = new ir_dereference_array(op[0], op[1]);
/* Do not use op[0] after this point. Use array.
*/
}
if (array->type->is_array()) {
- ir_variable *const v = array->as_variable();
+ /* If the array is a variable dereference, it dereferences the
+ * whole array, by definition. Use this to get the variable.
+ *
+ * FINISHME: Should some methods for getting / setting / testing
+ * 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))
v->max_array_access = idx;
}
ir_variable *var =
state->symbols->get_variable(this->primary_expression.identifier);
- result = new ir_dereference(var);
+ result = new ir_dereference_variable(var);
if (var != NULL) {
type = result->type;
case ast_int_constant:
type = glsl_type::int_type;
- result = new ir_constant(type, & this->primary_expression);
+ result = new ir_constant(this->primary_expression.int_constant);
break;
case ast_uint_constant:
type = glsl_type::uint_type;
- result = new ir_constant(type, & this->primary_expression);
+ result = new ir_constant(this->primary_expression.uint_constant);
break;
case ast_float_constant:
type = glsl_type::float_type;
- result = new ir_constant(type, & this->primary_expression);
+ result = new ir_constant(this->primary_expression.float_constant);
break;
case ast_bool_constant:
type = glsl_type::bool_type;
- result = new ir_constant(type, & this->primary_expression);
+ result = new ir_constant(bool(this->primary_expression.bool_constant));
break;
case ast_sequence: {
- struct simple_node *ptr;
-
/* It should not be possible to generate a sequence in the AST without
* any expressions in it.
*/
- assert(!is_empty_list(&this->expressions));
+ assert(!this->expressions.is_empty());
/* The r-value of a sequence is the last expression in the sequence. If
* the other expressions in the sequence do not have side-effects (and
* therefore add instructions to the instruction list), they get dropped
* on the floor.
*/
- foreach (ptr, &this->expressions)
- result = ((ast_node *)ptr)->hir(instructions, state);
+ foreach_list_typed (ast_node, ast, link, &this->expressions)
+ result = ast->hir(instructions, state);
type = result->type;
ast_compound_statement::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
{
- struct simple_node *ptr;
-
-
if (new_scope)
state->symbols->push_scope();
- foreach (ptr, &statements)
- ((ast_node *)ptr)->hir(instructions, state);
+ foreach_list_typed (ast_node, ast, link, &this->statements)
+ ast->hir(instructions, state);
if (new_scope)
state->symbols->pop_scope();
* float, vec2, vec3, vec4, mat2, mat3, and mat4, or arrays of
* these."
*/
- if (qual->varying && var->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 (qual->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 (qual->in && qual->out)
if (qual->uniform)
var->shader_in = true;
- if (qual->varying) {
- if (qual->in)
+
+ /* 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;
- if (qual->out)
+ 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)
ast_declarator_list::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
{
- struct simple_node *ptr;
const struct glsl_type *decl_type;
const char *type_name = NULL;
ir_rvalue *result = NULL;
+ YYLTYPE loc = this->get_location();
/* The type specifier may contain a structure definition. Process that
* before any of the variable declarations.
*/
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.
+ */
- foreach (ptr, &this->declarations) {
- struct ast_declaration *const decl = (struct ast_declaration * )ptr;
+ if (this->type->qualifier.invariant) {
+ } else 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;
- YYLTYPE loc = this->get_location();
/* FINISHME: Emit a warning if a variable declaration shadows a
* FINISHME: declaration at a higher scope.
? "attribute" : "varying");
}
- ir_dereference *const lhs = new ir_dereference(var);
+ ir_dereference *const lhs = new ir_dereference_variable(var);
ir_rvalue *rhs = decl->initializer->hir(instructions, state);
- /* Calculate the constant value if this is a const
+ /* Calculate the constant value if this is a const or uniform
* declaration.
*/
- if (this->type->qualifier.constant) {
+ 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 const variable `%s' must be a "
+ "initializer of %s variable `%s' must be a "
"constant expression",
+ (this->type->qualifier.constant)
+ ? "const" : "uniform",
decl->identifier);
} else {
rhs = constant_value;
bool temp = var->read_only;
if (this->type->qualifier.constant)
var->read_only = false;
- result = do_assignment(instructions, state, lhs, rhs,
- this->get_location());
+
+ /* Never emit code to initialize a uniform.
+ */
+ if (!this->type->qualifier.uniform)
+ result = do_assignment(instructions, state, lhs, rhs,
+ this->get_location());
var->read_only = temp;
}
}
void
-ast_parameter_declarator::parameters_to_hir(struct simple_node *ast_parameters,
+ast_parameter_declarator::parameters_to_hir(exec_list *ast_parameters,
bool formal,
exec_list *ir_parameters,
_mesa_glsl_parse_state *state)
{
- struct simple_node *ptr;
ast_parameter_declarator *void_param = NULL;
unsigned count = 0;
- foreach (ptr, ast_parameters) {
- ast_parameter_declarator *param = (ast_parameter_declarator *)ptr;
+ foreach_list_typed (ast_parameter_declarator, param, link, ast_parameters) {
param->formal_parameter = formal;
param->hir(ir_parameters, state);
if (loop != NULL) {
ir_loop_jump *const jump =
- new ir_loop_jump(loop,
- (mode == ast_break)
+ new ir_loop_jump((mode == ast_break)
? ir_loop_jump::jump_break
: ir_loop_jump::jump_continue);
instructions->push_tail(jump);
ir_if *const stmt = new ir_if(condition);
- if (then_statement != NULL) {
- ast_node *node = (ast_node *) then_statement;
- do {
- node->hir(& stmt->then_instructions, state);
- node = (ast_node *) node->next;
- } while (node != then_statement);
- }
+ if (then_statement != NULL)
+ then_statement->hir(& stmt->then_instructions, state);
- if (else_statement != NULL) {
- ast_node *node = (ast_node *) else_statement;
- do {
- node->hir(& stmt->else_instructions, state);
- node = (ast_node *) node->next;
- } while (node != else_statement);
- }
+ if (else_statement != NULL)
+ else_statement->hir(& stmt->else_instructions, state);
instructions->push_tail(stmt);
ir_if *const if_stmt = new ir_if(not_cond);
ir_jump *const break_stmt =
- new ir_loop_jump(stmt, ir_loop_jump::jump_break);
+ new ir_loop_jump(ir_loop_jump::jump_break);
if_stmt->then_instructions.push_tail(break_stmt);
stmt->body_instructions.push_tail(if_stmt);
if (mode != ast_do_while)
condition_to_hir(stmt, state);
- if (body != NULL) {
- ast_node *node = (ast_node *) body;
- do {
- node->hir(& stmt->body_instructions, state);
- node = (ast_node *) node->next;
- } while (node != body);
- }
+ if (body != NULL)
+ body->hir(& stmt->body_instructions, state);
if (rest_expression != NULL)
rest_expression->hir(& stmt->body_instructions, state);
ast_struct_specifier::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
{
- simple_node *ptr;
unsigned decl_count = 0;
/* Make an initial pass over the list of structure fields to determine how
* This means that we actually need to count the number of elements in the
* 'declarations' list in each of the elements.
*/
- foreach (ptr, & this->declarations) {
- ast_declarator_list *decl_list = (ast_declarator_list *) ptr;
- simple_node *decl_ptr;
-
- foreach (decl_ptr, & decl_list->declarations) {
+ foreach_list_typed (ast_declarator_list, decl_list, link,
+ &this->declarations) {
+ foreach_list_const (decl_ptr, & decl_list->declarations) {
decl_count++;
}
}
malloc(sizeof(*fields) * decl_count);
unsigned i = 0;
- foreach (ptr, & this->declarations) {
- ast_declarator_list *decl_list = (ast_declarator_list *) ptr;
- simple_node *decl_ptr;
+ foreach_list_typed (ast_declarator_list, decl_list, link,
+ &this->declarations) {
const char *type_name;
decl_list->type->specifier->hir(instructions, state);
const glsl_type *decl_type =
decl_list->type->specifier->glsl_type(& type_name, state);
- foreach (decl_ptr, & decl_list->declarations) {
- ast_declaration *const decl = (ast_declaration *) decl_ptr;
+ foreach_list_typed (ast_declaration, decl, link,
+ &decl_list->declarations) {
const struct glsl_type *const field_type =
(decl->is_array)
? process_array_type(decl_type, decl->array_size, state)
glsl_type *t = new glsl_type(fields, decl_count, name);
- state->symbols->add_type(name, t);
+ YYLTYPE loc = this->get_location();
+ 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,
+ sizeof(state->user_structures[0]) *
+ (state->num_user_structures + 1));
+ if (s != NULL) {
+ s[state->num_user_structures] = t;
+ state->user_structures = s;
+ state->num_user_structures++;
+ }
+ }
/* Structure type definitions do not have r-values.
*/