mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-23 17:40:11 +01:00
glsl: Avoid cascading errors when looking for a scalar boolean and failing.
By always using a boolean, we should generally avoid further complaints. The failure case I see is logic_not, where the user might understandably make the mistake of using `!' on a boolean vector (like a piglit case did recently!), and then get a further complaint that the new boolean type doesn't match the bvec it gets assigned to. Fixes invalid-logic-not-06.vert (assertion failure when the bad type ends up in an expression and ir_constant_expression gets angry). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=33314 Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
This commit is contained in:
parent
6a35cbb656
commit
01822706ec
1 changed files with 48 additions and 76 deletions
|
|
@ -848,6 +848,36 @@ do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1)
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For logical operations, we want to ensure that the operands are
|
||||||
|
* scalar booleans. If it isn't, emit an error and return a constant
|
||||||
|
* boolean to avoid triggering cascading error messages.
|
||||||
|
*/
|
||||||
|
ir_rvalue *
|
||||||
|
get_scalar_boolean_operand(exec_list *instructions,
|
||||||
|
struct _mesa_glsl_parse_state *state,
|
||||||
|
ast_expression *parent_expr,
|
||||||
|
int operand,
|
||||||
|
const char *operand_name,
|
||||||
|
bool *error_emitted)
|
||||||
|
{
|
||||||
|
ast_expression *expr = parent_expr->subexpressions[operand];
|
||||||
|
void *ctx = state;
|
||||||
|
ir_rvalue *val = expr->hir(instructions, state);
|
||||||
|
|
||||||
|
if (val->type->is_boolean() && val->type->is_scalar())
|
||||||
|
return val;
|
||||||
|
|
||||||
|
if (!*error_emitted) {
|
||||||
|
YYLTYPE loc = expr->get_location();
|
||||||
|
_mesa_glsl_error(&loc, state, "%s of `%s' must be scalar boolean",
|
||||||
|
operand_name,
|
||||||
|
parent_expr->operator_string(parent_expr->oper));
|
||||||
|
*error_emitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new(ctx) ir_constant(true);
|
||||||
|
}
|
||||||
|
|
||||||
ir_rvalue *
|
ir_rvalue *
|
||||||
ast_expression::hir(exec_list *instructions,
|
ast_expression::hir(exec_list *instructions,
|
||||||
struct _mesa_glsl_parse_state *state)
|
struct _mesa_glsl_parse_state *state)
|
||||||
|
|
@ -1079,30 +1109,14 @@ ast_expression::hir(exec_list *instructions,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ast_logic_and: {
|
case ast_logic_and: {
|
||||||
op[0] = this->subexpressions[0]->hir(instructions, state);
|
op[0] = get_scalar_boolean_operand(instructions, state, this, 0,
|
||||||
|
"LHS", &error_emitted);
|
||||||
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();
|
ir_constant *op0_const = op[0]->constant_expression_value();
|
||||||
if (op0_const) {
|
if (op0_const) {
|
||||||
if (op0_const->value.b[0]) {
|
if (op0_const->value.b[0]) {
|
||||||
op[1] = this->subexpressions[1]->hir(instructions, state);
|
result = get_scalar_boolean_operand(instructions, state, this, 1,
|
||||||
|
"RHS", &error_emitted);
|
||||||
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 {
|
} else {
|
||||||
result = op0_const;
|
result = op0_const;
|
||||||
}
|
}
|
||||||
|
|
@ -1116,16 +1130,9 @@ ast_expression::hir(exec_list *instructions,
|
||||||
ir_if *const stmt = new(ctx) ir_if(op[0]);
|
ir_if *const stmt = new(ctx) ir_if(op[0]);
|
||||||
instructions->push_tail(stmt);
|
instructions->push_tail(stmt);
|
||||||
|
|
||||||
op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state);
|
op[1] = get_scalar_boolean_operand(&stmt->then_instructions,
|
||||||
|
state, this, 1,
|
||||||
if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
|
"RHS", &error_emitted);
|
||||||
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(ctx) ir_dereference_variable(tmp);
|
ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
|
||||||
ir_assignment *const then_assign =
|
ir_assignment *const then_assign =
|
||||||
|
|
@ -1144,32 +1151,16 @@ ast_expression::hir(exec_list *instructions,
|
||||||
}
|
}
|
||||||
|
|
||||||
case ast_logic_or: {
|
case ast_logic_or: {
|
||||||
op[0] = this->subexpressions[0]->hir(instructions, state);
|
op[0] = get_scalar_boolean_operand(instructions, state, this, 0,
|
||||||
|
"LHS", &error_emitted);
|
||||||
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();
|
ir_constant *op0_const = op[0]->constant_expression_value();
|
||||||
if (op0_const) {
|
if (op0_const) {
|
||||||
if (op0_const->value.b[0]) {
|
if (op0_const->value.b[0]) {
|
||||||
result = op0_const;
|
result = op0_const;
|
||||||
} else {
|
} else {
|
||||||
op[1] = this->subexpressions[1]->hir(instructions, state);
|
result = get_scalar_boolean_operand(instructions, state, this, 1,
|
||||||
|
"RHS", &error_emitted);
|
||||||
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;
|
type = glsl_type::bool_type;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1181,15 +1172,9 @@ ast_expression::hir(exec_list *instructions,
|
||||||
ir_if *const stmt = new(ctx) ir_if(op[0]);
|
ir_if *const stmt = new(ctx) ir_if(op[0]);
|
||||||
instructions->push_tail(stmt);
|
instructions->push_tail(stmt);
|
||||||
|
|
||||||
op[1] = this->subexpressions[1]->hir(&stmt->else_instructions, state);
|
op[1] = get_scalar_boolean_operand(&stmt->else_instructions,
|
||||||
|
state, this, 1,
|
||||||
if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
|
"RHS", &error_emitted);
|
||||||
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(ctx) ir_dereference_variable(tmp);
|
ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
|
||||||
ir_assignment *const then_assign =
|
ir_assignment *const then_assign =
|
||||||
|
|
@ -1218,15 +1203,8 @@ ast_expression::hir(exec_list *instructions,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ast_logic_not:
|
case ast_logic_not:
|
||||||
op[0] = this->subexpressions[0]->hir(instructions, state);
|
op[0] = get_scalar_boolean_operand(instructions, state, this, 0,
|
||||||
|
"operand", &error_emitted);
|
||||||
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(ctx) ir_expression(operations[this->oper], glsl_type::bool_type,
|
result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type,
|
||||||
op[0], NULL);
|
op[0], NULL);
|
||||||
|
|
@ -1313,20 +1291,14 @@ ast_expression::hir(exec_list *instructions,
|
||||||
}
|
}
|
||||||
|
|
||||||
case ast_conditional: {
|
case ast_conditional: {
|
||||||
op[0] = this->subexpressions[0]->hir(instructions, state);
|
|
||||||
|
|
||||||
/* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec:
|
/* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec:
|
||||||
*
|
*
|
||||||
* "The ternary selection operator (?:). It operates on three
|
* "The ternary selection operator (?:). It operates on three
|
||||||
* expressions (exp1 ? exp2 : exp3). This operator evaluates the
|
* expressions (exp1 ? exp2 : exp3). This operator evaluates the
|
||||||
* first expression, which must result in a scalar Boolean."
|
* first expression, which must result in a scalar Boolean."
|
||||||
*/
|
*/
|
||||||
if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
|
op[0] = get_scalar_boolean_operand(instructions, state, this, 0,
|
||||||
YYLTYPE loc = this->subexpressions[0]->get_location();
|
"condition", &error_emitted);
|
||||||
|
|
||||||
_mesa_glsl_error(& loc, state, "?: condition must be scalar boolean");
|
|
||||||
error_emitted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The :? operator is implemented by generating an anonymous temporary
|
/* The :? operator is implemented by generating an anonymous temporary
|
||||||
* followed by an if-statement. The last instruction in each branch of
|
* followed by an if-statement. The last instruction in each branch of
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue