Note: this will round differently for x.5 where x is even.

total instructions in shared programs: 5953897 -> 5948654 (-0.09%)
instructions in affected programs:     88619 -> 83376 (-5.92%)
helped:                                696
---
If we implemented round() differently from roundEven(), we should
use it instead.

(mul (floor (add (abs x) 0.5) (sign x))) is 6 i965 instructions.
(roundEven x) is 1 instruction.

Most shaders with this pattern wrap it in int(...), which increases
the counts by one, to 7 and 2 respectively.

Alternatively, we could optimize this as

(trunc (add f (mul 0.5 (sign f)))), which would be 6 instructions,
and the int() conversion would be free. We could also apply f's sign
to 0.5 in two instructions, cutting the total to 4.

What do you think? Should we do precisely as they say? All but two
of the affected shaders seem to be translated from DX.

 src/glsl/opt_algebraic.cpp | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp
index c6f4a9c..eaa5f47 100644
--- a/src/glsl/opt_algebraic.cpp
+++ b/src/glsl/opt_algebraic.cpp
@@ -514,6 +514,38 @@ 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
+       *
+       *    (roundEven x)
+       */
+      for (int i = 0; i < 2; i++) {
+         ir_expression *sign = ir->operands[i]->as_expression();
+         ir_expression *floor = ir->operands[1 - i]->as_expression();
+
+         if (!sign || sign->operation != ir_unop_sign ||
+             !floor || floor->operation != ir_unop_floor)
+            continue;
+
+         ir_expression *add = floor->operands[0]->as_expression();
+
+         for (int j = 0; j < 2; j++) {
+            ir_expression *abs_expr = add->operands[j]->as_expression();
+            if (!abs_expr || abs_expr->operation != ir_unop_abs)
+               continue;
+
+            ir_constant *point_five = add->operands[1 - j]->as_constant();
+            if (!point_five->is_value(0.5, 0))
+               continue;
+
+            if (abs_expr->operands[0]->equals(sign->operands[0])) {
+               return round_even(abs_expr->operands[0]);
+            }
+         }
+      }
       break;
 
    case ir_binop_div:
-- 
2.0.4

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to