i915g: Use X tiling for textures
[mesa.git] / src / glsl / ast_to_hir.cpp
index f0c92187507bd4041270f4b46b64efcf50da3ba2..5157661b39eca7c6e15bc58a3157026ed1bfd618 100644 (file)
 #include "glsl_parser_extras.h"
 #include "ast.h"
 #include "glsl_types.h"
+#include "program/hash_table.h"
 #include "ir.h"
 
+static void
+detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
+                              exec_list *instructions);
+
 void
 _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
 {
@@ -86,6 +91,7 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
       ast->hir(instructions, state);
 
    detect_recursion_unlinked(state, instructions);
+   detect_conflicting_assignments(state, instructions);
 
    state->toplevel_ir = NULL;
 }
@@ -664,15 +670,25 @@ mark_whole_array_access(ir_rvalue *access)
 
 ir_rvalue *
 do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
+             const char *non_lvalue_description,
              ir_rvalue *lhs, ir_rvalue *rhs, bool is_initializer,
              YYLTYPE lhs_loc)
 {
    void *ctx = state;
    bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
 
+   ir_variable *lhs_var = lhs->variable_referenced();
+   if (lhs_var)
+      lhs_var->assigned = true;
+
    if (!error_emitted) {
-      if (lhs->variable_referenced() != NULL
-          && lhs->variable_referenced()->read_only) {
+      if (non_lvalue_description != NULL) {
+         _mesa_glsl_error(&lhs_loc, state,
+                          "assignment to %s",
+                         non_lvalue_description);
+        error_emitted = true;
+      } else if (lhs->variable_referenced() != NULL
+                && lhs->variable_referenced()->read_only) {
          _mesa_glsl_error(&lhs_loc, state,
                           "assignment to read-only variable '%s'",
                           lhs->variable_referenced()->name);
@@ -744,13 +760,11 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
                                           ir_var_temporary);
    ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var);
    instructions->push_tail(var);
-   instructions->push_tail(new(ctx) ir_assignment(deref_var,
-                                                 rhs,
-                                                 NULL));
+   instructions->push_tail(new(ctx) ir_assignment(deref_var, rhs));
    deref_var = new(ctx) ir_dereference_variable(var);
 
    if (!error_emitted)
-      instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var, NULL));
+      instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var));
 
    return new(ctx) ir_dereference_variable(var);
 }
@@ -767,12 +781,7 @@ get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue)
    var->mode = ir_var_auto;
 
    instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
-                                                 lvalue, NULL));
-
-   /* Once we've created this temporary, mark it read only so it's no
-    * longer considered an lvalue.
-    */
-   var->read_only = true;
+                                                 lvalue));
 
    return new(ctx) ir_dereference_variable(var);
 }
