[Mesa-dev] [RFC] glsl: Recognize pattern for roundEven().

Matt Turner mattst88 at gmail.com
Wed Jan 28 10:31:41 PST 2015


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



More information about the mesa-dev mailing list