glsl: Don't replace lrp pattern with lrp if arguments are not floats
[mesa.git] / src / compiler / glsl / opt_algebraic.cpp
index 1e58062cb0d804fb65b5e036be4896f6a6155649..7cef4fc6ef934f12b306a64d129ddc97f48ae386 100644 (file)
@@ -34,6 +34,7 @@
 #include "ir_optimization.h"
 #include "ir_builder.h"
 #include "compiler/glsl_types.h"
+#include "main/mtypes.h"
 
 using namespace ir_builder;
 
@@ -58,6 +59,8 @@ public:
    {
    }
 
+   virtual ir_visitor_status visit_enter(ir_assignment *ir);
+
    ir_rvalue *handle_expression(ir_expression *ir);
    void handle_rvalue(ir_rvalue **rvalue);
    bool reassociate_constant(ir_expression *ir1,
@@ -80,6 +83,23 @@ public:
 
 } /* unnamed namespace */
 
+ir_visitor_status
+ir_algebraic_visitor::visit_enter(ir_assignment *ir)
+{
+   ir_variable *var = ir->lhs->variable_referenced();
+   if (var->data.invariant || var->data.precise) {
+      /* If we're assigning to an invariant or precise variable, just bail.
+       * Most of the algebraic optimizations aren't precision-safe.
+       *
+       * FINISHME: Find out which optimizations are precision-safe and enable
+       * then only for invariant or precise trees.
+       */
+      return visit_continue_with_parent;
+   } else {
+      return visit_continue;
+   }
+}
+
 static inline bool
 is_vec_zero(ir_constant *ir)
 {
@@ -125,7 +145,7 @@ 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);
+   assert(ir->type->is_float());
 
    if (!is_valid_vec_const(ir))
       return false;
@@ -142,7 +162,7 @@ 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);
+   assert(ir->type->is_float());
 
    if (!is_valid_vec_const(ir))
       return false;
@@ -227,7 +247,7 @@ ir_algebraic_visitor::reassociate_operands(ir_expression *ir1,
 /**
  * Reassociates a constant down a tree of adds or multiplies.
  *
- * Consider (2 * (a * (b * 0.5))).  We want to send up with a * b.
+ * Consider (2 * (a * (b * 0.5))).  We want to end up with a * b.
  */
 bool
 ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
@@ -244,9 +264,11 @@ ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
        ir2->operands[1]->type->is_matrix())
       return false;
 
+   void *mem_ctx = ralloc_parent(ir2);
+
    ir_constant *ir2_const[2];
-   ir2_const[0] = ir2->operands[0]->constant_expression_value();
-   ir2_const[1] = ir2->operands[1]->constant_expression_value();
+   ir2_const[0] = ir2->operands[0]->constant_expression_value(mem_ctx);
+   ir2_const[1] = ir2->operands[1]->constant_expression_value(mem_ctx);
 
    if (ir2_const[0] && ir2_const[1])
       return false;
@@ -294,7 +316,6 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
 {
    ir_constant *op_const[4] = {NULL, NULL, NULL, NULL};
    ir_expression *op_expr[4] = {NULL, NULL, NULL, NULL};
-   unsigned int i;
 
    if (ir->operation == ir_binop_mul &&
        ir->operands[0]->type->is_matrix() &&
@@ -310,12 +331,13 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
       }
    }
 