@@ -1030,7 +1039,9 @@ ast_expression::hir(exec_list *instructions,
       op[0] = this->subexpressions[0]->hir(instructions, state);
       op[1] = this->subexpressions[1]->hir(instructions, state);
 
-      result = do_assignment(instructions, state, op[0], op[1], false,
+      result = do_assignment(instructions, state,
+                            this->subexpressions[0]->non_lvalue_description,
+                            op[0], op[1], false,
                             this->subexpressions[0]->get_location());
       error_emitted = result->type->is_error();
       break;
@@ -1195,15 +1206,9 @@ ast_expression::hir(exec_list *instructions,
       op[1] = get_scalar_boolean_operand(&rhs_instructions, state, this, 1,
                                         "RHS", &error_emitted);
 
-      ir_constant *op0_const = op[0]->constant_expression_value();
-      if (op0_const) {
-        if (op0_const->value.b[0]) {
-           instructions->append_list(&rhs_instructions);
-           result = op[1];
-        } else {
-           result = op0_const;
-        }
-        type = glsl_type::bool_type;
+      if (rhs_instructions.is_empty()) {
+        result = new(ctx) ir_expression(ir_binop_logic_and, op[0], op[1]);
+        type = result->type;
       } else {
         ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
                                                       "and_tmp",
@@ -1216,12 +1221,12 @@ ast_expression::hir(exec_list *instructions,
         stmt->then_instructions.append_list(&rhs_instructions);
         ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
         ir_assignment *const then_assign =
-           new(ctx) ir_assignment(then_deref, op[1], NULL);
+           new(ctx) ir_assignment(then_deref, op[1]);
         stmt->then_instructions.push_tail(then_assign);
 
         ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
         ir_assignment *const else_assign =
-           new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false), NULL);
+           new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false));
         stmt->else_instructions.push_tail(else_assign);
 
         result = new(ctx) ir_dereference_variable(tmp);
@@ -1237,14 +1242,9 @@ ast_expression::hir(exec_list *instructions,
       op[1] = get_scalar_boolean_operand(&rhs_instructions, state, this, 1,
                                         "RHS", &error_emitted);
 
-      ir_constant *op0_const = op[0]->constant_expression_value();
-      if (op0_const) {
-        if (op0_const->value.b[0]) {
-           result = op0_const;
-        } else {
-           result = op[1];
-        }
-        type = glsl_type::bool_type;
+      if (rhs_instructions.is_empty()) {
+        result = new(ctx) ir_expression(ir_binop_logic_or, op[0], op[1]);
+        type = result->type;
       } else {
         ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
                                                       "or_tmp",
@@ -1256,13 +1256,13 @@ ast_expression::hir(exec_list *instructions,
 
         ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
         ir_assignment *const then_assign =
-           new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true), NULL);
+           new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true));
         stmt->then_instructions.push_tail(then_assign);
 
         stmt->else_instructions.append_list(&rhs_instructions);
         ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
         ir_assignment *const else_assign =
-           new(ctx) ir_assignment(else_deref, op[1], NULL);
+           new(ctx) ir_assignment(else_deref, op[1]);
         stmt->else_instructions.push_tail(else_assign);
 
         result = new(ctx) ir_dereference_variable(tmp);
@@ -1310,6 +1310,7 @@ ast_expression::hir(exec_list *instructions,
                                                   op[0], op[1]);
 
       result = do_assignment(instructions, state,
+                            this->subexpressions[0]->non_lvalue_description,
                             op[0]->clone(ctx, NULL), temp_rhs, false,
                             this->subexpressions[0]->get_location());
       error_emitted = (op[0]->type->is_error());
@@ -1335,6 +1336,7 @@ ast_expression::hir(exec_list *instructions,
                                        op[0], op[1]);
 
       result = do_assignment(instructions, state,
+                            this->subexpressions[0]->non_lvalue_description,
                             op[0]->clone(ctx, NULL), temp_rhs, false,
                             this->subexpressions[0]->get_location());
       error_emitted = type->is_error();
@@ -1349,8 +1351,9 @@ ast_expression::hir(exec_list *instructions,
                                &loc);
       ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
                                                    type, op[0], op[1]);
-      result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
-                             temp_rhs, false,
+      result = do_assignment(instructions, state,
+                            this->subexpressions[0]->non_lvalue_description,
+                            op[0]->clone(ctx, NULL), temp_rhs, false,
                              this->subexpressions[0]->get_location());
       error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
       break;
@@ -1365,8 +1368,9 @@ ast_expression::hir(exec_list *instructions,
                                    state, &loc);
       ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
                                                    type, op[0], op[1]);
-      result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
-                             temp_rhs, false,
+      result = do_assignment(instructions, state,
+                            this->subexpressions[0]->non_lvalue_description,
+                            op[0]->clone(ctx, NULL), temp_rhs, false,
                              this->subexpressions[0]->get_location());
       error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
       break;
