binaryen
binaryen copied to clipboard
Code motion with the same side effects in branches does not always work
It seems CodeFolding can't handle such case with side effects (division):
export function not_branchless_ceil_div(x: i32, y: i32): i32 {
return x >= 0 ? x / y : (x + y - 1) / y;
}
export function branchless_ceil_div(x: i32, y: i32): i32 {
return (x >= 0 ? x : x + y - 1) / y;
}
Which output:
(module
(func (export "not_branchless_ceil_div") $a (param $0 i32) (param $1 i32) (result i32)
local.get $0
i32.const 0
i32.ge_s
if (result i32)
local.get $0
local.get $1
i32.div_s
else
local.get $0
local.get $1
i32.add
i32.const 1
i32.sub
local.get $1
i32.div_s
end
)
(func (export "branchless_ceil_div") $b (param $0 i32) (param $1 i32) (result i32)
local.get $0
local.get $0
local.get $1
i32.add
i32.const 1
i32.sub
local.get $0
i32.const 0
i32.ge_s
select
local.get $1
i32.div_s
)
)
But with CodeFolding both code should be identically branchless.
Thought?
(The "branchless" option still has ? : so it has a branch?)
I think the /y could be merged, that is true. CodeFolding might not be the pass that does it, though - OptimizeInstructions has logic for that, see the optimizeTernary function (see comment Identical code on both arms can be folded out).
But optimizeTernary only applies for select which can't be produced by selectify due to side effect (division). That's why I think it should be done by CodeFolding pass which operate on block-level
optimizeTernary can run on both select and if.
Ah, now I see. Thanks! Will create a PR