Optimize comparisons of adjusted values
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).
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)
)
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)
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
All comparisons <, >=, etc should be handled with +. That leaves things like shifts, and float operations, as mentioned above.