@@ -1446,14 +1450,14 @@ ast_expression::hir(exec_list *instructions,
         ir_dereference *const then_deref =
            new(ctx) ir_dereference_variable(tmp);
         ir_assignment *const then_assign =
-           new(ctx) ir_assignment(then_deref, op[1], NULL);
+           new(ctx) ir_assignment(then_deref, op[1]);
         stmt->then_instructions.push_tail(then_assign);
 
         else_instructions.move_nodes_to(& stmt->else_instructions);
         ir_dereference *const else_deref =
            new(ctx) ir_dereference_variable(tmp);
         ir_assignment *const else_assign =
-           new(ctx) ir_assignment(else_deref, op[2], NULL);
+           new(ctx) ir_assignment(else_deref, op[2]);
         stmt->else_instructions.push_tail(else_assign);
 
         result = new(ctx) ir_dereference_variable(tmp);
@@ -1463,6 +1467,9 @@ ast_expression::hir(exec_list *instructions,
 
    case ast_pre_inc:
    case ast_pre_dec: {
+      this->non_lvalue_description = (this->oper == ast_pre_inc)
+        ? "pre-increment operation" : "pre-decrement operation";
+
       op[0] = this->subexpressions[0]->hir(instructions, state);
       op[1] = constant_one_for_inc_dec(ctx, op[0]->type);
 
@@ -1473,6 +1480,7 @@ ast_expression::hir(exec_list *instructions,
                                        op[0], op[1]);
 
       result = do_assignment(instructions, state,
+                            this->subexpressions[0]->non_lvalue_description,
                             op[0]->clone(ctx, NULL), temp_rhs, false,
                             this->subexpressions[0]->get_location());
       error_emitted = op[0]->type->is_error();
@@ -1481,6 +1489,8 @@ ast_expression::hir(exec_list *instructions,
 
    case ast_post_inc:
    case ast_post_dec: {
+      this->non_lvalue_description = (this->oper == ast_post_inc)
+        ? "post-increment operation" : "post-decrement operation";
       op[0] = this->subexpressions[0]->hir(instructions, state);
       op[1] = constant_one_for_inc_dec(ctx, op[0]->type);
 
@@ -1498,6 +1508,7 @@ ast_expression::hir(exec_list *instructions,
       result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL));
 
       (void)do_assignment(instructions, state,
+                         this->subexpressions[0]->non_lvalue_description,
                          op[0]->clone(ctx, NULL), temp_rhs, false,
                          this->subexpressions[0]->get_location());
 
@@ -1688,14 +1699,14 @@ ast_expression::hir(exec_list *instructions,
       ir_variable *var = 
         state->symbols->get_variable(this->primary_expression.identifier);
 
-      result = new(ctx) ir_dereference_variable(var);
-
       if (var != NULL) {
         var->used = true;
+        result = new(ctx) ir_dereference_variable(var);
       } else {
         _mesa_glsl_error(& loc, state, "`%s' undeclared",
                          this->primary_expression.identifier);
 
+        result = ir_rvalue::error_value(ctx);
         error_emitted = true;
       }
       break;
@@ -1906,7 +1917,8 @@ static void
 apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
                                 ir_variable *var,
                                 struct _mesa_glsl_parse_state *state,
-                                YYLTYPE *loc)
+                                YYLTYPE *loc,
+                                bool ubo_qualifiers_valid)
 {
    if (qual->flags.q.invariant) {
       if (var->used) {
@@ -1996,6 +2008,15 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
    else
       var->interpolation = INTERP_QUALIFIER_NONE;
 
+   if (var->interpolation != INTERP_QUALIFIER_NONE &&
+       !(state->target == vertex_shader && var->mode == ir_var_out) &&
+       !(state->target == fragment_shader && var->mode == ir_var_in)) {
+      _mesa_glsl_error(loc, state,
+                      "interpolation qualifier `%s' can only be applied to "
+                      "vertex shader outputs and fragment shader inputs.",
+                      var->interpolation_string());
+   }
+
    var->pixel_center_integer = qual->flags.q.pixel_center_integer;
    var->origin_upper_left = qual->flags.q.origin_upper_left;
    if ((qual->flags.q.origin_upper_left || qual->flags.q.pixel_center_integer)
@@ -2065,14 +2086,36 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
         } else {
            var->location = qual->location;
         }
+
+        if (qual->flags.q.explicit_index) {
+            /* From the GLSL 4.30 specification, section 4.4.2 (Output
+             * Layout Qualifiers):
+             *
+             * "It is also a compile-time error if a fragment shader
+             *  sets a layout index to less than 0 or greater than 1."
+             *
+             * Older specifications don't mandate a behavior; we take
+             * this as a clarification and always generate the error.
+             */
+            if (qual->index < 0 || qual->index > 1) {
+               _mesa_glsl_error(loc, state,
+                                "explicit index may only be 0 or 1\n");
+            } else {
+               var->explicit_index = true;
+               var->index = qual->index;
+            }
+        }
       }
+   } else if (qual->flags.q.explicit_index) {
+        _mesa_glsl_error(loc, state,
+                         "explicit index requires explicit location\n");
    }
 
    /* Does the declaration use the 'layout' keyword?
     */
    const bool uses_layout = qual->flags.q.pixel_center_integer
       || qual->flags.q.origin_upper_left
-      || qual->flags.q.explicit_location;
+      || qual->flags.q.explicit_location; /* no need for index since it relies on location */
 
    /* Does the declaration use the deprecated 'attribute' or 'varying'
     * keywords?
@@ -2150,6 +2193,23 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
        var->depth_layout = ir_depth_layout_unchanged;
    else
        var->depth_layout = ir_depth_layout_none;
+
+   if (qual->flags.q.std140 ||
+       qual->flags.q.packed ||
+       qual->flags.q.shared) {
+      _mesa_glsl_error(loc, state,
+                       "uniform block layout qualifiers std140, packed, and "
+                      "shared can only be applied to uniform blocks, not "
+                      "members");
+   }
+
+   if (!ubo_qualifiers_valid &&
+       (qual->flags.q.row_major || qual->flags.q.column_major)) {
+      _mesa_glsl_error(loc, state,
+                       "uniform block layout qualifiers row_major and "
+                      "column_major can only be applied to uniform block "
+                      "members");
+   }
 }
 
 /**
@@ -2365,6 +2425,7 @@ process_initializer(ir_variable *var, ast_declaration *decl,
       const glsl_type *initializer_type;
       if (!type->qualifier.flags.q.uniform) {
         result = do_assignment(initializer_instructions, state,
+                               NULL,
                                lhs, rhs, true,
                                type->get_location());
         initializer_type = result->type;
@@ -2569,7 +2630,7 @@ ast_declarator_list::hir(exec_list *instructions,
       }
 
       apply_type_qualifier_to_variable(& this->type->qualifier, var, state,
-                                      & loc);
+                                      & loc, this->ubo_qualifiers_valid);
 
       if (this->type->qualifier.flags.q.invariant) {
         if ((state->target == vertex_shader) && !(var->mode == ir_var_out ||
@@ -2986,7 +3047,8 @@ ast_parameter_declarator::hir(exec_list *instructions,
    /* Apply any specified qualifiers to the parameter declaration.  Note that
     * for function parameters the default mode is 'in'.
     */
-   apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc);
+   apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc,
+                                   false);
 
    /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
     *
@@ -3367,7 +3429,7 @@ ast_jump_statement::hir(exec_list *instructions,
                          "continue may only appear in a loop");
       } else if (mode == ast_break &&
                 state->loop_nesting_ast == NULL &&
-                state->switch_nesting_ast == NULL) {
+                state->switch_state.switch_nesting_ast == NULL) {
         YYLTYPE loc = this->get_location();
 
         _mesa_glsl_error(& loc, state,
@@ -3385,18 +3447,16 @@ ast_jump_statement::hir(exec_list *instructions,
                                                          state);
         }
 
-        if (state->is_switch_innermost &&
+        if (state->switch_state.is_switch_innermost &&
             mode == ast_break) {
            /* 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 =
               new(ctx) ir_dereference_variable(is_break_var);
            ir_constant *const true_val = new(ctx) ir_constant(true);
            ir_assignment *const set_break_var =
-              new(ctx) ir_assignment(deref_is_break_var,
-                                     true_val,
-                                     NULL);
+              new(ctx) ir_assignment(deref_is_break_var, true_val);
            
            instructions->push_tail(set_break_var);
         }
@@ -3477,11 +3537,9 @@ ast_switch_statement::hir(exec_list *instructions,
     *
     *    "The type of init-expression in a switch statement must be a 
     *     scalar integer." 
-    *
-    * The checks are separated so that higher quality diagnostics can be
-    * generated for cases where the rule is violated.
     */
-   if (!test_expression->type->is_integer()) {
+   if (!test_expression->type->is_scalar() ||
+       !test_expression->type->is_integer()) {
       YYLTYPE loc = this->test_expression->get_location();
 
       _mesa_glsl_error(& loc,
@@ -3492,61 +3550,54 @@ ast_switch_statement::hir(exec_list *instructions,
 
    /* Track the switch-statement nesting in a stack-like manner.
     */
-   ir_variable *saved_test_var = state->test_var;
-   ir_variable *saved_is_fallthru_var = state->is_fallthru_var;
-   
-   bool save_is_switch_innermost = state->is_switch_innermost;
-   ast_switch_statement *saved_nesting_ast = state->switch_nesting_ast;
+   struct glsl_switch_state saved = state->switch_state;
 
-   state->is_switch_innermost = true;
-   state->switch_nesting_ast = this;
+   state->switch_state.is_switch_innermost = true;
+   state->switch_state.switch_nesting_ast = this;
+   state->switch_state.labels_ht = hash_table_ctor(0, hash_table_pointer_hash,
+                                                  hash_table_pointer_compare);
+   state->switch_state.previous_default = NULL;
 
    /* Initalize is_fallthru state to false.
     */
    ir_rvalue *const is_fallthru_val = new (ctx) ir_constant(false);
-   state->is_fallthru_var = new(ctx) ir_variable(glsl_type::bool_type,
-                                               "switch_is_fallthru_tmp",
-                                               ir_var_temporary);
-   instructions->push_tail(state->is_fallthru_var);
+   state->switch_state.is_fallthru_var =
+      new(ctx) ir_variable(glsl_type::bool_type,
+                          "switch_is_fallthru_tmp",
+                          ir_var_temporary);
+   instructions->push_tail(state->switch_state.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,
-                                                 is_fallthru_val,
-                                                 NULL));
+                                                 is_fallthru_val));
 
    /* Initalize is_break state to false.
     */
    ir_rvalue *const is_break_val = new (ctx) ir_constant(false);
-   state->is_break_var = new(ctx) ir_variable(glsl_type::bool_type,
-                                             "switch_is_break_tmp",
-                                             ir_var_temporary);
-   instructions->push_tail(state->is_break_var);
+   state->switch_state.is_break_var = new(ctx) ir_variable(glsl_type::bool_type,
+                                                          "switch_is_break_tmp",
+                                                          ir_var_temporary);
+   instructions->push_tail(state->switch_state.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,
-                                                 is_break_val,
-                                                 NULL));
+                                                 is_break_val));
 
    /* Cache test expression.
     */
    test_to_hir(instructions, state);
-   
+
    /* Emit code for body of switch stmt.
     */
    body->hir(instructions, state);
 
-   /* Restore previous nesting before returning.
-    */
-   state->switch_nesting_ast = saved_nesting_ast;
-   state->is_switch_innermost = save_is_switch_innermost;
+   hash_table_dtor(state->switch_state.labels_ht);
 
-   state->test_var = saved_test_var;
-   state->is_fallthru_var = saved_is_fallthru_var;
+   state->switch_state = saved;
 
-   /* Switch statements do not have r-values.
-    */
+   /* Switch statements do not have r-values. */
    return NULL;
 }
 
@@ -3557,22 +3608,19 @@ ast_switch_statement::test_to_hir(exec_list *instructions,
 {
    void *ctx = state;
 
-   /* Cache value of test expression.
-    */
+   /* Cache value of test expression. */
    ir_rvalue *const test_val =
       test_expression->hir(instructions,
                           state);
 
-   state->test_var = new(ctx) ir_variable(glsl_type::int_type,
-                                         "switch_test_tmp",
-                                         ir_var_temporary);
+   state->switch_state.test_var = new(ctx) ir_variable(test_val->type,
+                                                      "switch_test_tmp",
+                                                      ir_var_temporary);
    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(new(ctx) ir_assignment(deref_test_var,
-                                                 test_val,
-                                                 NULL));
+   instructions->push_tail(state->switch_state.test_var);
+   instructions->push_tail(new(ctx) ir_assignment(deref_test_var, test_val));
 }
 
 
@@ -3582,58 +3630,51 @@ ast_switch_body::hir(exec_list *instructions,
 {
    if (stmts != NULL)
       stmts->hir(instructions, state);
-      
-   /* Switch bodies do not have r-values.
-    */
+
+   /* Switch bodies do not have r-values. */
    return NULL;
 }
 
-
 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);
-         
-   /* Case statements do not have r-values.
-    */
+
+   /* Case statements do not have r-values. */
    return NULL;
 }
 
-
 ir_rvalue *
 ast_case_statement::hir(exec_list *instructions,
                        struct _mesa_glsl_parse_state *state)
 {
    labels->hir(instructions, state);
-   
-   /* Conditionally set fallthru state based on break state.
-    */
+
+   /* Conditionally set fallthru state based on break state. */
    ir_constant *const false_val = new(state) ir_constant(false);
    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 =
-      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 =
       new(state) ir_assignment(deref_is_fallthru_var,
                               false_val,
                               deref_is_break_var);
    instructions->push_tail(reset_fallthru_on_break);
 
-   /* Guard case statements depending on fallthru state.
-    */
+   /* Guard case statements depending on fallthru state. */
    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);
-   
+
    foreach_list_typed (ast_node, stmt, link, & this->stmts)
       stmt->hir(& test_fallthru->then_instructions, state);
 
    instructions->push_tail(test_fallthru);
-         
-   /* Case statements do not have r-values.
-    */
+
+   /* Case statements do not have r-values. */
    return NULL;
 }
 
