nir/spirv: Array lengths are constants not literals
[mesa.git] / src / glsl / opt_algebraic.cpp
index 6784242ff5d8ac078d23c89ee3572364735474cf..c4b871511990c4ab2ed1fa720fef8bcf311e23b1 100644 (file)
@@ -98,6 +98,12 @@ is_vec_two(ir_constant *ir)
    return (ir == NULL) ? false : ir->is_value(2.0, 2);
 }
 
+static inline bool
+is_vec_four(ir_constant *ir)
+{
+   return (ir == NULL) ? false : ir->is_value(4.0, 4);
+}
+
 static inline bool
 is_vec_negative_one(ir_constant *ir)
 {
@@ -290,6 +296,20 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
    ir_expression *op_expr[4] = {NULL, NULL, NULL, NULL};
    unsigned int i;
 
+   if (ir->operation == ir_binop_mul &&
+       ir->operands[0]->type->is_matrix() &&
+       ir->operands[1]->type->is_vector()) {
+      ir_expression *matrix_mul = ir->operands[0]->as_expression();
+
+      if (matrix_mul && matrix_mul->operation == ir_binop_mul &&
+         matrix_mul->operands[0]->type->is_matrix() &&
+         matrix_mul->operands[1]->type->is_matrix()) {
+
+         return mul(matrix_mul->operands[0],
+                    mul(matrix_mul->operands[1], ir->operands[1]));
+      }
+   }
+
    assert(ir->get_num_operands() <= 4);
    for (i = 0; i < ir->get_num_operands(); i++) {
       if (ir->operands[i]->type->is_matrix())
@@ -421,6 +441,18 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
       break;
    }
 
+   case ir_unop_saturate:
+      if (op_expr[0] && op_expr[0]->operation == ir_binop_add) {
+         ir_expression *b2f_0 = op_expr[0]->operands[0]->as_expression();
+         ir_expression *b2f_1 = op_expr[0]->operands[1]->as_expression();
+
+         if (b2f_0 && b2f_0->operation == ir_unop_b2f &&
+             b2f_1 && b2f_1->operation == ir_unop_b2f) {
+            return b2f(logic_or(b2f_0->operands[0], b2f_1->operands[0]));
+         }
+      }
+      break;
+
    case ir_binop_add:
       if (is_vec_zero(op_const[0]))
         return ir->operands[1];
@@ -518,6 +550,10 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
       if (is_vec_negative_one(op_const[1]))
          return neg(ir->operands[0]);
 
+      if (op_expr[0] && op_expr[0]->operation == ir_unop_b2f &&
+          op_expr[1] && op_expr[1]->operation == ir_unop_b2f) {
+         return b2f(logic_and(op_expr[0]->operands[0], op_expr[1]->operands[0]));
+      }
 
       /* Reassociate multiplication of constants so that we can do
        * constant folding.
@@ -544,6 +580,8 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
             continue;
 
          ir_expression *add_expr = floor_expr->operands[0]->as_expression();
+         if (!add_expr || add_expr->operation != ir_binop_add)
+            continue;
 
          for (int j = 0; j < 2; j++) {
             ir_expression *abs_expr = add_expr->operands[j]->as_expression();
@@ -551,7 +589,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
                continue;
 
             ir_constant *point_five = add_expr->operands[1 - j]->as_constant();
-            if (!point_five->is_value(0.5, 0))
+            if (!point_five || !point_five->is_value(0.5, 0))
                continue;
 
             if (abs_expr->operands[0]->equals(sign_expr->operands[0])) {
@@ -626,9 +664,18 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
          if (!is_vec_zero(zero))
             continue;
 
-         return new(mem_ctx) ir_expression(ir->operation,
-                                           add->operands[0],
-                                           neg(add->operands[1]));
+         /* Depending of the zero position we want to optimize
+          * (0 cmp x+y) into (-x cmp y) or (x+y cmp 0) into (x cmp -y)
+          */
+         if (add_pos == 1) {
+            return new(mem_ctx) ir_expression(ir->operation,
+                                              neg(add->operands[0]),
+                                              add->operands[1]);
+         } else {
+            return new(mem_ctx) ir_expression(ir->operation,
+                                              add->operands[0],
+                                              neg(add->operands[1]));
+         }
       }
       break;
 
@@ -733,6 +780,20 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
          return mul(x, x);
       }
 
+      if (is_vec_four(op_const[1])) {
+         ir_variable *x = new(ir) ir_variable(ir->operands[1]->type, "x",
+                                              ir_var_temporary);
+         base_ir->insert_before(x);
+         base_ir->insert_before(assign(x, ir->operands[0]));
+
+         ir_variable *squared = new(ir) ir_variable(ir->operands[1]->type,
+                                                    "squared",
+                                                    ir_var_temporary);
+         base_ir->insert_before(squared);
+         base_ir->insert_before(assign(squared, mul(x, x)));
+         return mul(squared, squared);
+      }
+
       break;
 
    case ir_binop_min:
