mesa: Add a flag for forcing all GLSL extensions to "warn".
[mesa.git] / src / glsl / ir_constant_expression.cpp
index 048c020c835347e275dd70d77fc4357abb0d56b5..adca62e8d74681340a21e401667db62fd3fd83f2 100644 (file)
 #include "ir_visitor.h"
 #include "glsl_types.h"
 
+/* Using C99 rounding functions for roundToEven() implementation is
+ * difficult, because round(), rint, and nearbyint() are affected by
+ * fesetenv(), which the application may have done for its own
+ * purposes.  Mesa's IROUND macro is close to what we want, but it
+ * rounds away from 0 on n + 0.5.
+ */
+static int
+round_to_even(float val)
+{
+   int rounded = IROUND(val);
+
+   if (val - floor(val) == 0.5) {
+      if (rounded % 2 != 0)
+        rounded += val > 0 ? -1 : 1;
+   }
+
+   return rounded;
+}
+
 static float
 dot(ir_constant *op0, ir_constant *op1)
 {
@@ -54,7 +73,10 @@ dot(ir_constant *op0, ir_constant *op1)
 ir_constant *
 ir_expression::constant_expression_value()
 {
-   ir_constant *op[2] = { NULL, NULL };
+   if (this->type->is_error())
+      return NULL;
+
+   ir_constant *op[Elements(this->operands)] = { NULL, };
    ir_constant_data data;
 
    memset(&data, 0, sizeof(data));
@@ -66,7 +88,9 @@ ir_expression::constant_expression_value()
    }
 
    if (op[1] != NULL)
-      assert(op[0]->type->base_type == op[1]->type->base_type);
+      assert(op[0]->type->base_type == op[1]->type->base_type ||
+            this->operation == ir_binop_lshift ||
+            this->operation == ir_binop_rshift);
 
    bool op0_scalar = op[0]->type->is_scalar();
    bool op1_scalar = op[1] != NULL && op[1]->type->is_scalar();
@@ -83,7 +107,7 @@ ir_expression::constant_expression_value()
       components = op[1]->type->components();
    }
 
-   void *ctx = talloc_parent(this);
+   void *ctx = ralloc_parent(this);
 
    /* Handle array operations here, rather than below. */
    if (op[0]->type->is_array()) {
@@ -124,31 +148,31 @@ ir_expression::constant_expression_value()
    case ir_unop_f2i:
       assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
-        data.i[c] = op[0]->value.f[c];
+        data.i[c] = (int) op[0]->value.f[c];
       }
       break;
    case ir_unop_i2f:
       assert(op[0]->type->base_type == GLSL_TYPE_INT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
-        data.f[c] = op[0]->value.i[c];
+        data.f[c] = (float) op[0]->value.i[c];
       }
       break;
    case ir_unop_u2f:
       assert(op[0]->type->base_type == GLSL_TYPE_UINT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
-        data.f[c] = op[0]->value.u[c];
+        data.f[c] = (float) op[0]->value.u[c];
       }
       break;
    case ir_unop_b2f:
       assert(op[0]->type->base_type == GLSL_TYPE_BOOL);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
-        data.f[c] = op[0]->value.b[c] ? 1.0 : 0.0;
+        data.f[c] = op[0]->value.b[c] ? 1.0F : 0.0F;
       }
       break;
    case ir_unop_f2b:
       assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
-        data.b[c] = bool(op[0]->value.f[c]);
+        data.b[c] = op[0]->value.f[c] != 0.0F ? true : false;
       }
       break;
    case ir_unop_b2i:
@@ -160,10 +184,21 @@ ir_expression::constant_expression_value()
    case ir_unop_i2b:
       assert(op[0]->type->is_integer());
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
-        data.b[c] = bool(op[0]->value.u[c]);
+        data.b[c] = op[0]->value.u[c] ? true : false;
+      }
+      break;
+   case ir_unop_u2i:
+      assert(op[0]->type->base_type == GLSL_TYPE_UINT);
+      for (unsigned c = 0; c < op[0]->type->components(); c++) {
+        data.i[c] = op[0]->value.u[c];
+      }
+      break;
+   case ir_unop_i2u:
+      assert(op[0]->type->base_type == GLSL_TYPE_INT);
+      for (unsigned c = 0; c < op[0]->type->components(); c++) {
+        data.u[c] = op[0]->value.i[c];
       }
       break;
