mesa/cs: Add a MESA_SHADER_COMPUTE stage and update switch statements.
[mesa.git] / src / glsl / ast_to_hir.cpp
index f13ac51c164f534417502141d6009e6388b68438..fc28703ddc37bf1f1b35b100ae40b7100787d722 100644 (file)
@@ -740,14 +740,15 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
 {
    void *ctx = state;
    bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
+   ir_rvalue *extract_channel = NULL;
 
    /* If the assignment LHS comes back as an ir_binop_vector_extract
     * expression, move it to the RHS as an ir_triop_vector_insert.
     */
    if (lhs->ir_type == ir_type_expression) {
-      ir_expression *const expr = lhs->as_expression();
+      ir_expression *const lhs_expr = lhs->as_expression();
 
-      if (unlikely(expr->operation == ir_binop_vector_extract)) {
+      if (unlikely(lhs_expr->operation == ir_binop_vector_extract)) {
          ir_rvalue *new_rhs =
             validate_assignment(state, lhs_loc, lhs->type,
                                 rhs, is_initializer);
@@ -755,12 +756,24 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
          if (new_rhs == NULL) {
             return lhs;
          } else {
+            /* This converts:
+             * - LHS: (expression float vector_extract <vec> <channel>)
+             * - RHS: <scalar>
+             * into:
+             * - LHS: <vec>
+             * - RHS: (expression vec2 vector_insert <vec> <channel> <scalar>)
+             *
+             * The LHS type is now a vector instead of a scalar.  Since GLSL
+             * allows assignments to be used as rvalues, we need to re-extract
+             * the channel from assignment_temp when returning the rvalue.
+             */
+            extract_channel = lhs_expr->operands[1];
             rhs = new(ctx) ir_expression(ir_triop_vector_insert,
-                                         expr->operands[0]->type,
-                                         expr->operands[0],
+                                         lhs_expr->operands[0]->type,
+                                         lhs_expr->operands[0],
                                          new_rhs,
-                                         expr->operands[1]);
-            lhs = expr->operands[0]->clone(ctx, NULL);
+                                         extract_channel);
+            lhs = lhs_expr->operands[0]->clone(ctx, NULL);
          }
       }
    }
@@ -856,6 +869,11 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
    if (!error_emitted)
       instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var));
 
+   if (extract_channel) {
+      return new(ctx) ir_expression(ir_binop_vector_extract,
+                                    new(ctx) ir_dereference_variable(var),
+                                    extract_channel->clone(ctx, NULL));
+   }
    return new(ctx) ir_dereference_variable(var);
 }
 
@@ -2137,6 +2155,12 @@ validate_explicit_location(const struct ast_type_qualifier *qual,
 
       fail = true;
       break;
+
+   case MESA_SHADER_COMPUTE:
+      _mesa_glsl_error(loc, state,
+                       "compute shader variables cannot be given "
+                       "explicit locations");
+      return;
    };
 
    if (fail) {
@@ -2319,6 +2343,9 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
         if (var->data.mode == ir_var_shader_in)
            var->data.invariant = true;
         break;
+      case MESA_SHADER_COMPUTE:
+         /* Invariance isn't meaningful in compute shaders. */
+         break;
       }
    }
 