@@ -744,48 +805,65 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
        * a saturate operation
        */
       for (int op = 0; op < 2; op++) {
-         ir_expression *minmax = op_expr[op];
+         ir_expression *inner_expr = op_expr[op];
          ir_constant *outer_const = op_const[1 - op];
          ir_expression_operation op_cond = (ir->operation == ir_binop_max) ?
             ir_binop_min : ir_binop_max;
 
-         if (!minmax || !outer_const || (minmax->operation != op_cond))
+         if (!inner_expr || !outer_const || (inner_expr->operation != op_cond))
             continue;
 
+         /* One of these has to be a constant */
+         if (!inner_expr->operands[0]->as_constant() &&
+             !inner_expr->operands[1]->as_constant())
+            break;
+
          /* Found a min(max) combination. Now try to see if its operands
           * meet our conditions that we can do just a single saturate operation
           */
          for (int minmax_op = 0; minmax_op < 2; minmax_op++) {
-            ir_rvalue *inner_val_a = minmax->operands[minmax_op];
-            ir_rvalue *inner_val_b = minmax->operands[1 - minmax_op];
-
-            if (!inner_val_a || !inner_val_b)
-               continue;
-
-            /* Found a {min|max} ({max|min} (x, 0.0), 1.0) operation and its variations */
-            if ((outer_const->is_one() && inner_val_a->is_zero()) ||
-                (inner_val_a->is_one() && outer_const->is_zero()))
-               return saturate(inner_val_b);
+            ir_rvalue *x = inner_expr->operands[minmax_op];
+            ir_rvalue *y = inner_expr->operands[1 - minmax_op];
 
-            /* Found a {min|max} ({max|min} (x, 0.0), b) where b < 1.0
-             * and its variations
-             */
-            if (is_less_than_one(outer_const) && inner_val_b->is_zero())
-               return expr(ir_binop_min, saturate(inner_val_a), outer_const);
-
-            if (!inner_val_b->as_constant())
+            ir_constant *inner_const = y->as_constant();
+            if (!inner_const)
                continue;
 
-            if (is_less_than_one(inner_val_b->as_constant()) && outer_const->is_zero())
-               return expr(ir_binop_min, saturate(inner_val_a), inner_val_b);
-
-            /* Found a {min|max} ({max|min} (x, b), 1.0), where b > 0.0
-             * and its variations
-             */
-            if (outer_const->is_one() && is_greater_than_zero(inner_val_b->as_constant()))
-               return expr(ir_binop_max, saturate(inner_val_a), inner_val_b);
-            if (inner_val_b->as_constant()->is_one() && is_greater_than_zero(outer_const))
-               return expr(ir_binop_max, saturate(inner_val_a), outer_const);
+            /* min(max(x, 0.0), 1.0) is sat(x) */
+            if (ir->operation == ir_binop_min &&
+                inner_const->is_zero() &&
+                outer_const->is_one())
+               return saturate(x);
+
+            /* max(min(x, 1.0), 0.0) is sat(x) */
+            if (ir->operation == ir_binop_max &&
+                inner_const->is_one() &&
+                outer_const->is_zero())
+               return saturate(x);
+
+            /* min(max(x, 0.0), b) where b < 1.0 is sat(min(x, b)) */
+            if (ir->operation == ir_binop_min &&
+                inner_const->is_zero() &&
+                is_less_than_one(outer_const))
+               return saturate(expr(ir_binop_min, x, outer_const));
+
+            /* max(min(x, b), 0.0) where b < 1.0 is sat(min(x, b)) */
+            if (ir->operation == ir_binop_max &&
+                is_less_than_one(inner_const) &&
+                outer_const->is_zero())
+               return saturate(expr(ir_binop_min, x, inner_const));
+
+            /* max(min(x, 1.0), b) where b > 0.0 is sat(max(x, b)) */
+            if (ir->operation == ir_binop_max &&
+                inner_const->is_one() &&
+                is_greater_than_zero(outer_const))
+               return saturate(expr(ir_binop_max, x, outer_const));
+
+            /* min(max(x, b), 1.0) where b > 0.0 is sat(max(x, b)) */
+            if (ir->operation == ir_binop_min &&
+                is_greater_than_zero(inner_const) &&
+                outer_const->is_one())
+               return saturate(expr(ir_binop_max, x, inner_const));
          }
       }
 
@@ -849,6 +927,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
             one = new(mem_ctx) ir_constant(1.0, op2_components);
             break;
          default:
+            one = NULL;
             unreachable("unexpected type");
          }