gallivm: fix no-op n:n lp_build_resize()
[mesa.git] / src / glsl / ir_constant_expression.cpp
index c09e56a3d08d427ca7efd74afc7b9ec6e4344c68..8afe8f776e6d17d8f5ef9f1b9f1b5aea88a45e9f 100644 (file)
 #include "glsl_types.h"
 #include "program/hash_table.h"
 
+#if defined(_MSC_VER) && (_MSC_VER < 1800)
+static int isnormal(double x)
+{
+   return _fpclass(x) == _FPCLASS_NN || _fpclass(x) == _FPCLASS_PN;
+}
+#elif defined(__SUNPRO_CC)
+#include <ieeefp.h>
+static int isnormal(double x)
+{
+   return fpclass(x) == FP_NORMAL;
+}
+#endif
+
+#if defined(_MSC_VER)
+static double copysign(double x, double y)
+{
+   return _copysign(x, y);
+}
+#endif
+
 static float
 dot(ir_constant *op0, ir_constant *op1)
 {
@@ -366,8 +386,104 @@ unpack_half_1x16(uint16_t u)
    return _mesa_half_to_float(u);
 }
 
+/**
+ * Get the constant that is ultimately referenced by an r-value, in a constant
+ * expression evaluation context.
+ *
+ * The offset is used when the reference is to a specific column of a matrix.
+ */
+static bool
+constant_referenced(const ir_dereference *deref,
+                    struct hash_table *variable_context,
+                    ir_constant *&store, int &offset)
+{
+   store = NULL;
+   offset = 0;
+
+   if (variable_context == NULL)
+      return false;
+
+   switch (deref->ir_type) {
+   case ir_type_dereference_array: {
+      const ir_dereference_array *const da =
+         (const ir_dereference_array *) deref;
+
+      ir_constant *const index_c =
+         da->array_index->constant_expression_value(variable_context);
+
+      if (!index_c || !index_c->type->is_scalar() || !index_c->type->is_integer())
+         break;
+
+      const int index = index_c->type->base_type == GLSL_TYPE_INT ?
+         index_c->get_int_component(0) :
+         index_c->get_uint_component(0);
+
+      ir_constant *substore;
+      int suboffset;
+
+      const ir_dereference *const deref = da->array->as_dereference();
+      if (!deref)
+         break;
+
+      if (!constant_referenced(deref, variable_context, substore, suboffset))
+         break;
+
+      const glsl_type *const vt = da->array->type;
+      if (vt->is_array()) {
+         store = substore->get_array_element(index);
+         offset = 0;
+      } else if (vt->is_matrix()) {
+         store = substore;
+         offset = index * vt->vector_elements;
+      } else if (vt->is_vector()) {
+         store = substore;
+         offset = suboffset + index;
+      }
+
+      break;
+   }
+
+   case ir_type_dereference_record: {
+      const ir_dereference_record *const dr =
+         (const ir_dereference_record *) deref;
+
+      const ir_dereference *const deref = dr->record->as_dereference();
+      if (!deref)
+         break;
+
+      ir_constant *substore;
+      int suboffset;
+
+      if (!constant_referenced(deref, variable_context, substore, suboffset))
+         break;
+
+      /* Since we're dropping it on the floor...
+       */
+      assert(suboffset == 0);
+
+      store = substore->get_record_field(dr->field);
+      break;
+   }
+
+   case ir_type_dereference_variable: {
+      const ir_dereference_variable *const dv =
+         (const ir_dereference_variable *) deref;
+
+      store = (ir_constant *) hash_table_find(variable_context, dv->var);
+      break;
+   }
+
+   default:
+      assert(!"Should not get here.");
+      break;
+   }
+
+   return store != NULL;
+}
+
+
 ir_constant *
-ir_rvalue::constant_expression_value(struct hash_table *variable_context)
+ir_rvalue::constant_expression_value(struct hash_table *)
 {
    assert(this->type->is_error());
    return NULL;
@@ -391,9 +507,19 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
    }
 
    if (op[1] != NULL)
-      assert(op[0]->type->base_type == op[1]->type->base_type ||
-            this->operation == ir_binop_lshift ||
-            this->operation == ir_binop_rshift);
+      switch (this->operation) {
+      case ir_binop_lshift:
+      case ir_binop_rshift:
+      case ir_binop_ldexp:
+      case ir_binop_vector_extract:
+      case ir_triop_csel:
+      case ir_triop_bitfield_extract:
+         break;
+
+      default:
+         assert(op[0]->type->base_type == op[1]->type->base_type);
+         break;
+      }
 
    bool op0_scalar = op[0]->type->is_scalar();
    bool op1_scalar = op[1] != NULL && op[1]->type->is_scalar();
