glsl: fix the type of ir_constant_data::u16
[mesa.git] / src / compiler / glsl / opt_constant_folding.cpp
index de13c9e068ec67b7eb5307918583a8dcd7740d84..3b9394d1358ad7c6712e8e6e6863f1f0e2d84e1d 100644 (file)
@@ -61,11 +61,11 @@ public:
 
 } /* unnamed namespace */
 
-void
-ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
+bool
+ir_constant_fold(ir_rvalue **rvalue)
 {
    if (*rvalue == NULL || (*rvalue)->ir_type == ir_type_constant)
-      return;
+      return false;
 
    /* Note that we do rvalue visitoring on leaving.  So if an
     * expression has a non-constant operand, no need to go looking
@@ -74,22 +74,46 @@ ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
     */
    ir_expression *expr = (*rvalue)->as_expression();
    if (expr) {
-      for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
+      for (unsigned int i = 0; i < expr->num_operands; i++) {
         if (!expr->operands[i]->as_constant())
-           return;
+           return false;
       }
    }
 
    /* Ditto for swizzles. */
    ir_swizzle *swiz = (*rvalue)->as_swizzle();
    if (swiz && !swiz->val->as_constant())
-      return;
+      return false;
+
+   /* Ditto for array dereferences */
+   ir_dereference_array *array_ref = (*rvalue)->as_dereference_array();
+   if (array_ref && (!array_ref->array->as_constant() ||
+                     !array_ref->array_index->as_constant()))
+      return false;
+
+   /* No constant folding can be performed on variable dereferences.  We need
+    * to explicitly avoid them, as calling constant_expression_value() on a
+    * variable dereference will return a clone of var->constant_value.  This
+    * would make us propagate the value into the tree, which isn't our job.
+    */
+   ir_dereference_variable *var_ref = (*rvalue)->as_dereference_variable();
+   if (var_ref)
+      return false;
 
-   ir_constant *constant = (*rvalue)->constant_expression_value();
+   ir_constant *constant =
+      (*rvalue)->constant_expression_value(ralloc_parent(*rvalue));
    if (constant) {
       *rvalue = constant;
-      this->progress = true;
+      return true;
    }
+   return false;
+}
+
+void
+ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+   if (ir_constant_fold(rvalue))
+      this->progress = true;
 }
 
 ir_visitor_status
@@ -166,7 +190,7 @@ ir_constant_folding_visitor::visit_enter(ir_call *ir)
    }
 
    /* Next, see if the call can be replaced with an assignment of a constant */
-   ir_constant *const_val = ir->constant_expression_value();
+   ir_constant *const_val = ir->constant_expression_value(ralloc_parent(ir));
 
    if (const_val != NULL) {
       ir_assignment *assignment =