nir/spirv: pull out logic for getting builtin locations
[mesa.git] / src / glsl / opt_algebraic.cpp
index 616ed37b952a7cafe913a5e79576f9864f11341f..fa5db70f2dd3b3ae6eed13adebd9b03a4c571439 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)
 {
@@ -119,6 +125,8 @@ is_valid_vec_const(ir_constant *ir)
 static inline bool
 is_less_than_one(ir_constant *ir)
 {
+   assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+
    if (!is_valid_vec_const(ir))
       return false;
 
@@ -134,6 +142,8 @@ is_less_than_one(ir_constant *ir)
 static inline bool
 is_greater_than_zero(ir_constant *ir)
 {
+   assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+
    if (!is_valid_vec_const(ir))
       return false;
 
@@ -286,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())
@@ -376,6 +400,15 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
       }
       break;
 
+   case ir_unop_f2i:
+   case ir_unop_f2u:
+      if (op_expr[0] && op_expr[0]->operation == ir_unop_trunc) {
+         return new(mem_ctx) ir_expression(ir->operation,
+                                           ir->type,
+                                           op_expr[0]->operands[0]);
+      }
+      break;
+
    case ir_unop_logic_not: {
       enum ir_expression_operation new_op = ir_unop_logic_not;
 
@@ -408,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];
@@ -505,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.
@@ -514,10 +563,47 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
       if (op_const[1] && !op_const[0])
         reassociate_constant(ir, 1, op_const[1], op_expr[0]);
 
+      /* Optimizes
+       *
+       *    (mul (floor (add (abs x) 0.5) (sign x)))
+       *
+       * into
+       *
+       *    (trunc (add x (mul (sign x) 0.5)))
+       */
+      for (int i = 0; i < 2; i++) {
+         ir_expression *sign_expr = ir->operands[i]->as_expression();
+         ir_expression *floor_expr = ir->operands[1 - i]->as_expression();
+
+         if (!sign_expr || sign_expr->operation != ir_unop_sign ||
+             !floor_expr || floor_expr->operation != ir_unop_floor)
+            continue;
+
+         ir_expression *add_expr = floor_expr->operands[0]->as_expression();
+         if (!add_expr)
+            continue;
+
+         for (int j = 0; j < 2; j++) {
+            ir_expression *abs_expr = add_expr->operands[j]->as_expression();
+            if (!abs_expr || abs_expr->operation != ir_unop_abs)
+               continue;
+
+            ir_constant *point_five = add_expr->operands[1 - j]->as_constant();
+            if (!point_five->is_value(0.5, 0))
+               continue;
+
+            if (abs_expr->operands[0]->equals(sign_expr->operands[0])) {
+               return trunc(add(abs_expr->operands[0],
+                                mul(sign_expr, point_five)));
+            }
+         }
+      }
       break;
 
    case ir_binop_div:
-      if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) {
+      if (is_vec_one(op_const[0]) && (
+                ir->type->base_type == GLSL_TYPE_FLOAT ||
+                ir->type->base_type == GLSL_TYPE_DOUBLE)) {
         return new(mem_ctx) ir_expression(ir_unop_rcp,
                                           ir->operands[1]->type,
                                           ir->operands[1],
@@ -538,7 +624,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
          unsigned components[4] = { 0 }, count = 0;
 
          for (unsigned c = 0; c < op_const[i]->type->vector_elements; c++) {
-            if (op_const[i]->value.f[c] == 0.0)
+            if (op_const[i]->is_zero())
                continue;
 
             components[count] = c;
@@ -554,7 +640,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
 
          /* Swizzle both operands to remove the channels that were zero. */
          return new(mem_ctx)
-            ir_expression(op, glsl_type::float_type,
+            ir_expression(op, ir->type,
                           new(mem_ctx) ir_swizzle(ir->operands[0],
                                                   components, count),
                           new(mem_ctx) ir_swizzle(ir->operands[1],
@@ -578,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;
 
@@ -685,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:
@@ -696,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);
-
-            /* 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);
+            ir_rvalue *x = inner_expr->operands[minmax_op];
+            ir_rvalue *y = inner_expr->operands[1 - minmax_op];
 
-            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));
          }
       }
 
@@ -791,7 +917,20 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
          return mul(ir->operands[1], ir->operands[2]);
       } else if (is_vec_zero(op_const[1])) {
          unsigned op2_components = ir->operands[2]->type->vector_elements;
-         ir_constant *one = new(mem_ctx) ir_constant(1.0f, op2_components);
+         ir_constant *one;
+
+         switch (ir->type->base_type) {
+         case GLSL_TYPE_FLOAT:
+            one = new(mem_ctx) ir_constant(1.0f, op2_components);
+            break;
+         case GLSL_TYPE_DOUBLE:
+            one = new(mem_ctx) ir_constant(1.0, op2_components);
+            break;
+         default:
+            one = NULL;
+            unreachable("unexpected type");
+         }
+
          return mul(ir->operands[0], add(one, neg(ir->operands[2])));
       }
       break;