ir_constant: Return zero on out-of-bounds vector accesses
[mesa.git] / src / compiler / glsl / ir.cpp
index 8c0ae833ebbb101947fbf95d95835c65f2167d20..71be1e1c7c133e14769b6e482cb0d6c2d0187a41 100644 (file)
  * DEALINGS IN THE SOFTWARE.
  */
 #include <string.h>
-#include "main/core.h" /* for MAX2 */
 #include "ir.h"
+#include "util/half_float.h"
 #include "compiler/glsl_types.h"
+#include "glsl_parser_extras.h"
+
 
 ir_rvalue::ir_rvalue(enum ir_node_type t)
    : ir_instruction(t)
@@ -201,11 +203,16 @@ ir_expression::ir_expression(int op, const struct glsl_type *type,
    this->operands[1] = op1;
    this->operands[2] = op2;
    this->operands[3] = op3;
+   init_num_operands();
+
 #ifndef NDEBUG
-   int num_operands = get_num_operands(this->operation);
-   for (int i = num_operands; i < 4; i++) {
+   for (unsigned i = num_operands; i < 4; i++) {
       assert(this->operands[i] == NULL);
    }
+
+   for (unsigned i = 0; i < num_operands; i++) {
+      assert(this->operands[i] != NULL);
+   }
 #endif
 }
 
@@ -219,6 +226,9 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
    this->operands[3] = NULL;
 
    assert(op <= ir_last_unop);
+   init_num_operands();
+   assert(num_operands == 1);
+   assert(this->operands[0]);
 
    switch (this->operation) {
    case ir_unop_bit_not:
@@ -248,7 +258,9 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
    case ir_unop_dFdy_fine:
    case ir_unop_bitfield_reverse:
    case ir_unop_interpolate_at_centroid:
+   case ir_unop_clz:
    case ir_unop_saturate:
+   case ir_unop_atan:
       this->type = op0->type;
       break;
 
@@ -271,6 +283,7 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
    case ir_unop_i2f:
    case ir_unop_u2f:
    case ir_unop_d2f:
+   case ir_unop_f162f:
    case ir_unop_bitcast_i2f:
    case ir_unop_bitcast_u2f:
    case ir_unop_i642f:
@@ -279,9 +292,49 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
                                           op0->type->vector_elements, 1);
       break;
 
+   case ir_unop_f2f16:
+   case ir_unop_f2fmp:
+   case ir_unop_b2f16:
+      this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT16,
+                                          op0->type->vector_elements, 1);
+      break;
+
+   case ir_unop_i2imp:
+      this->type = glsl_type::get_instance(GLSL_TYPE_INT16,
+                                          op0->type->vector_elements, 1);
+      break;
+
+   case ir_unop_i2i:
+      if (op0->type->base_type == GLSL_TYPE_INT) {
+         this->type = glsl_type::get_instance(GLSL_TYPE_INT16,
+                                              op0->type->vector_elements, 1);
+      } else {
+         assert(op0->type->base_type == GLSL_TYPE_INT16);
+         this->type = glsl_type::get_instance(GLSL_TYPE_INT,
+                                              op0->type->vector_elements, 1);
+      }
+      break;
+
+   case ir_unop_u2u:
+      if (op0->type->base_type == GLSL_TYPE_UINT) {
+         this->type = glsl_type::get_instance(GLSL_TYPE_UINT16,
+                                              op0->type->vector_elements, 1);
+      } else {
+         assert(op0->type->base_type == GLSL_TYPE_UINT16);
+         this->type = glsl_type::get_instance(GLSL_TYPE_UINT,
+                                              op0->type->vector_elements, 1);
+      }
+      break;
+
+   case ir_unop_u2ump:
+      this->type = glsl_type::get_instance(GLSL_TYPE_UINT16,
+                                          op0->type->vector_elements, 1);
+      break;
+
    case ir_unop_f2b:
    case ir_unop_i2b:
    case ir_unop_d2b:
+   case ir_unop_f162b:
    case ir_unop_i642b:
       this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
                                           op0->type->vector_elements, 1);
@@ -324,9 +377,6 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
       this->type = glsl_type::get_instance(GLSL_TYPE_UINT64,
                                           op0->type->vector_elements, 1);
       break;
-   case ir_unop_noise:
-      this->type = glsl_type::float_type;
-      break;
 
    case ir_unop_unpack_double_2x32:
    case ir_unop_unpack_uint_2x32:
@@ -368,6 +418,16 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
       this->type = glsl_type::vec4_type;
       break;
 
+   case ir_unop_unpack_sampler_2x32:
+   case ir_unop_unpack_image_2x32:
+      this->type = glsl_type::uvec2_type;
+      break;
+
+   case ir_unop_pack_sampler_2x32:
+   case ir_unop_pack_image_2x32:
+      this->type = op0->type;
+      break;
+
    case ir_unop_frexp_sig:
       this->type = op0->type;
       break;
@@ -381,20 +441,6 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
       this->type = glsl_type::int_type;
       break;
 
