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