@@ -1230,6 +1356,29 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
       }
       break;
 
+   case ir_binop_vector_extract: {
+      const int c = CLAMP(op[1]->value.i[0], 0,
+                         (int) op[0]->type->vector_elements - 1);
+
+      switch (op[0]->type->base_type) {
+      case GLSL_TYPE_UINT:
+         data.u[0] = op[0]->value.u[c];
+         break;
+      case GLSL_TYPE_INT:
+         data.i[0] = op[0]->value.i[c];
+         break;
+      case GLSL_TYPE_FLOAT:
+         data.f[0] = op[0]->value.f[c];
+         break;
+      case GLSL_TYPE_BOOL:
+         data.b[0] = op[0]->value.b[c];
+         break;
+      default:
+         assert(0);
+      }
+      break;
+   }
+
    case ir_binop_bit_xor:
       for (unsigned c = 0, c0 = 0, c1 = 0;
            c < components;
@@ -1248,6 +1397,139 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
       }
       break;
 
+   case ir_unop_bitfield_reverse:
+      /* http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious */
+      for (unsigned c = 0; c < components; c++) {
+         unsigned int v = op[0]->value.u[c]; // input bits to be reversed
+         unsigned int r = v; // r will be reversed bits of v; first get LSB of v
+         int s = sizeof(v) * CHAR_BIT - 1; // extra shift needed at end
+
+         for (v >>= 1; v; v >>= 1) {
+            r <<= 1;
+            r |= v & 1;
+            s--;
+         }
+         r <<= s; // shift when v's highest bits are zero
+
+         data.u[c] = r;
+      }
+      break;
+
+   case ir_unop_bit_count:
+      for (unsigned c = 0; c < components; c++) {
+         unsigned count = 0;
+         unsigned v = op[0]->value.u[c];
+
+         for (; v; count++) {
+            v &= v - 1;
+         }
+         data.u[c] = count;
+      }
+      break;
+
+   case ir_unop_find_msb:
+      for (unsigned c = 0; c < components; c++) {
+         int v = op[0]->value.i[c];
+
+         if (v == 0 || (op[0]->type->base_type == GLSL_TYPE_INT && v == -1))
+            data.i[c] = -1;
+         else {
+            int count = 0;
+            int top_bit = op[0]->type->base_type == GLSL_TYPE_UINT
+                          ? 0 : v & (1 << 31);
+
+            while (((v & (1 << 31)) == top_bit) && count != 32) {
+               count++;
+               v <<= 1;
+            }
+
+            data.i[c] = 31 - count;
+         }
+      }
+      break;
+
+   case ir_unop_find_lsb:
+      for (unsigned c = 0; c < components; c++) {
+         if (op[0]->value.i[c] == 0)
+            data.i[c] = -1;
+         else {
+            unsigned pos = 0;
+            unsigned v = op[0]->value.u[c];
+
+            for (; !(v & 1); v >>= 1) {
+               pos++;
+            }
+            data.u[c] = pos;
+         }
+      }
+      break;
+
+   case ir_triop_bitfield_extract: {
+      int offset = op[1]->value.i[0];
+      int bits = op[2]->value.i[0];
+
+      for (unsigned c = 0; c < components; c++) {
+         if (bits == 0)
+            data.u[c] = 0;
+         else if (offset < 0 || bits < 0)
+            data.u[c] = 0; /* Undefined, per spec. */
+         else if (offset + bits > 32)
+            data.u[c] = 0; /* Undefined, per spec. */
+         else {
+            if (op[0]->type->base_type == GLSL_TYPE_INT) {
+               /* int so that the right shift will sign-extend. */
+               int value = op[0]->value.i[c];
+               value <<= 32 - bits - offset;
+               value >>= 32 - bits;
+               data.i[c] = value;
+            } else {
+               unsigned value = op[0]->value.u[c];
+               value <<= 32 - bits - offset;
+               value >>= 32 - bits;
+               data.u[c] = value;
+            }
+         }
+      }
+      break;
+   }
+
+   case ir_binop_bfm: {
+      int bits = op[0]->value.i[0];
+      int offset = op[1]->value.i[0];
+
+      for (unsigned c = 0; c < components; c++) {
+         if (bits == 0)
+            data.u[c] = op[0]->value.u[c];
+         else if (offset < 0 || bits < 0)
+            data.u[c] = 0; /* Undefined for bitfieldInsert, per spec. */
+         else if (offset + bits > 32)
+            data.u[c] = 0; /* Undefined for bitfieldInsert, per spec. */
+         else
+            data.u[c] = ((1 << bits) - 1) << offset;
+      }
+      break;
+   }
+
+   case ir_binop_ldexp:
+      for (unsigned c = 0; c < components; c++) {
+         data.f[c] = ldexp(op[0]->value.f[c], op[1]->value.i[c]);
+         /* Flush subnormal values to zero. */
+         if (!isnormal(data.f[c]))
+            data.f[c] = copysign(0.0f, op[0]->value.f[c]);
+      }
+      break;
+
+   case ir_triop_fma:
+      assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+      assert(op[1]->type->base_type == GLSL_TYPE_FLOAT);
+      assert(op[2]->type->base_type == GLSL_TYPE_FLOAT);
+
+      for (unsigned c = 0; c < components; c++) {
+         data.f[c] = op[0]->value.f[c] * op[1]->value.f[c]
+                                       + op[2]->value.f[c];
+      }
+      break;
+
    case ir_triop_lrp: {
       assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
       assert(op[1]->type->base_type == GLSL_TYPE_FLOAT);
@@ -1261,6 +1543,65 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
       break;
    }
 