@@ -3644,13 +3685,11 @@ ast_case_label_list::hir(exec_list *instructions,
 {
    foreach_list_typed (ast_case_label, label, link, & this->labels)
       label->hir(instructions, state);
-         
-   /* Case labels do not have r-values.
-    */
+
+   /* Case labels do not have r-values. */
    return NULL;
 }
 
-
 ir_rvalue *
 ast_case_label::hir(exec_list *instructions,
                    struct _mesa_glsl_parse_state *state)
@@ -3658,49 +3697,83 @@ ast_case_label::hir(exec_list *instructions,
    void *ctx = state;
 
    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);
 
-   /* If not default case, ...
-    */
+   /* If not default case, ... */
    if (this->test_value != NULL) {
       /* Conditionally set fallthru state based on
        * comparison of cached test expression value to case label.
        */
-      ir_rvalue *const test_val = this->test_value->hir(instructions, state);
+      ir_rvalue *const label_rval = this->test_value->hir(instructions, state);
+      ir_constant *label_const = label_rval->constant_expression_value();
+
+      if (!label_const) {
+        YYLTYPE loc = this->test_value->get_location();
+
+        _mesa_glsl_error(& loc, state,
+                         "switch statement case label must be a "
+                         "constant expression");
+
+        /* Stuff a dummy value in to allow processing to continue. */
+        label_const = new(ctx) ir_constant(0);
+      } else {
+        ast_expression *previous_label = (ast_expression *)
+           hash_table_find(state->switch_state.labels_ht,
+                           (void *)(uintptr_t)label_const->value.u[0]);
+
+        if (previous_label) {
+           YYLTYPE loc = this->test_value->get_location();
+           _mesa_glsl_error(& loc, state,
+                            "duplicate case value");
+
+           loc = previous_label->get_location();
+           _mesa_glsl_error(& loc, state,
+                            "this is the previous case label");
+        } else {
+           hash_table_insert(state->switch_state.labels_ht,
+                             this->test_value,
+                             (void *)(uintptr_t)label_const->value.u[0]);
+        }
+      }
 
       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,
-                                                         glsl_type::bool_type,
-                                                         test_val,
+                                                         label_const,
                                                          deref_test_var);
 
       ir_assignment *set_fallthru_on_test =
         new(ctx) ir_assignment(deref_fallthru_var,
                                true_val,
                                test_cond);
-   
+
       instructions->push_tail(set_fallthru_on_test);
    } else { /* default case */
-      /* Set falltrhu state.
-       */
+      if (state->switch_state.previous_default) {
+        YYLTYPE loc = this->get_location();
+        _mesa_glsl_error(& loc, state,
+                         "multiple default labels in one switch");
+
+        loc = state->switch_state.previous_default->get_location();
+        _mesa_glsl_error(& loc, state,
+                         "this is the first default label");
+      }
+      state->switch_state.previous_default = this;
+
+      /* Set falltrhu state. */
       ir_assignment *set_fallthru =
-        new(ctx) ir_assignment(deref_fallthru_var,
-                               true_val,
-                               NULL);
-   
+        new(ctx) ir_assignment(deref_fallthru_var, true_val);
+
       instructions->push_tail(set_fallthru);
    }