-
    case ir_unop_any:
       assert(op[0]->type->is_boolean());
       data.b[0] = false;
@@ -180,6 +215,13 @@ ir_expression::constant_expression_value()
       }
       break;
 
+   case ir_unop_round_even:
+      assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+      for (unsigned c = 0; c < op[0]->type->components(); c++) {
+        data.f[c] = round_to_even(op[0]->value.f[c]);
+      }
+      break;
+
    case ir_unop_ceil:
       assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
@@ -213,6 +255,7 @@ ir_expression::constant_expression_value()
       break;
 
    case ir_unop_sin:
+   case ir_unop_sin_reduced:
       assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
         data.f[c] = sinf(op[0]->value.f[c]);
@@ -220,6 +263,7 @@ ir_expression::constant_expression_value()
       break;
 
    case ir_unop_cos:
+   case ir_unop_cos_reduced:
       assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
         data.f[c] = cosf(op[0]->value.f[c]);
@@ -230,7 +274,7 @@ ir_expression::constant_expression_value()
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
         switch (this->type->base_type) {
         case GLSL_TYPE_UINT:
-           data.u[c] = -op[0]->value.u[c];
+           data.u[c] = -((int) op[0]->value.u[c]);
            break;
         case GLSL_TYPE_INT:
            data.i[c] = -op[0]->value.i[c];
@@ -296,7 +340,7 @@ ir_expression::constant_expression_value()
            break;
         case GLSL_TYPE_FLOAT:
            if (op[0]->value.f[c] != 0.0)
-              data.f[c] = 1.0 / op[0]->value.f[c];
+              data.f[c] = 1.0F / op[0]->value.f[c];
            break;
         default:
            assert(0);
@@ -307,7 +351,7 @@ ir_expression::constant_expression_value()
    case ir_unop_rsq:
       assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
-        data.f[c] = 1.0 / sqrtf(op[0]->value.f[c]);
+        data.f[c] = 1.0F / sqrtf(op[0]->value.f[c]);
       }
       break;
 
@@ -409,17 +453,6 @@ ir_expression::constant_expression_value()
       }
       break;
 
