Repository navigation
[OptimizeInstructions] Fix trapOnNull unreachable If - #9339
Conversation
In Binaryen IR, `Ifs` with unreachable conditions are unreachable even if the arms have concrete types, whereas `Block`s keep the concrete type of their final element even when an earlier element is `unreachable`. Unreachable `If`s can validly appear as the reference operand of an instruction like `array.set` or `struct.set`, even if their concrete arms have unrelated types. In `OptimizeInstructions::trapOnNull`, under `--traps-never-happen`, when one arm of an `If` flowed out a null reference, the `If` was replaced with a drop of the condition followed by the other arm. This created invalid IR when the condition was unreachable and the other arm had an unrelated type. Fix the problem by only doing this optimization when the `If` condition is not unreachable.
There was a problem hiding this comment.
Code Review
This pull request prevents the optimization of If instructions when the condition is unreachable to avoid generating invalid intermediate representation, and adds a corresponding test case. The reviewer suggests defensively combining the null check for iff->ifFalse with the condition check instead of using an assertion, which improves robustness against unexpected IR states.
| if (iff->condition->type != Type::unreachable) { | ||
| assert(iff->ifFalse); |
There was a problem hiding this comment.
| if (auto* iff = ref->dynCast<If>()) { | ||
| if (iff->ifFalse) { | ||
| if (iff->condition->type != Type::unreachable) { | ||
| assert(iff->ifFalse); |
There was a problem hiding this comment.
I think I'm missing context here. Why must an if whose condition isn't unreachable have an else? Can't we have an if without an else?
There was a problem hiding this comment.
We know that the If here has a concrete output type because it will flow into some instruction that will do an implicit null check on that output. In Binaryen IR, an If can only have a concrete output type if it has two arms. A single-arm if always has type Type::none or Type::unreachable. (If you tried to have a concrete-typed single-arm If, what value would it produce when the condition is false?)
Notably, Wasm can have concretely typed single-arm ifs when the if takes input parameters that match its results. Binaryen IR doesn't support input parameters, though.
In Binaryen IR,
Ifswith unreachable conditions are unreachable even if the arms have concrete types, whereasBlocks keep the concrete type of their final element even when an earlier element isunreachable. UnreachableIfs can validly appear as the reference operand of an instruction likearray.setorstruct.set, even if their concrete arms have unrelated types.In
OptimizeInstructions::trapOnNull, under--traps-never-happen, when one arm of anIfflowed out a null reference, theIfwas replaced with a drop of the condition followed by the other arm. This created invalid IR when the condition was unreachable and the other arm had an unrelated type. Fix the problem by only doing this optimization when theIfcondition is not unreachable.