X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fast_to_hir.cpp;h=5157661b39eca7c6e15bc58a3157026ed1bfd618;hb=2acc7193743199701f8f6d1877a59ece0ec4fa5b;hp=f0c92187507bd4041270f4b46b64efcf50da3ba2;hpb=39464489510270bbe472d11f7614c04ce1b6ae33;p=mesa.git diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index f0c92187507..5157661b39e 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -54,8 +54,13 @@ #include "glsl_parser_extras.h" #include "ast.h" #include "glsl_types.h" +#include "program/hash_table.h" #include "ir.h" +static void +detect_conflicting_assignments(struct _mesa_glsl_parse_state *state, + exec_list *instructions); + void _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { @@ -86,6 +91,7 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) ast->hir(instructions, state); detect_recursion_unlinked(state, instructions); + detect_conflicting_assignments(state, instructions); state->toplevel_ir = NULL; } @@ -664,15 +670,25 @@ mark_whole_array_access(ir_rvalue *access) ir_rvalue * do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, + const char *non_lvalue_description, ir_rvalue *lhs, ir_rvalue *rhs, bool is_initializer, YYLTYPE lhs_loc) { void *ctx = state; bool error_emitted = (lhs->type->is_error() || rhs->type->is_error()); + ir_variable *lhs_var = lhs->variable_referenced(); + if (lhs_var) + lhs_var->assigned = true; + if (!error_emitted) { - if (lhs->variable_referenced() != NULL - && lhs->variable_referenced()->read_only) { + if (non_lvalue_description != NULL) { + _mesa_glsl_error(&lhs_loc, state, + "assignment to %s", + non_lvalue_description); + error_emitted = true; + } else if (lhs->variable_referenced() != NULL + && lhs->variable_referenced()->read_only) { _mesa_glsl_error(&lhs_loc, state, "assignment to read-only variable '%s'", lhs->variable_referenced()->name); @@ -744,13 +760,11 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, ir_var_temporary); ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var); instructions->push_tail(var); - instructions->push_tail(new(ctx) ir_assignment(deref_var, - rhs, - NULL)); + instructions->push_tail(new(ctx) ir_assignment(deref_var, rhs)); deref_var = new(ctx) ir_dereference_variable(var); if (!error_emitted) - instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var, NULL)); + instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var)); return new(ctx) ir_dereference_variable(var); } @@ -767,12 +781,7 @@ get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue) var->mode = ir_var_auto; instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var), - lvalue, NULL)); - - /* Once we've created this temporary, mark it read only so it's no - * longer considered an lvalue. - */ - var->read_only = true; + lvalue)); return new(ctx) ir_dereference_variable(var); } @@ -1030,7 +1039,9 @@ ast_expression::hir(exec_list *instructions, 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], false, + result = do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0], op[1], false, this->subexpressions[0]->get_location()); error_emitted = result->type->is_error(); break; @@ -1195,15 +1206,9 @@ ast_expression::hir(exec_list *instructions, op[1] = get_scalar_boolean_operand(&rhs_instructions, state, this, 1, "RHS", &error_emitted); - ir_constant *op0_const = op[0]->constant_expression_value(); - if (op0_const) { - if (op0_const->value.b[0]) { - instructions->append_list(&rhs_instructions); - result = op[1]; - } else { - result = op0_const; - } - type = glsl_type::bool_type; + if (rhs_instructions.is_empty()) { + result = new(ctx) ir_expression(ir_binop_logic_and, op[0], op[1]); + type = result->type; } else { ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type, "and_tmp", @@ -1216,12 +1221,12 @@ ast_expression::hir(exec_list *instructions, stmt->then_instructions.append_list(&rhs_instructions); ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const then_assign = - new(ctx) ir_assignment(then_deref, op[1], NULL); + new(ctx) ir_assignment(then_deref, op[1]); stmt->then_instructions.push_tail(then_assign); ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const else_assign = - new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false), NULL); + new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false)); stmt->else_instructions.push_tail(else_assign); result = new(ctx) ir_dereference_variable(tmp); @@ -1237,14 +1242,9 @@ ast_expression::hir(exec_list *instructions, op[1] = get_scalar_boolean_operand(&rhs_instructions, state, this, 1, "RHS", &error_emitted); - ir_constant *op0_const = op[0]->constant_expression_value(); - if (op0_const) { - if (op0_const->value.b[0]) { - result = op0_const; - } else { - result = op[1]; - } - type = glsl_type::bool_type; + if (rhs_instructions.is_empty()) { + result = new(ctx) ir_expression(ir_binop_logic_or, op[0], op[1]); + type = result->type; } else { ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type, "or_tmp", @@ -1256,13 +1256,13 @@ ast_expression::hir(exec_list *instructions, ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const then_assign = - new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true), NULL); + new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true)); stmt->then_instructions.push_tail(then_assign); stmt->else_instructions.append_list(&rhs_instructions); ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const else_assign = - new(ctx) ir_assignment(else_deref, op[1], NULL); + new(ctx) ir_assignment(else_deref, op[1]); stmt->else_instructions.push_tail(else_assign); result = new(ctx) ir_dereference_variable(tmp); @@ -1310,6 +1310,7 @@ ast_expression::hir(exec_list *instructions, op[0], op[1]); result = do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, op[0]->clone(ctx, NULL), temp_rhs, false, this->subexpressions[0]->get_location()); error_emitted = (op[0]->type->is_error()); @@ -1335,6 +1336,7 @@ ast_expression::hir(exec_list *instructions, op[0], op[1]); result = do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, op[0]->clone(ctx, NULL), temp_rhs, false, this->subexpressions[0]->get_location()); error_emitted = type->is_error(); @@ -1349,8 +1351,9 @@ ast_expression::hir(exec_list *instructions, &loc); ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); - result = do_assignment(instructions, state, op[0]->clone(ctx, NULL), - temp_rhs, false, + result = do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0]->clone(ctx, NULL), temp_rhs, false, this->subexpressions[0]->get_location()); error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); break; @@ -1365,8 +1368,9 @@ ast_expression::hir(exec_list *instructions, state, &loc); ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); - result = do_assignment(instructions, state, op[0]->clone(ctx, NULL), - temp_rhs, false, + result = do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0]->clone(ctx, NULL), temp_rhs, false, this->subexpressions[0]->get_location()); error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); break; @@ -1446,14 +1450,14 @@ ast_expression::hir(exec_list *instructions, ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const then_assign = - new(ctx) ir_assignment(then_deref, op[1], NULL); + new(ctx) ir_assignment(then_deref, op[1]); stmt->then_instructions.push_tail(then_assign); else_instructions.move_nodes_to(& stmt->else_instructions); ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const else_assign = - new(ctx) ir_assignment(else_deref, op[2], NULL); + new(ctx) ir_assignment(else_deref, op[2]); stmt->else_instructions.push_tail(else_assign); result = new(ctx) ir_dereference_variable(tmp); @@ -1463,6 +1467,9 @@ ast_expression::hir(exec_list *instructions, case ast_pre_inc: case ast_pre_dec: { + this->non_lvalue_description = (this->oper == ast_pre_inc) + ? "pre-increment operation" : "pre-decrement operation"; + op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = constant_one_for_inc_dec(ctx, op[0]->type); @@ -1473,6 +1480,7 @@ ast_expression::hir(exec_list *instructions, op[0], op[1]); result = do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, op[0]->clone(ctx, NULL), temp_rhs, false, this->subexpressions[0]->get_location()); error_emitted = op[0]->type->is_error(); @@ -1481,6 +1489,8 @@ ast_expression::hir(exec_list *instructions, case ast_post_inc: case ast_post_dec: { + this->non_lvalue_description = (this->oper == ast_post_inc) + ? "post-increment operation" : "post-decrement operation"; op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = constant_one_for_inc_dec(ctx, op[0]->type); @@ -1498,6 +1508,7 @@ ast_expression::hir(exec_list *instructions, result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL)); (void)do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, op[0]->clone(ctx, NULL), temp_rhs, false, this->subexpressions[0]->get_location()); @@ -1688,14 +1699,14 @@ ast_expression::hir(exec_list *instructions, ir_variable *var = state->symbols->get_variable(this->primary_expression.identifier); - result = new(ctx) ir_dereference_variable(var); - if (var != NULL) { var->used = true; + result = new(ctx) ir_dereference_variable(var); } else { _mesa_glsl_error(& loc, state, "`%s' undeclared", this->primary_expression.identifier); + result = ir_rvalue::error_value(ctx); error_emitted = true; } break; @@ -1906,7 +1917,8 @@ static void apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, ir_variable *var, struct _mesa_glsl_parse_state *state, - YYLTYPE *loc) + YYLTYPE *loc, + bool ubo_qualifiers_valid) { if (qual->flags.q.invariant) { if (var->used) { @@ -1996,6 +2008,15 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, else var->interpolation = INTERP_QUALIFIER_NONE; + if (var->interpolation != INTERP_QUALIFIER_NONE && + !(state->target == vertex_shader && var->mode == ir_var_out) && + !(state->target == fragment_shader && var->mode == ir_var_in)) { + _mesa_glsl_error(loc, state, + "interpolation qualifier `%s' can only be applied to " + "vertex shader outputs and fragment shader inputs.", + var->interpolation_string()); + } + var->pixel_center_integer = qual->flags.q.pixel_center_integer; var->origin_upper_left = qual->flags.q.origin_upper_left; if ((qual->flags.q.origin_upper_left || qual->flags.q.pixel_center_integer) @@ -2065,14 +2086,36 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, } else { var->location = qual->location; } + + if (qual->flags.q.explicit_index) { + /* From the GLSL 4.30 specification, section 4.4.2 (Output + * Layout Qualifiers): + * + * "It is also a compile-time error if a fragment shader + * sets a layout index to less than 0 or greater than 1." + * + * Older specifications don't mandate a behavior; we take + * this as a clarification and always generate the error. + */ + if (qual->index < 0 || qual->index > 1) { + _mesa_glsl_error(loc, state, + "explicit index may only be 0 or 1\n"); + } else { + var->explicit_index = true; + var->index = qual->index; + } + } } + } else if (qual->flags.q.explicit_index) { + _mesa_glsl_error(loc, state, + "explicit index requires explicit location\n"); } /* Does the declaration use the 'layout' keyword? */ const bool uses_layout = qual->flags.q.pixel_center_integer || qual->flags.q.origin_upper_left - || qual->flags.q.explicit_location; + || qual->flags.q.explicit_location; /* no need for index since it relies on location */ /* Does the declaration use the deprecated 'attribute' or 'varying' * keywords? @@ -2150,6 +2193,23 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->depth_layout = ir_depth_layout_unchanged; else var->depth_layout = ir_depth_layout_none; + + if (qual->flags.q.std140 || + qual->flags.q.packed || + qual->flags.q.shared) { + _mesa_glsl_error(loc, state, + "uniform block layout qualifiers std140, packed, and " + "shared can only be applied to uniform blocks, not " + "members"); + } + + if (!ubo_qualifiers_valid && + (qual->flags.q.row_major || qual->flags.q.column_major)) { + _mesa_glsl_error(loc, state, + "uniform block layout qualifiers row_major and " + "column_major can only be applied to uniform block " + "members"); + } } /** @@ -2365,6 +2425,7 @@ process_initializer(ir_variable *var, ast_declaration *decl, const glsl_type *initializer_type; if (!type->qualifier.flags.q.uniform) { result = do_assignment(initializer_instructions, state, + NULL, lhs, rhs, true, type->get_location()); initializer_type = result->type; @@ -2569,7 +2630,7 @@ ast_declarator_list::hir(exec_list *instructions, } apply_type_qualifier_to_variable(& this->type->qualifier, var, state, - & loc); + & loc, this->ubo_qualifiers_valid); if (this->type->qualifier.flags.q.invariant) { if ((state->target == vertex_shader) && !(var->mode == ir_var_out || @@ -2986,7 +3047,8 @@ ast_parameter_declarator::hir(exec_list *instructions, /* 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); + apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc, + false); /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec: * @@ -3367,7 +3429,7 @@ ast_jump_statement::hir(exec_list *instructions, "continue may only appear in a loop"); } else if (mode == ast_break && state->loop_nesting_ast == NULL && - state->switch_nesting_ast == NULL) { + state->switch_state.switch_nesting_ast == NULL) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, @@ -3385,18 +3447,16 @@ ast_jump_statement::hir(exec_list *instructions, state); } - if (state->is_switch_innermost && + if (state->switch_state.is_switch_innermost && mode == ast_break) { /* Force break out of switch by setting is_break switch state. */ - ir_variable *const is_break_var = state->is_break_var; + ir_variable *const is_break_var = state->switch_state.is_break_var; ir_dereference_variable *const deref_is_break_var = new(ctx) ir_dereference_variable(is_break_var); ir_constant *const true_val = new(ctx) ir_constant(true); ir_assignment *const set_break_var = - new(ctx) ir_assignment(deref_is_break_var, - true_val, - NULL); + new(ctx) ir_assignment(deref_is_break_var, true_val); instructions->push_tail(set_break_var); } @@ -3477,11 +3537,9 @@ ast_switch_statement::hir(exec_list *instructions, * * "The type of init-expression in a switch statement must be a * scalar integer." - * - * The checks are separated so that higher quality diagnostics can be - * generated for cases where the rule is violated. */ - if (!test_expression->type->is_integer()) { + if (!test_expression->type->is_scalar() || + !test_expression->type->is_integer()) { YYLTYPE loc = this->test_expression->get_location(); _mesa_glsl_error(& loc, @@ -3492,61 +3550,54 @@ ast_switch_statement::hir(exec_list *instructions, /* Track the switch-statement nesting in a stack-like manner. */ - ir_variable *saved_test_var = state->test_var; - ir_variable *saved_is_fallthru_var = state->is_fallthru_var; - - bool save_is_switch_innermost = state->is_switch_innermost; - ast_switch_statement *saved_nesting_ast = state->switch_nesting_ast; + struct glsl_switch_state saved = state->switch_state; - state->is_switch_innermost = true; - state->switch_nesting_ast = this; + state->switch_state.is_switch_innermost = true; + state->switch_state.switch_nesting_ast = this; + state->switch_state.labels_ht = hash_table_ctor(0, hash_table_pointer_hash, + hash_table_pointer_compare); + state->switch_state.previous_default = NULL; /* Initalize is_fallthru state to false. */ ir_rvalue *const is_fallthru_val = new (ctx) ir_constant(false); - state->is_fallthru_var = new(ctx) ir_variable(glsl_type::bool_type, - "switch_is_fallthru_tmp", - ir_var_temporary); - instructions->push_tail(state->is_fallthru_var); + state->switch_state.is_fallthru_var = + new(ctx) ir_variable(glsl_type::bool_type, + "switch_is_fallthru_tmp", + ir_var_temporary); + instructions->push_tail(state->switch_state.is_fallthru_var); ir_dereference_variable *deref_is_fallthru_var = - new(ctx) ir_dereference_variable(state->is_fallthru_var); + new(ctx) ir_dereference_variable(state->switch_state.is_fallthru_var); instructions->push_tail(new(ctx) ir_assignment(deref_is_fallthru_var, - is_fallthru_val, - NULL)); + is_fallthru_val)); /* Initalize is_break state to false. */ ir_rvalue *const is_break_val = new (ctx) ir_constant(false); - state->is_break_var = new(ctx) ir_variable(glsl_type::bool_type, - "switch_is_break_tmp", - ir_var_temporary); - instructions->push_tail(state->is_break_var); + state->switch_state.is_break_var = new(ctx) ir_variable(glsl_type::bool_type, + "switch_is_break_tmp", + ir_var_temporary); + instructions->push_tail(state->switch_state.is_break_var); ir_dereference_variable *deref_is_break_var = - new(ctx) ir_dereference_variable(state->is_break_var); + new(ctx) ir_dereference_variable(state->switch_state.is_break_var); instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var, - is_break_val, - NULL)); + is_break_val)); /* Cache test expression. */ test_to_hir(instructions, state); - + /* Emit code for body of switch stmt. */ body->hir(instructions, state); - /* Restore previous nesting before returning. - */ - state->switch_nesting_ast = saved_nesting_ast; - state->is_switch_innermost = save_is_switch_innermost; + hash_table_dtor(state->switch_state.labels_ht); - state->test_var = saved_test_var; - state->is_fallthru_var = saved_is_fallthru_var; + state->switch_state = saved; - /* Switch statements do not have r-values. - */ + /* Switch statements do not have r-values. */ return NULL; } @@ -3557,22 +3608,19 @@ ast_switch_statement::test_to_hir(exec_list *instructions, { void *ctx = state; - /* Cache value of test expression. - */ + /* Cache value of test expression. */ ir_rvalue *const test_val = test_expression->hir(instructions, state); - state->test_var = new(ctx) ir_variable(glsl_type::int_type, - "switch_test_tmp", - ir_var_temporary); + state->switch_state.test_var = new(ctx) ir_variable(test_val->type, + "switch_test_tmp", + ir_var_temporary); ir_dereference_variable *deref_test_var = - new(ctx) ir_dereference_variable(state->test_var); + new(ctx) ir_dereference_variable(state->switch_state.test_var); - instructions->push_tail(state->test_var); - instructions->push_tail(new(ctx) ir_assignment(deref_test_var, - test_val, - NULL)); + instructions->push_tail(state->switch_state.test_var); + instructions->push_tail(new(ctx) ir_assignment(deref_test_var, test_val)); } @@ -3582,58 +3630,51 @@ ast_switch_body::hir(exec_list *instructions, { if (stmts != NULL) stmts->hir(instructions, state); - - /* Switch bodies do not have r-values. - */ + + /* Switch bodies do not have r-values. */ return NULL; } - ir_rvalue * ast_case_statement_list::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { foreach_list_typed (ast_case_statement, case_stmt, link, & this->cases) case_stmt->hir(instructions, state); - - /* Case statements do not have r-values. - */ + + /* Case statements do not have r-values. */ return NULL; } - ir_rvalue * ast_case_statement::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { labels->hir(instructions, state); - - /* Conditionally set fallthru state based on break state. - */ + + /* Conditionally set fallthru state based on break state. */ ir_constant *const false_val = new(state) ir_constant(false); ir_dereference_variable *const deref_is_fallthru_var = - new(state) ir_dereference_variable(state->is_fallthru_var); + new(state) ir_dereference_variable(state->switch_state.is_fallthru_var); ir_dereference_variable *const deref_is_break_var = - new(state) ir_dereference_variable(state->is_break_var); + new(state) ir_dereference_variable(state->switch_state.is_break_var); ir_assignment *const reset_fallthru_on_break = new(state) ir_assignment(deref_is_fallthru_var, false_val, deref_is_break_var); instructions->push_tail(reset_fallthru_on_break); - /* Guard case statements depending on fallthru state. - */ + /* Guard case statements depending on fallthru state. */ ir_dereference_variable *const deref_fallthru_guard = - new(state) ir_dereference_variable(state->is_fallthru_var); + new(state) ir_dereference_variable(state->switch_state.is_fallthru_var); ir_if *const test_fallthru = new(state) ir_if(deref_fallthru_guard); - + foreach_list_typed (ast_node, stmt, link, & this->stmts) stmt->hir(& test_fallthru->then_instructions, state); instructions->push_tail(test_fallthru); - - /* Case statements do not have r-values. - */ + + /* Case statements do not have r-values. */ return NULL; } @@ -3644,13 +3685,11 @@ ast_case_label_list::hir(exec_list *instructions, { foreach_list_typed (ast_case_label, label, link, & this->labels) label->hir(instructions, state); - - /* Case labels do not have r-values. - */ + + /* Case labels do not have r-values. */ return NULL; } - ir_rvalue * ast_case_label::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -3658,49 +3697,83 @@ ast_case_label::hir(exec_list *instructions, void *ctx = state; ir_dereference_variable *deref_fallthru_var = - new(ctx) ir_dereference_variable(state->is_fallthru_var); - + new(ctx) ir_dereference_variable(state->switch_state.is_fallthru_var); + ir_rvalue *const true_val = new(ctx) ir_constant(true); - /* If not default case, ... - */ + /* If not default case, ... */ if (this->test_value != NULL) { /* Conditionally set fallthru state based on * comparison of cached test expression value to case label. */ - ir_rvalue *const test_val = this->test_value->hir(instructions, state); + ir_rvalue *const label_rval = this->test_value->hir(instructions, state); + ir_constant *label_const = label_rval->constant_expression_value(); + + if (!label_const) { + YYLTYPE loc = this->test_value->get_location(); + + _mesa_glsl_error(& loc, state, + "switch statement case label must be a " + "constant expression"); + + /* Stuff a dummy value in to allow processing to continue. */ + label_const = new(ctx) ir_constant(0); + } else { + ast_expression *previous_label = (ast_expression *) + hash_table_find(state->switch_state.labels_ht, + (void *)(uintptr_t)label_const->value.u[0]); + + if (previous_label) { + YYLTYPE loc = this->test_value->get_location(); + _mesa_glsl_error(& loc, state, + "duplicate case value"); + + loc = previous_label->get_location(); + _mesa_glsl_error(& loc, state, + "this is the previous case label"); + } else { + hash_table_insert(state->switch_state.labels_ht, + this->test_value, + (void *)(uintptr_t)label_const->value.u[0]); + } + } ir_dereference_variable *deref_test_var = - new(ctx) ir_dereference_variable(state->test_var); + new(ctx) ir_dereference_variable(state->switch_state.test_var); ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal, - glsl_type::bool_type, - test_val, + label_const, deref_test_var); ir_assignment *set_fallthru_on_test = new(ctx) ir_assignment(deref_fallthru_var, true_val, test_cond); - + instructions->push_tail(set_fallthru_on_test); } else { /* default case */ - /* Set falltrhu state. - */ + if (state->switch_state.previous_default) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(& loc, state, + "multiple default labels in one switch"); + + loc = state->switch_state.previous_default->get_location(); + _mesa_glsl_error(& loc, state, + "this is the first default label"); + } + state->switch_state.previous_default = this; + + /* Set falltrhu state. */ ir_assignment *set_fallthru = - new(ctx) ir_assignment(deref_fallthru_var, - true_val, - NULL); - + new(ctx) ir_assignment(deref_fallthru_var, true_val); + instructions->push_tail(set_fallthru); } - - /* Case statements do not have r-values. - */ + + /* Case statements do not have r-values. */ return NULL; } - void ast_iteration_statement::condition_to_hir(ir_loop *stmt, struct _mesa_glsl_parse_state *state) @@ -3722,8 +3795,7 @@ ast_iteration_statement::condition_to_hir(ir_loop *stmt, * like 'if (!condition) break;' as the loop termination condition. */ ir_rvalue *const not_cond = - new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond, - NULL); + new(ctx) ir_expression(ir_unop_logic_not, cond); ir_if *const if_stmt = new(ctx) ir_if(not_cond); @@ -3754,8 +3826,7 @@ ast_iteration_statement::hir(exec_list *instructions, ir_loop *const stmt = new(ctx) ir_loop(); instructions->push_tail(stmt); - /* Track the current loop nesting. - */ + /* Track the current loop nesting. */ ast_iteration_statement *nesting_ast = state->loop_nesting_ast; state->loop_nesting_ast = this; @@ -3763,8 +3834,8 @@ ast_iteration_statement::hir(exec_list *instructions, /* Likewise, indicate that following code is closest to a loop, * NOT closest to a switch. */ - bool saved_is_switch_innermost = state->is_switch_innermost; - state->is_switch_innermost = false; + bool saved_is_switch_innermost = state->switch_state.is_switch_innermost; + state->switch_state.is_switch_innermost = false; if (mode != ast_do_while) condition_to_hir(stmt, state); @@ -3781,10 +3852,9 @@ ast_iteration_statement::hir(exec_list *instructions, if (mode != ast_do_while) state->symbols->pop_scope(); - /* Restore previous nesting before returning. - */ + /* Restore previous nesting before returning. */ state->loop_nesting_ast = nesting_ast; - state->is_switch_innermost = saved_is_switch_innermost; + state->switch_state.is_switch_innermost = saved_is_switch_innermost; /* Loops do not have r-values. */ @@ -3836,8 +3906,8 @@ ast_type_specifier::hir(exec_list *instructions, "arrays"); return NULL; } - if (this->type_specifier != ast_float - && this->type_specifier != ast_int) { + if (strcmp(this->type_name, "float") != 0 && + strcmp(this->type_name, "int") != 0) { _mesa_glsl_error(&loc, state, "default precision statements apply only to types " "float and int"); @@ -3938,3 +4008,154 @@ ast_struct_specifier::hir(exec_list *instructions, */ return NULL; } + +static struct gl_uniform_block * +get_next_uniform_block(struct _mesa_glsl_parse_state *state) +{ + if (state->num_uniform_blocks >= state->uniform_block_array_size) { + state->uniform_block_array_size *= 2; + if (state->uniform_block_array_size <= 4) + state->uniform_block_array_size = 4; + + state->uniform_blocks = reralloc(state, + state->uniform_blocks, + struct gl_uniform_block, + state->uniform_block_array_size); + } + + memset(&state->uniform_blocks[state->num_uniform_blocks], + 0, sizeof(*state->uniform_blocks)); + return &state->uniform_blocks[state->num_uniform_blocks++]; +} + +ir_rvalue * +ast_uniform_block::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + /* The ast_uniform_block has a list of ast_declarator_lists. We + * need to turn those into ir_variables with an association + * with this uniform block. + */ + struct gl_uniform_block *ubo = get_next_uniform_block(state); + ubo->Name = ralloc_strdup(state->uniform_blocks, this->block_name); + + unsigned int num_variables = 0; + foreach_list_typed(ast_declarator_list, decl_list, link, &declarations) { + foreach_list_const(node, &decl_list->declarations) { + num_variables++; + } + } + + bool block_row_major = this->layout.flags.q.row_major; + + ubo->Uniforms = rzalloc_array(state->uniform_blocks, + struct gl_uniform_buffer_variable, + num_variables); + + foreach_list_typed(ast_declarator_list, decl_list, link, &declarations) { + exec_list declared_variables; + + decl_list->hir(&declared_variables, state); + + foreach_list_const(node, &declared_variables) { + struct ir_variable *var = (ir_variable *)node; + + struct gl_uniform_buffer_variable *ubo_var = + &ubo->Uniforms[ubo->NumUniforms++]; + + var->uniform_block = ubo - state->uniform_blocks; + + ubo_var->Name = ralloc_strdup(state->uniform_blocks, var->name); + ubo_var->Type = var->type; + ubo_var->Buffer = ubo - state->uniform_blocks; + ubo_var->Offset = 0; /* Assigned at link time. */ + + if (var->type->is_matrix() || + (var->type->is_array() && var->type->fields.array->is_matrix())) { + ubo_var->RowMajor = block_row_major; + if (decl_list->type->qualifier.flags.q.row_major) + ubo_var->RowMajor = true; + else if (decl_list->type->qualifier.flags.q.column_major) + ubo_var->RowMajor = false; + } + + /* From the GL_ARB_uniform_buffer_object spec: + * + * "Sampler types are not allowed inside of uniform + * blocks. All other types, arrays, and structures + * allowed for uniforms are allowed within a uniform + * block." + */ + if (var->type->contains_sampler()) { + YYLTYPE loc = decl_list->get_location(); + _mesa_glsl_error(&loc, state, + "Uniform in non-default uniform block contains sampler\n"); + } + } + + instructions->append_list(&declared_variables); + } + + return NULL; +} + +static void +detect_conflicting_assignments(struct _mesa_glsl_parse_state *state, + exec_list *instructions) +{ + bool gl_FragColor_assigned = false; + bool gl_FragData_assigned = false; + bool user_defined_fs_output_assigned = false; + ir_variable *user_defined_fs_output = NULL; + + /* It would be nice to have proper location information. */ + YYLTYPE loc; + memset(&loc, 0, sizeof(loc)); + + foreach_list(node, instructions) { + ir_variable *var = ((ir_instruction *)node)->as_variable(); + + if (!var || !var->assigned) + continue; + + if (strcmp(var->name, "gl_FragColor") == 0) + gl_FragColor_assigned = true; + else if (strcmp(var->name, "gl_FragData") == 0) + gl_FragData_assigned = true; + else if (strncmp(var->name, "gl_", 3) != 0) { + if (state->target == fragment_shader && + (var->mode == ir_var_out || var->mode == ir_var_inout)) { + user_defined_fs_output_assigned = true; + user_defined_fs_output = var; + } + } + } + + /* From the GLSL 1.30 spec: + * + * "If a shader statically assigns a value to gl_FragColor, it + * may not assign a value to any element of gl_FragData. If a + * shader statically writes a value to any element of + * gl_FragData, it may not assign a value to + * gl_FragColor. That is, a shader may assign values to either + * gl_FragColor or gl_FragData, but not both. Multiple shaders + * linked together must also consistently write just one of + * these variables. Similarly, if user declared output + * variables are in use (statically assigned to), then the + * built-in variables gl_FragColor and gl_FragData may not be + * assigned to. These incorrect usages all generate compile + * time errors." + */ + if (gl_FragColor_assigned && gl_FragData_assigned) { + _mesa_glsl_error(&loc, state, "fragment shader writes to both " + "`gl_FragColor' and `gl_FragData'\n"); + } else if (gl_FragColor_assigned && user_defined_fs_output_assigned) { + _mesa_glsl_error(&loc, state, "fragment shader writes to both " + "`gl_FragColor' and `%s'\n", + user_defined_fs_output->name); + } else if (gl_FragData_assigned && user_defined_fs_output_assigned) { + _mesa_glsl_error(&loc, state, "fragment shader writes to both " + "`gl_FragData' and `%s'\n", + user_defined_fs_output->name); + } +}