-   case ir_unop_ballot:
-      this->type = glsl_type::uint64_t_type;
-      break;
-
-   case ir_unop_read_first_invocation:
-      this->type = op0->type;
-      break;
-
-   case ir_unop_vote_any:
-   case ir_unop_vote_all:
-   case ir_unop_vote_eq:
-      this->type = glsl_type::bool_type;
-      break;
-
    case ir_unop_bitcast_i642d:
    case ir_unop_bitcast_u642d:
       this->type = glsl_type::get_instance(GLSL_TYPE_DOUBLE,
@@ -427,6 +473,11 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
    this->operands[3] = NULL;
 
    assert(op > ir_last_unop);
+   init_num_operands();
+   assert(num_operands == 2);
+   for (unsigned i = 0; i < num_operands; i++) {
+      assert(this->operands[i] != NULL);
+   }
 
    switch (this->operation) {
    case ir_binop_all_equal:
@@ -442,6 +493,7 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
    case ir_binop_mul:
    case ir_binop_div:
    case ir_binop_mod:
+   case ir_binop_atan2:
       if (op0->type->is_scalar()) {
         this->type = op1->type;
       } else if (op1->type->is_scalar()) {
@@ -476,10 +528,8 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
 
    case ir_binop_equal:
    case ir_binop_nequal:
-   case ir_binop_lequal:
    case ir_binop_gequal:
    case ir_binop_less:
-   case ir_binop_greater:
       assert(op0->type == op1->type);
       this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
                                           op0->type->vector_elements, 1);
@@ -490,6 +540,7 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
       break;
 
    case ir_binop_imul_high:
+   case ir_binop_mul_32x16:
    case ir_binop_carry:
    case ir_binop_borrow:
    case ir_binop_lshift:
@@ -500,12 +551,46 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
       this->type = op0->type;
       break;
 
-   case ir_binop_vector_extract:
-      this->type = op0->type->get_scalar_type();
+   case ir_binop_add_sat:
+   case ir_binop_sub_sat:
+   case ir_binop_avg:
+   case ir_binop_avg_round:
+      assert(op0->type == op1->type);
+      this->type = op0->type;
       break;
 
-   case ir_binop_read_invocation:
-      this->type = op0->type;
+   case ir_binop_abs_sub: {
+      enum glsl_base_type base;
+
+      assert(op0->type == op1->type);
+
+      switch (op0->type->base_type) {
+      case GLSL_TYPE_UINT:
+      case GLSL_TYPE_INT:
+         base = GLSL_TYPE_UINT;
+         break;
+      case GLSL_TYPE_UINT8:
+      case GLSL_TYPE_INT8:
+         base = GLSL_TYPE_UINT8;
+         break;
+      case GLSL_TYPE_UINT16:
+      case GLSL_TYPE_INT16:
+         base = GLSL_TYPE_UINT16;
+         break;
+      case GLSL_TYPE_UINT64:
+      case GLSL_TYPE_INT64:
+         base = GLSL_TYPE_UINT64;
+         break;
+      default:
+         unreachable(!"Invalid base type.");
+      }
+
+      this->type = glsl_type::get_instance(base, op0->type->vector_elements, 1);
+      break;
+   }
+
+   case ir_binop_vector_extract:
+      this->type = op0->type->get_scalar_type();
       break;
 
    default:
@@ -525,6 +610,11 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1,
    this->operands[3] = NULL;
 
    assert(op > ir_last_binop && op <= ir_last_triop);
+   init_num_operands();
+   assert(num_operands == 3);
+   for (unsigned i = 0; i < num_operands; i++) {
+      assert(this->operands[i] != NULL);
+   }
 
    switch (this->operation) {
    case ir_triop_fma:
@@ -544,7 +634,11 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1,
    }
 }
 
-unsigned int
+/**
+ * This is only here for ir_reader to used for testing purposes. Please use
+ * the precomputed num_operands field if you need the number of operands.
+ */
+unsigned
 ir_expression::get_num_operands(ir_expression_operation op)
 {
    assert(op <= ir_last_opcode);
@@ -561,8 +655,7 @@ ir_expression::get_num_operands(ir_expression_operation op)
    if (op <= ir_last_quadop)
       return 4;
 
-   assert(false);
-   return 0;
+   unreachable("Could not calculate number of operands");
 }
 
 #include "ir_expression_operation_strings.h"
@@ -612,22 +705,35 @@ ir_expression::variable_referenced() const
 ir_constant::ir_constant()
    : ir_rvalue(ir_type_constant)
 {
-   this->array_elements = NULL;
+   this->const_elements = NULL;
 }
 
 ir_constant::ir_constant(const struct glsl_type *type,
                         const ir_constant_data *data)
    : ir_rvalue(ir_type_constant)
 {
-   this->array_elements = NULL;
+   this->const_elements = NULL;
 
    assert((type->base_type >= GLSL_TYPE_UINT)
-         && (type->base_type <= GLSL_TYPE_BOOL));
+         && (type->base_type <= GLSL_TYPE_IMAGE));
 
    this->type = type;
    memcpy(& this->value, data, sizeof(this->value));
 }
 
+ir_constant::ir_constant(float16_t f16, unsigned vector_elements)
+   : ir_rvalue(ir_type_constant)
+{
+   assert(vector_elements <= 4);
+   this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT16, vector_elements, 1);
+   for (unsigned i = 0; i < vector_elements; i++) {
+      this->value.f16[i] = f16.bits;
+   }
+   for (unsigned i = vector_elements; i < 16; i++)  {
+      this->value.f[i] = 0;
+   }
+}
+
 ir_constant::ir_constant(float f, unsigned vector_elements)
    : ir_rvalue(ir_type_constant)
 {
@@ -654,6 +760,32 @@ ir_constant::ir_constant(double d, unsigned vector_elements)
    }
 }
 
