[Mesa-dev] [PATCH v3] glsl: handle a switch where default is in the middle of cases

Ian Romanick idr at freedesktop.org
Wed Jul 16 12:12:44 PDT 2014


Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>

At some point we should do some significant re-work of the
switch-statement handling in Mesa.  The current structure makes it hard
to do a lot of things (e.g., jump-tables for uniform control flow).

On 07/13/2014 11:45 PM, Tapani Pälli wrote:
> 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 at intel.com>
> Reviewed-by: Roland Scheidegger <sroland at vmware.com> (v2)
> ---
>  src/glsl/ast_to_hir.cpp       | 83 +++++++++++++++++++++++++++++++++++++++++--
>  src/glsl/glsl_parser_extras.h |  3 ++
>  2 files changed, 83 insertions(+), 3 deletions(-)
> 
> diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
> index 885bee5..0e0013e 100644
> --- a/src/glsl/ast_to_hir.cpp
> +++ b/src/glsl/ast_to_hir.cpp
> @@ -4513,6 +4513,12 @@ ast_switch_statement::hir(exec_list *instructions,
>     instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var,
>                                                    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.
>      */
>     test_to_hir(instructions, state);
> @@ -4567,8 +4573,71 @@ 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);
> +   exec_list default_case, after_default, tmp;
> +
> +   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. */
>     return NULL;
> @@ -4728,9 +4797,17 @@ ast_case_label::hir(exec_list *instructions,
>        }
>        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. */
>        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);
>     }
> diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
> index 1791816..6df41d4 100644
> --- a/src/glsl/glsl_parser_extras.h
> +++ b/src/glsl/glsl_parser_extras.h
> @@ -43,6 +43,9 @@ struct glsl_switch_state {
>     ir_variable *is_break_var;
>     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 */
>     struct hash_table *labels_ht;
>     class ast_case_label *previous_default;
> 



More information about the mesa-dev mailing list