+   case ir_triop_csel:
+      for (unsigned c = 0; c < components; c++) {
+         data.u[c] = op[0]->value.b[c] ? op[1]->value.u[c]
+                                       : op[2]->value.u[c];
+      }
+      break;
+
+   case ir_triop_vector_insert: {
+      const unsigned idx = op[2]->value.u[0];
+
+      memcpy(&data, &op[0]->value, sizeof(data));
+
+      switch (this->type->base_type) {
+      case GLSL_TYPE_INT:
+        data.i[idx] = op[1]->value.i[0];
+        break;
+      case GLSL_TYPE_UINT:
+        data.u[idx] = op[1]->value.u[0];
+        break;
+      case GLSL_TYPE_FLOAT:
+        data.f[idx] = op[1]->value.f[0];
+        break;
+      case GLSL_TYPE_BOOL:
+        data.b[idx] = op[1]->value.b[0];
+        break;
+      default:
+        assert(!"Should not get here.");
+        break;
+      }
+      break;
+   }
+
+   case ir_quadop_bitfield_insert: {
+      int offset = op[2]->value.i[0];
+      int bits = op[3]->value.i[0];
+
+      for (unsigned c = 0; c < components; c++) {
+         if (bits == 0)
+            data.u[c] = op[0]->value.u[c];
+         else if (offset < 0 || bits < 0)
+            data.u[c] = 0; /* Undefined, per spec. */
+         else if (offset + bits > 32)
+            data.u[c] = 0; /* Undefined, per spec. */
+         else {
+            unsigned insert_mask = ((1 << bits) - 1) << offset;
+
+            unsigned insert = op[1]->value.u[c];
+            insert <<= offset;
+            insert &= insert_mask;
+
+            unsigned base = op[0]->value.u[c];
+            base &= ~insert_mask;
+
+            data.u[c] = base | insert;
+         }
+      }
+      break;
+   }
+
    case ir_quadop_vector:
       for (unsigned c = 0; c < this->type->vector_elements; c++) {
         switch (this->type->base_type) {
@@ -1289,7 +1630,7 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
 
 
 ir_constant *
-ir_texture::constant_expression_value(struct hash_table *variable_context)
+ir_texture::constant_expression_value(struct hash_table *)
 {
    /* texture lookups aren't constant expressions */
    return NULL;
@@ -1325,19 +1666,6 @@ ir_swizzle::constant_expression_value(struct hash_table *variable_context)
 }
 
 
-void
-ir_dereference_variable::constant_referenced(struct hash_table *variable_context,
-                                            ir_constant *&store, int &offset) const
-{
-   if (variable_context) {
-      store = (ir_constant *)hash_table_find(variable_context, var);
-      offset = 0;
-   } else {
-      store = NULL;
-      offset = 0;
-   }
-}
-
 ir_constant *
 ir_dereference_variable::constant_expression_value(struct hash_table *variable_context)
 {
@@ -1355,7 +1683,7 @@ ir_dereference_variable::constant_expression_value(struct hash_table *variable_c
    /* The constant_value of a uniform variable is its initializer,
     * not the lifetime constant value of the uniform.
     */
-   if (var->mode == ir_var_uniform)
+   if (var->data.mode == ir_var_uniform)
       return NULL;
 
    if (!var->constant_value)
@@ -1365,60 +1693,6 @@ ir_dereference_variable::constant_expression_value(struct hash_table *variable_c
 }
 
 
-void
-ir_dereference_array::constant_referenced(struct hash_table *variable_context,
-                                         ir_constant *&store, int &offset) const
-{
-   ir_constant *index_c = array_index->constant_expression_value(variable_context);
-
-   if (!index_c || !index_c->type->is_scalar() || !index_c->type->is_integer()) {
-      store = 0;
-      offset = 0;
-      return;
-   }
-
-   int index = index_c->type->base_type == GLSL_TYPE_INT ?
-      index_c->get_int_component(0) :
-      index_c->get_uint_component(0);
-
-   ir_constant *substore;
-   int suboffset;
-   const ir_dereference *deref = array->as_dereference();
-   if (!deref) {
-      store = 0;
-      offset = 0;
-      return;
-   }
-
-   deref->constant_referenced(variable_context, substore, suboffset);
-
-   if (!substore) {
-      store = 0;
-      offset = 0;
-      return;
-   }
-
-   const glsl_type *vt = array->type;
-   if (vt->is_array()) {
-      store = substore->get_array_element(index);
-      offset = 0;
-      return;
-   }
-   if (vt->is_matrix()) {
-      store = substore;
-      offset = index * vt->vector_elements;
-      return;
-   }
-   if (vt->is_vector()) {
-      store = substore;
-      offset = suboffset + index;
-      return;
-   }
-
-   store = 0;
-   offset = 0;
-}
-
 ir_constant *
 ir_dereference_array::constant_expression_value(struct hash_table *variable_context)
 {
@@ -1474,33 +1748,8 @@ ir_dereference_array::constant_expression_value(struct hash_table *variable_cont
 }
 
 
-void
-ir_dereference_record::constant_referenced(struct hash_table *variable_context,
-                                          ir_constant *&store, int &offset) const
-{
-   ir_constant *substore;
-   int suboffset;
-   const ir_dereference *deref = record->as_dereference();
-   if (!deref) {
-      store = 0;
-      offset = 0;
-      return;
-   }
-
-   deref->constant_referenced(variable_context, substore, suboffset);
-
-   if (!substore) {
-      store = 0;
-      offset = 0;
-      return;
-   }
-
-   store = substore->get_record_field(field);
-   offset = 0;
-}
-
 ir_constant *
-ir_dereference_record::constant_expression_value(struct hash_table *variable_context)
+ir_dereference_record::constant_expression_value(struct hash_table *)
 {
    ir_constant *v = this->record->constant_expression_value();
 
@@ -1509,7 +1758,7 @@ ir_dereference_record::constant_expression_value(struct hash_table *variable_con
 
 
 ir_constant *
-ir_assignment::constant_expression_value(struct hash_table *variable_context)
+ir_assignment::constant_expression_value(struct hash_table *)
 {
    /* FINISHME: Handle CEs involving assignment (return RHS) */
    return NULL;
@@ -1517,7 +1766,7 @@ ir_assignment::constant_expression_value(struct hash_table *variable_context)
 
 
 ir_constant *
-ir_constant::constant_expression_value(struct hash_table *variable_context)
+ir_constant::constant_expression_value(struct hash_table *)
 {
    return this;
 }
@@ -1558,9 +1807,8 @@ bool ir_function_signature::constant_expression_evaluate_expression_list(const s
 
         ir_constant *store = NULL;
         int offset = 0;
-        asg->lhs->constant_referenced(variable_context, store, offset);
 
-        if (!store)
+        if (!constant_referenced(asg->lhs, variable_context, store, offset))
            return false;
 
         ir_constant *value = asg->rhs->constant_expression_value(variable_context);
@@ -1591,9 +1839,9 @@ bool ir_function_signature::constant_expression_evaluate_expression_list(const s
 
         ir_constant *store = NULL;
         int offset = 0;
-        call->return_deref->constant_referenced(variable_context, store, offset);
 
-        if (!store)
+        if (!constant_referenced(call->return_deref, variable_context,
+                                  store, offset))
            return false;
 
         ir_constant *value = call->constant_expression_value(variable_context);
@@ -1650,7 +1898,7 @@ ir_function_signature::constant_expression_value(exec_list *actual_parameters, s
     * "Function calls to user-defined functions (non-built-in functions)
     *  cannot be used to form constant expressions."
     */
-   if (!this->is_builtin)
+   if (!this->is_builtin())
       return NULL;
 
    /*