glsl/types: add new subroutine type (v3.2)
[mesa.git] / src / glsl / ir.cpp
index 9c58f869dc46495a76426da3333dee37d835f13c..fa1d85a5026703062955a0b0fb42b324f1d068c7 100644 (file)
@@ -46,11 +46,6 @@ bool ir_rvalue::is_negative_one() const
    return false;
 }
 
-bool ir_rvalue::is_basis() const
-{
-   return false;
-}
-
 /**
  * Modify the swizzle make to move one component to another
  *
@@ -245,8 +240,6 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
    case ir_unop_round_even:
    case ir_unop_sin:
    case ir_unop_cos:
-   case ir_unop_sin_reduced:
-   case ir_unop_cos_reduced:
    case ir_unop_dFdx:
    case ir_unop_dFdx_coarse:
    case ir_unop_dFdx_fine:
@@ -262,10 +255,12 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
    case ir_unop_f2i:
    case ir_unop_b2i:
    case ir_unop_u2i:
+   case ir_unop_d2i:
    case ir_unop_bitcast_f2i:
    case ir_unop_bit_count:
    case ir_unop_find_msb:
    case ir_unop_find_lsb:
+   case ir_unop_subroutine_to_int:
       this->type = glsl_type::get_instance(GLSL_TYPE_INT,
                                           op0->type->vector_elements, 1);
       break;
@@ -273,6 +268,7 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
    case ir_unop_b2f:
    case ir_unop_i2f:
    case ir_unop_u2f:
+   case ir_unop_d2f:
    case ir_unop_bitcast_i2f:
    case ir_unop_bitcast_u2f:
       this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
@@ -281,12 +277,21 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
 
    case ir_unop_f2b:
    case ir_unop_i2b:
+   case ir_unop_d2b:
       this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
                                           op0->type->vector_elements, 1);
       break;
 
+   case ir_unop_f2d:
+   case ir_unop_i2d:
+   case ir_unop_u2d:
+      this->type = glsl_type::get_instance(GLSL_TYPE_DOUBLE,
+                                          op0->type->vector_elements, 1);
+      break;
+
    case ir_unop_i2u:
    case ir_unop_f2u:
+   case ir_unop_d2u:
    case ir_unop_bitcast_f2u:
       this->type = glsl_type::get_instance(GLSL_TYPE_UINT,
                                           op0->type->vector_elements, 1);
@@ -298,6 +303,10 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
       this->type = glsl_type::float_type;
       break;
 
+   case ir_unop_unpack_double_2x32:
+      this->type = glsl_type::uvec2_type;
+      break;
+
    case ir_unop_any:
       this->type = glsl_type::bool_type;
       break;
@@ -310,6 +319,10 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
       this->type = glsl_type::uint_type;
       break;
 
+   case ir_unop_pack_double_2x32:
+      this->type = glsl_type::double_type;
+      break;
+
    case ir_unop_unpack_snorm_2x16:
    case ir_unop_unpack_unorm_2x16:
    case ir_unop_unpack_half_2x16:
@@ -321,6 +334,14 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
       this->type = glsl_type::vec4_type;
       break;
 
+   case ir_unop_frexp_sig:
+      this->type = op0->type;
+      break;
+   case ir_unop_frexp_exp:
+      this->type = glsl_type::get_instance(GLSL_TYPE_INT,
+                                          op0->type->vector_elements, 1);
+      break;
+
    default:
       assert(!"not reached: missing automatic type setup for ir_expression");
       this->type = op0->type;
@@ -358,10 +379,12 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
       } else if (op1->type->is_scalar()) {
         this->type = op0->type;
       } else {
-        /* FINISHME: matrix types */
-        assert(!op0->type->is_matrix() && !op1->type->is_matrix());
-        assert(op0->type == op1->type);
-        this->type = op0->type;
+         if (this->operation == ir_binop_mul) {
+            this->type = glsl_type::get_mul_type(op0->type, op1->type);
+         } else {
+            assert(op0->type == op1->type);
+            this->type = op0->type;
+         }
       }
       break;
 
