/* * Copyright © 2010 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /** * \file ast_to_hir.c * Convert abstract syntax to to high-level intermediate reprensentation (HIR). * * During the conversion to HIR, the majority of the symantic checking is * preformed on the program. This includes: * * * Symbol table management * * Type checking * * Function binding * * The majority of this work could be done during parsing, and the parser could * probably generate HIR directly. However, this results in frequent changes * to the parser code. Since we do not assume that every system this complier * is built on will have Flex and Bison installed, we have to store the code * generated by these tools in our version control system. In other parts of * the system we've seen problems where a parser was changed but the generated * code was not committed, merge conflicts where created because two developers * had slightly different versions of Bison installed, etc. * * I have also noticed that running Bison generated parsers in GDB is very * irritating. When you get a segfault on '$$ = $1->foo', you can't very * well 'print $1' in GDB. * * As a result, my preference is to put as little C code as possible in the * parser (and lexer) sources. */ #include #include "main/imports.h" #include "glsl_symbol_table.h" #include "glsl_parser_extras.h" #include "ast.h" #include "glsl_types.h" #include "ir.h" void _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { _mesa_glsl_initialize_variables(instructions, state); _mesa_glsl_initialize_constructors(instructions, state); _mesa_glsl_initialize_functions(instructions, state); state->current_function = NULL; foreach_list_typed (ast_node, ast, link, & state->translation_unit) ast->hir(instructions, state); } /** * If a conversion is available, convert one operand to a different type * * The \c from \c ir_rvalue is converted "in place". * * \param to Type that the operand it to be converted to * \param from Operand that is being converted * \param state GLSL compiler state * * \return * If a conversion is possible (or unnecessary), \c true is returned. * Otherwise \c false is returned. */ static bool apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from, struct _mesa_glsl_parse_state *state) { if (to->base_type == from->type->base_type) return true; /* This conversion was added in GLSL 1.20. If the compilation mode is * GLSL 1.10, the conversion is skipped. */ if (state->language_version < 120) return false; /* From page 27 (page 33 of the PDF) of the GLSL 1.50 spec: * * "There are no implicit array or structure conversions. For * example, an array of int cannot be implicitly converted to an * array of float. There are no implicit conversions between * signed and unsigned integers." */ /* FINISHME: The above comment is partially a lie. There is int/uint * FINISHME: conversion for immediate constants. */ if (!to->is_float() || !from->type->is_numeric()) return false; switch (from->type->base_type) { case GLSL_TYPE_INT: from = new ir_expression(ir_unop_i2f, to, from, NULL); break; case GLSL_TYPE_UINT: from = new ir_expression(ir_unop_u2f, to, from, NULL); break; case GLSL_TYPE_BOOL: from = new ir_expression(ir_unop_b2f, to, from, NULL); break; default: assert(0); } return true; } static const struct glsl_type * arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, bool multiply, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { const glsl_type *type_a = value_a->type; const glsl_type *type_b = value_b->type; /* From GLSL 1.50 spec, page 56: * * "The arithmetic binary operators add (+), subtract (-), * multiply (*), and divide (/) operate on integer and * floating-point scalars, vectors, and matrices." */ if (!type_a->is_numeric() || !type_b->is_numeric()) { _mesa_glsl_error(loc, state, "Operands to arithmetic operators must be numeric"); return glsl_type::error_type; } /* "If one operand is floating-point based and the other is * not, then the conversions from Section 4.1.10 "Implicit * Conversions" are applied to the non-floating-point-based operand." */ if (!apply_implicit_conversion(type_a, value_b, state) && !apply_implicit_conversion(type_b, value_a, state)) { _mesa_glsl_error(loc, state, "Could not implicitly convert operands to " "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." * * From this rule and the preceeding conversion it can be inferred that * both types must be GLSL_TYPE_FLOAT, or GLSL_TYPE_UINT, or GLSL_TYPE_INT. * The is_numeric check above already filtered out the case where either * type is not one of these, so now the base types need only be tested for * equality. */ if (type_a->base_type != type_b->base_type) { _mesa_glsl_error(loc, state, "base type mismatch for arithmetic operator"); return glsl_type::error_type; } /* "All arithmetic binary operators result in the same fundamental type * (signed integer, unsigned integer, or floating-point) as the * operands they operate on, after operand type conversion. After * conversion, the following cases are valid * * * The two operands are scalars. In this case the operation is * applied, resulting in a scalar." */ if (type_a->is_scalar() && type_b->is_scalar()) return type_a; /* "* One operand is a scalar, and the other is a vector or matrix. * In this case, the scalar operation is applied independently to each * component of the vector or matrix, resulting in the same size * vector or matrix." */ if (type_a->is_scalar()) { if (!type_b->is_scalar()) return type_b; } else if (type_b->is_scalar()) { return type_a; } /* All of the combinations of , , * , , and have been * handled. */ assert(!type_a->is_scalar()); assert(!type_b->is_scalar()); /* "* The two operands are vectors of the same size. In this case, the * operation is done component-wise resulting in the same size * vector." */ if (type_a->is_vector() && type_b->is_vector()) { if (type_a == type_b) { return type_a; } else { _mesa_glsl_error(loc, state, "vector size mismatch for arithmetic operator"); return glsl_type::error_type; } } /* All of the combinations of , , * , , , and * have been handled. At least one of the operands must * be matrix. Further, since there are no integer matrix types, the base * type of both operands must be float. */ assert(type_a->is_matrix() || type_b->is_matrix()); assert(type_a->base_type == GLSL_TYPE_FLOAT); assert(type_b->base_type == GLSL_TYPE_FLOAT); /* "* The operator is add (+), subtract (-), or divide (/), and the * operands are matrices with the same number of rows and the same * number of columns. In this case, the operation is done component- * wise resulting in the same size matrix." * * The operator is multiply (*), where both operands are matrices or * one operand is a vector and the other a matrix. A right vector * operand is treated as a column vector and a left vector operand as a * row vector. In all these cases, it is required that the number of * columns of the left operand is equal to the number of rows of the * right operand. Then, the multiply (*) operation does a linear * algebraic multiply, yielding an object that has the same number of * rows as the left operand and the same number of columns as the right * operand. Section 5.10 "Vector and Matrix Operations" explains in * more detail how vectors and matrices are operated on." */ if (! multiply) { if (type_a == type_b) return type_a; } else { if (type_a->is_matrix() && type_b->is_matrix()) { /* Matrix multiply. The columns of A must match the rows of B. Given * the other previously tested constraints, this means the vector type * of a row from A must be the same as the vector type of a column from * B. */ if (type_a->row_type() == type_b->column_type()) { /* The resulting matrix has the number of columns of matrix B and * the number of rows of matrix A. We get the row count of A by * looking at the size of a vector that makes up a column. The * transpose (size of a row) is done for B. */ const glsl_type *const type = glsl_type::get_instance(type_a->base_type, type_a->column_type()->vector_elements, type_b->row_type()->vector_elements); assert(type != glsl_type::error_type); return type; } } else if (type_a->is_matrix()) { /* A is a matrix and B is a column vector. Columns of A must match * rows of B. Given the other previously tested constraints, this * 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; } else { assert(type_b->is_matrix()); /* A is a row vector and B is a matrix. Columns of A must match rows * of B. Given the other previously tested constraints, this means * 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; } _mesa_glsl_error(loc, state, "size mismatch for matrix multiplication"); return glsl_type::error_type; } /* "All other cases are illegal." */ _mesa_glsl_error(loc, state, "type mismatch"); return glsl_type::error_type; } static const struct glsl_type * unary_arithmetic_result_type(const struct glsl_type *type, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { /* From GLSL 1.50 spec, page 57: * * "The arithmetic unary operators negate (-), post- and pre-increment * and decrement (-- and ++) operate on integer or floating-point * values (including vectors and matrices). All unary operators work * component-wise on their operands. These result with the same type * they operated on." */ if (!type->is_numeric()) { _mesa_glsl_error(loc, state, "Operands to arithmetic operators must be numeric"); return glsl_type::error_type; } return type; } static const struct glsl_type * modulus_result_type(const struct glsl_type *type_a, const struct glsl_type *type_b, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { /* From GLSL 1.50 spec, page 56: * "The operator modulus (%) operates on signed or unsigned integers or * integer vectors. The operand types must both be signed or both be * unsigned." */ if (!type_a->is_integer() || !type_b->is_integer() || (type_a->base_type != type_b->base_type)) { _mesa_glsl_error(loc, state, "type mismatch"); return glsl_type::error_type; } /* "The operands cannot be vectors of differing size. If one operand is * a scalar and the other vector, then the scalar is applied component- * wise to the vector, resulting in the same type as the vector. If both * are vectors of the same size, the result is computed component-wise." */ if (type_a->is_vector()) { if (!type_b->is_vector() || (type_a->vector_elements == type_b->vector_elements)) return type_a; } else return type_b; /* "The operator modulus (%) is not defined for any other data types * (non-integer types)." */ _mesa_glsl_error(loc, state, "type mismatch"); return glsl_type::error_type; } static const struct glsl_type * relational_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { 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 * than or equal (>=), and less than or equal (<=) operate only on * scalar integer and scalar floating-point expressions." */ if (!type_a->is_numeric() || !type_b->is_numeric() || !type_a->is_scalar() || !type_b->is_scalar()) { _mesa_glsl_error(loc, state, "Operands to relational operators must be scalar and " "numeric"); return glsl_type::error_type; } /* "Either the operands' types must match, or the conversions from * Section 4.1.10 "Implicit Conversions" will be applied to the integer * operand, after which the types must match." */ if (!apply_implicit_conversion(type_a, value_b, state) && !apply_implicit_conversion(type_b, value_a, state)) { _mesa_glsl_error(loc, state, "Could not implicitly convert operands to " "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"); return glsl_type::error_type; } /* "The result is scalar Boolean." */ return glsl_type::bool_type; } /** * Validates that a value can be assigned to a location with a specified type * * Validates that \c rhs can be assigned to some location. If the types are * not an exact match but an automatic conversion is possible, \c rhs will be * converted. * * \return * \c NULL if \c rhs cannot be assigned to a location with type \c lhs_type. * Otherwise the actual RHS to be assigned will be returned. This may be * \c rhs, or it may be \c rhs after some type conversion. * * \note * In addition to being used for assignments, this function is used to * type-check return values. */ ir_rvalue * validate_assignment(struct _mesa_glsl_parse_state *state, const glsl_type *lhs_type, ir_rvalue *rhs) { 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. */ if (rhs_type->is_error()) return rhs; /* If the types are identical, the assignment can trivially proceed. */ if (rhs_type == lhs_type) return rhs; /* If the array element types are the same and the size of the LHS is zero, * the assignment is okay. * * Note: Whole-array assignments are not permitted in GLSL 1.10, but this * is handled by ir_dereference::is_lvalue. */ if (lhs_type->is_array() && rhs->type->is_array() && (lhs_type->element_type() == rhs->type->element_type()) && (lhs_type->array_size() == 0)) { return rhs; } /* 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 * do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, ir_rvalue *lhs, ir_rvalue *rhs, YYLTYPE lhs_loc) { 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; } } ir_rvalue *new_rhs = validate_assignment(state, lhs->type, rhs); if (new_rhs == NULL) { _mesa_glsl_error(& lhs_loc, state, "type mismatch"); } else { rhs = new_rhs; /* If the LHS array was not declared with a size, it takes it size from * the RHS. If the LHS is an l-value and a whole array, it must be a * dereference of a variable. Any other case would require that the LHS * is either not an l-value or not a whole array. */ if (lhs->type->array_size() == 0) { ir_dereference *const d = lhs->as_dereference(); assert(d != NULL); ir_variable *const var = d->variable_referenced(); assert(var != NULL); if (var->max_array_access >= unsigned(rhs->type->array_size())) { /* FINISHME: This should actually log the location of the RHS. */ _mesa_glsl_error(& lhs_loc, state, "array size must be > %u due to " "previous access", var->max_array_access); } var->type = glsl_type::get_array_instance(lhs->type->element_type(), rhs->type->array_size()); } } ir_instruction *tmp = new ir_assignment(lhs, rhs, NULL); instructions->push_tail(tmp); return rhs; } /** * 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) { char *name = (char *) malloc(sizeof(char) * 13); snprintf(name, 13, "tmp_%08X", state->temp_index); state->temp_index++; ir_variable *const var = new ir_variable(type, name); instructions->push_tail(var); return var; } static ir_rvalue * get_lvalue_copy(exec_list *instructions, struct _mesa_glsl_parse_state *state, ir_rvalue *lvalue, YYLTYPE loc) { ir_variable *var; ir_rvalue *var_deref; /* FINISHME: Give unique names to the temporaries. */ var = new ir_variable(lvalue->type, "_internal_tmp"); var->mode = ir_var_auto; var_deref = new ir_dereference_variable(var); do_assignment(instructions, state, var_deref, lvalue, loc); /* 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; } ir_rvalue * ast_node::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { (void) instructions; (void) state; return NULL; } ir_rvalue * ast_expression::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { static const int operations[AST_NUM_OPERATORS] = { -1, /* ast_assign doesn't convert to ir_expression. */ -1, /* ast_plus doesn't convert to ir_expression. */ ir_unop_neg, ir_binop_add, ir_binop_sub, ir_binop_mul, ir_binop_div, ir_binop_mod, ir_binop_lshift, ir_binop_rshift, ir_binop_less, ir_binop_greater, ir_binop_lequal, ir_binop_gequal, ir_binop_equal, ir_binop_nequal, ir_binop_bit_and, ir_binop_bit_xor, ir_binop_bit_or, ir_unop_bit_not, ir_binop_logic_and, ir_binop_logic_xor, ir_binop_logic_or, ir_unop_logic_not, /* Note: The following block of expression types actually convert * to multiple IR instructions. */ ir_binop_mul, /* ast_mul_assign */ ir_binop_div, /* ast_div_assign */ ir_binop_mod, /* ast_mod_assign */ ir_binop_add, /* ast_add_assign */ ir_binop_sub, /* ast_sub_assign */ ir_binop_lshift, /* ast_ls_assign */ ir_binop_rshift, /* ast_rs_assign */ ir_binop_bit_and, /* ast_and_assign */ ir_binop_bit_xor, /* ast_xor_assign */ ir_binop_bit_or, /* ast_or_assign */ -1, /* ast_conditional doesn't convert to ir_expression. */ ir_binop_add, /* ast_pre_inc. */ ir_binop_sub, /* ast_pre_dec. */ ir_binop_add, /* ast_post_inc. */ ir_binop_sub, /* ast_post_dec. */ -1, /* ast_field_selection doesn't conv to ir_expression. */ -1, /* ast_array_index doesn't convert to ir_expression. */ -1, /* ast_function_call doesn't conv to ir_expression. */ -1, /* ast_identifier doesn't convert to ir_expression. */ -1, /* ast_int_constant doesn't convert to ir_expression. */ -1, /* ast_uint_constant doesn't conv to ir_expression. */ -1, /* ast_float_constant doesn't conv to ir_expression. */ -1, /* ast_bool_constant doesn't conv to ir_expression. */ -1, /* ast_sequence doesn't convert to ir_expression. */ }; ir_rvalue *result = NULL; ir_rvalue *op[2]; const struct glsl_type *type = glsl_type::error_type; bool error_emitted = false; YYLTYPE loc; loc = this->get_location(); switch (this->oper) { case ast_assign: { op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); result = do_assignment(instructions, state, op[0], op[1], this->subexpressions[0]->get_location()); error_emitted = result->type->is_error(); type = result->type; break; } 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; result = op[0]; break; case ast_neg: op[0] = this->subexpressions[0]->hir(instructions, state); type = unary_arithmetic_result_type(op[0]->type, state, & loc); error_emitted = type->is_error(); result = new ir_expression(operations[this->oper], type, op[0], NULL); break; case ast_add: case ast_sub: case ast_mul: case ast_div: op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); type = arithmetic_result_type(op[0], op[1], (this->oper == ast_mul), state, & loc); error_emitted = type->is_error(); result = new ir_expression(operations[this->oper], type, op[0], op[1]); break; case ast_mod: op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); type = modulus_result_type(op[0]->type, op[1]->type, state, & loc); assert(operations[this->oper] == ir_binop_mod); result = new ir_expression(operations[this->oper], type, op[0], op[1]); error_emitted = type->is_error(); break; case ast_lshift: case ast_rshift: _mesa_glsl_error(& loc, state, "FINISHME: implement bit-shift operators"); error_emitted = true; break; case ast_less: case ast_greater: case ast_lequal: case ast_gequal: op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); type = relational_result_type(op[0], op[1], state, & loc); /* The relational operators must either generate an error or result * in a scalar boolean. See page 57 of the GLSL 1.50 spec. */ assert(type->is_error() || ((type->base_type == GLSL_TYPE_BOOL) && type->is_scalar())); result = new ir_expression(operations[this->oper], type, op[0], op[1]); error_emitted = type->is_error(); break; case ast_nequal: case ast_equal: op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); /* From page 58 (page 64 of the PDF) of the GLSL 1.50 spec: * * "The equality operators equal (==), and not equal (!=) * operate on all types. They result in a scalar Boolean. If * the operand types do not match, then there must be a * conversion from Section 4.1.10 "Implicit Conversions" * applied to one operand that can make them match, in which * case this conversion is done." */ if ((!apply_implicit_conversion(op[0]->type, op[1], state) && !apply_implicit_conversion(op[1]->type, op[0], state)) || (op[0]->type != op[1]->type)) { _mesa_glsl_error(& loc, state, "operands of `%s' must have the same " "type", (this->oper == ast_equal) ? "==" : "!="); error_emitted = true; } else if ((state->language_version <= 110) && (op[0]->type->is_array() || op[1]->type->is_array())) { _mesa_glsl_error(& loc, state, "array comparisons forbidden in " "GLSL 1.10"); error_emitted = true; } result = new ir_expression(operations[this->oper], glsl_type::bool_type, op[0], op[1]); type = glsl_type::bool_type; assert(result->type == glsl_type::bool_type); break; case ast_bit_and: case ast_bit_xor: case ast_bit_or: case ast_bit_not: _mesa_glsl_error(& loc, state, "FINISHME: implement bit-wise operators"); error_emitted = true; break; case ast_logic_and: { op[0] = this->subexpressions[0]->hir(instructions, state); if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[0]->get_location(); _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean", operator_string(this->oper)); error_emitted = true; } ir_constant *op0_const = op[0]->constant_expression_value(); if (op0_const) { if (op0_const->value.b[0]) { op[1] = this->subexpressions[1]->hir(instructions, state); if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[1]->get_location(); _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean", operator_string(this->oper)); error_emitted = true; } result = op[1]; } else { result = op0_const; } type = glsl_type::bool_type; } else { ir_if *const stmt = new ir_if(op[0]); instructions->push_tail(stmt); op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state); if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[1]->get_location(); _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean", operator_string(this->oper)); error_emitted = true; } ir_variable *const tmp = generate_temporary(glsl_type::bool_type, instructions, state); 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_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_variable(tmp); type = tmp->type; } break; } case ast_logic_or: { op[0] = this->subexpressions[0]->hir(instructions, state); if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[0]->get_location(); _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean", operator_string(this->oper)); error_emitted = true; } ir_constant *op0_const = op[0]->constant_expression_value(); if (op0_const) { if (op0_const->value.b[0]) { result = op0_const; } else { op[1] = this->subexpressions[1]->hir(instructions, state); if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[1]->get_location(); _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean", operator_string(this->oper)); error_emitted = true; } result = op[1]; } type = glsl_type::bool_type; } else { ir_if *const stmt = new 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); if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[1]->get_location(); _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean", operator_string(this->oper)); error_emitted = true; } 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_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_variable(tmp); type = tmp->type; } break; } case ast_logic_xor: op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); result = new ir_expression(operations[this->oper], glsl_type::bool_type, op[0], op[1]); type = glsl_type::bool_type; break; case ast_logic_not: op[0] = this->subexpressions[0]->hir(instructions, state); if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[0]->get_location(); _mesa_glsl_error(& loc, state, "operand of `!' must be scalar boolean"); error_emitted = true; } result = new ir_expression(operations[this->oper], glsl_type::bool_type, op[0], NULL); type = glsl_type::bool_type; break; case ast_mul_assign: case ast_div_assign: case ast_add_assign: case ast_sub_assign: { op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); type = arithmetic_result_type(op[0], op[1], (this->oper == ast_mul_assign), state, & loc); ir_rvalue *temp_rhs = new ir_expression(operations[this->oper], type, op[0], op[1]); result = do_assignment(instructions, state, op[0], temp_rhs, this->subexpressions[0]->get_location()); type = result->type; error_emitted = (op[0]->type->is_error()); /* GLSL 1.10 does not allow array assignment. However, we don't have to * explicitly test for this because none of the binary expression * operators allow array operands either. */ break; } case ast_mod_assign: { op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); type = modulus_result_type(op[0]->type, op[1]->type, state, & loc); assert(operations[this->oper] == ir_binop_mod); struct ir_rvalue *temp_rhs; temp_rhs = new ir_expression(operations[this->oper], type, op[0], op[1]); result = do_assignment(instructions, state, op[0], temp_rhs, this->subexpressions[0]->get_location()); type = result->type; error_emitted = type->is_error(); break; } case ast_ls_assign: case ast_rs_assign: _mesa_glsl_error(& loc, state, "FINISHME: implement bit-shift assignment operators"); error_emitted = true; break; case ast_and_assign: case ast_xor_assign: case ast_or_assign: _mesa_glsl_error(& loc, state, "FINISHME: implement logic assignment operators"); error_emitted = true; break; case ast_conditional: { op[0] = this->subexpressions[0]->hir(instructions, state); /* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec: * * "The ternary selection operator (?:). It operates on three * expressions (exp1 ? exp2 : exp3). This operator evaluates the * first expression, which must result in a scalar Boolean." */ if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[0]->get_location(); _mesa_glsl_error(& loc, state, "?: condition must be scalar boolean"); error_emitted = true; } /* The :? operator is implemented by generating an anonymous temporary * followed by an if-statement. The last instruction in each branch of * the if-statement assigns a value to the anonymous temporary. This * temporary is the r-value of the expression. */ exec_list then_instructions; exec_list else_instructions; 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: * * "The second and third expressions can be any type, as * long their types match, or there is a conversion in * Section 4.1.10 "Implicit Conversions" that can be applied * to one of the expressions to make their types match. This * resulting matching type is the type of the entire * expression." */ if ((!apply_implicit_conversion(op[1]->type, op[2], state) && !apply_implicit_conversion(op[2]->type, op[1], state)) || (op[1]->type != op[2]->type)) { YYLTYPE loc = this->subexpressions[1]->get_location(); _mesa_glsl_error(& loc, state, "Second and third operands of ?: " "operator must have matching types."); error_emitted = true; type = glsl_type::error_type; } else { type = op[1]->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; } case ast_pre_inc: case ast_pre_dec: { op[0] = this->subexpressions[0]->hir(instructions, state); if (op[0]->type->base_type == GLSL_TYPE_FLOAT) op[1] = new ir_constant(1.0f); else op[1] = new ir_constant(1); type = arithmetic_result_type(op[0], op[1], false, state, & loc); struct ir_rvalue *temp_rhs; temp_rhs = new ir_expression(operations[this->oper], type, op[0], op[1]); result = do_assignment(instructions, state, op[0], temp_rhs, this->subexpressions[0]->get_location()); type = result->type; error_emitted = op[0]->type->is_error(); break; } case ast_post_inc: case ast_post_dec: { op[0] = this->subexpressions[0]->hir(instructions, state); if (op[0]->type->base_type == GLSL_TYPE_FLOAT) op[1] = new ir_constant(1.0f); else op[1] = new ir_constant(1); error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); type = arithmetic_result_type(op[0], op[1], false, state, & loc); struct ir_rvalue *temp_rhs; temp_rhs = new 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, state, op[0], this->subexpressions[0]->get_location()); (void)do_assignment(instructions, state, op[0], temp_rhs, this->subexpressions[0]->get_location()); type = result->type; error_emitted = op[0]->type->is_error(); break; } case ast_field_selection: result = _mesa_ast_field_selection_to_hir(this, instructions, state); type = result->type; break; case ast_array_index: { YYLTYPE index_loc = subexpressions[1]->get_location(); op[0] = subexpressions[0]->hir(instructions, state); op[1] = subexpressions[1]->hir(instructions, state); error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); ir_rvalue *const array = op[0]; result = new ir_dereference_array(op[0], op[1]); /* Do not use op[0] after this point. Use array. */ op[0] = NULL; if (error_emitted) break; if (!array->type->is_array() && !array->type->is_matrix() && !array->type->is_vector()) { _mesa_glsl_error(& index_loc, state, "cannot dereference non-array / non-matrix / " "non-vector"); error_emitted = true; } if (!op[1]->type->is_integer()) { _mesa_glsl_error(& index_loc, state, "array index must be integer type"); error_emitted = true; } else if (!op[1]->type->is_scalar()) { _mesa_glsl_error(& index_loc, state, "array index must be scalar"); error_emitted = true; } /* If the array index is a constant expression and the array has a * declared size, ensure that the access is in-bounds. If the array * index is not a constant expression, ensure that the array has a * declared size. */ ir_constant *const const_index = op[1]->constant_expression_value(); if (const_index != NULL) { const int idx = const_index->value.i[0]; const char *type_name; unsigned bound = 0; if (array->type->is_matrix()) { type_name = "matrix"; } else if (array->type->is_vector()) { type_name = "vector"; } else { type_name = "array"; } /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec: * * "It is illegal to declare an array with a size, and then * later (in the same shader) index the same array with an * integral constant expression greater than or equal to the * declared size. It is also illegal to index an array with a * negative constant expression." */ if (array->type->is_matrix()) { if (array->type->row_type()->vector_elements <= idx) { bound = array->type->row_type()->vector_elements; } } else if (array->type->is_vector()) { if (array->type->vector_elements <= idx) { bound = array->type->vector_elements; } } else { if ((array->type->array_size() > 0) && (array->type->array_size() <= idx)) { bound = array->type->array_size(); } } if (bound > 0) { _mesa_glsl_error(& loc, state, "%s index must be < %u", type_name, bound); error_emitted = true; } else if (idx < 0) { _mesa_glsl_error(& loc, state, "%s index must be >= 0", type_name); error_emitted = true; } if (array->type->is_array()) { /* 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; } } if (error_emitted) result->type = glsl_type::error_type; type = result->type; break; } case ast_function_call: /* Should *NEVER* get here. ast_function_call should always be handled * by ast_function_expression::hir. */ assert(0); break; case ast_identifier: { /* ast_identifier can appear several places in a full abstract syntax * tree. This particular use must be at location specified in the grammar * as 'variable_identifier'. */ ir_variable *var = state->symbols->get_variable(this->primary_expression.identifier); result = new ir_dereference_variable(var); if (var != NULL) { type = result->type; } else { _mesa_glsl_error(& loc, state, "`%s' undeclared", this->primary_expression.identifier); error_emitted = true; } break; } case ast_int_constant: type = glsl_type::int_type; result = new ir_constant(this->primary_expression.int_constant); break; case ast_uint_constant: type = glsl_type::uint_type; result = new ir_constant(this->primary_expression.uint_constant); break; case ast_float_constant: type = glsl_type::float_type; result = new ir_constant(this->primary_expression.float_constant); break; case ast_bool_constant: type = glsl_type::bool_type; result = new ir_constant(bool(this->primary_expression.bool_constant)); break; case ast_sequence: { /* It should not be possible to generate a sequence in the AST without * any expressions in it. */ 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_list_typed (ast_node, ast, link, &this->expressions) result = ast->hir(instructions, state); type = result->type; /* Any errors should have already been emitted in the loop above. */ error_emitted = true; break; } } if (type->is_error() && !error_emitted) _mesa_glsl_error(& loc, state, "type mismatch"); return result; } ir_rvalue * ast_expression_statement::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { /* It is possible to have expression statements that don't have an * expression. This is the solitary semicolon: * * for (i = 0; i < 5; i++) * ; * * In this case the expression will be NULL. Test for NULL and don't do * anything in that case. */ if (expression != NULL) expression->hir(instructions, state); /* Statements do not have r-values. */ return NULL; } ir_rvalue * ast_compound_statement::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { if (new_scope) state->symbols->push_scope(); foreach_list_typed (ast_node, ast, link, &this->statements) ast->hir(instructions, state); if (new_scope) state->symbols->pop_scope(); /* Compound statements do not have r-values. */ return NULL; } static const glsl_type * process_array_type(const glsl_type *base, ast_node *array_size, struct _mesa_glsl_parse_state *state) { unsigned length = 0; /* FINISHME: Reject delcarations of multidimensional arrays. */ if (array_size != NULL) { exec_list dummy_instructions; ir_rvalue *const ir = array_size->hir(& dummy_instructions, state); YYLTYPE loc = array_size->get_location(); /* FINISHME: Verify that the grammar forbids side-effects in array * FINISHME: sizes. i.e., 'vec4 [x = 12] data' */ assert(dummy_instructions.is_empty()); if (ir != NULL) { if (!ir->type->is_integer()) { _mesa_glsl_error(& loc, state, "array size must be integer type"); } else if (!ir->type->is_scalar()) { _mesa_glsl_error(& loc, state, "array size must be scalar type"); } else { ir_constant *const size = ir->constant_expression_value(); if (size == NULL) { _mesa_glsl_error(& loc, state, "array size must be a " "constant valued expression"); } else if (size->value.i[0] <= 0) { _mesa_glsl_error(& loc, state, "array size must be > 0"); } else { assert(size->type == ir->type); length = size->value.u[0]; } } } } return glsl_type::get_array_instance(base, length); } const glsl_type * ast_type_specifier::glsl_type(const char **name, struct _mesa_glsl_parse_state *state) const { const struct glsl_type *type; if ((this->type_specifier == ast_struct) && (this->type_name == NULL)) { /* FINISHME: Handle annonymous structures. */ type = NULL; } else { type = state->symbols->get_type(this->type_name); *name = this->type_name; if (this->is_array) { type = process_array_type(type, this->array_size, state); } } return type; } static void apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, struct ir_variable *var, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { if (qual->invariant) var->invariant = 1; /* FINISHME: Mark 'in' variables at global scope as read-only. */ if (qual->constant || qual->attribute || qual->uniform || (qual->varying && (state->target == fragment_shader))) var->read_only = 1; if (qual->centroid) var->centroid = 1; if (qual->attribute && state->target != vertex_shader) { var->type = glsl_type::error_type; _mesa_glsl_error(loc, state, "`attribute' variables may not be declared in the " "%s shader", _mesa_glsl_shader_target_name(state->target)); } /* From page 25 (page 31 of the PDF) of the GLSL 1.10 spec: * * "The varying qualifier can be used only with the data types * float, vec2, vec3, vec4, mat2, mat3, and mat4, or arrays of * these." */ if (qual->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) var->mode = ir_var_inout; else if (qual->attribute || qual->in || (qual->varying && (state->target == fragment_shader))) var->mode = ir_var_in; else if (qual->out || (qual->varying && (state->target == vertex_shader))) 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; if (qual->varying) { if (qual->in) var->shader_in = true; if (qual->out) var->shader_out = true; } if (qual->flat) var->interpolation = ir_var_flat; else if (qual->noperspective) var->interpolation = ir_var_noperspective; else var->interpolation = ir_var_smooth; if (var->type->is_array() && (state->language_version >= 120)) { var->array_lvalue = true; } } ir_rvalue * ast_declarator_list::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { 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. */ (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. */ 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; /* FINISHME: Emit a warning if a variable declaration shadows a * FINISHME: declaration at a higher scope. */ if ((decl_type == NULL) || decl_type->is_void()) { if (type_name != NULL) { _mesa_glsl_error(& loc, state, "invalid type `%s' in declaration of `%s'", type_name, decl->identifier); } else { _mesa_glsl_error(& loc, state, "invalid type in declaration of `%s'", decl->identifier); } continue; } if (decl->is_array) { var_type = process_array_type(decl_type, decl->array_size, state); } else { var_type = decl_type; } var = new ir_variable(var_type, decl->identifier); /* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification; * * "Global variables can only use the qualifiers const, * attribute, uni form, or varying. Only one may be * specified. * * Local variables can only use the qualifier const." * * This is relaxed in GLSL 1.30. */ if (state->language_version < 120) { if (this->type->qualifier.out) { _mesa_glsl_error(& loc, state, "`out' qualifier in declaration of `%s' " "only valid for function parameters in GLSL 1.10.", decl->identifier); } if (this->type->qualifier.in) { _mesa_glsl_error(& loc, state, "`in' qualifier in declaration of `%s' " "only valid for function parameters in GLSL 1.10.", decl->identifier); } /* FINISHME: Test for other invalid qualifiers. */ } 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 (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); } 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 = ""; /* There is no need to check for 'inout' here because the parser will * only allow that in function parameter lists. */ if (this->type->qualifier.attribute) { mode = "attribute"; } else if (this->type->qualifier.uniform) { mode = "uniform"; } else if (this->type->qualifier.varying) { mode = "varying"; } else if (this->type->qualifier.in) { mode = "in"; extra = " or in function parameter list"; } else if (this->type->qualifier.out) { mode = "out"; extra = " or in function parameter list"; } if (mode) { _mesa_glsl_error(& loc, state, "%s variable `%s' must be declared at " "global scope%s", mode, var->name, extra); } } else if (var->mode == ir_var_in) { if (state->target == vertex_shader) { bool error_emitted = false; /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec: * * "Vertex shader inputs can only be float, floating-point * vectors, matrices, signed and unsigned integers and integer * vectors. Vertex shader inputs can also form arrays of these * types, but not structures." * * From page 31 (page 27 of the PDF) of the GLSL 1.30 spec: * * "Vertex shader inputs can only be float, floating-point * vectors, matrices, signed and unsigned integers and integer * vectors. They cannot be arrays or structures." * * From page 23 (page 29 of the PDF) of the GLSL 1.20 spec: * * "The attribute qualifier can be used only with float, * floating-point vectors, and matrices. Attribute variables * cannot be declared as arrays or structures." */ const glsl_type *check_type = var->type->is_array() ? var->type->fields.array : var->type; switch (check_type->base_type) { case GLSL_TYPE_FLOAT: break; case GLSL_TYPE_UINT: case GLSL_TYPE_INT: if (state->language_version > 120) break; /* FALLTHROUGH */ default: _mesa_glsl_error(& loc, state, "vertex shader input / attribute cannot have " "type %s`%s'", var->type->is_array() ? "array of " : "", check_type->name); error_emitted = true; } if (!error_emitted && (state->language_version <= 130) && var->type->is_array()) { _mesa_glsl_error(& loc, state, "vertex shader input / attribute cannot have " "array type"); error_emitted = true; } } } if (decl->initializer != NULL) { YYLTYPE initializer_loc = decl->initializer->get_location(); /* From page 24 (page 30 of the PDF) of the GLSL 1.10 spec: * * "All uniform variables are read-only and are initialized either * directly by an application via API commands, or indirectly by * OpenGL." */ if ((state->language_version <= 110) && (var->mode == ir_var_uniform)) { _mesa_glsl_error(& initializer_loc, state, "cannot initialize uniforms in GLSL 1.10"); } if (var->type->is_sampler()) { _mesa_glsl_error(& initializer_loc, state, "cannot initialize samplers"); } if ((var->mode == ir_var_in) && (state->current_function == NULL)) { _mesa_glsl_error(& initializer_loc, state, "cannot initialize %s shader input / %s", _mesa_glsl_shader_target_name(state->target), (state->target == vertex_shader) ? "attribute" : "varying"); } 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 * declaration. */ if (this->type->qualifier.constant) { 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 " "constant expression", decl->identifier); } else { rhs = constant_value; var->constant_value = constant_value; } } if (rhs && !rhs->type->is_error()) { bool temp = var->read_only; if (this->type->qualifier.constant) var->read_only = false; result = do_assignment(instructions, state, lhs, rhs, this->get_location()); var->read_only = temp; } } /* From page 23 (page 29 of the PDF) of the GLSL 1.10 spec: * * "It is an error to write to a const variable outside of * its declaration, so they must be initialized when * declared." */ if (this->type->qualifier.constant && decl->initializer == NULL) { _mesa_glsl_error(& loc, state, "const declaration of `%s' must be initialized"); } /* Add the vairable to the symbol table after processing the initializer. * 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: * * "Within a declaration, the scope of a name starts immediately * after the initializer if present or immediately after the name * being declared if not." */ const bool added_variable = state->symbols->add_variable(decl->identifier, var); assert(added_variable); } /* Generally, variable declarations do not have r-values. However, * one is used for the declaration in * * while (bool b = some_condition()) { * ... * } * * so we return the rvalue from the last seen declaration here. */ return result; } ir_rvalue * ast_parameter_declarator::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { const struct glsl_type *type; const char *name = NULL; YYLTYPE loc = this->get_location(); type = this->type->specifier->glsl_type(& name, state); if (type == NULL) { if (name != NULL) { _mesa_glsl_error(& loc, state, "invalid type `%s' in declaration of `%s'", name, this->identifier); } else { _mesa_glsl_error(& loc, state, "invalid type in declaration of `%s'", this->identifier); } type = glsl_type::error_type; } /* From page 62 (page 68 of the PDF) of the GLSL 1.50 spec: * * "Functions that accept no input arguments need not use void in the * argument list because prototypes (or definitions) are required and * therefore there is no ambiguity when an empty argument list "( )" is * declared. The idiom "(void)" as a parameter list is provided for * convenience." * * Placing this check here prevents a void parameter being set up * for a function, which avoids tripping up checks for main taking * parameters and lookups of an unnamed symbol. */ if (type->is_void()) { if (this->identifier != NULL) _mesa_glsl_error(& loc, state, "named parameter cannot have type `void'"); is_void = true; return NULL; } if (formal_parameter && (this->identifier == NULL)) { _mesa_glsl_error(& loc, state, "formal parameter lacks a name"); return NULL; } is_void = false; ir_variable *var = new ir_variable(type, this->identifier); /* 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'. */ 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); /* Parameter declarations do not have r-values. */ return NULL; } void ast_parameter_declarator::parameters_to_hir(exec_list *ast_parameters, bool formal, exec_list *ir_parameters, _mesa_glsl_parse_state *state) { ast_parameter_declarator *void_param = NULL; unsigned count = 0; foreach_list_typed (ast_parameter_declarator, param, link, ast_parameters) { param->formal_parameter = formal; param->hir(ir_parameters, state); if (param->is_void) void_param = param; count++; } if ((void_param != NULL) && (count > 1)) { YYLTYPE loc = void_param->get_location(); _mesa_glsl_error(& loc, state, "`void' parameter must be only parameter"); } } ir_rvalue * ast_function::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { ir_function *f = NULL; ir_function_signature *sig = NULL; exec_list hir_parameters; /* 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. */ ast_parameter_declarator::parameters_to_hir(& this->parameters, is_definition, & hir_parameters, state); const char *return_type_name; const glsl_type *return_type = this->return_type->specifier->glsl_type(& return_type_name, state); assert(return_type != NULL); /* Verify that this function's signature either doesn't match a previously * seen signature for a function with the same name, or, if a match is found, * that the previously seen signature does not have an associated definition. */ const char *const name = identifier; f = state->symbols->get_function(name); if (f != NULL) { ir_function_signature *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' parameter `%s' " "qualifiers don't match prototype", name, badvar); } if (sig->return_type != return_type) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(&loc, state, "function `%s' return type doesn't " "match prototype", name); } if (is_definition && sig->is_defined) { 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 ir_function(name); state->symbols->add_function(f->name, f); /* Emit the new function header */ instructions->push_tail(f); } /* Verify the return type of main() */ if (strcmp(name, "main") == 0) { if (! return_type->is_void()) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "main() must return void"); } if (!hir_parameters.is_empty()) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "main() must not take any parameters"); } } /* Finish storing the information about this new function in its signature. */ if (sig == NULL) { sig = new ir_function_signature(return_type); f->add_signature(sig); } sig->replace_parameters(&hir_parameters); signature = sig; /* Function declarations (prototypes) do not have r-values. */ return NULL; } ir_rvalue * ast_function_definition::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { prototype->is_definition = true; prototype->hir(instructions, state); ir_function_signature *signature = prototype->signature; assert(state->current_function == NULL); state->current_function = signature; /* Duplicate parameters declared in the prototype as concrete variables. * Add these to the symbol table. */ state->symbols->push_scope(); foreach_iter(exec_list_iterator, iter, signature->parameters) { ir_variable *const var = ((ir_instruction *) iter.get())->as_variable(); assert(var != NULL); /* The only way a parameter would "exist" is if two parameters have * the same name. */ if (state->symbols->name_declared_this_scope(var->name)) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "parameter `%s' redeclared", var->name); } else { state->symbols->add_variable(var->name, var); } } /* Convert the body of the function to HIR. */ this->body->hir(&signature->body, state); signature->is_defined = true; state->symbols->pop_scope(); assert(state->current_function == signature); state->current_function = NULL; /* Function definitions do not have r-values. */ return NULL; } ir_rvalue * ast_jump_statement::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { switch (mode) { case ast_return: { ir_return *inst; assert(state->current_function); if (opt_return_value) { if (state->current_function->return_type->base_type == GLSL_TYPE_VOID) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "`return` with a value, in function `%s' " "returning void", state->current_function->function_name()); } ir_expression *const ret = (ir_expression *) opt_return_value->hir(instructions, state); assert(ret != NULL); /* FINISHME: Make sure the type of the return value matches the return * FINISHME: type of the enclosing function. */ inst = new ir_return(ret); } else { if (state->current_function->return_type->base_type != GLSL_TYPE_VOID) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "`return' with no value, in function %s returning " "non-void", state->current_function->function_name()); } inst = new ir_return; } instructions->push_tail(inst); break; } 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"); } break; case ast_break: case ast_continue: /* FINISHME: Handle switch-statements. They cannot contain 'continue', * FINISHME: and they use a different IR instruction for 'break'. */ /* FINISHME: Correctly handle the nesting. If a switch-statement is * FINISHME: inside a loop, a 'continue' is valid and will bind to the * FINISHME: loop. */ if (state->loop_or_switch_nesting == NULL) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "`%s' may only appear in a loop", (mode == ast_break) ? "break" : "continue"); } else { ir_loop *const loop = state->loop_or_switch_nesting->as_loop(); if (loop != NULL) { ir_loop_jump *const jump = new ir_loop_jump(loop, (mode == ast_break) ? ir_loop_jump::jump_break : ir_loop_jump::jump_continue); instructions->push_tail(jump); } } break; } /* Jump instructions do not have r-values. */ return NULL; } ir_rvalue * ast_selection_statement::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { ir_rvalue *const condition = this->condition->hir(instructions, state); /* From page 66 (page 72 of the PDF) of the GLSL 1.50 spec: * * "Any expression whose type evaluates to a Boolean can be used as the * conditional expression bool-expression. Vector types are not accepted * as the expression to if." * * The checks are separated so that higher quality diagnostics can be * generated for cases where both rules are violated. */ if (!condition->type->is_boolean() || !condition->type->is_scalar()) { YYLTYPE loc = this->condition->get_location(); _mesa_glsl_error(& loc, state, "if-statement condition must be scalar " "boolean"); } ir_if *const stmt = new ir_if(condition); if (then_statement != NULL) then_statement->hir(& stmt->then_instructions, state); if (else_statement != NULL) else_statement->hir(& stmt->else_instructions, state); instructions->push_tail(stmt); /* if-statements do not have r-values. */ return NULL; } void ast_iteration_statement::condition_to_hir(ir_loop *stmt, struct _mesa_glsl_parse_state *state) { if (condition != NULL) { ir_rvalue *const cond = condition->hir(& stmt->body_instructions, state); if ((cond == NULL) || !cond->type->is_boolean() || !cond->type->is_scalar()) { YYLTYPE loc = condition->get_location(); _mesa_glsl_error(& loc, state, "loop condition must be scalar boolean"); } else { /* As the first code in the loop body, generate a block that looks * like 'if (!condition) break;' as the loop termination condition. */ ir_rvalue *const not_cond = new ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond, NULL); 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); if_stmt->then_instructions.push_tail(break_stmt); stmt->body_instructions.push_tail(if_stmt); } } } ir_rvalue * ast_iteration_statement::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { /* For-loops and while-loops start a new scope, but do-while loops do not. */ if (mode != ast_do_while) state->symbols->push_scope(); if (init_statement != NULL) init_statement->hir(instructions, state); ir_loop *const stmt = new ir_loop(); instructions->push_tail(stmt); /* Track the current loop and / or switch-statement nesting. */ ir_instruction *const nesting = state->loop_or_switch_nesting; state->loop_or_switch_nesting = stmt; if (mode != ast_do_while) condition_to_hir(stmt, state); if (body != NULL) body->hir(& stmt->body_instructions, state); if (rest_expression != NULL) rest_expression->hir(& stmt->body_instructions, state); if (mode == ast_do_while) condition_to_hir(stmt, state); if (mode != ast_do_while) state->symbols->pop_scope(); /* Restore previous nesting before returning. */ state->loop_or_switch_nesting = nesting; /* Loops do not have r-values. */ return NULL; } ir_rvalue * ast_type_specifier::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { if (this->structure != NULL) return this->structure->hir(instructions, state); return NULL; } ir_rvalue * ast_struct_specifier::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { unsigned decl_count = 0; /* Make an initial pass over the list of structure fields to determine how * many there are. Each element in this list is an ast_declarator_list. * This means that we actually need to count the number of elements in the * 'declarations' list in each of the elements. */ foreach_list_typed (ast_declarator_list, decl_list, link, &this->declarations) { foreach_list_const (decl_ptr, & decl_list->declarations) { decl_count++; } } /* Allocate storage for the structure fields and process the field * declarations. As the declarations are processed, try to also convert * the types to HIR. This ensures that structure definitions embedded in * other structure definitions are processed. */ glsl_struct_field *const fields = (glsl_struct_field *) malloc(sizeof(*fields) * decl_count); unsigned i = 0; 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_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) : decl_type; fields[i].type = (field_type != NULL) ? field_type : glsl_type::error_type; fields[i].name = decl->identifier; i++; } } assert(i == decl_count); const char *name; if (this->name == NULL) { static unsigned anon_count = 1; char buf[32]; snprintf(buf, sizeof(buf), "#anon_struct_%04x", anon_count); anon_count++; name = strdup(buf); } else { name = this->name; } glsl_type *t = new glsl_type(fields, decl_count, name); 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. */ return NULL; }