X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=ast_to_hir.cpp;h=7b4a855f57674d20852f0dc3e530322e0cd8e72d;hb=8d3e59f1f399d7c1f7604779f1d62e876c609d9e;hp=fbadd403188aeaa72951a799bc8c5fc103dc1d9e;hpb=ab79d4ec6e7c5639084f71f93857f39239e8b848;p=mesa.git diff --git a/ast_to_hir.cpp b/ast_to_hir.cpp index fbadd403188..7b4a855f576 100644 --- a/ast_to_hir.cpp +++ b/ast_to_hir.cpp @@ -120,7 +120,8 @@ apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from, from = new ir_expression(ir_unop_u2f, to, from, NULL); break; case GLSL_TYPE_BOOL: - assert(!"FINISHME: Convert bool to float."); + from = new ir_expression(ir_unop_b2f, to, from, NULL); + break; default: assert(0); } @@ -132,7 +133,7 @@ apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from, static const struct glsl_type * arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, bool multiply, - struct _mesa_glsl_parse_state *state) + 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; @@ -144,6 +145,8 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, * 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; } @@ -154,6 +157,9 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, */ 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; } @@ -167,6 +173,8 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, * 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; } @@ -205,7 +213,13 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, * vector." */ if (type_a->is_vector() && type_b->is_vector()) { - return (type_a == type_b) ? type_a : glsl_type::error_type; + 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 , , @@ -234,7 +248,8 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, * more detail how vectors and matrices are operated on." */ if (! multiply) { - return (type_a == type_b) ? type_a : glsl_type::error_type; + 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 @@ -248,10 +263,13 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, * looking at the size of a vector that makes up a column. The * transpose (size of a row) is done for B. */ - return + 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 @@ -272,17 +290,22 @@ arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_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) +unary_arithmetic_result_type(const struct glsl_type *type, + struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { /* From GLSL 1.50 spec, page 57: * @@ -292,8 +315,11 @@ unary_arithmetic_result_type(const struct glsl_type *type) * component-wise on their operands. These result with the same type * they operated on." */ - if (!type->is_numeric()) + if (!type->is_numeric()) { + _mesa_glsl_error(loc, state, + "Operands to arithmetic operators must be numeric"); return glsl_type::error_type; + } return type; } @@ -301,7 +327,8 @@ unary_arithmetic_result_type(const struct glsl_type *type) static const struct glsl_type * modulus_result_type(const struct glsl_type *type_a, - const struct glsl_type *type_b) + 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 @@ -310,6 +337,7 @@ modulus_result_type(const struct glsl_type *type_a, */ 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; } @@ -328,13 +356,14 @@ modulus_result_type(const struct glsl_type *type_a, /* "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) + 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; @@ -347,8 +376,12 @@ relational_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, if (!type_a->is_numeric() || !type_b->is_numeric() || !type_a->is_scalar() - || !type_b->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 @@ -356,11 +389,16 @@ relational_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, */ 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; } - if (type_a->base_type != type_b->base_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." */ @@ -395,13 +433,23 @@ validate_assignment(const glsl_type *lhs_type, ir_rvalue *rhs) if (rhs_type->is_error()) return rhs; - /* FINISHME: For GLSL 1.10, check that the types are not arrays. */ - /* 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; + } + /* FINISHME: Check for and apply automatic conversions. */ return NULL; } @@ -426,6 +474,31 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, _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->var->as_variable(); + + 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); @@ -582,9 +655,9 @@ ast_expression::hir(exec_list *instructions, case ast_neg: op[0] = this->subexpressions[0]->hir(instructions, state); - type = unary_arithmetic_result_type(op[0]->type); + type = unary_arithmetic_result_type(op[0]->type, state, & loc); - error_emitted = op[0]->type->is_error(); + error_emitted = type->is_error(); result = new ir_expression(operations[this->oper], type, op[0], NULL); @@ -599,7 +672,8 @@ ast_expression::hir(exec_list *instructions, type = arithmetic_result_type(op[0], op[1], (this->oper == ast_mul), - state); + state, & loc); + error_emitted = type->is_error(); result = new ir_expression(operations[this->oper], type, op[0], op[1]); @@ -609,19 +683,19 @@ ast_expression::hir(exec_list *instructions, op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); - error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); - - type = modulus_result_type(op[0]->type, op[1]->type); + 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: - /* FINISHME: Implement bit-shift operators. */ + _mesa_glsl_error(& loc, state, "FINISHME: implement bit-shift operators"); + error_emitted = true; break; case ast_less: @@ -631,9 +705,7 @@ ast_expression::hir(exec_list *instructions, op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); - error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); - - type = relational_result_type(op[0], op[1], 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. @@ -644,6 +716,7 @@ ast_expression::hir(exec_list *instructions, result = new ir_expression(operations[this->oper], type, op[0], op[1]); + error_emitted = type->is_error(); break; case ast_nequal: @@ -684,14 +757,159 @@ ast_expression::hir(exec_list *instructions, case ast_bit_xor: case ast_bit_or: case ast_bit_not: - /* FINISHME: Implement bit-wise operators. */ + _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(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_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); + 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(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_assignment *const else_assign = + new ir_assignment(else_deref, op[1], NULL); + stmt->else_instructions.push_tail(else_assign); + + result = new ir_dereference(tmp); + type = tmp->type; + } break; + } - case ast_logic_and: case ast_logic_xor: - case ast_logic_or: + 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: - /* FINISHME: Implement logical operators. */ + 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: @@ -703,7 +921,7 @@ ast_expression::hir(exec_list *instructions, type = arithmetic_result_type(op[0], op[1], (this->oper == ast_mul_assign), - state); + state, & loc); ir_rvalue *temp_rhs = new ir_expression(operations[this->oper], type, op[0], op[1]); @@ -725,9 +943,7 @@ ast_expression::hir(exec_list *instructions, op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); - error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); - - type = modulus_result_type(op[0]->type, op[1]->type); + type = modulus_result_type(op[0]->type, op[1]->type, state, & loc); assert(operations[this->oper] == ir_binop_mod); @@ -738,17 +954,23 @@ ast_expression::hir(exec_list *instructions, result = do_assignment(instructions, state, op[0], temp_rhs, this->subexpressions[0]->get_location()); type = result->type; - error_emitted = op[0]->type->is_error(); + 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: { @@ -824,7 +1046,7 @@ ast_expression::hir(exec_list *instructions, else op[1] = new ir_constant(1); - type = arithmetic_result_type(op[0], op[1], false, state); + 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, @@ -847,7 +1069,7 @@ ast_expression::hir(exec_list *instructions, error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); - type = arithmetic_result_type(op[0], op[1], false, state); + 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, @@ -872,8 +1094,119 @@ ast_expression::hir(exec_list *instructions, type = result->type; break; - case ast_array_index: + 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_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]); + + delete op[0]; + array = lhs->var; + } else { + result = new ir_dereference(op[0], op[1]); + array = op[0]; + } + + /* 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()) { + ir_variable *const v = array->as_variable(); + 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 @@ -1042,22 +1375,21 @@ process_array_type(const glsl_type *base, ast_node *array_size, } -static const struct glsl_type * -type_specifier_to_glsl_type(const struct ast_type_specifier *spec, - const char **name, - struct _mesa_glsl_parse_state *state) +const glsl_type * +ast_type_specifier::glsl_type(const char **name, + struct _mesa_glsl_parse_state *state) const { - const glsl_type *type; + const struct glsl_type *type; - if (spec->type_specifier == ast_struct) { + if (this->type_specifier == ast_struct) { /* FINISHME: Handle annonymous structures. */ type = NULL; } else { - type = state->symbols->get_type(spec->type_name); - *name = spec->type_name; + type = state->symbols->get_type(this->type_name); + *name = this->type_name; - if (spec->is_array) { - type = process_array_type(type, spec->array_size, state); + if (this->is_array) { + type = process_array_type(type, this->array_size, state); } } @@ -1082,11 +1414,24 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, if (qual->centroid) var->centroid = 1; - if (qual->attribute && state->target == fragment_shader) { + 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 " - "fragment shader"); + "%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 && 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->in && qual->out) @@ -1101,12 +1446,25 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, 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; + } } @@ -1117,15 +1475,14 @@ ast_declarator_list::hir(exec_list *instructions, struct simple_node *ptr; const struct glsl_type *decl_type; const char *type_name = NULL; - + ir_rvalue *result = NULL; /* 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 = type_specifier_to_glsl_type(this->type->specifier, - & type_name, state); + decl_type = this->type->specifier->glsl_type(& type_name, state); foreach (ptr, &this->declarations) { struct ast_declaration *const decl = (struct ast_declaration * )ptr; @@ -1158,36 +1515,124 @@ ast_declarator_list::hir(exec_list *instructions, var = new ir_variable(var_type, decl->identifier); - /* FINISHME: Variables that are attribute, uniform, varying, in, or - * FINISHME: out varibles must be declared either at global scope or - * FINISHME: in a parameter list (in and out only). + /* 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. + * 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)) { - YYLTYPE loc = this->get_location(); + 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); + } - _mesa_glsl_error(& loc, state, "`%s' redeclared", - decl->identifier); continue; } - instructions->push_tail(var); - - if (this->type->qualifier.attribute - && (state->current_function != NULL)) { + /* 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, - "attribute variable `%s' must be declared at global " - "scope", - var->name); + "identifier `%s' uses reserved `gl_' prefix", + decl->identifier); } - if ((var->mode == ir_var_in) && (state->current_function == NULL)) { + 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; @@ -1263,25 +1708,51 @@ ast_declarator_list::hir(exec_list *instructions, if ((var->mode == ir_var_in) && (state->current_function == NULL)) { _mesa_glsl_error(& initializer_loc, state, "cannot initialize %s shader input / %s", - (state->target == vertex_shader) - ? "vertex" : "fragment", + _mesa_glsl_shader_target_name(state->target), (state->target == vertex_shader) ? "attribute" : "varying"); } ir_dereference *const lhs = new ir_dereference(var); - ir_rvalue *const rhs = decl->initializer->hir(instructions, state); + ir_rvalue *rhs = decl->initializer->hir(instructions, state); - /* FINISHME: If the declaration is either 'const' or 'uniform', the - * FINISHME: initializer (rhs) must be a constant expression. + /* 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->type->is_error()) { - (void) do_assignment(instructions, state, lhs, rhs, - this->get_location()); + 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 @@ -1296,9 +1767,17 @@ ast_declarator_list::hir(exec_list *instructions, assert(added_variable); } - /* Variable declarations do not have r-values. + + /* 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 NULL; + return result; } @@ -1310,7 +1789,7 @@ ast_parameter_declarator::hir(exec_list *instructions, const char *name = NULL; YYLTYPE loc = this->get_location(); - type = type_specifier_to_glsl_type(this->type->specifier, & name, state); + type = this->type->specifier->glsl_type(& name, state); if (type == NULL) { if (name != NULL) { @@ -1326,6 +1805,33 @@ ast_parameter_declarator::hir(exec_list *instructions, 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 @@ -1347,15 +1853,32 @@ ast_parameter_declarator::hir(exec_list *instructions, } -static void -ast_function_parameters_to_hir(struct simple_node *ast_parameters, - exec_list *ir_parameters, - struct _mesa_glsl_parse_state *state) +void +ast_parameter_declarator::parameters_to_hir(struct simple_node *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_node *)ptr)->hir(ir_parameters, state); + ast_parameter_declarator *param = (ast_parameter_declarator *)ptr; + 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"); } } @@ -1366,49 +1889,50 @@ parameter_lists_match(exec_list *list_a, exec_list *list_b) exec_list_iterator iter_a = list_a->iterator(); exec_list_iterator iter_b = list_b->iterator(); - while (iter_a.has_next()) { - /* If all of the parameters from the other parameter list have been - * exhausted, the lists have different length and, by definition, - * do not match. - */ - if (!iter_b.has_next()) - return false; + while (iter_a.has_next() && iter_b.has_next()) { + ir_variable *a = (ir_variable *)iter_a.get(); + ir_variable *b = (ir_variable *)iter_b.get(); /* If the types of the parameters do not match, the parameters lists * are different. */ - /* FINISHME */ - + if (a->type != b->type) + return false; iter_a.next(); iter_b.next(); } + /* Unless both lists are exhausted, they differ in length and, by + * definition, do not match. + */ + if (iter_a.has_next() != iter_b.has_next()) + return false; + return true; } ir_rvalue * -ast_function_definition::hir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) +ast_function::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) { - ir_label *label; - ir_function_signature *signature = NULL; ir_function *f = NULL; - exec_list parameters; + 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_function_parameters_to_hir(& this->prototype->parameters, & parameters, - state); + ast_parameter_declarator::parameters_to_hir(& this->parameters, + is_definition, + & hir_parameters, state); const char *return_type_name; const glsl_type *return_type = - type_specifier_to_glsl_type(this->prototype->return_type->specifier, - & return_type_name, state); + this->return_type->specifier->glsl_type(& return_type_name, state); assert(return_type != NULL); @@ -1416,30 +1940,60 @@ ast_function_definition::hir(exec_list *instructions, * 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 = this->prototype->identifier; + const char *const name = identifier; f = state->symbols->get_function(name); if (f != NULL) { - foreach_iter(exec_list_iterator, iter, f->signatures) { - signature = (struct ir_function_signature *) iter.get(); + foreach_iter(exec_list_iterator, iter, *f) { + sig = (struct ir_function_signature *) iter.get(); /* Compare the parameter list of the function being defined to the * existing function. If the parameter lists match, then the return * type must also match and the existing function must not have a * definition. */ - if (parameter_lists_match(& parameters, & signature->parameters)) { - /* FINISHME: Compare return types. */ + if (parameter_lists_match(& hir_parameters, & sig->parameters)) { + exec_list_iterator iter_a = hir_parameters.iterator(); + exec_list_iterator iter_b = sig->parameters.iterator(); + + /* check that the qualifiers match. */ + while (iter_a.has_next()) { + ir_variable *a = (ir_variable *)iter_a.get(); + ir_variable *b = (ir_variable *)iter_b.get(); + + if (a->read_only != b->read_only || + a->interpolation != b->interpolation || + a->centroid != b->centroid) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, + "function `%s' parameter `%s' qualifiers " + "don't match prototype", + name, a->name); + } + + iter_a.next(); + iter_b.next(); + } - if (signature->definition != NULL) { + 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); - signature = NULL; + sig = NULL; break; } } - signature = NULL; + sig = NULL; } } else if (state->symbols->name_declared_this_scope(name)) { @@ -1449,32 +2003,41 @@ ast_function_definition::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "function name `%s' conflicts with " "non-function", name); - signature = NULL; + 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 != glsl_type::get_instance(GLSL_TYPE_VOID, 0, 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 (signature == NULL) { - signature = new ir_function_signature(return_type); - f->signatures.push_tail(signature); - } else { + if (sig == NULL) { + sig = new ir_function_signature(return_type); + f->add_signature(sig); + } else if (is_definition) { /* Destroy all of the previous parameter information. The previous * parameter information comes from the function prototype, and it can * either include invalid parameter names or may not have names at all. */ - foreach_iter(exec_list_iterator, iter, signature->parameters) { + foreach_iter(exec_list_iterator, iter, sig->parameters) { assert(((ir_instruction *) iter.get())->as_variable() != NULL); iter.remove(); @@ -1482,34 +2045,35 @@ ast_function_definition::hir(exec_list *instructions, } } + hir_parameters.move_nodes_to(& sig->parameters); + signature = sig; - assert(state->current_function == NULL); - state->current_function = signature; + /* Function declarations (prototypes) do not have r-values. + */ + return NULL; +} - ast_function_parameters_to_hir(& this->prototype->parameters, - & signature->parameters, - state); - /* FINISHME: Set signature->return_type */ - label = new ir_label(name); - if (signature->definition == NULL) { - signature->definition = label; - } - instructions->push_tail(label); +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; - /* Add the function parameters to the symbol table. During this step the - * parameter declarations are also moved from the temporary "parameters" list - * to the instruction list. There are other more efficient ways to do this, - * but they involve ugly linked-list gymnastics. + /* 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, parameters) { - ir_variable *const var = (ir_variable *) iter.get(); + foreach_iter(exec_list_iterator, iter, signature->parameters) { + ir_variable *const var = ((ir_instruction *) iter.get())->as_variable(); - assert(((ir_instruction *) var)->as_variable() != NULL); - - iter.remove(); - instructions->push_tail(var); + assert(var != NULL); /* The only way a parameter would "exist" is if two parameters have * the same name. @@ -1523,11 +2087,9 @@ ast_function_definition::hir(exec_list *instructions, } } - /* Convert the body of the function to HIR, and append the resulting - * instructions to the list that currently consists of the function label - * and the function parameters. - */ - this->body->hir(instructions, state); + /* Convert the body of the function to HIR. */ + this->body->hir(&signature->body, state); + signature->is_defined = true; state->symbols->pop_scope(); @@ -1545,11 +2107,12 @@ ast_jump_statement::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { - if (mode == ast_return) { + switch (mode) { + case ast_return: { ir_return *inst; + assert(state->current_function); if (opt_return_value) { - assert(state->current_function); if (state->current_function->return_type->base_type == GLSL_TYPE_VOID) { YYLTYPE loc = this->get_location(); @@ -1557,7 +2120,7 @@ ast_jump_statement::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "`return` with a value, in function `%s' " "returning void", - state->current_function->definition->label); + state->current_function->function_name()); } ir_expression *const ret = (ir_expression *) @@ -1570,12 +2133,61 @@ ast_jump_statement::hir(exec_list *instructions, inst = new ir_return(ret); } else { - /* FINISHME: Make sure the enclosing function has a void return type. - */ + 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. @@ -1630,3 +2242,87 @@ ast_selection_statement::hir(exec_list *instructions, */ 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) { + ast_node *node = (ast_node *) body; + do { + node->hir(& stmt->body_instructions, state); + node = (ast_node *) node->next; + } while (node != body); + } + + 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; +}