-   
-   /* Case statements do not have r-values.
-    */
+
+   /* Case statements do not have r-values. */
    return NULL;
 }
 
-
 void
 ast_iteration_statement::condition_to_hir(ir_loop *stmt,
                                          struct _mesa_glsl_parse_state *state)
@@ -3722,8 +3795,7 @@ ast_iteration_statement::condition_to_hir(ir_loop *stmt,
          * like 'if (!condition) break;' as the loop termination condition.
          */
         ir_rvalue *const not_cond =
-           new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond,
-                                  NULL);
+           new(ctx) ir_expression(ir_unop_logic_not, cond);
 
         ir_if *const if_stmt = new(ctx) ir_if(not_cond);
 
@@ -3754,8 +3826,7 @@ ast_iteration_statement::hir(exec_list *instructions,
    ir_loop *const stmt = new(ctx) ir_loop();
    instructions->push_tail(stmt);
 
-   /* Track the current loop nesting.
-    */
+   /* Track the current loop nesting. */
    ast_iteration_statement *nesting_ast = state->loop_nesting_ast;
 
    state->loop_nesting_ast = this;
@@ -3763,8 +3834,8 @@ ast_iteration_statement::hir(exec_list *instructions,
    /* Likewise, indicate that following code is closest to a loop,
     * NOT closest to a switch.
     */
-   bool saved_is_switch_innermost = state->is_switch_innermost;
-   state->is_switch_innermost = false;
+   bool saved_is_switch_innermost = state->switch_state.is_switch_innermost;
+   state->switch_state.is_switch_innermost = false;
 
    if (mode != ast_do_while)
       condition_to_hir(stmt, state);
@@ -3781,10 +3852,9 @@ ast_iteration_statement::hir(exec_list *instructions,
    if (mode != ast_do_while)
       state->symbols->pop_scope();
 
-   /* Restore previous nesting before returning.
-    */
+   /* Restore previous nesting before returning. */
    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.
     */
@@ -3836,8 +3906,8 @@ ast_type_specifier::hir(exec_list *instructions,
                           "arrays");
          return NULL;
       }
-      if (this->type_specifier != ast_float
-          && this->type_specifier != ast_int) {
+      if (strcmp(this->type_name, "float") != 0 &&
+         strcmp(this->type_name, "int") != 0) {
          _mesa_glsl_error(&loc, state,
                           "default precision statements apply only to types "
                           "float and int");
@@ -3938,3 +4008,154 @@ ast_struct_specifier::hir(exec_list *instructions,
     */
    return NULL;
 }
+
+static struct gl_uniform_block *
+get_next_uniform_block(struct _mesa_glsl_parse_state *state)
+{
+   if (state->num_uniform_blocks >= state->uniform_block_array_size) {
+      state->uniform_block_array_size *= 2;
+      if (state->uniform_block_array_size <= 4)
+        state->uniform_block_array_size = 4;
+
+      state->uniform_blocks = reralloc(state,
+                                      state->uniform_blocks,
+                                      struct gl_uniform_block,
+                                      state->uniform_block_array_size);
+   }
+
+   memset(&state->uniform_blocks[state->num_uniform_blocks],
+         0, sizeof(*state->uniform_blocks));
+   return &state->uniform_blocks[state->num_uniform_blocks++];
+}
+
+ir_rvalue *
+ast_uniform_block::hir(exec_list *instructions,
+                      struct _mesa_glsl_parse_state *state)
+{
+   /* The ast_uniform_block has a list of ast_declarator_lists.  We
+    * need to turn those into ir_variables with an association
+    * with this uniform block.
+    */
+   struct gl_uniform_block *ubo = get_next_uniform_block(state);
+   ubo->Name = ralloc_strdup(state->uniform_blocks, this->block_name);
+
+   unsigned int num_variables = 0;
+   foreach_list_typed(ast_declarator_list, decl_list, link, &declarations) {
+      foreach_list_const(node, &decl_list->declarations) {
+        num_variables++;
+      }
+   }
+
+   bool block_row_major = this->layout.flags.q.row_major;
+
+   ubo->Uniforms = rzalloc_array(state->uniform_blocks,
+                                struct gl_uniform_buffer_variable,
+                                num_variables);
+
+   foreach_list_typed(ast_declarator_list, decl_list, link, &declarations) {
+      exec_list declared_variables;
+
+      decl_list->hir(&declared_variables, state);
+
+      foreach_list_const(node, &declared_variables) {
+        struct ir_variable *var = (ir_variable *)node;
+
+        struct gl_uniform_buffer_variable *ubo_var =
+           &ubo->Uniforms[ubo->NumUniforms++];
+
+        var->uniform_block = ubo - state->uniform_blocks;
+
+        ubo_var->Name = ralloc_strdup(state->uniform_blocks, var->name);
+        ubo_var->Type = var->type;
+        ubo_var->Buffer = ubo - state->uniform_blocks;
+        ubo_var->Offset = 0; /* Assigned at link time. */
+
+        if (var->type->is_matrix() ||
+            (var->type->is_array() && var->type->fields.array->is_matrix())) {
+           ubo_var->RowMajor = block_row_major;
+           if (decl_list->type->qualifier.flags.q.row_major)
+              ubo_var->RowMajor = true;
+           else if (decl_list->type->qualifier.flags.q.column_major)
+              ubo_var->RowMajor = false;
+        }
+
+        /* From the GL_ARB_uniform_buffer_object spec:
+         *
+         *     "Sampler types are not allowed inside of uniform
+         *      blocks. All other types, arrays, and structures
+         *      allowed for uniforms are allowed within a uniform
+         *      block."
+         */
+        if (var->type->contains_sampler()) {
+           YYLTYPE loc = decl_list->get_location();
+           _mesa_glsl_error(&loc, state,
+                            "Uniform in non-default uniform block contains sampler\n");
+        }
+      }
+
+      instructions->append_list(&declared_variables);
+   }
+
+   return NULL;
+}
+
+static void
+detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
+                              exec_list *instructions)
+{
+   bool gl_FragColor_assigned = false;
+   bool gl_FragData_assigned = false;
+   bool user_defined_fs_output_assigned = false;
+   ir_variable *user_defined_fs_output = NULL;
+
+   /* It would be nice to have proper location information. */
+   YYLTYPE loc;
+   memset(&loc, 0, sizeof(loc));
+
+   foreach_list(node, instructions) {
+      ir_variable *var = ((ir_instruction *)node)->as_variable();
+
+      if (!var || !var->assigned)
+        continue;
+
+      if (strcmp(var->name, "gl_FragColor") == 0)
+        gl_FragColor_assigned = true;
+      else if (strcmp(var->name, "gl_FragData") == 0)
+        gl_FragData_assigned = true;
+      else if (strncmp(var->name, "gl_", 3) != 0) {
+        if (state->target == fragment_shader &&
+            (var->mode == ir_var_out || var->mode == ir_var_inout)) {
+           user_defined_fs_output_assigned = true;
+           user_defined_fs_output = var;
+        }
+      }
+   }
+
+   /* From the GLSL 1.30 spec:
+    *
+    *     "If a shader statically assigns a value to gl_FragColor, it
+    *      may not assign a value to any element of gl_FragData. If a
+    *      shader statically writes a value to any element of
+    *      gl_FragData, it may not assign a value to
+    *      gl_FragColor. That is, a shader may assign values to either
+    *      gl_FragColor or gl_FragData, but not both. Multiple shaders
+    *      linked together must also consistently write just one of
+    *      these variables.  Similarly, if user declared output
+    *      variables are in use (statically assigned to), then the
+    *      built-in variables gl_FragColor and gl_FragData may not be
+    *      assigned to. These incorrect usages all generate compile
+    *      time errors."
+    */
+   if (gl_FragColor_assigned && gl_FragData_assigned) {
+      _mesa_glsl_error(&loc, state, "fragment shader writes to both "
+                      "`gl_FragColor' and `gl_FragData'\n");
+   } else if (gl_FragColor_assigned && user_defined_fs_output_assigned) {
+      _mesa_glsl_error(&loc, state, "fragment shader writes to both "
+                      "`gl_FragColor' and `%s'\n",
+                      user_defined_fs_output->name);
+   } else if (gl_FragData_assigned && user_defined_fs_output_assigned) {
+      _mesa_glsl_error(&loc, state, "fragment shader writes to both "
+                      "`gl_FragData' and `%s'\n",
+                      user_defined_fs_output->name);
+   }
+}