-   case ir_binop_cross:
-      assert(op[0]->type == glsl_type::vec3_type);
-      assert(op[1]->type == glsl_type::vec3_type);
-      data.f[0] = (op[0]->value.f[1] * op[1]->value.f[2] -
-                  op[1]->value.f[1] * op[0]->value.f[2]);
-      data.f[1] = (op[0]->value.f[2] * op[1]->value.f[0] -
-                  op[1]->value.f[2] * op[0]->value.f[0]);
-      data.f[2] = (op[0]->value.f[0] * op[1]->value.f[1] -
-                  op[1]->value.f[0] * op[0]->value.f[1]);
-      break;
-
    case ir_binop_add:
       assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
       for (unsigned c = 0, c0 = 0, c1 = 0;
@@ -513,6 +546,7 @@ ir_expression::constant_expression_value()
 
       break;
    case ir_binop_div:
+      /* FINISHME: Emit warning when division-by-zero is detected. */
       assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
       for (unsigned c = 0, c0 = 0, c1 = 0;
           c < components;
@@ -520,10 +554,18 @@ ir_expression::constant_expression_value()
 
         switch (op[0]->type->base_type) {
         case GLSL_TYPE_UINT:
-           data.u[c] = op[0]->value.u[c0] / op[1]->value.u[c1];
+           if (op[1]->value.u[c1] == 0) {
+              data.u[c] = 0;
+           } else {
+              data.u[c] = op[0]->value.u[c0] / op[1]->value.u[c1];
+           }
            break;
         case GLSL_TYPE_INT:
-           data.i[c] = op[0]->value.i[c0] / op[1]->value.i[c1];
+           if (op[1]->value.i[c1] == 0) {
+              data.i[c] = 0;
+           } else {
+              data.i[c] = op[0]->value.i[c0] / op[1]->value.i[c1];
+           }
            break;
         case GLSL_TYPE_FLOAT:
            data.f[c] = op[0]->value.f[c0] / op[1]->value.f[c1];
@@ -535,6 +577,7 @@ ir_expression::constant_expression_value()
 
       break;
    case ir_binop_mod:
+      /* FINISHME: Emit warning when division-by-zero is detected. */
       assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar);
       for (unsigned c = 0, c0 = 0, c1 = 0;
           c < components;
@@ -542,10 +585,18 @@ ir_expression::constant_expression_value()
 
         switch (op[0]->type->base_type) {
         case GLSL_TYPE_UINT:
-           data.u[c] = op[0]->value.u[c0] % op[1]->value.u[c1];
+           if (op[1]->value.u[c1] == 0) {
+              data.u[c] = 0;
+           } else {
+              data.u[c] = op[0]->value.u[c0] % op[1]->value.u[c1];
+           }
            break;
         case GLSL_TYPE_INT:
-           data.i[c] = op[0]->value.i[c0] % op[1]->value.i[c1];
+           if (op[1]->value.i[c1] == 0) {
+              data.i[c] = 0;
+           } else {
+              data.i[c] = op[0]->value.i[c0] % op[1]->value.i[c1];
+           }
            break;
         case GLSL_TYPE_FLOAT:
            /* We don't use fmod because it rounds toward zero; GLSL specifies
@@ -578,63 +629,75 @@ ir_expression::constant_expression_value()
       break;
 
    case ir_binop_less:
-      switch (op[0]->type->base_type) {
-      case GLSL_TYPE_UINT:
-        data.b[0] = op[0]->value.u[0] < op[1]->value.u[0];
-        break;
-      case GLSL_TYPE_INT:
-        data.b[0] = op[0]->value.i[0] < op[1]->value.i[0];
-        break;
-      case GLSL_TYPE_FLOAT:
-        data.b[0] = op[0]->value.f[0] < op[1]->value.f[0];
-        break;
-      default:
-        assert(0);
+      assert(op[0]->type == op[1]->type);
+      for (unsigned c = 0; c < op[0]->type->components(); c++) {
+        switch (op[0]->type->base_type) {
+        case GLSL_TYPE_UINT:
+           data.b[0] = op[0]->value.u[0] < op[1]->value.u[0];
+           break;
+        case GLSL_TYPE_INT:
+           data.b[0] = op[0]->value.i[0] < op[1]->value.i[0];
+           break;
+        case GLSL_TYPE_FLOAT:
+           data.b[0] = op[0]->value.f[0] < op[1]->value.f[0];
+           break;
+        default:
+           assert(0);
+        }
       }
       break;
    case ir_binop_greater:
-      switch (op[0]->type->base_type) {
-      case GLSL_TYPE_UINT:
-        data.b[0] = op[0]->value.u[0] > op[1]->value.u[0];
-        break;
-      case GLSL_TYPE_INT:
-        data.b[0] = op[0]->value.i[0] > op[1]->value.i[0];
-        break;
-      case GLSL_TYPE_FLOAT:
-        data.b[0] = op[0]->value.f[0] > op[1]->value.f[0];
-        break;
-      default:
-        assert(0);
+      assert(op[0]->type == op[1]->type);
+      for (unsigned c = 0; c < op[0]->type->components(); c++) {
+        switch (op[0]->type->base_type) {
+        case GLSL_TYPE_UINT:
+           data.b[c] = op[0]->value.u[c] > op[1]->value.u[c];
+           break;
+        case GLSL_TYPE_INT:
+           data.b[c] = op[0]->value.i[c] > op[1]->value.i[c];
+           break;
+        case GLSL_TYPE_FLOAT:
+           data.b[c] = op[0]->value.f[c] > op[1]->value.f[c];
+           break;
+        default:
+           assert(0);
+        }
       }
       break;
    case ir_binop_lequal:
-      switch (op[0]->type->base_type) {
-      case GLSL_TYPE_UINT:
-        data.b[0] = op[0]->value.u[0] <= op[1]->value.u[0];
-        break;
-      case GLSL_TYPE_INT:
-        data.b[0] = op[0]->value.i[0] <= op[1]->value.i[0];
-        break;
-      case GLSL_TYPE_FLOAT:
-        data.b[0] = op[0]->value.f[0] <= op[1]->value.f[0];
-        break;
-      default:
-        assert(0);
+      assert(op[0]->type == op[1]->type);
+      for (unsigned c = 0; c < op[0]->type->components(); c++) {
+        switch (op[0]->type->base_type) {
+        case GLSL_TYPE_UINT:
+           data.b[0] = op[0]->value.u[0] <= op[1]->value.u[0];
+           break;
+        case GLSL_TYPE_INT:
+           data.b[0] = op[0]->value.i[0] <= op[1]->value.i[0];
+           break;
+        case GLSL_TYPE_FLOAT:
+           data.b[0] = op[0]->value.f[0] <= op[1]->value.f[0];
+           break;
+        default:
+           assert(0);
+        }
       }
       break;
    case ir_binop_gequal:
-      switch (op[0]->type->base_type) {
-      case GLSL_TYPE_UINT:
-        data.b[0] = op[0]->value.u[0] >= op[1]->value.u[0];
-        break;
-      case GLSL_TYPE_INT:
-        data.b[0] = op[0]->value.i[0] >= op[1]->value.i[0];
-        break;
-      case GLSL_TYPE_FLOAT:
-        data.b[0] = op[0]->value.f[0] >= op[1]->value.f[0];
-        break;
-      default:
-        assert(0);
+      assert(op[0]->type == op[1]->type);
+      for (unsigned c = 0; c < op[0]->type->components(); c++) {
+        switch (op[0]->type->base_type) {
+        case GLSL_TYPE_UINT:
+           data.b[0] = op[0]->value.u[0] >= op[1]->value.u[0];
+           break;
+        case GLSL_TYPE_INT:
+           data.b[0] = op[0]->value.i[0] >= op[1]->value.i[0];
+           break;
+        case GLSL_TYPE_FLOAT:
+           data.b[0] = op[0]->value.f[0] >= op[1]->value.f[0];
+           break;
+        default:
+           assert(0);
+        }
       }
       break;
    case ir_binop_equal:
@@ -650,13 +713,16 @@ ir_expression::constant_expression_value()
         case GLSL_TYPE_FLOAT:
            data.b[c] = op[0]->value.f[c] == op[1]->value.f[c];
            break;
+        case GLSL_TYPE_BOOL:
+           data.b[c] = op[0]->value.b[c] == op[1]->value.b[c];
+           break;
         default:
            assert(0);
         }
       }
       break;
    case ir_binop_nequal:
-      assert(op[0]->type != op[1]->type);
+      assert(op[0]->type == op[1]->type);
       for (unsigned c = 0; c < components; c++) {
         switch (op[0]->type->base_type) {
         case GLSL_TYPE_UINT:
@@ -668,6 +734,9 @@ ir_expression::constant_expression_value()
         case GLSL_TYPE_FLOAT:
            data.b[c] = op[0]->value.f[c] != op[1]->value.f[c];
            break;
+        case GLSL_TYPE_BOOL:
+           data.b[c] = op[0]->value.b[c] != op[1]->value.b[c];
+           break;
         default:
            assert(0);
         }
@@ -782,6 +851,24 @@ ir_expression::constant_expression_value()
       }
       break;
 
+   case ir_quadop_vector:
+      for (unsigned c = 0; c < this->type->vector_elements; c++) {
+        switch (this->type->base_type) {
+        case GLSL_TYPE_INT:
+           data.i[c] = op[c]->value.i[0];
+           break;
+        case GLSL_TYPE_UINT:
+           data.u[c] = op[c]->value.u[0];
+           break;
+        case GLSL_TYPE_FLOAT:
+           data.f[c] = op[c]->value.f[0];
+           break;
+        default:
+           assert(0);
+        }
+      }
+      break;
+
    default:
       /* FINISHME: Should handle all expression types. */
       return NULL;
@@ -821,7 +908,7 @@ ir_swizzle::constant_expression_value()
         }
       }
 
-      void *ctx = talloc_parent(this);
+      void *ctx = ralloc_parent(this);
       return new(ctx) ir_constant(this->type, &data);
    }
    return NULL;
@@ -844,7 +931,7 @@ ir_dereference_variable::constant_expression_value()
    if (!var->constant_value)
       return NULL;
 
-   return var->constant_value->clone(talloc_parent(var), NULL);
+   return var->constant_value->clone(ralloc_parent(var), NULL);
 }
 
 
