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

Ian Romanick idr at freedesktop.org
Wed Jan 28 11:20:01 PST 2015


On 01/28/2015 10:31 AM, Matt Turner wrote:
> 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)))

If I'm not mistaken, this isn't round-to-even.  Doesn't this round 4.5
to 5?  roundEven(4.5) should be 4.  This looks like "half-up" rounding.
 Which is very different.  See
http://userguide.icu-project.org/formatparse/numbers/rounding-modes

If we're going to make any clever change here, we really should have a
thorough test case first.

> +       *
> +       * 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:
> 



More information about the mesa-dev mailing list