X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=ast_to_hir.cpp;h=7b4a855f57674d20852f0dc3e530322e0cd8e72d;hb=8d3e59f1f399d7c1f7604779f1d62e876c609d9e;hp=ddeab8db67c93ca104e8b3be6f3e2915f256c393;hpb=326c676236e6a3c90db63e4d0c893aa4f9c21876;p=mesa.git diff --git a/ast_to_hir.cpp b/ast_to_hir.cpp index ddeab8db67c..7b4a855f576 100644 --- a/ast_to_hir.cpp +++ b/ast_to_hir.cpp @@ -761,11 +761,8 @@ ast_expression::hir(exec_list *instructions, error_emitted = true; break; - case ast_logic_and: - case ast_logic_xor: - case ast_logic_or: + case ast_logic_and: { op[0] = this->subexpressions[0]->hir(instructions, state); - op[1] = this->subexpressions[1]->hir(instructions, state); if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { YYLTYPE loc = this->subexpressions[0]->get_location(); @@ -775,14 +772,125 @@ ast_expression::hir(exec_list *instructions, error_emitted = true; } - if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[1]->get_location(); + 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); - _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean", + 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_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; @@ -1306,11 +1414,12 @@ 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: @@ -1337,6 +1446,15 @@ 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) @@ -1357,7 +1475,7 @@ 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 @@ -1449,7 +1567,7 @@ ast_declarator_list::hir(exec_list *instructions, * FINISHME: required or not. */ - if (var->type->array_size() <= earlier->max_array_access) { + 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 " @@ -1590,8 +1708,7 @@ 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"); } @@ -1619,8 +1736,8 @@ ast_declarator_list::hir(exec_list *instructions, bool temp = var->read_only; if (this->type->qualifier.constant) var->read_only = false; - (void) do_assignment(instructions, state, lhs, rhs, - this->get_location()); + result = do_assignment(instructions, state, lhs, rhs, + this->get_location()); var->read_only = temp; } } @@ -1650,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; } @@ -1764,17 +1889,10 @@ 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()) { + 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 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; - /* If the types of the parameters do not match, the parameters lists * are different. */ @@ -1785,6 +1903,12 @@ parameter_lists_match(exec_list *list_a, exec_list *list_b) 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; } @@ -1798,11 +1922,6 @@ ast_function::hir(exec_list *instructions, exec_list hir_parameters; - /* The prototype part of a function does not generate anything in the IR - * instruction stream. - */ - (void) instructions; - /* 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. @@ -1833,9 +1952,39 @@ ast_function::hir(exec_list *instructions, * definition. */ if (parameter_lists_match(& hir_parameters, & sig->parameters)) { - /* FINISHME: Compare return types. */ + 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 (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->definition != NULL)) { + if (is_definition && sig->is_defined) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "function `%s' redefined", name); @@ -1858,6 +2007,9 @@ ast_function::hir(exec_list *instructions, } 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() */ @@ -1914,24 +2066,14 @@ ast_function_definition::hir(exec_list *instructions, assert(state->current_function == NULL); state->current_function = signature; - ir_label *label = new ir_label(signature->function_name()); - if (signature->definition == NULL) { - signature->definition = label; - } - instructions->push_tail(label); - /* 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 proto = ((ir_instruction *) iter.get())->as_variable(); + ir_variable *const var = ((ir_instruction *) iter.get())->as_variable(); - assert(proto != NULL); - - ir_variable *const var = proto->clone(); - - instructions->push_tail(var); + assert(var != NULL); /* The only way a parameter would "exist" is if two parameters have * the same name. @@ -1945,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(); @@ -1967,7 +2107,8 @@ 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); @@ -1979,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 *) @@ -1999,15 +2140,16 @@ ast_jump_statement::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "`return' with no value, in function %s returning " "non-void", - state->current_function->definition->label); + state->current_function->function_name()); } inst = new ir_return; } instructions->push_tail(inst); + break; } - if (mode == ast_discard) { + case ast_discard: /* FINISHME: discard support */ if (state->target != fragment_shader) { YYLTYPE loc = this->get_location(); @@ -2015,6 +2157,37 @@ ast_jump_statement::hir(exec_list *instructions, _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. @@ -2069,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; +}