[Mesa-dev] [PATCH 5/5] Change ir_function_signature::constant_expression_value to run through the function.

Olivier Galibert galibert at pobox.com
Fri Apr 27 01:28:04 PDT 2012


That removes code duplication with
ir_expression::constant_expression_value and builtins/ir/*.

Signed-off-by: Olivier Galibert <galibert at pobox.com>
---
 src/glsl/ir_constant_expression.cpp |  450 +++++++----------------------------
 1 file changed, 80 insertions(+), 370 deletions(-)

diff --git a/src/glsl/ir_constant_expression.cpp b/src/glsl/ir_constant_expression.cpp
index ee1cc1a..a7aafaa 100644
--- a/src/glsl/ir_constant_expression.cpp
+++ b/src/glsl/ir_constant_expression.cpp
@@ -1050,396 +1050,106 @@ ir_function_signature::constant_expression_value(exec_list *actual_parameters)
    if (!this->is_builtin)
       return NULL;
 
-   unsigned num_parameters = 0;
+   /*
+    * Of the builtin functions, only the texture lookups and the noise
+    * ones must not be used in constant expressions.  They all include
+    * specific opcodes so they don't need to be special-cased at this
+    * point.
+    */
+
+   /* Initialize the table of dereferencable names with the function
+    * parameters.  Verify their const-ness on the way.
+    *
+    * We expect the correctness of the number of parameters to have
+    * been checked earlier.
+    */
+   hash_table *deref_hash = hash_table_ctor(8, hash_table_string_hash,
+					    hash_table_string_compare);
+
+   const exec_node *parameter_info = parameters.head;
 
-   /* Check if all parameters are constant */
-   ir_constant *op[3];
    foreach_list(n, actual_parameters) {
-      ir_constant *constant = ((ir_rvalue *) n)->constant_expression_value();
+      ir_constant *constant = ((ir_rvalue *) n)->constant_expression_value(NULL);
       if (constant == NULL)
 	 return NULL;
 
-      op[num_parameters] = constant;
+      ir_variable *var = (ir_variable *)parameter_info;
+      hash_table_insert(deref_hash, constant, var->name);
 
-      assert(num_parameters < 3);
-      num_parameters++;
+      parameter_info = parameter_info->next;
    }
 
-   /* Individual cases below can either:
-    * - Assign "expr" a new ir_expression to evaluate (for basic opcodes)
-    * - Fill "data" with appopriate constant data
-    * - Return an ir_constant directly.
-    */
-   void *mem_ctx = ralloc_parent(this);
-   ir_expression *expr = NULL;
+   ir_constant *result = NULL;
 
-   ir_constant_data data;
-   memset(&data, 0, sizeof(data));
+   /* Now run the builtin function until something non-constant
+    * happens or we get the result.
+    */
 