@@ -2874,7 +2901,6 @@ ast_declarator_list::hir(exec_list *instructions,
       }
 
       foreach_list_typed (ast_declaration, decl, link, &this->declarations) {
-        assert(!decl->is_array);
         assert(decl->array_specifier == NULL);
         assert(decl->initializer == NULL);
 
@@ -4012,17 +4038,22 @@ ast_jump_statement::hir(exec_list *instructions,
         _mesa_glsl_error(& loc, state,
                          "break may only appear in a loop or a switch");
       } else {
-        /* For a loop, inline the for loop expression again,
-         * since we don't know where near the end of
-         * the loop body the normal copy of it
-         * is going to be placed.
+        /* For a loop, inline the for loop expression again, since we don't
+         * know where near the end of the loop body the normal copy of it is
+         * going to be placed.  Same goes for the condition for a do-while
+         * loop.
          */
         if (state->loop_nesting_ast != NULL &&
-            mode == ast_continue &&
-            state->loop_nesting_ast->rest_expression) {
-           state->loop_nesting_ast->rest_expression->hir(instructions,
-                                                         state);
-        }
+            mode == ast_continue) {
+            if (state->loop_nesting_ast->rest_expression) {
+               state->loop_nesting_ast->rest_expression->hir(instructions,
+                                                             state);
+            }
+            if (state->loop_nesting_ast->mode ==
+                ast_iteration_statement::ast_do_while) {
+               state->loop_nesting_ast->condition_to_hir(instructions, state);
+            }
+         }
 
         if (state->switch_state.is_switch_innermost &&
             mode == ast_break) {
@@ -4352,14 +4383,14 @@ ast_case_label::hir(exec_list *instructions,
 }
 
 void
-ast_iteration_statement::condition_to_hir(ir_loop *stmt,
+ast_iteration_statement::condition_to_hir(exec_list *instructions,
                                          struct _mesa_glsl_parse_state *state)
 {
    void *ctx = state;
 
    if (condition != NULL) {
       ir_rvalue *const cond =
-        condition->hir(& stmt->body_instructions, state);
+        condition->hir(instructions, state);
 
       if ((cond == NULL)
          || !cond->type->is_boolean() || !cond->type->is_scalar()) {
@@ -4380,7 +4411,7 @@ ast_iteration_statement::condition_to_hir(ir_loop *stmt,
            new(ctx) ir_loop_jump(ir_loop_jump::jump_break);
 
         if_stmt->then_instructions.push_tail(break_stmt);
-        stmt->body_instructions.push_tail(if_stmt);
+        instructions->push_tail(if_stmt);
       }
    }
 }
@@ -4415,7 +4446,7 @@ ast_iteration_statement::hir(exec_list *instructions,
    state->switch_state.is_switch_innermost = false;
 
    if (mode != ast_do_while)
-      condition_to_hir(stmt, state);
+      condition_to_hir(&stmt->body_instructions, state);
 
    if (body != NULL)
       body->hir(& stmt->body_instructions, state);
@@ -4424,7 +4455,7 @@ ast_iteration_statement::hir(exec_list *instructions,
       rest_expression->hir(& stmt->body_instructions, state);
 
    if (mode == ast_do_while)
-      condition_to_hir(stmt, state);
+      condition_to_hir(&stmt->body_instructions, state);
 
    if (mode != ast_do_while)
       state->symbols->pop_scope();
@@ -4507,7 +4538,7 @@ ast_type_specifier::hir(exec_list *instructions,
          return NULL;
       }
 
-      if (this->is_array) {
+      if (this->array_specifier != NULL) {
          _mesa_glsl_error(&loc, state,
                           "default precision statements do not apply to "
                           "arrays");
@@ -4924,7 +4955,7 @@ ast_interface_block::hir(exec_list *instructions,
                              _mesa_shader_stage_to_string(state->stage));
          }
          if (this->instance_name == NULL ||
-             strcmp(this->instance_name, "gl_in") != 0 || !this->is_array) {
+             strcmp(this->instance_name, "gl_in") != 0 || this->array_specifier == NULL) {
             _mesa_glsl_error(&loc, state,
                              "gl_PerVertex input must be redeclared as "
                              "gl_in[]");
@@ -5026,7 +5057,7 @@ ast_interface_block::hir(exec_list *instructions,
     *     variable (or input block, see interface blocks below) needs to be
     *     declared as an array.
     */
-   if (state->stage == MESA_SHADER_GEOMETRY && !this->is_array &&
+   if (state->stage == MESA_SHADER_GEOMETRY && this->array_specifier == NULL &&
        var_mode == ir_var_shader_in) {
       _mesa_glsl_error(&loc, state, "geometry shader inputs must be arrays");
    }
@@ -5060,7 +5091,7 @@ ast_interface_block::hir(exec_list *instructions,
 
       ir_variable *var;
 
-      if (this->is_array) {
+      if (this->array_specifier != NULL) {
          /* Section 4.3.7 (Interface Blocks) of the GLSL 1.50 spec says:
           *
           *     For uniform blocks declared an array, each individual array
@@ -5121,7 +5152,7 @@ ast_interface_block::hir(exec_list *instructions,
       /* In order to have an array size, the block must also be declared with
        * an instane name.
        */
-      assert(!this->is_array);
+      assert(this->array_specifier == NULL);
 
       for (unsigned i = 0; i < num_variables; i++) {
          ir_variable *var =