@@ -395,7 +418,7 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
       break;
 
    case ir_binop_dot:
-      this->type = glsl_type::float_type;
+      this->type = op0->type->get_base_type();
       break;
 
    case ir_binop_pack_half_2x16_split:
@@ -499,6 +522,13 @@ static const char *const operator_strs[] = {
    "u2f",
    "i2u",
    "u2i",
+   "d2f",
+   "f2d",
+   "d2i",
+   "i2d",
+   "d2u",
+   "u2d",
+   "d2b",
    "bitcast_i2f",
    "bitcast_f2i",
    "bitcast_u2f",
@@ -511,8 +541,6 @@ static const char *const operator_strs[] = {
    "round_even",
    "sin",
    "cos",
-   "sin_reduced",
-   "cos_reduced",
    "dFdx",
    "dFdxCoarse",
    "dFdxFine",
@@ -536,7 +564,12 @@ static const char *const operator_strs[] = {
    "find_msb",
    "find_lsb",
    "sat",
+   "packDouble2x32",
+   "unpackDouble2x32",
+   "frexp_sig",
+   "frexp_exp",
    "noise",
+   "subroutine_to_int",
    "interpolate_at_centroid",
    "+",
    "-",
@@ -585,8 +618,8 @@ static const char *const operator_strs[] = {
 
 const char *ir_expression::operator_string(ir_expression_operation op)
 {
-   assert((unsigned int) op < Elements(operator_strs));
-   assert(Elements(operator_strs) == (ir_quadop_vector + 1));
+   assert((unsigned int) op < ARRAY_SIZE(operator_strs));
+   assert(ARRAY_SIZE(operator_strs) == (ir_quadop_vector + 1));
    return operator_strs[op];
 }
 
@@ -651,6 +684,19 @@ ir_constant::ir_constant(float f, unsigned vector_elements)
    }
 }
 
+ir_constant::ir_constant(double d, unsigned vector_elements)
+   : ir_rvalue(ir_type_constant)
+{
+   assert(vector_elements <= 4);
+   this->type = glsl_type::get_instance(GLSL_TYPE_DOUBLE, vector_elements, 1);
+   for (unsigned i = 0; i < vector_elements; i++) {
+      this->value.d[i] = d;
+   }
+   for (unsigned i = vector_elements; i < 16; i++)  {
+      this->value.d[i] = 0.0;
+   }
+}
+
 ir_constant::ir_constant(unsigned int u, unsigned vector_elements)
    : ir_rvalue(ir_type_constant)
 {
@@ -700,6 +746,7 @@ ir_constant::ir_constant(const ir_constant *c, unsigned i)
    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_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;
    }
 }
@@ -751,9 +798,16 @@ 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);
-        for (unsigned i = 0; i < type->matrix_columns; i++)
-           this->value.f[i * type->vector_elements + i] = value->value.f[0];
+         assert(type->base_type == GLSL_TYPE_FLOAT ||
+                type->base_type == GLSL_TYPE_DOUBLE);
+         for (unsigned i = 0; i < type->matrix_columns; i++) {
+            if (type->base_type == GLSL_TYPE_FLOAT)
+               this->value.f[i * type->vector_elements + i] =
+                  value->value.f[0];
+            else
+               this->value.d[i * type->vector_elements + i] =
+                  value->value.d[0];
+         }
       } else {
         /* Vector or scalar - fill all components */
         switch (type->base_type) {
@@ -766,6 +820,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_DOUBLE:
+           for (unsigned i = 0; i < type->components(); i++)
+              this->value.d[i] = value->value.d[0];
+           break;
         case GLSL_TYPE_BOOL:
            for (unsigned i = 0; i < type->components(); i++)
               this->value.b[i] = value->value.b[0];
@@ -824,6 +882,9 @@ ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
         case GLSL_TYPE_BOOL:
            this->value.b[i] = value->get_bool_component(j);
            break;
+        case GLSL_TYPE_DOUBLE:
+           this->value.d[i] = value->get_double_component(j);
+           break;
         default:
            /* FINISHME: What to do?  Exceptions are not the answer.
             */
@@ -853,7 +914,7 @@ ir_constant::zero(void *mem_ctx, const glsl_type *type)
       c->array_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->element_type());
+        c->array_elements[i] = ir_constant::zero(c, type->fields.array);
    }
 
    if (type->is_record()) {
@@ -874,6 +935,7 @@ ir_constant::get_bool_component(unsigned i) const
    case GLSL_TYPE_INT:   return this->value.i[i] != 0;
    case GLSL_TYPE_FLOAT: return ((int)this->value.f[i]) != 0;
    case GLSL_TYPE_BOOL:  return this->value.b[i];
+   case GLSL_TYPE_DOUBLE: return this->value.d[i] != 0.0;
    default:              assert(!"Should not get here."); break;
    }
 