-   assert(ir->get_num_operands() <= 4);
-   for (i = 0; i < ir->get_num_operands(); i++) {
+   assert(ir->num_operands <= 4);
+   for (unsigned i = 0; i < ir->num_operands; i++) {
       if (ir->operands[i]->type->is_matrix())
         return ir;
 
-      op_const[i] = ir->operands[i]->constant_expression_value();
+      op_const[i] =
+         ir->operands[i]->constant_expression_value(ralloc_parent(ir));
       op_expr[i] = ir->operands[i]->as_expression();
    }
 
@@ -417,8 +439,6 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
 
       switch (op_expr[0]->operation) {
       case ir_binop_less:    new_op = ir_binop_gequal;  break;
-      case ir_binop_greater: new_op = ir_binop_lequal;  break;
-      case ir_binop_lequal:  new_op = ir_binop_greater; break;
       case ir_binop_gequal:  new_op = ir_binop_less;    break;
       case ir_binop_equal:   new_op = ir_binop_nequal;  break;
       case ir_binop_nequal:  new_op = ir_binop_equal;   break;
@@ -453,12 +473,52 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
       }
       break;
 
+      /* This macro CANNOT use the do { } while(true) mechanism because
+       * then the breaks apply to the loop instead of the switch!
+       */
+#define HANDLE_PACK_UNPACK_INVERSE(inverse_operation)                   \
+      {                                                                 \
+         ir_expression *const op = ir->operands[0]->as_expression();    \
+         if (op == NULL)                                                \
+            break;                                                      \
+         if (op->operation == (inverse_operation))                      \
+            return op->operands[0];                                     \
+         break;                                                         \
+      }
+
+   case ir_unop_unpack_uint_2x32:
+      HANDLE_PACK_UNPACK_INVERSE(ir_unop_pack_uint_2x32);
+   case ir_unop_pack_uint_2x32:
+      HANDLE_PACK_UNPACK_INVERSE(ir_unop_unpack_uint_2x32);
+   case ir_unop_unpack_int_2x32:
+      HANDLE_PACK_UNPACK_INVERSE(ir_unop_pack_int_2x32);
+   case ir_unop_pack_int_2x32:
+      HANDLE_PACK_UNPACK_INVERSE(ir_unop_unpack_int_2x32);
+   case ir_unop_unpack_double_2x32:
+      HANDLE_PACK_UNPACK_INVERSE(ir_unop_pack_double_2x32);
+   case ir_unop_pack_double_2x32:
+      HANDLE_PACK_UNPACK_INVERSE(ir_unop_unpack_double_2x32);
+
+#undef HANDLE_PACK_UNPACK_INVERSE
+
    case ir_binop_add:
       if (is_vec_zero(op_const[0]))
         return ir->operands[1];
       if (is_vec_zero(op_const[1]))
         return ir->operands[0];
 
+      /* Replace (x + (-x)) with constant 0 */
+      for (int i = 0; i < 2; i++) {
+         if (op_expr[i]) {
+            if (op_expr[i]->operation == ir_unop_neg) {
+               ir_rvalue *other = ir->operands[(i + 1) % 2];
+               if (other && op_expr[i]->operands[0]->equals(other)) {
+                  return ir_constant::zero(ir, ir->type);
+               }
+            }
+         }
+      }
+
       /* Reassociate addition of constants so that we can do constant
        * folding.
        */
@@ -518,7 +578,8 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
                ir_rvalue *y_operand = inner_add->operands[1 - neg_pos];
                ir_rvalue *a_operand = mul->operands[1 - inner_add_pos];
 
-               if (x_operand->type != y_operand->type ||
+               if (!x_operand->type->is_float_16_32_64() ||
+                   x_operand->type != y_operand->type ||
                    x_operand->type != a_operand->type)
                   continue;
 
@@ -602,8 +663,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
 
    case ir_binop_div:
       if (is_vec_one(op_const[0]) && (
-                ir->type->base_type == GLSL_TYPE_FLOAT ||
-                ir->type->base_type == GLSL_TYPE_DOUBLE)) {
+                ir->type->is_float() || ir->type->is_double())) {
         return new(mem_ctx) ir_expression(ir_unop_rcp,
                                           ir->operands[1]->type,
                                           ir->operands[1],
@@ -649,8 +709,6 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
       break;
 
    case ir_binop_less:
-   case ir_binop_lequal:
-   case ir_binop_greater:
    case ir_binop_gequal:
    case ir_binop_equal:
    case ir_binop_nequal:
@@ -664,6 +722,12 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
          if (!is_vec_zero(zero))
             continue;
 
+         /* We are allowed to add scalars with a vector or matrix. In that
+          * case lets just exit early.
+          */
+         if (add->operands[0]->type != add->operands[1]->type)
+            continue;
+
          /* 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)
           */
@@ -798,7 +862,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
 
    case ir_binop_min:
    case ir_binop_max:
-      if (ir->type->base_type != GLSL_TYPE_FLOAT || options->EmitNoSat)
+      if (!ir->type->is_float() || options->EmitNoSat)
          break;
 
       /* Replace min(max) operations and its commutative combinations with
@@ -920,6 +984,9 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
          ir_constant *one;
 
          switch (ir->type->base_type) {
+         case GLSL_TYPE_FLOAT16:
+            one = new(mem_ctx) ir_constant(float16_t::one(), op2_components);
+            break;
          case GLSL_TYPE_FLOAT:
             one = new(mem_ctx) ir_constant(1.0f, op2_components);
             break;
@@ -942,6 +1009,16 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
         return ir->operands[2];
       break;
 
+   /* Remove interpolateAt* instructions for demoted inputs. They are
+    * assigned a constant expression to facilitate this.
+    */
+   case ir_unop_interpolate_at_centroid:
+   case ir_binop_interpolate_at_offset:
+   case ir_binop_interpolate_at_sample:
+      if (op_const[0])
+         return ir->operands[0];
+      break;
+
    default:
       break;
    }