+ir_constant::ir_constant(int16_t i16, unsigned vector_elements)
+   : ir_rvalue(ir_type_constant)
+{
+   assert(vector_elements <= 4);
+   this->type = glsl_type::get_instance(GLSL_TYPE_INT16, vector_elements, 1);
+   for (unsigned i = 0; i < vector_elements; i++) {
+      this->value.i16[i] = i16;
+   }
+   for (unsigned i = vector_elements; i < 16; i++) {
+      this->value.i16[i] = 0;
+   }
+}
+
+ir_constant::ir_constant(uint16_t u16, unsigned vector_elements)
+   : ir_rvalue(ir_type_constant)
+{
+   assert(vector_elements <= 4);
+   this->type = glsl_type::get_instance(GLSL_TYPE_UINT16, vector_elements, 1);
+   for (unsigned i = 0; i < vector_elements; i++) {
+      this->value.u16[i] = u16;
+   }
+   for (unsigned i = vector_elements; i < 16; i++) {
+      this->value.u16[i] = 0;
+   }
+}
+
 ir_constant::ir_constant(unsigned int u, unsigned vector_elements)
    : ir_rvalue(ir_type_constant)
 {
@@ -722,13 +854,30 @@ ir_constant::ir_constant(bool b, unsigned vector_elements)
 ir_constant::ir_constant(const ir_constant *c, unsigned i)
    : ir_rvalue(ir_type_constant)
 {
-   this->array_elements = NULL;
+   this->const_elements = NULL;
    this->type = c->type->get_base_type();
 
+   /* Section 5.11 (Out-of-Bounds Accesses) of the GLSL 4.60 spec says:
+    *
+    *    In the subsections described above for array, vector, matrix and
+    *    structure accesses, any out-of-bounds access produced undefined
+    *    behavior....Out-of-bounds reads return undefined values, which
+    *    include values from other variables of the active program or zero.
+    *
+    * GL_KHR_robustness and GL_ARB_robustness encourage us to return zero.
+    */
+   if (i >= c->type->vector_elements) {
+      this->value = { { 0 } };
+      return;
+   }
+
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:  this->value.u16[0] = c->value.u16[i]; break;
+   case GLSL_TYPE_INT16:  this->value.i16[0] = c->value.i16[i]; break;
    case GLSL_TYPE_UINT:  this->value.u[0] = c->value.u[i]; break;
    case GLSL_TYPE_INT:   this->value.i[0] = c->value.i[i]; break;
    case GLSL_TYPE_FLOAT: this->value.f[0] = c->value.f[i]; break;
+   case GLSL_TYPE_FLOAT16: this->value.f16[0] = c->value.f16[i]; break;
    case GLSL_TYPE_BOOL:  this->value.b[0] = c->value.b[i]; break;
    case GLSL_TYPE_DOUBLE: this->value.d[0] = c->value.d[i]; break;
    default:              assert(!"Should not get here."); break;
@@ -738,34 +887,25 @@ ir_constant::ir_constant(const ir_constant *c, unsigned i)
 ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
    : ir_rvalue(ir_type_constant)
 {
-   this->array_elements = NULL;
+   this->const_elements = NULL;
    this->type = type;
 
    assert(type->is_scalar() || type->is_vector() || type->is_matrix()
-         || type->is_record() || type->is_array());
-
-   if (type->is_array()) {
-      this->array_elements = ralloc_array(this, ir_constant *, type->length);
-      unsigned i = 0;
-      foreach_in_list(ir_constant, value, value_list) {
-        assert(value->as_constant() != NULL);
-
-        this->array_elements[i++] = value;
-      }
-      return;
-   }
+         || type->is_struct() || type->is_array());
 
    /* If the constant is a record, the types of each of the entries in
     * value_list must be a 1-for-1 match with the structure components.  Each
     * entry must also be a constant.  Just move the nodes from the value_list
     * to the list in the ir_constant.
     */
-   /* FINISHME: Should there be some type checking and / or assertions here? */
-   /* FINISHME: Should the new constant take ownership of the nodes from
-    * FINISHME: value_list, or should it make copies?
-    */
-   if (type->is_record()) {
-      value_list->move_nodes_to(& this->components);
+   if (type->is_array() || type->is_struct()) {
+      this->const_elements = ralloc_array(this, ir_constant *, type->length);
+      unsigned i = 0;
+      foreach_in_list(ir_constant, value, value_list) {
+        assert(value->as_constant() != NULL);
+
+        this->const_elements[i++] = value;
+      }
       return;
    }
 
@@ -783,19 +923,32 @@ ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
    if (value->type->is_scalar() && value->next->is_tail_sentinel()) {
       if (type->is_matrix()) {
         /* Matrix - fill diagonal (rest is already set to 0) */
-         assert(type->base_type == GLSL_TYPE_FLOAT ||
-                type->is_double());
          for (unsigned i = 0; i < type->matrix_columns; i++) {
-            if (type->base_type == GLSL_TYPE_FLOAT)
+            switch (type->base_type) {
+            case GLSL_TYPE_FLOAT:
                this->value.f[i * type->vector_elements + i] =
                   value->value.f[0];
-            else
+               break;
+            case GLSL_TYPE_DOUBLE:
                this->value.d[i * type->vector_elements + i] =
                   value->value.d[0];
+               break;
+            case GLSL_TYPE_FLOAT16:
+               this->value.f16[i * type->vector_elements + i] =
+                  value->value.f16[0];
+               break;
+            default:
+               assert(!"unexpected matrix base type");
+            }
          }
       } else {
         /* Vector or scalar - fill all components */
         switch (type->base_type) {
+         case GLSL_TYPE_UINT16:
+        case GLSL_TYPE_INT16:
+           for (unsigned i = 0; i < type->components(); i++)
+              this->value.u16[i] = value->value.u16[0];
+           break;
         case GLSL_TYPE_UINT:
         case GLSL_TYPE_INT:
            for (unsigned i = 0; i < type->components(); i++)
@@ -805,6 +958,10 @@ ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
            for (unsigned i = 0; i < type->components(); i++)
               this->value.f[i] = value->value.f[0];
            break;
+        case GLSL_TYPE_FLOAT16:
+           for (unsigned i = 0; i < type->components(); i++)
+              this->value.f16[i] = value->value.f16[0];
+           break;
         case GLSL_TYPE_DOUBLE:
            for (unsigned i = 0; i < type->components(); i++)
               this->value.d[i] = value->value.d[0];
@@ -818,6 +975,10 @@ ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
            for (unsigned i = 0; i < type->components(); i++)
               this->value.b[i] = value->value.b[0];
            break;
+        case GLSL_TYPE_SAMPLER:
+        case GLSL_TYPE_IMAGE:
+           this->value.u64[0] = value->value.u64[0];
+           break;
         default:
            assert(!"Should not get here.");
            break;
@@ -861,6 +1022,12 @@ ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
 
       for (unsigned j = 0; j < value->type->components(); j++) {
         switch (type->base_type) {
+         case GLSL_TYPE_UINT16:
+           this->value.u16[i] = value->get_uint16_component(j);
+           break;
+        case GLSL_TYPE_INT16:
+           this->value.i16[i] = value->get_int16_component(j);
+           break;
         case GLSL_TYPE_UINT:
            this->value.u[i] = value->get_uint_component(j);
            break;
@@ -870,6 +1037,9 @@ ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
         case GLSL_TYPE_FLOAT:
            this->value.f[i] = value->get_float_component(j);
            break;
+        case GLSL_TYPE_FLOAT16:
+           this->value.f16[i] = value->get_float16_component(j);
+           break;
         case GLSL_TYPE_BOOL:
            this->value.b[i] = value->get_bool_component(j);
            break;
@@ -903,23 +1073,25 @@ ir_constant *
 ir_constant::zero(void *mem_ctx, const glsl_type *type)
 {
    assert(type->is_scalar() || type->is_vector() || type->is_matrix()
-         || type->is_record() || type->is_array());
+         || type->is_struct() || type->is_array());
 
    ir_constant *c = new(mem_ctx) ir_constant;
    c->type = type;
    memset(&c->value, 0, sizeof(c->value));
 
    if (type->is_array()) {
-      c->array_elements = ralloc_array(c, ir_constant *, type->length);
+      c->const_elements = ralloc_array(c, ir_constant *, type->length);
 
       for (unsigned i = 0; i < type->length; i++)
-        c->array_elements[i] = ir_constant::zero(c, type->fields.array);
+        c->const_elements[i] = ir_constant::zero(c, type->fields.array);
    }
 
-   if (type->is_record()) {
+   if (type->is_struct()) {
+      c->const_elements = ralloc_array(c, ir_constant *, type->length);
+
       for (unsigned i = 0; i < type->length; i++) {
-        ir_constant *comp = ir_constant::zero(mem_ctx, type->fields.structure[i].type);
-        c->components.push_tail(comp);
+         c->const_elements[i] =
+            ir_constant::zero(mem_ctx, type->fields.structure[i].type);
       }
    }
 
@@ -930,11 +1102,16 @@ bool
 ir_constant::get_bool_component(unsigned i) const
 {
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return this->value.u16[i] != 0;
+   case GLSL_TYPE_INT16: return this->value.i16[i] != 0;
    case GLSL_TYPE_UINT:  return this->value.u[i] != 0;
    case GLSL_TYPE_INT:   return this->value.i[i] != 0;
    case GLSL_TYPE_FLOAT: return ((int)this->value.f[i]) != 0;
+   case GLSL_TYPE_FLOAT16: return ((int)_mesa_half_to_float(this->value.f16[i])) != 0;
    case GLSL_TYPE_BOOL:  return this->value.b[i];
    case GLSL_TYPE_DOUBLE: return this->value.d[i] != 0.0;
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_UINT64: return this->value.u64[i] != 0;
    case GLSL_TYPE_INT64:  return this->value.i64[i] != 0;
    default:              assert(!"Should not get here."); break;
@@ -950,11 +1127,16 @@ float
 ir_constant::get_float_component(unsigned i) const
 {
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return (float) this->value.u16[i];
+   case GLSL_TYPE_INT16: return (float) this->value.i16[i];
    case GLSL_TYPE_UINT:  return (float) this->value.u[i];
    case GLSL_TYPE_INT:   return (float) this->value.i[i];
    case GLSL_TYPE_FLOAT: return this->value.f[i];
+   case GLSL_TYPE_FLOAT16: return _mesa_half_to_float(this->value.f16[i]);
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1.0f : 0.0f;
    case GLSL_TYPE_DOUBLE: return (float) this->value.d[i];
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_UINT64: return (float) this->value.u64[i];
    case GLSL_TYPE_INT64:  return (float) this->value.i64[i];
    default:              assert(!"Should not get here."); break;
@@ -966,15 +1148,29 @@ ir_constant::get_float_component(unsigned i) const
    return 0.0;
 }
 
+uint16_t
+ir_constant::get_float16_component(unsigned i) const
+{
+   if (this->type->base_type == GLSL_TYPE_FLOAT16)
+      return this->value.f16[i];
+   else
+      return _mesa_float_to_half(get_float_component(i));
+}
+
 double
 ir_constant::get_double_component(unsigned i) const
 {
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return (double) this->value.u16[i];
+   case GLSL_TYPE_INT16: return (double) this->value.i16[i];
    case GLSL_TYPE_UINT:  return (double) this->value.u[i];
    case GLSL_TYPE_INT:   return (double) this->value.i[i];
    case GLSL_TYPE_FLOAT: return (double) this->value.f[i];
+   case GLSL_TYPE_FLOAT16: return (double) _mesa_half_to_float(this->value.f16[i]);
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1.0 : 0.0;
    case GLSL_TYPE_DOUBLE: return this->value.d[i];
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_UINT64: return (double) this->value.u64[i];
    case GLSL_TYPE_INT64:  return (double) this->value.i64[i];
    default:              assert(!"Should not get here."); break;
@@ -986,15 +1182,70 @@ ir_constant::get_double_component(unsigned i) const
    return 0.0;
 }
 
+int16_t
+ir_constant::get_int16_component(unsigned i) const
+{
+   switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return this->value.u16[i];
+   case GLSL_TYPE_INT16: return this->value.i16[i];
+   case GLSL_TYPE_UINT:  return this->value.u[i];
+   case GLSL_TYPE_INT:   return this->value.i[i];
+   case GLSL_TYPE_FLOAT: return (int16_t) this->value.f[i];
+   case GLSL_TYPE_FLOAT16: return (int16_t) _mesa_half_to_float(this->value.f16[i]);
+   case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1 : 0;
+   case GLSL_TYPE_DOUBLE: return (int16_t) this->value.d[i];
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
+   case GLSL_TYPE_UINT64: return (int16_t) this->value.u64[i];
+   case GLSL_TYPE_INT64:  return (int16_t) this->value.i64[i];
+   default:              assert(!"Should not get here."); break;
+   }
+
+   /* Must return something to make the compiler happy.  This is clearly an
+    * error case.
+    */
+   return 0;
+}
+
+uint16_t
+ir_constant::get_uint16_component(unsigned i) const
+{
+   switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return this->value.u16[i];
+   case GLSL_TYPE_INT16: return this->value.i16[i];
+   case GLSL_TYPE_UINT:  return this->value.u[i];
+   case GLSL_TYPE_INT:   return this->value.i[i];
+   case GLSL_TYPE_FLOAT: return (uint16_t) this->value.f[i];
+   case GLSL_TYPE_FLOAT16: return (uint16_t) _mesa_half_to_float(this->value.f16[i]);
+   case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1 : 0;
+   case GLSL_TYPE_DOUBLE: return (uint16_t) this->value.d[i];
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
+   case GLSL_TYPE_UINT64: return (uint16_t) this->value.u64[i];
+   case GLSL_TYPE_INT64:  return (uint16_t) this->value.i64[i];
+   default:              assert(!"Should not get here."); break;
+   }
+
+   /* Must return something to make the compiler happy.  This is clearly an
+    * error case.
+    */
+   return 0;
+}
+
 int
 ir_constant::get_int_component(unsigned i) const
 {
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return this->value.u16[i];
+   case GLSL_TYPE_INT16: return this->value.i16[i];
    case GLSL_TYPE_UINT:  return this->value.u[i];
    case GLSL_TYPE_INT:   return this->value.i[i];
    case GLSL_TYPE_FLOAT: return (int) this->value.f[i];
+   case GLSL_TYPE_FLOAT16: return (int) _mesa_half_to_float(this->value.f16[i]);
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1 : 0;
    case GLSL_TYPE_DOUBLE: return (int) this->value.d[i];
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_UINT64: return (int) this->value.u64[i];
    case GLSL_TYPE_INT64:  return (int) this->value.i64[i];
    default:              assert(!"Should not get here."); break;
@@ -1010,11 +1261,16 @@ unsigned
 ir_constant::get_uint_component(unsigned i) const
 {
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return this->value.u16[i];
+   case GLSL_TYPE_INT16: return this->value.i16[i];
    case GLSL_TYPE_UINT:  return this->value.u[i];
    case GLSL_TYPE_INT:   return this->value.i[i];
    case GLSL_TYPE_FLOAT: return (unsigned) this->value.f[i];
+   case GLSL_TYPE_FLOAT16: return (unsigned) _mesa_half_to_float(this->value.f16[i]);
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1 : 0;
    case GLSL_TYPE_DOUBLE: return (unsigned) this->value.d[i];
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_UINT64: return (unsigned) this->value.u64[i];
    case GLSL_TYPE_INT64:  return (unsigned) this->value.i64[i];
    default:              assert(!"Should not get here."); break;
@@ -1030,11 +1286,16 @@ int64_t
 ir_constant::get_int64_component(unsigned i) const
 {
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return this->value.u16[i];
+   case GLSL_TYPE_INT16: return this->value.i16[i];
    case GLSL_TYPE_UINT:  return this->value.u[i];
    case GLSL_TYPE_INT:   return this->value.i[i];
    case GLSL_TYPE_FLOAT: return (int64_t) this->value.f[i];
+   case GLSL_TYPE_FLOAT16: return (int64_t) _mesa_half_to_float(this->value.f16[i]);
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1 : 0;
    case GLSL_TYPE_DOUBLE: return (int64_t) this->value.d[i];
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_UINT64: return (int64_t) this->value.u64[i];
    case GLSL_TYPE_INT64:  return this->value.i64[i];
    default:              assert(!"Should not get here."); break;
@@ -1050,11 +1311,16 @@ uint64_t
 ir_constant::get_uint64_component(unsigned i) const
 {
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:return this->value.u16[i];
+   case GLSL_TYPE_INT16: return this->value.i16[i];
    case GLSL_TYPE_UINT:  return this->value.u[i];
    case GLSL_TYPE_INT:   return this->value.i[i];
    case GLSL_TYPE_FLOAT: return (uint64_t) this->value.f[i];
+   case GLSL_TYPE_FLOAT16: return (uint64_t) _mesa_half_to_float(this->value.f16[i]);
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1 : 0;
    case GLSL_TYPE_DOUBLE: return (uint64_t) this->value.d[i];
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_UINT64: return this->value.u64[i];
    case GLSL_TYPE_INT64:  return (uint64_t) this->value.i64[i];
    default:              assert(!"Should not get here."); break;
@@ -1086,42 +1352,31 @@ ir_constant::get_array_element(unsigned i) const
    else if (i >= this->type->length)
       i = this->type->length - 1;
 
-   return array_elements[i];
+   return const_elements[i];
 }
 
 ir_constant *
-ir_constant::get_record_field(const char *name)
+ir_constant::get_record_field(int idx)
 {
-   int idx = this->type->field_index(name);
-
-   if (idx < 0)
-      return NULL;
+   assert(this->type->is_struct());
+   assert(idx >= 0 && (unsigned) idx < this->type->length);
 
-   if (this->components.is_empty())
-      return NULL;
-
-   exec_node *node = this->components.get_head_raw();
-   for (int i = 0; i < idx; i++) {
-      node = node->next;
-
-      /* If the end of the list is encountered before the element matching the
-       * requested field is found, return NULL.
-       */
-      if (node->is_tail_sentinel())
-        return NULL;
-   }
-
-   return (ir_constant *) node;
+   return const_elements[idx];
 }
 
 void
 ir_constant::copy_offset(ir_constant *src, int offset)
 {
    switch (this->type->base_type) {
+   case GLSL_TYPE_UINT16:
+   case GLSL_TYPE_INT16:
    case GLSL_TYPE_UINT:
    case GLSL_TYPE_INT:
    case GLSL_TYPE_FLOAT:
+   case GLSL_TYPE_FLOAT16:
    case GLSL_TYPE_DOUBLE:
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
    case GLSL_TYPE_UINT64:
    case GLSL_TYPE_INT64:
    case GLSL_TYPE_BOOL: {
@@ -1129,6 +1384,12 @@ ir_constant::copy_offset(ir_constant *src, int offset)
       assert (size <= this->type->components() - offset);
       for (unsigned int i=0; i<size; i++) {
         switch (this->type->base_type) {
+         case GLSL_TYPE_UINT16:
+           value.u16[i+offset] = src->get_uint16_component(i);
+           break;
+        case GLSL_TYPE_INT16:
+           value.i16[i+offset] = src->get_int16_component(i);
+           break;
         case GLSL_TYPE_UINT:
            value.u[i+offset] = src->get_uint_component(i);
            break;
@@ -1138,13 +1399,18 @@ ir_constant::copy_offset(ir_constant *src, int offset)
         case GLSL_TYPE_FLOAT:
            value.f[i+offset] = src->get_float_component(i);
            break;
+        case GLSL_TYPE_FLOAT16:
+           value.f16[i+offset] = src->get_float16_component(i);
+           break;
         case GLSL_TYPE_BOOL:
            value.b[i+offset] = src->get_bool_component(i);
            break;
         case GLSL_TYPE_DOUBLE:
            value.d[i+offset] = src->get_double_component(i);
            break;
-         case GLSL_TYPE_UINT64:
+        case GLSL_TYPE_SAMPLER:
+        case GLSL_TYPE_IMAGE:
+        case GLSL_TYPE_UINT64:
            value.u64[i+offset] = src->get_uint64_component(i);
            break;
         case GLSL_TYPE_INT64:
@@ -1157,19 +1423,11 @@ ir_constant::copy_offset(ir_constant *src, int offset)
       break;
    }
 
-   case GLSL_TYPE_STRUCT: {
-      assert (src->type == this->type);
-      this->components.make_empty();
-      foreach_in_list(ir_constant, orig, &src->components) {
-        this->components.push_tail(orig->clone(this, NULL));
-      }
-      break;
-   }
-
+   case GLSL_TYPE_STRUCT:
    case GLSL_TYPE_ARRAY: {
       assert (src->type == this->type);
       for (unsigned i = 0; i < this->type->length; i++) {
-        this->array_elements[i] = src->array_elements[i]->clone(this, NULL);
+        this->const_elements[i] = src->const_elements[i]->clone(this, NULL);
       }
       break;
    }
@@ -1183,7 +1441,7 @@ ir_constant::copy_offset(ir_constant *src, int offset)
 void
 ir_constant::copy_masked_offset(ir_constant *src, int offset, unsigned int mask)
 {
-   assert (!type->is_array() && !type->is_record());
+   assert (!type->is_array() && !type->is_struct());
 
    if (!type->is_vector() && !type->is_matrix()) {
       offset = 0;
@@ -1194,6 +1452,12 @@ ir_constant::copy_masked_offset(ir_constant *src, int offset, unsigned int mask)
    for (int i=0; i<4; i++) {
       if (mask & (1 << i)) {
         switch (this->type->base_type) {
+         case GLSL_TYPE_UINT16:
+           value.u16[i+offset] = src->get_uint16_component(id++);
+           break;
+        case GLSL_TYPE_INT16:
+           value.i16[i+offset] = src->get_int16_component(id++);
+           break;
         case GLSL_TYPE_UINT:
            value.u[i+offset] = src->get_uint_component(id++);
            break;
@@ -1203,13 +1467,18 @@ ir_constant::copy_masked_offset(ir_constant *src, int offset, unsigned int mask)
         case GLSL_TYPE_FLOAT:
            value.f[i+offset] = src->get_float_component(id++);
            break;
+        case GLSL_TYPE_FLOAT16:
+           value.f16[i+offset] = src->get_float16_component(id++);
+           break;
         case GLSL_TYPE_BOOL:
            value.b[i+offset] = src->get_bool_component(id++);
            break;
         case GLSL_TYPE_DOUBLE:
            value.d[i+offset] = src->get_double_component(id++);
            break;
-         case GLSL_TYPE_UINT64:
+        case GLSL_TYPE_SAMPLER:
+        case GLSL_TYPE_IMAGE:
+        case GLSL_TYPE_UINT64:
            value.u64[i+offset] = src->get_uint64_component(id++);
            break;
         case GLSL_TYPE_INT64:
@@ -1229,36 +1498,24 @@ ir_constant::has_value(const ir_constant *c) const
    if (this->type != c->type)
       return false;
 
-   if (this->type->is_array()) {
+   if (this->type->is_array() || this->type->is_struct()) {
       for (unsigned i = 0; i < this->type->length; i++) {
-        if (!this->array_elements[i]->has_value(c->array_elements[i]))
-           return false;
-      }
-      return true;
-   }
-
-   if (this->type->is_record()) {
-      const exec_node *a_node = this->components.get_head_raw();
-      const exec_node *b_node = c->components.get_head_raw();
-
-      while (!a_node->is_tail_sentinel()) {
-        assert(!b_node->is_tail_sentinel());
-
-        const ir_constant *const a_field = (ir_constant *) a_node;
-        const ir_constant *const b_field = (ir_constant *) b_node;
-
-        if (!a_field->has_value(b_field))
+        if (!this->const_elements[i]->has_value(c->const_elements[i]))
            return false;
-
-        a_node = a_node->next;
-        b_node = b_node->next;
       }
-
       return true;
    }
 
    for (unsigned i = 0; i < this->type->components(); i++) {
       switch (this->type->base_type) {
+      case GLSL_TYPE_UINT16:
+        if (this->value.u16[i] != c->value.u16[i])
+           return false;
+        break;
+      case GLSL_TYPE_INT16:
+        if (this->value.i16[i] != c->value.i16[i])
+           return false;
+        break;
       case GLSL_TYPE_UINT:
         if (this->value.u[i] != c->value.u[i])
            return false;
@@ -1271,6 +1528,12 @@ ir_constant::has_value(const ir_constant *c) const
         if (this->value.f[i] != c->value.f[i])
            return false;
         break;
+      case GLSL_TYPE_FLOAT16:
+       /* Convert to float to make sure NaN and ±0.0 compares correctly */
+        if (_mesa_half_to_float(this->value.f16[i]) !=
+             _mesa_half_to_float(c->value.f16[i]))
+           return false;
+        break;
       case GLSL_TYPE_BOOL:
         if (this->value.b[i] != c->value.b[i])
            return false;
@@ -1279,6 +1542,8 @@ ir_constant::has_value(const ir_constant *c) const
         if (this->value.d[i] != c->value.d[i])
            return false;
         break;
+      case GLSL_TYPE_SAMPLER:
+      case GLSL_TYPE_IMAGE:
       case GLSL_TYPE_UINT64:
         if (this->value.u64[i] != c->value.u64[i])
            return false;
@@ -1312,6 +1577,18 @@ ir_constant::is_value(float f, int i) const
         if (this->value.f[c] != f)
            return false;
         break;
+      case GLSL_TYPE_FLOAT16:
+         if (_mesa_half_to_float(this->value.f16[c]) != f)
+            return false;
+         break;
+      case GLSL_TYPE_INT16:
+        if (this->value.i16[c] != int16_t(i))
+           return false;
+        break;
+      case GLSL_TYPE_UINT16:
+        if (this->value.u16[c] != uint16_t(i))
+           return false;
+        break;
       case GLSL_TYPE_INT:
         if (this->value.i[c] != i)
            return false;
@@ -1328,6 +1605,8 @@ ir_constant::is_value(float f, int i) const
         if (this->value.d[c] != double(f))
            return false;
         break;
+      case GLSL_TYPE_SAMPLER:
+      case GLSL_TYPE_IMAGE:
       case GLSL_TYPE_UINT64:
         if (this->value.u64[c] != uint64_t(i))
            return false;
@@ -1370,7 +1649,7 @@ ir_constant::is_negative_one() const
 bool
 ir_constant::is_uint16_constant() const
 {
-   if (!type->is_integer())
+   if (!type->is_integer_32())
       return false;
 
    return value.u[0] < (1 << 16);
@@ -1438,8 +1717,8 @@ ir_dereference_record::ir_dereference_record(ir_rvalue *value,
    assert(value != NULL);
 
    this->record = value;
-   this->field = ralloc_strdup(this, field);
    this->type = this->record->type->field_type(field);
+   this->field_idx = this->record->type->field_index(field);
 }
 
 
@@ -1450,12 +1729,12 @@ ir_dereference_record::ir_dereference_record(ir_variable *var,
    void *ctx = ralloc_parent(var);
 
    this->record = new(ctx) ir_dereference_variable(var);
-   this->field = ralloc_strdup(this, field);
    this->type = this->record->type->field_type(field);
+   this->field_idx = this->record->type->field_index(field);
 }
 
 bool
-ir_dereference::is_lvalue() const
+ir_dereference::is_lvalue(const struct _mesa_glsl_parse_state *state) const
 {
    ir_variable *var = this->variable_referenced();
 
@@ -1464,6 +1743,20 @@ ir_dereference::is_lvalue() const
    if ((var == NULL) || var->data.read_only)
       return false;
 
+   /* From section 4.1.7 of the ARB_bindless_texture spec:
+    *
+    * "Samplers can be used as l-values, so can be assigned into and used as
+    *  "out" and "inout" function parameters."
+    *
+    * From section 4.1.X of the ARB_bindless_texture spec:
+    *
+    * "Images can be used as l-values, so can be assigned into and used as
+    *  "out" and "inout" function parameters."
+    */
+   if ((!state || state->has_bindless()) &&
+       (this->type->contains_sampler() || this->type->contains_image()))
+      return true;
+
    /* From section 4.1.7 of the GLSL 4.40 spec:
     *
     *   "Opaque variables cannot be treated as l-values; hence cannot
@@ -1510,7 +1803,7 @@ ir_texture::set_sampler(ir_dereference *sampler, const glsl_type *type)
       assert(type->base_type == GLSL_TYPE_INT);
    } else if (this->op == ir_lod) {
       assert(type->vector_elements == 2);
-      assert(type->base_type == GLSL_TYPE_FLOAT);
+      assert(type->is_float());
    } else if (this->op == ir_samples_identical) {
       assert(type == glsl_type::bool_type);
       assert(sampler->type->is_sampler());
@@ -1583,10 +1876,8 @@ ir_swizzle::ir_swizzle(ir_rvalue *val, const unsigned *comp,
 }
 
 ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask)
-   : ir_rvalue(ir_type_swizzle)
+   : ir_rvalue(ir_type_swizzle), val(val), mask(mask)
 {
-   this->val = val;
-   this->mask = mask;
    this->type = glsl_type::get_instance(val->type->base_type,
                                        mask.num_components, 1);
 }
@@ -1718,41 +2009,63 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
    this->u.max_ifc_array_access = NULL;
 
    this->data.explicit_location = false;
+   this->data.explicit_index = false;
+   this->data.explicit_binding = false;
+   this->data.explicit_component = false;
    this->data.has_initializer = false;
+   this->data.is_implicit_initializer = false;
+   this->data.is_unmatched_generic_inout = false;
+   this->data.is_xfb_only = false;
+   this->data.explicit_xfb_buffer = false;
+   this->data.explicit_xfb_offset = false;
+   this->data.explicit_xfb_stride = false;
    this->data.location = -1;
    this->data.location_frac = 0;
+   this->data.matrix_layout = GLSL_MATRIX_LAYOUT_INHERITED;
+   this->data.from_named_ifc_block = false;
+   this->data.must_be_shader_input = false;
+   this->data.index = 0;
    this->data.binding = 0;
    this->data.warn_extension_index = 0;
    this->constant_value = NULL;
    this->constant_initializer = NULL;
-   this->data.origin_upper_left = false;
-   this->data.pixel_center_integer = false;
    this->data.depth_layout = ir_depth_layout_none;
    this->data.used = false;
+   this->data.assigned = false;
    this->data.always_active_io = false;
    this->data.read_only = false;
    this->data.centroid = false;
    this->data.sample = false;
    this->data.patch = false;
+   this->data.explicit_invariant = false;
    this->data.invariant = false;
+   this->data.precise = false;
    this->data.how_declared = ir_var_declared_normally;
    this->data.mode = mode;
    this->data.interpolation = INTERP_MODE_NONE;
    this->data.max_array_access = -1;
    this->data.offset = 0;
    this->data.precision = GLSL_PRECISION_NONE;
-   this->data.image_read_only = false;
-   this->data.image_write_only = false;
-   this->data.image_coherent = false;
-   this->data.image_volatile = false;
-   this->data.image_restrict = false;
+   this->data.memory_read_only = false;
+   this->data.memory_write_only = false;
+   this->data.memory_coherent = false;
+   this->data.memory_volatile = false;
+   this->data.memory_restrict = false;
    this->data.from_ssbo_unsized_array = false;
+   this->data.implicit_sized_array = false;
    this->data.fb_fetch_output = false;
+   this->data.bindless = false;
+   this->data.bound = false;
+   this->data.image_format = PIPE_FORMAT_NONE;
+   this->data._num_state_slots = 0;
+   this->data.param_index = 0;
+   this->data.stream = 0;
+   this->data.xfb_buffer = -1;
+   this->data.xfb_stride = -1;
 
-   if (type != NULL) {
-      if (type->is_sampler())
-         this->data.read_only = true;
+   this->interface_type = NULL;
 
+   if (type != NULL) {
       if (type->is_interface())
          this->init_interface_type(type);
       else if (type->without_array()->is_interface())
@@ -1806,6 +2119,7 @@ ir_function_signature::ir_function_signature(const glsl_type *return_type,
                                              builtin_available_predicate b)
    : ir_instruction(ir_type_function_signature),
      return_type(return_type), is_defined(false),
+     return_precision(GLSL_PRECISION_NONE),
      intrinsic_id(ir_intrinsic_invalid), builtin_avail(b), _function(NULL)
 {
    this->origin = NULL;
@@ -1865,11 +2179,11 @@ ir_function_signature::qualifiers_match(exec_list *params)
          a->data.centroid != b->data.centroid ||
           a->data.sample != b->data.sample ||
           a->data.patch != b->data.patch ||
-          a->data.image_read_only != b->data.image_read_only ||
-          a->data.image_write_only != b->data.image_write_only ||
-          a->data.image_coherent != b->data.image_coherent ||
-          a->data.image_volatile != b->data.image_volatile ||
-          a->data.image_restrict != b->data.image_restrict) {
+          a->data.memory_read_only != b->data.memory_read_only ||
+          a->data.memory_write_only != b->data.memory_write_only ||
+          a->data.memory_coherent != b->data.memory_coherent ||
+          a->data.memory_volatile != b->data.memory_volatile ||
+          a->data.memory_restrict != b->data.memory_restrict) {
 
         /* parameter a's qualifiers don't match */
         return a->name;
@@ -1946,15 +2260,10 @@ steal_memory(ir_instruction *ir, void *new_ctx)
    /* The components of aggregate constants are not visited by the normal
     * visitor, so steal their values by hand.
     */
-   if (constant != NULL) {
-      if (constant->type->is_record()) {
-        foreach_in_list(ir_constant, field, &constant->components) {
-           steal_memory(field, ir);
-        }
-      } else if (constant->type->is_array()) {
-        for (unsigned int i = 0; i < constant->type->length; i++) {
-           steal_memory(constant->array_elements[i], ir);
-        }
+   if (constant != NULL &&
+       (constant->type->is_array() || constant->type->is_struct())) {
+      for (unsigned int i = 0; i < constant->type->length; i++) {
+         steal_memory(constant->const_elements[i], ir);
       }
    }