glsl: Save and restore the whole switch state for nesting.

This stuffs them all in a struct for sanity.  Fixes piglit
glsl-1.30/execution/switch/fs-uniform-nested.

NOTE: This is a candidate for the 8.0 branch.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
This commit is contained in:
Eric Anholt 2012-01-28 11:26:02 -08:00
parent b8c9252570
commit 22d81f154f
3 changed files with 225 additions and 230 deletions

View file

@ -3405,7 +3405,7 @@ ast_jump_statement::hir(exec_list *instructions,
"continue may only appear in a loop"); "continue may only appear in a loop");
} else if (mode == ast_break && } else if (mode == ast_break &&
state->loop_nesting_ast == NULL && state->loop_nesting_ast == NULL &&
state->switch_nesting_ast == NULL) { state->switch_state.switch_nesting_ast == NULL) {
YYLTYPE loc = this->get_location(); YYLTYPE loc = this->get_location();
_mesa_glsl_error(& loc, state, _mesa_glsl_error(& loc, state,
@ -3423,11 +3423,11 @@ ast_jump_statement::hir(exec_list *instructions,
state); state);
} }
if (state->is_switch_innermost && if (state->switch_state.is_switch_innermost &&
mode == ast_break) { mode == ast_break) {
/* Force break out of switch by setting is_break switch state. /* 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 = ir_dereference_variable *const deref_is_break_var =
new(ctx) ir_dereference_variable(is_break_var); new(ctx) ir_dereference_variable(is_break_var);
ir_constant *const true_val = new(ctx) ir_constant(true); ir_constant *const true_val = new(ctx) ir_constant(true);
@ -3530,25 +3530,22 @@ ast_switch_statement::hir(exec_list *instructions,
/* Track the switch-statement nesting in a stack-like manner. /* Track the switch-statement nesting in a stack-like manner.
*/ */
ir_variable *saved_test_var = state->test_var; struct glsl_switch_state saved = state->switch_state;
ir_variable *saved_is_fallthru_var = state->is_fallthru_var;
bool save_is_switch_innermost = state->is_switch_innermost; state->switch_state.is_switch_innermost = true;
ast_switch_statement *saved_nesting_ast = state->switch_nesting_ast; state->switch_state.switch_nesting_ast = this;
state->is_switch_innermost = true;
state->switch_nesting_ast = this;
/* Initalize is_fallthru state to false. /* Initalize is_fallthru state to false.
*/ */
ir_rvalue *const is_fallthru_val = new (ctx) ir_constant(false); ir_rvalue *const is_fallthru_val = new (ctx) ir_constant(false);
state->is_fallthru_var = new(ctx) ir_variable(glsl_type::bool_type, state->switch_state.is_fallthru_var =
new(ctx) ir_variable(glsl_type::bool_type,
"switch_is_fallthru_tmp", "switch_is_fallthru_tmp",
ir_var_temporary); ir_var_temporary);
instructions->push_tail(state->is_fallthru_var); instructions->push_tail(state->switch_state.is_fallthru_var);
ir_dereference_variable *deref_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, instructions->push_tail(new(ctx) ir_assignment(deref_is_fallthru_var,
is_fallthru_val, is_fallthru_val,
NULL)); NULL));
@ -3556,13 +3553,13 @@ ast_switch_statement::hir(exec_list *instructions,
/* Initalize is_break state to false. /* Initalize is_break state to false.
*/ */
ir_rvalue *const is_break_val = new (ctx) ir_constant(false); ir_rvalue *const is_break_val = new (ctx) ir_constant(false);
state->is_break_var = new(ctx) ir_variable(glsl_type::bool_type, state->switch_state.is_break_var = new(ctx) ir_variable(glsl_type::bool_type,
"switch_is_break_tmp", "switch_is_break_tmp",
ir_var_temporary); ir_var_temporary);
instructions->push_tail(state->is_break_var); instructions->push_tail(state->switch_state.is_break_var);
ir_dereference_variable *deref_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, instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var,
is_break_val, is_break_val,
NULL)); NULL));
@ -3575,13 +3572,7 @@ ast_switch_statement::hir(exec_list *instructions,
*/ */
body->hir(instructions, state); body->hir(instructions, state);
/* Restore previous nesting before returning. state->switch_state = saved;
*/
state->switch_nesting_ast = saved_nesting_ast;
state->is_switch_innermost = save_is_switch_innermost;
state->test_var = saved_test_var;
state->is_fallthru_var = saved_is_fallthru_var;
/* Switch statements do not have r-values. /* Switch statements do not have r-values.
*/ */
@ -3601,13 +3592,13 @@ ast_switch_statement::test_to_hir(exec_list *instructions,
test_expression->hir(instructions, test_expression->hir(instructions,
state); state);
state->test_var = new(ctx) ir_variable(glsl_type::int_type, state->switch_state.test_var = new(ctx) ir_variable(glsl_type::int_type,
"switch_test_tmp", "switch_test_tmp",
ir_var_temporary); ir_var_temporary);
ir_dereference_variable *deref_test_var = 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(state->switch_state.test_var);
instructions->push_tail(new(ctx) ir_assignment(deref_test_var, instructions->push_tail(new(ctx) ir_assignment(deref_test_var,
test_val, test_val,
NULL)); NULL));
@ -3650,9 +3641,9 @@ ast_case_statement::hir(exec_list *instructions,
*/ */
ir_constant *const false_val = new(state) ir_constant(false); ir_constant *const false_val = new(state) ir_constant(false);
ir_dereference_variable *const deref_is_fallthru_var = 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 = 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 = ir_assignment *const reset_fallthru_on_break =
new(state) ir_assignment(deref_is_fallthru_var, new(state) ir_assignment(deref_is_fallthru_var,
false_val, false_val,
@ -3662,7 +3653,7 @@ ast_case_statement::hir(exec_list *instructions,
/* Guard case statements depending on fallthru state. /* Guard case statements depending on fallthru state.
*/ */
ir_dereference_variable *const deref_fallthru_guard = 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); ir_if *const test_fallthru = new(state) ir_if(deref_fallthru_guard);
foreach_list_typed (ast_node, stmt, link, & this->stmts) foreach_list_typed (ast_node, stmt, link, & this->stmts)
@ -3696,7 +3687,7 @@ ast_case_label::hir(exec_list *instructions,
void *ctx = state; void *ctx = state;
ir_dereference_variable *deref_fallthru_var = 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); ir_rvalue *const true_val = new(ctx) ir_constant(true);
@ -3709,7 +3700,7 @@ ast_case_label::hir(exec_list *instructions,
ir_rvalue *const test_val = this->test_value->hir(instructions, state); ir_rvalue *const test_val = this->test_value->hir(instructions, state);
ir_dereference_variable *deref_test_var = 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, ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal,
glsl_type::bool_type, glsl_type::bool_type,
@ -3801,8 +3792,8 @@ ast_iteration_statement::hir(exec_list *instructions,
/* Likewise, indicate that following code is closest to a loop, /* Likewise, indicate that following code is closest to a loop,
* NOT closest to a switch. * NOT closest to a switch.
*/ */
bool saved_is_switch_innermost = state->is_switch_innermost; bool saved_is_switch_innermost = state->switch_state.is_switch_innermost;
state->is_switch_innermost = false; state->switch_state.is_switch_innermost = false;
if (mode != ast_do_while) if (mode != ast_do_while)
condition_to_hir(stmt, state); condition_to_hir(stmt, state);
@ -3822,7 +3813,7 @@ ast_iteration_statement::hir(exec_list *instructions,
/* Restore previous nesting before returning. /* Restore previous nesting before returning.
*/ */
state->loop_nesting_ast = nesting_ast; 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. /* Loops do not have r-values.
*/ */

View file

@ -51,7 +51,7 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx,
this->info_log = ralloc_strdup(mem_ctx, ""); this->info_log = ralloc_strdup(mem_ctx, "");
this->error = false; this->error = false;
this->loop_nesting_ast = NULL; this->loop_nesting_ast = NULL;
this->switch_nesting_ast = NULL; this->switch_state.switch_nesting_ast = NULL;
this->num_builtins_to_link = 0; this->num_builtins_to_link = 0;

View file

@ -42,6 +42,15 @@ enum _mesa_glsl_parser_targets {
struct gl_context; struct gl_context;
struct glsl_switch_state {
/** Temporary variables needed for switch statement. */
ir_variable *test_var;
ir_variable *is_fallthru_var;
ir_variable *is_break_var;
class ast_switch_statement *switch_nesting_ast;
bool is_switch_innermost; // if switch stmt is closest to break, ...
};
struct _mesa_glsl_parse_state { struct _mesa_glsl_parse_state {
_mesa_glsl_parse_state(struct gl_context *ctx, GLenum target, _mesa_glsl_parse_state(struct gl_context *ctx, GLenum target,
void *mem_ctx); void *mem_ctx);
@ -150,13 +159,8 @@ struct _mesa_glsl_parse_state {
/** Loop or switch statement containing the current instructions. */ /** Loop or switch statement containing the current instructions. */
class ast_iteration_statement *loop_nesting_ast; class ast_iteration_statement *loop_nesting_ast;
class ast_switch_statement *switch_nesting_ast;
bool is_switch_innermost; // if switch stmt is closest to break, ...
/** Temporary variables needed for switch statement. */ struct glsl_switch_state switch_state;
ir_variable *test_var;
ir_variable *is_fallthru_var;
ir_variable *is_break_var;
/** List of structures defined in user code. */ /** List of structures defined in user code. */
const glsl_type **user_structures; const glsl_type **user_structures;