binaryen icon indicating copy to clipboard operation
binaryen copied to clipboard

Optimize comparisons of adjusted values

Open kripken opened this issue 3 years ago • 4 comments

E.g.

  (i32.gt_u
   (i32.shr_u
    (local.get $0)
    (i32.const 1)
   )
   (i32.const 100)
  )
 =->
  (i32.gt_u
   (local.get $0)
   (i32.const 201)
  )

Instead of dividing by 2 and then comparing, we can compare the original value.

More variations: add a constant, or both add and multiply/divide.

Found by the superoptimizer https://github.com/WebAssembly/binaryen/pull/4994 (for comparison to other findings: rule #8, benefit 30492).

kripken avatar Sep 02 '22 19:09 kripken

Another example from rule #10:

(i32.lt_s
 (i32.shr_s
  (local.get $0)
  (i32.const 1)
 )
 (i32.const 12)
)
 =->
(i32.lt_s
 (local.get $0)
 (i32.const 24)
)

kripken avatar Sep 02 '22 19:09 kripken

This also happens with floats, though there we may need fast-math, e.g.

(f32.ge
 (f32.add
  (local.get $0)
  (f32.const -9.99999993922529e-09)
 )
 (f32.const 0)
)
 =->
(f32.gt
 (local.get $0)
 (f32.const 9.99999905104687e-09)
)

(rule #21)

kripken avatar Sep 02 '22 19:09 kripken

Another example:

 (i32.gt_u
  (i32.add
   (i32.shr_u
    (local.get $0)
    (i32.const 1)
   )
   (i32.const 8)
  )
  (i32.const 65535)
 )

The add's left operand is less than 32 bits, so it cannot overflow even with an added 8, and so x + 8 >= 65535 can be turned into x >= 65527.

edit: This and related things seem to be the top superoptimizer finding for Java and Dart, followed by https://github.com/WebAssembly/binaryen/issues/5008#issuecomment-1235824896

kripken avatar Sep 06 '22 23:09 kripken

All comparisons <, >=, etc should be handled with +. That leaves things like shifts, and float operations, as mentioned above.

kripken avatar Sep 13 '22 17:09 kripken