@@ -891,6 +953,25 @@ ir_constant::get_float_component(unsigned i) const
    case GLSL_TYPE_INT:   return (float) this->value.i[i];
    case GLSL_TYPE_FLOAT: return this->value.f[i];
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1.0f : 0.0f;
+   case GLSL_TYPE_DOUBLE: return (float) this->value.d[i];
+   default:              assert(!"Should not get here."); break;
+   }
+
+   /* Must return something to make the compiler happy.  This is clearly an
+    * error case.
+    */
+   return 0.0;
+}
+
+double
+ir_constant::get_double_component(unsigned i) const
+{
+   switch (this->type->base_type) {
+   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_BOOL:  return this->value.b[i] ? 1.0 : 0.0;
+   case GLSL_TYPE_DOUBLE: return this->value.d[i];
    default:              assert(!"Should not get here."); break;
    }
 
@@ -908,6 +989,7 @@ ir_constant::get_int_component(unsigned i) const
    case GLSL_TYPE_INT:   return this->value.i[i];
    case GLSL_TYPE_FLOAT: return (int) this->value.f[i];
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1 : 0;
+   case GLSL_TYPE_DOUBLE: return (int) this->value.d[i];
    default:              assert(!"Should not get here."); break;
    }
 
@@ -925,6 +1007,7 @@ ir_constant::get_uint_component(unsigned i) const
    case GLSL_TYPE_INT:   return this->value.i[i];
    case GLSL_TYPE_FLOAT: return (unsigned) this->value.f[i];
    case GLSL_TYPE_BOOL:  return this->value.b[i] ? 1 : 0;
+   case GLSL_TYPE_DOUBLE: return (unsigned) this->value.d[i];
    default:              assert(!"Should not get here."); break;
    }
 
@@ -989,6 +1072,7 @@ ir_constant::copy_offset(ir_constant *src, int offset)
    case GLSL_TYPE_UINT:
    case GLSL_TYPE_INT:
    case GLSL_TYPE_FLOAT:
+   case GLSL_TYPE_DOUBLE:
    case GLSL_TYPE_BOOL: {
       unsigned int size = src->type->components();
       assert (size <= this->type->components() - offset);
@@ -1006,6 +1090,9 @@ ir_constant::copy_offset(ir_constant *src, int offset)
         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;
         default: // Shut up the compiler
            break;
         }
@@ -1062,6 +1149,9 @@ ir_constant::copy_masked_offset(ir_constant *src, int offset, unsigned int mask)
         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;
         default:
            assert(!"Should not get here.");
            return;
@@ -1122,6 +1212,10 @@ ir_constant::has_value(const ir_constant *c) const
         if (this->value.b[i] != c->value.b[i])
            return false;
         break;
+      case GLSL_TYPE_DOUBLE:
+        if (this->value.d[i] != c->value.d[i])
+           return false;
+        break;
       default:
         assert(!"Should not get here.");
         return false;