@@ -855,7 +942,7 @@ ir_dereference_array::constant_expression_value()
    ir_constant *idx = this->array_index->constant_expression_value();
 
    if ((array != NULL) && (idx != NULL)) {
-      void *ctx = talloc_parent(this);
+      void *ctx = ralloc_parent(this);
       if (array->type->is_matrix()) {
         /* Array access of a matrix results in a vector.
          */
@@ -960,7 +1047,7 @@ ir_call::constant_expression_value()
     * - Fill "data" with appopriate constant data
     * - Return an ir_constant directly.
     */
-   void *mem_ctx = talloc_parent(this);
+   void *mem_ctx = ralloc_parent(this);
    ir_expression *expr = NULL;
 
    ir_constant_data data;
@@ -987,10 +1074,18 @@ ir_call::constant_expression_value()
       assert(op[0]->type->is_float());
       for (unsigned c = 0; c < op[0]->type->components(); c++)
         data.f[c] = acosf(op[0]->value.f[c]);
+   } else if (strcmp(callee, "acosh") == 0) {
+      assert(op[0]->type->is_float());
+      for (unsigned c = 0; c < op[0]->type->components(); c++)
+        data.f[c] = acoshf(op[0]->value.f[c]);
    } else if (strcmp(callee, "asin") == 0) {
       assert(op[0]->type->is_float());
       for (unsigned c = 0; c < op[0]->type->components(); c++)
         data.f[c] = asinf(op[0]->value.f[c]);
+   } else if (strcmp(callee, "asinh") == 0) {
+      assert(op[0]->type->is_float());
+      for (unsigned c = 0; c < op[0]->type->components(); c++)
+        data.f[c] = asinhf(op[0]->value.f[c]);
    } else if (strcmp(callee, "atan") == 0) {
       assert(op[0]->type->is_float());
       if (num_parameters == 2) {
@@ -1001,6 +1096,10 @@ ir_call::constant_expression_value()
         for (unsigned c = 0; c < op[0]->type->components(); c++)
            data.f[c] = atanf(op[0]->value.f[c]);
       }
+   } else if (strcmp(callee, "atanh") == 0) {
+      assert(op[0]->type->is_float());
+      for (unsigned c = 0; c < op[0]->type->components(); c++)
+        data.f[c] = atanhf(op[0]->value.f[c]);
    } else if (strcmp(callee, "dFdx") == 0 || strcmp(callee, "dFdy") == 0) {
       return ir_constant::zero(mem_ctx, this->type);
    } else if (strcmp(callee, "ceil") == 0) {
@@ -1037,11 +1136,18 @@ ir_call::constant_expression_value()
       for (unsigned c = 0; c < op[0]->type->components(); c++)
         data.f[c] = coshf(op[0]->value.f[c]);
    } else if (strcmp(callee, "cross") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_binop_cross, type, op[0], op[1]);
+      assert(op[0]->type == glsl_type::vec3_type);
+      assert(op[1]->type == glsl_type::vec3_type);
+      data.f[0] = (op[0]->value.f[1] * op[1]->value.f[2] -
+                  op[1]->value.f[1] * op[0]->value.f[2]);
+      data.f[1] = (op[0]->value.f[2] * op[1]->value.f[0] -
+                  op[1]->value.f[2] * op[0]->value.f[0]);
+      data.f[2] = (op[0]->value.f[0] * op[1]->value.f[1] -
+                  op[1]->value.f[0] * op[0]->value.f[1]);
    } else if (strcmp(callee, "degrees") == 0) {
       assert(op[0]->type->is_float());
       for (unsigned c = 0; c < op[0]->type->components(); c++)
-        data.f[c] = 180.0/M_PI * op[0]->value.f[c];
+        data.f[c] = 180.0F / M_PI * op[0]->value.f[c];
    } else if (strcmp(callee, "distance") == 0) {
       assert(op[0]->type->is_float() && op[1]->type->is_float());
       float length_squared = 0.0;
@@ -1232,7 +1338,7 @@ ir_call::constant_expression_value()
    } else if (strcmp(callee, "radians") == 0) {
       assert(op[0]->type->is_float());
       for (unsigned c = 0; c < op[0]->type->components(); c++)
-        data.f[c] = M_PI/180.0 * op[0]->value.f[c];
+        data.f[c] = M_PI / 180.0F * op[0]->value.f[c];
    } else if (strcmp(callee, "reflect") == 0) {
       assert(op[0]->type->is_float());
       float dot_NI = dot(op[1], op[0]);
@@ -1241,7 +1347,7 @@ ir_call::constant_expression_value()
    } else if (strcmp(callee, "refract") == 0) {
       const float eta = op[2]->value.f[0];
       const float dot_NI = dot(op[1], op[0]);
-      const float k = 1.0 - eta * eta * (1.0 - dot_NI * dot_NI);
+      const float k = 1.0F - eta * eta * (1.0F - dot_NI * dot_NI);
       if (k < 0.0) {
         return ir_constant::zero(mem_ctx, this->type);
       } else {
@@ -1250,6 +1356,9 @@ ir_call::constant_expression_value()
                            * op[1]->value.f[c];
         }
       }