-   const char *callee = this->function_name();
-   if (strcmp(callee, "abs") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_abs, type, op[0], NULL);
-   } else if (strcmp(callee, "all") == 0) {
-      assert(op[0]->type->is_boolean());
-      for (unsigned c = 0; c < op[0]->type->components(); c++) {
-	 if (!op[0]->value.b[c])
-	    return new(mem_ctx) ir_constant(false);
-      }
-      return new(mem_ctx) ir_constant(true);
-   } else if (strcmp(callee, "any") == 0) {
-      assert(op[0]->type->is_boolean());
-      for (unsigned c = 0; c < op[0]->type->components(); c++) {
-	 if (op[0]->value.b[c])
-	    return new(mem_ctx) ir_constant(true);
-      }
-      return new(mem_ctx) ir_constant(false);
-   } else if (strcmp(callee, "acos") == 0) {
-      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) {
-	 assert(op[1]->type->is_float());
-	 for (unsigned c = 0; c < op[0]->type->components(); c++)
-	    data.f[c] = atan2f(op[0]->value.f[c], op[1]->value.f[c]);
-      } else {
-	 for (unsigned c = 0; c < op[0]->type->components(); c++)
-	    data.f[c] = atanf(op[0]->value.f[c]);
+   foreach_list(n, &body) {
+      ir_instruction *inst = (ir_instruction *)n;
+      switch(inst->ir_type) {
+	 /*
+	  * (declare () type symbol)
+	  *
+	  * Create a default-valued constant of the correct type.
+	  */
+      case ir_type_variable: {
+	 ir_variable *var = inst->as_variable();
+	 hash_table_insert(deref_hash, ir_constant::zero(this, var->type), var->name);
+	 break;
       }
-   } 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, type);
-   } else if (strcmp(callee, "ceil") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_ceil, type, op[0], NULL);
-   } else if (strcmp(callee, "clamp") == 0) {
-      assert(num_parameters == 3);
-      unsigned c1_inc = op[1]->type->is_scalar() ? 0 : 1;
-      unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
-      for (unsigned c = 0, c1 = 0, c2 = 0;
-	   c < op[0]->type->components();
-	   c1 += c1_inc, c2 += c2_inc, c++) {
 
-	 switch (op[0]->type->base_type) {
-	 case GLSL_TYPE_UINT:
-	    data.u[c] = CLAMP(op[0]->value.u[c], op[1]->value.u[c1],
-			      op[2]->value.u[c2]);
-	    break;
-	 case GLSL_TYPE_INT:
-	    data.i[c] = CLAMP(op[0]->value.i[c], op[1]->value.i[c1],
-			      op[2]->value.i[c2]);
-	    break;
-	 case GLSL_TYPE_FLOAT:
-	    data.f[c] = CLAMP(op[0]->value.f[c], op[1]->value.f[c1],
-			      op[2]->value.f[c2]);
-	    break;
-	 default:
-	    assert(!"Should not get here.");
+	/*
+	 * (assign [condition] (write-mask) (ref) (value))
+	 *
+	 * Do the assignement.  Bail out if a condition is present.
+	 */
+      case ir_type_assignment: {
+	 ir_assignment *asg = inst->as_assignment();
+	 if(asg->condition) {
+	    result = NULL;
+	    goto done;
 	 }
-      }
-   } else if (strcmp(callee, "cos") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_cos, type, op[0], NULL);
-   } else if (strcmp(callee, "cosh") == 0) {
-      assert(op[0]->type->is_float());
-      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) {
-      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.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;
-      for (unsigned c = 0; c < op[0]->type->components(); c++) {
-	 float t = op[0]->value.f[c] - op[1]->value.f[c];
-	 length_squared += t * t;
-      }
-      return new(mem_ctx) ir_constant(sqrtf(length_squared));
-   } else if (strcmp(callee, "dot") == 0) {
-      return new(mem_ctx) ir_constant(dot(op[0], op[1]));
-   } else if (strcmp(callee, "equal") == 0) {
-      assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
-      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;
-	 case GLSL_TYPE_BOOL:
-	    data.b[c] = op[0]->value.b[c] == op[1]->value.b[c];
-	    break;
-	 default:
-	    assert(!"Should not get here.");
-	 }
-      }
-   } else if (strcmp(callee, "exp") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_exp, type, op[0], NULL);
-   } else if (strcmp(callee, "exp2") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_exp2, type, op[0], NULL);
-   } else if (strcmp(callee, "faceforward") == 0) {
-      if (dot(op[2], op[1]) < 0)
-	 return op[0];
-      for (unsigned c = 0; c < op[0]->type->components(); c++)
-	 data.f[c] = -op[0]->value.f[c];
-   } else if (strcmp(callee, "floor") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_floor, type, op[0], NULL);
-   } else if (strcmp(callee, "fract") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_fract, type, op[0], NULL);
-   } else if (strcmp(callee, "fwidth") == 0) {
-      return ir_constant::zero(mem_ctx, type);
-   } else if (strcmp(callee, "greaterThan") == 0) {
-      assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
-      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(!"Should not get here.");
-	 }
-      }
-   } else if (strcmp(callee, "greaterThanEqual") == 0) {
-      assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
-      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(!"Should not get here.");
-	 }
-      }
-   } else if (strcmp(callee, "inversesqrt") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_rsq, type, op[0], NULL);
-   } else if (strcmp(callee, "length") == 0) {
-      return new(mem_ctx) ir_constant(sqrtf(dot(op[0], op[0])));
-   } else if (strcmp(callee, "lessThan") == 0) {
-      assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
-      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(!"Should not get here.");
-	 }
-      }
-   } else if (strcmp(callee, "lessThanEqual") == 0) {
-      assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
-      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(!"Should not get here.");
-	 }
-      }
-   } else if (strcmp(callee, "log") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_log, type, op[0], NULL);
-   } else if (strcmp(callee, "log2") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_log2, type, op[0], NULL);
-   } else if (strcmp(callee, "matrixCompMult") == 0) {
-      assert(op[0]->type->is_float() && op[1]->type->is_float());
-      for (unsigned c = 0; c < op[0]->type->components(); c++)
-	 data.f[c] = op[0]->value.f[c] * op[1]->value.f[c];
-   } else if (strcmp(callee, "max") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_binop_max, type, op[0], op[1]);
-   } else if (strcmp(callee, "min") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_binop_min, type, op[0], op[1]);
-   } else if (strcmp(callee, "mix") == 0) {
-      assert(op[0]->type->is_float() && op[1]->type->is_float());
-      if (op[2]->type->is_float()) {
-	 unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
-	 unsigned components = op[0]->type->components();
-	 for (unsigned c = 0, c2 = 0; c < components; c2 += c2_inc, c++) {
-	    data.f[c] = op[0]->value.f[c] * (1 - op[2]->value.f[c2]) +
-			op[1]->value.f[c] * op[2]->value.f[c2];
+
+	 ir_constant *store = NULL;
+	 int offset = 0;
+	 asg->lhs->constant_referenced(deref_hash, store, offset);
+	 if(!store) {
+	    result = NULL;
+	    goto done;
 	 }
-      } else {
-	 assert(op[2]->type->is_boolean());
-	 for (unsigned c = 0; c < op[0]->type->components(); c++)
-	    data.f[c] = op[op[2]->value.b[c] ? 1 : 0]->value.f[c];
-      }
-   } else if (strcmp(callee, "mod") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_binop_mod, type, op[0], op[1]);
-   } else if (strcmp(callee, "normalize") == 0) {
-      assert(op[0]->type->is_float());
-      float length = sqrtf(dot(op[0], op[0]));
 
-      if (length == 0)
-	 return ir_constant::zero(mem_ctx, type);
+	 ir_constant *value = asg->rhs->constant_expression_value(deref_hash);
 
-      for (unsigned c = 0; c < op[0]->type->components(); c++)
-	 data.f[c] = op[0]->value.f[c] / length;
-   } else if (strcmp(callee, "not") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_logic_not, type, op[0], NULL);
-   } else if (strcmp(callee, "notEqual") == 0) {
-      assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
-      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;
-	 case GLSL_TYPE_BOOL:
-	    data.b[c] = op[0]->value.b[c] != op[1]->value.b[c];
-	    break;
-	 default:
-	    assert(!"Should not get here.");
-	 }
-      }
-   } else if (strcmp(callee, "outerProduct") == 0) {
-      assert(op[0]->type->is_vector() && op[1]->type->is_vector());
-      const unsigned m = op[0]->type->vector_elements;
-      const unsigned n = op[1]->type->vector_elements;
-      for (unsigned j = 0; j < n; j++) {
-	 for (unsigned i = 0; i < m; i++) {
-	    data.f[i+m*j] = op[0]->value.f[i] * op[1]->value.f[j];
-	 }
-      }
-   } else if (strcmp(callee, "pow") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_binop_pow, type, op[0], op[1]);
-   } 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.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]);
-      for (unsigned c = 0; c < op[0]->type->components(); c++)
-	 data.f[c] = op[0]->value.f[c] - 2 * dot_NI * op[1]->value.f[c];
-   } 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.0F - eta * eta * (1.0F - dot_NI * dot_NI);
-      if (k < 0.0) {
-	 return ir_constant::zero(mem_ctx, type);
-      } else {
-	 for (unsigned c = 0; c < type->components(); c++) {
-	    data.f[c] = eta * op[0]->value.f[c] - (eta * dot_NI + sqrtf(k))
-			    * 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) {
-      expr = new(mem_ctx) ir_expression(ir_unop_sin, type, op[0], NULL);
-   } else if (strcmp(callee, "sinh") == 0) {
-      assert(op[0]->type->is_float());
-      for (unsigned c = 0; c < op[0]->type->components(); c++)
-	 data.f[c] = sinhf(op[0]->value.f[c]);
-   } else if (strcmp(callee, "smoothstep") == 0) {
-      assert(num_parameters == 3);
-      assert(op[1]->type == op[0]->type);
-      unsigned edge_inc = op[0]->type->is_scalar() ? 0 : 1;
-      for (unsigned c = 0, e = 0; c < type->components(); e += edge_inc, c++) {
-	 const float edge0 = op[0]->value.f[e];
-	 const float edge1 = op[1]->value.f[e];
-	 if (edge0 == edge1) {
-	    data.f[c] = 0.0; /* Avoid a crash - results are undefined anyway */
-	 } else {
-	    const float numerator = op[2]->value.f[c] - edge0;
-	    const float denominator = edge1 - edge0;
-	    const float t = CLAMP(numerator/denominator, 0, 1);
-	    data.f[c] = t * t * (3 - 2 * t);
+	 if(!value) {
+	    result = NULL;
+	    goto done;
 	 }
+
+	 store->copy_masked_offset(value, offset, asg->write_mask);
+	 break;
       }
-   } else if (strcmp(callee, "sqrt") == 0) {
-      expr = new(mem_ctx) ir_expression(ir_unop_sqrt, type, op[0], NULL);
-   } else if (strcmp(callee, "step") == 0) {
-      assert(op[0]->type->is_float() && op[1]->type->is_float());
-      /* 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.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++)
-	 data.f[c] = tanf(op[0]->value.f[c]);
-   } else if (strcmp(callee, "tanh") == 0) {
-      assert(op[0]->type->is_float());
-      for (unsigned c = 0; c < op[0]->type->components(); c++)
-	 data.f[c] = tanhf(op[0]->value.f[c]);
-   } else if (strcmp(callee, "transpose") == 0) {
-      assert(op[0]->type->is_matrix());
-      const unsigned n = op[0]->type->vector_elements;
-      const unsigned m = op[0]->type->matrix_columns;
-      for (unsigned j = 0; j < m; j++) {
-	 for (unsigned i = 0; i < n; i++) {
-	    data.f[m*i+j] += op[0]->value.f[i+n*j];
-	 }
+
+	 /* (return (expression))
+	  *
+	  * End of the line, compute the result and exit.
+	  */
+      case ir_type_return:
+	 result = inst->as_return()->value->constant_expression_value(deref_hash);
+	 goto done;
+
+	 /* Every other expression type, we drop out.  Maybe some
+	    builtins will need jumps someday, but not yet. */
+      default:
+	 goto done;
       }
-   } 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;
    }
+ done:
 
-   if (expr != NULL)
-      return expr->constant_expression_value();
+   if(result)
+      result = result->clone(ralloc_parent(this), NULL);
 
-   return new(mem_ctx) ir_constant(type, &data);
+   hash_table_dtor(deref_hash);
+
+   return result;
 }
-- 
1.7.10.280.gaa39



More information about the mesa-dev mailing list