@@ -1159,6 +1253,10 @@ ir_constant::is_value(float f, int i) const
         if (this->value.b[c] != bool(i))
            return false;
         break;
+      case GLSL_TYPE_DOUBLE:
+        if (this->value.d[c] != double(f))
+           return false;
+        break;
       default:
         /* The only other base types are structures, arrays, and samplers.
          * Samplers cannot be constants, and the others should have been
@@ -1190,49 +1288,6 @@ ir_constant::is_negative_one() const
    return is_value(-1.0, -1);
 }
 
-bool
-ir_constant::is_basis() const
-{
-   if (!this->type->is_scalar() && !this->type->is_vector())
-      return false;
-
-   if (this->type->is_boolean())
-      return false;
-
-   unsigned ones = 0;
-   for (unsigned c = 0; c < this->type->vector_elements; c++) {
-      switch (this->type->base_type) {
-      case GLSL_TYPE_FLOAT:
-        if (this->value.f[c] == 1.0)
-           ones++;
-        else if (this->value.f[c] != 0.0)
-           return false;
-        break;
-      case GLSL_TYPE_INT:
-        if (this->value.i[c] == 1)
-           ones++;
-        else if (this->value.i[c] != 0)
-           return false;
-        break;
-      case GLSL_TYPE_UINT:
-        if (int(this->value.u[c]) == 1)
-           ones++;
-        else if (int(this->value.u[c]) != 0)
-           return false;
-        break;
-      default:
-        /* The only other base types are structures, arrays, samplers, and
-         * booleans.  Samplers cannot be constants, and the others should
-         * have been filtered out above.
-         */
-        assert(!"Should not get here.");
-        return false;
-      }
-   }
-
-   return ones == 1;
-}
-
 bool
 ir_constant::is_uint16_constant() const
 {
@@ -1288,7 +1343,7 @@ ir_dereference_array::set_array(ir_rvalue *value)
    const glsl_type *const vt = this->array->type;
 
    if (vt->is_array()) {
-      type = vt->element_type();
+      type = vt->fields.array;
    } else if (vt->is_matrix()) {
       type = vt->column_type();
    } else if (vt->is_vector()) {
@@ -1543,6 +1598,8 @@ ir_swizzle::variable_referenced() const
 }
 
 
+bool ir_variable::temporaries_allocate_names = false;
+
 const char ir_variable::tmp_name[] = "compiler_temp";
 
 ir_variable::ir_variable(const struct glsl_type *type, const char *name,
@@ -1551,6 +1608,9 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
 {
    this->type = type;
 
+   if (mode == ir_var_temporary && !ir_variable::temporaries_allocate_names)
+      name = NULL;
+
    /* The ir_variable clone method may call this constructor with name set to
     * tmp_name.
     */
@@ -1585,6 +1645,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
    this->data.read_only = false;
    this->data.centroid = false;
    this->data.sample = false;
+   this->data.patch = false;
    this->data.invariant = false;
    this->data.how_declared = ir_var_declared_normally;
    this->data.mode = mode;
@@ -1647,7 +1708,7 @@ const char *const ir_variable::warn_extension_table[] = {
 void
 ir_variable::enable_extension_warning(const char *extension)
 {
-   for (unsigned i = 0; i < Elements(warn_extension_table); i++) {
+   for (unsigned i = 0; i < ARRAY_SIZE(warn_extension_table); i++) {
       if (strcmp(warn_extension_table[i], extension) == 0) {
          this->data.warn_extension_index = i;
          return;
@@ -1727,6 +1788,7 @@ ir_function_signature::qualifiers_match(exec_list *params)
          a->data.interpolation != b->data.interpolation ||
          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 ||
@@ -1917,6 +1979,9 @@ mode_string(const ir_variable *var)
    case ir_var_uniform:
       return "uniform";
 
+   case ir_var_shader_storage:
+      return "buffer";
+
    case ir_var_shader_in:
       return "shader input";