+   } else if (strcmp(callee, "round") == 0 ||
+             strcmp(callee, "roundEven") == 0) {
+      expr = new(mem_ctx) ir_expression(ir_unop_round_even, op[0]);
    } else if (strcmp(callee, "sign") == 0) {
       expr = new(mem_ctx) ir_expression(ir_unop_sign, type, op[0], NULL);
    } else if (strcmp(callee, "sin") == 0) {
@@ -1281,7 +1390,7 @@ ir_call::constant_expression_value()
       /* op[0] (edge) may be either a scalar or a vector */
       const unsigned c0_inc = op[0]->type->is_scalar() ? 0 : 1;
       for (unsigned c = 0, c0 = 0; c < type->components(); c0 += c0_inc, c++)
-        data.f[c] = (op[1]->value.f[c] < op[0]->value.f[c0]) ? 0.0 : 1.0;
+        data.f[c] = (op[1]->value.f[c] < op[0]->value.f[c0]) ? 0.0F : 1.0F;
    } else if (strcmp(callee, "tan") == 0) {
       assert(op[0]->type->is_float());
       for (unsigned c = 0; c < op[0]->type->components(); c++)
@@ -1299,6 +1408,8 @@ ir_call::constant_expression_value()
            data.f[m*i+j] += op[0]->value.f[i+n*j];
         }
       }
+   } else if (strcmp(callee, "trunc") == 0) {
+      expr = new(mem_ctx) ir_expression(ir_unop_trunc, op[0]);
    } else {
       /* Unsupported builtin - some are not allowed in constant expressions. */
       return NULL;