mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-22 09:10:11 +01:00
glsl: handle a switch where default is in the middle of cases
This fixes following tests in es3conform: shaders.switch.default_not_last_dynamic_vertex shaders.switch.default_not_last_dynamic_fragment and makes following tests in Piglit pass: glsl-1.30/execution/switch/fs-default-notlast-fallthrough glsl-1.30/execution/switch/fs-default_notlast No Piglit regressions. v2: take away unnecessary ir_if, just use conditional assignment v3: use foreach_in_list instead of foreach_list Signed-off-by: Tapani Pälli <tapani.palli@intel.com> Reviewed-by: Roland Scheidegger <sroland@vmware.com> (v2) Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> (v3)
This commit is contained in:
parent
9e47ed2f77
commit
48deb4dbf2
2 changed files with 83 additions and 3 deletions
|
|
@ -4513,6 +4513,12 @@ ast_switch_statement::hir(exec_list *instructions,
|
||||||
instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var,
|
instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var,
|
||||||
is_break_val));
|
is_break_val));
|
||||||
|
|
||||||
|
state->switch_state.run_default =
|
||||||
|
new(ctx) ir_variable(glsl_type::bool_type,
|
||||||
|
"run_default_tmp",
|
||||||
|
ir_var_temporary);
|
||||||
|
instructions->push_tail(state->switch_state.run_default);
|
||||||
|
|
||||||
/* Cache test expression.
|
/* Cache test expression.
|
||||||
*/
|
*/
|
||||||
test_to_hir(instructions, state);
|
test_to_hir(instructions, state);
|
||||||
|
|
@ -4567,8 +4573,71 @@ ir_rvalue *
|
||||||
ast_case_statement_list::hir(exec_list *instructions,
|
ast_case_statement_list::hir(exec_list *instructions,
|
||||||
struct _mesa_glsl_parse_state *state)
|
struct _mesa_glsl_parse_state *state)
|
||||||
{
|
{
|
||||||
foreach_list_typed (ast_case_statement, case_stmt, link, & this->cases)
|
exec_list default_case, after_default, tmp;
|
||||||
case_stmt->hir(instructions, state);
|
|
||||||
|
foreach_list_typed (ast_case_statement, case_stmt, link, & this->cases) {
|
||||||
|
case_stmt->hir(&tmp, state);
|
||||||
|
|
||||||
|
/* Default case. */
|
||||||
|
if (state->switch_state.previous_default && default_case.is_empty()) {
|
||||||
|
default_case.append_list(&tmp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If default case found, append 'after_default' list. */
|
||||||
|
if (!default_case.is_empty())
|
||||||
|
after_default.append_list(&tmp);
|
||||||
|
else
|
||||||
|
instructions->append_list(&tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the default case. This is done here because default might not be
|
||||||
|
* the last case. We need to add checks against following cases first to see
|
||||||
|
* if default should be chosen or not.
|
||||||
|
*/
|
||||||
|
if (!default_case.is_empty()) {
|
||||||
|
|
||||||
|
/* Default case was the last one, no checks required. */
|
||||||
|
if (after_default.is_empty()) {
|
||||||
|
instructions->append_list(&default_case);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_rvalue *const true_val = new (state) ir_constant(true);
|
||||||
|
ir_dereference_variable *deref_run_default_var =
|
||||||
|
new(state) ir_dereference_variable(state->switch_state.run_default);
|
||||||
|
|
||||||
|
/* Choose to run default case initially, following conditional
|
||||||
|
* assignments might change this.
|
||||||
|
*/
|
||||||
|
ir_assignment *const init_var =
|
||||||
|
new(state) ir_assignment(deref_run_default_var, true_val);
|
||||||
|
instructions->push_tail(init_var);
|
||||||
|
|
||||||
|
foreach_in_list(ir_instruction, ir, &after_default) {
|
||||||
|
ir_assignment *assign = ir->as_assignment();
|
||||||
|
|
||||||
|
if (!assign)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Clone the check between case label and init expression. */
|
||||||
|
ir_expression *exp = (ir_expression*) assign->condition;
|
||||||
|
ir_expression *clone = exp->clone(state, NULL);
|
||||||
|
|
||||||
|
ir_dereference_variable *deref_var =
|
||||||
|
new(state) ir_dereference_variable(state->switch_state.run_default);
|
||||||
|
ir_rvalue *const false_val = new (state) ir_constant(false);
|
||||||
|
|
||||||
|
ir_assignment *const set_false =
|
||||||
|
new(state) ir_assignment(deref_var, false_val, clone);
|
||||||
|
|
||||||
|
instructions->push_tail(set_false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append default case and all cases after it. */
|
||||||
|
instructions->append_list(&default_case);
|
||||||
|
instructions->append_list(&after_default);
|
||||||
|
}
|
||||||
|
|
||||||
/* Case statements do not have r-values. */
|
/* Case statements do not have r-values. */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -4728,9 +4797,17 @@ ast_case_label::hir(exec_list *instructions,
|
||||||
}
|
}
|
||||||
state->switch_state.previous_default = this;
|
state->switch_state.previous_default = this;
|
||||||
|
|
||||||
|
/* Set fallthru condition on 'run_default' bool. */
|
||||||
|
ir_dereference_variable *deref_run_default =
|
||||||
|
new(ctx) ir_dereference_variable(state->switch_state.run_default);
|
||||||
|
ir_rvalue *const cond_true = new(ctx) ir_constant(true);
|
||||||
|
ir_expression *test_cond = new(ctx) ir_expression(ir_binop_all_equal,
|
||||||
|
cond_true,
|
||||||
|
deref_run_default);
|
||||||
|
|
||||||
/* Set falltrhu state. */
|
/* Set falltrhu state. */
|
||||||
ir_assignment *set_fallthru =
|
ir_assignment *set_fallthru =
|
||||||
new(ctx) ir_assignment(deref_fallthru_var, true_val);
|
new(ctx) ir_assignment(deref_fallthru_var, true_val, test_cond);
|
||||||
|
|
||||||
instructions->push_tail(set_fallthru);
|
instructions->push_tail(set_fallthru);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@ struct glsl_switch_state {
|
||||||
ir_variable *is_break_var;
|
ir_variable *is_break_var;
|
||||||
class ast_switch_statement *switch_nesting_ast;
|
class ast_switch_statement *switch_nesting_ast;
|
||||||
|
|
||||||
|
/** Used to set condition if 'default' label should be chosen. */
|
||||||
|
ir_variable *run_default;
|
||||||
|
|
||||||
/** Table of constant values already used in case labels */
|
/** Table of constant values already used in case labels */
|
||||||
struct hash_table *labels_ht;
|
struct hash_table *labels_ht;
|
||||||
class ast_case_label *previous_default;
|
class ast_case_label *previous_default;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue