glsl: Use the without_array predicate to simplify some code
[mesa.git] / src / glsl / ast_to_hir.cpp
index 92e0f90b81c87563779f459aede21463633790e8..397a575501db2867b3017426849305f2049ead95 100644 (file)
@@ -112,8 +112,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
     * applications depend on this behavior, and it matches what nearly all
     * other drivers do.
     */
-   foreach_list_safe(node, instructions) {
-      ir_variable *const var = ((ir_instruction *) node)->as_variable();
+   foreach_in_list_safe(ir_instruction, node, instructions) {
+      ir_variable *const var = node->as_variable();
 
       if (var == NULL)
          continue;
@@ -2461,6 +2461,11 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
    if (qual->flags.q.sample)
       var->data.sample = 1;
 
+   if (state->stage == MESA_SHADER_GEOMETRY &&
+       qual->flags.q.out && qual->flags.q.stream) {
+      var->data.stream = qual->stream;
+   }
+
    if (qual->flags.q.attribute && state->stage != MESA_SHADER_VERTEX) {
       var->type = glsl_type::error_type;
       _mesa_glsl_error(loc, state,
@@ -4205,10 +4210,8 @@ ast_function_definition::hir(exec_list *instructions,
     * Add these to the symbol table.
     */
    state->symbols->push_scope();
-   foreach_list(n, &signature->parameters) {
-      ir_variable *const var = ((ir_instruction *) n)->as_variable();
-
-      assert(var != NULL);
+   foreach_in_list(ir_variable, var, &signature->parameters) {
+      assert(var->as_variable() != NULL);
 
       /* The only way a parameter would "exist" is if two parameters have
        * the same name.
@@ -4510,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);
@@ -4564,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()) {
+
+      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);
+
+      /* Default case was the last one, no checks required. */
+      if (after_default.is_empty()) {
+         instructions->append_list(&default_case);
+         return NULL;
+      }
+
+      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;
@@ -4725,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);
    }
@@ -5004,9 +5084,7 @@ ast_process_structure_or_interface_block(exec_list *instructions,
     * 'declarations' list in each of the elements.
     */
    foreach_list_typed (ast_declarator_list, decl_list, link, declarations) {
-      foreach_list_const (decl_ptr, & decl_list->declarations) {
-         decl_count++;
-      }
+      decl_count += decl_list->declarations.length();
    }
 
    /* Allocate storage for the fields and process the field
@@ -5100,6 +5178,9 @@ ast_process_structure_or_interface_block(exec_list *instructions,
          fields[i].centroid = qual->flags.q.centroid ? 1 : 0;
          fields[i].sample = qual->flags.q.sample ? 1 : 0;
 
+         /* Only save explicitly defined streams in block's field */
+         fields[i].stream = qual->flags.q.explicit_stream ? qual->stream : -1;
+
          if (qual->flags.q.row_major || qual->flags.q.column_major) {
             if (!qual->flags.q.uniform) {
                _mesa_glsl_error(&loc, state,
@@ -5122,8 +5203,7 @@ ast_process_structure_or_interface_block(exec_list *instructions,
                              "in uniform blocks or structures.");
          }
 
-         if (field_type->is_matrix() ||
-             (field_type->is_array() && field_type->fields.array->is_matrix())) {
+         if (field_type->without_array()->is_matrix()) {
             fields[i].row_major = block_row_major;
             if (qual->flags.q.row_major)
                fields[i].row_major = true;
@@ -5131,7 +5211,7 @@ ast_process_structure_or_interface_block(exec_list *instructions,
                fields[i].row_major = false;
          }
 
-      i++;
+         i++;
       }
    }
 
@@ -5287,6 +5367,12 @@ ast_interface_block::hir(exec_list *instructions,
    bool block_row_major = this->layout.flags.q.row_major;
    exec_list declared_variables;
    glsl_struct_field *fields;
+
+   /* Treat an interface block as one level of nesting, so that embedded struct
+    * specifiers will be disallowed.
+    */
+   state->struct_specifier_depth++;
+
    unsigned int num_variables =
       ast_process_structure_or_interface_block(&declared_variables,
                                                state,
@@ -5298,6 +5384,8 @@ ast_interface_block::hir(exec_list *instructions,
                                                redeclaring_per_vertex,
                                                var_mode);
 
+   state->struct_specifier_depth--;
+
    if (!redeclaring_per_vertex)
       validate_identifier(this->block_name, loc, state);
 
@@ -5540,6 +5628,17 @@ ast_interface_block::hir(exec_list *instructions,
          var->data.sample = fields[i].sample;
          var->init_interface_type(block_type);
 
+         if (fields[i].stream != -1 &&
+             ((unsigned)fields[i].stream) != this->layout.stream) {
+            _mesa_glsl_error(&loc, state,
+                             "stream layout qualifier on "
+                             "interface block member `%s' does not match "
+                             "the interface block (%d vs %d)",
+                             var->name, fields[i].stream, this->layout.stream);
+         }
+
+         var->data.stream = this->layout.stream;
+
          if (redeclaring_per_vertex) {
             ir_variable *earlier =
                get_variable_being_redeclared(var, loc, state,
@@ -5594,8 +5693,8 @@ ast_interface_block::hir(exec_list *instructions,
           * thinking there are conflicting definitions of gl_PerVertex in the
           * shader.
           */
-         foreach_list_safe(node, instructions) {
-            ir_variable *const var = ((ir_instruction *) node)->as_variable();
+         foreach_in_list_safe(ir_instruction, node, instructions) {
+            ir_variable *const var = node->as_variable();
             if (var != NULL &&
                 var->get_interface_type() == earlier_per_vertex &&
                 var->data.mode == var_mode) {
@@ -5651,8 +5750,8 @@ ast_gs_input_layout::hir(exec_list *instructions,
    /* If any shader inputs occurred before this declaration and did not
     * specify an array size, their size is determined now.
     */
-   foreach_list (node, instructions) {
-      ir_variable *var = ((ir_instruction *) node)->as_variable();
+   foreach_in_list(ir_instruction, node, instructions) {
+      ir_variable *var = node->as_variable();
       if (var == NULL || var->data.mode != ir_var_shader_in)
          continue;
 
@@ -5769,8 +5868,8 @@ detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
    YYLTYPE loc;
    memset(&loc, 0, sizeof(loc));
 
-   foreach_list(node, instructions) {
-      ir_variable *var = ((ir_instruction *)node)->as_variable();
+   foreach_in_list(ir_instruction, node, instructions) {
+      ir_variable *var = node->as_variable();
 
       if (!var || !var->data.assigned)
          continue;
@@ -5859,8 +5958,8 @@ remove_per_vertex_blocks(exec_list *instructions,
    /* Remove any ir_variable declarations that refer to the interface block
     * we're removing.
     */
-   foreach_list_safe(node, instructions) {
-      ir_variable *const var = ((ir_instruction *) node)->as_variable();
+   foreach_in_list_safe(ir_instruction, node, instructions) {
+      ir_variable *const var = node->as_variable();
       if (var != NULL && var->get_interface_type() == per_vertex &&
           var->data.mode == mode) {
          state->symbols->disable_variable(var->name);