Repository navigation
Conversation
Instead of using a single tuple-typed scratch local for multivalue control flow inputs, allocate one scalar scratch local per input value. This avoids eagerly packaging scalar inputs into a tuple on scope entry. It also avoids allocating extra tuple scratch locals to extract elements when inputs are consumed inside the scope. Scalar input locals do have some downsides. Scopes that pass all of their inputs through untouched must now repackage them with tuple.make. Multivalue loop trampolines in fixLoopWithInput also still need a tuple scratch local to unpack branch values into the scalar input locals. However, real parameterized scopes usually consume their inputs as individual values. Scalar input locals can also be coalesced directly by standard local passes without tuple optimization, and they will allow individual parameters to be tunneled across nested scopes with different arities in a future commit.
When entering a nested control flow scope whose input parameters are scratch local.gets from the enclosing scope's inputs, reuse the enclosing scope's scratch locals directly instead of allocating new scratch locals. Share the movement logic in pushScope with moving legacy EH pops into nested unnamed blocks.
There was a problem hiding this comment.
Code Review
This pull request optimizes input parameter handling in IRBuilder::pushScope by allowing pops to move into unnamed blocks and reusing scratch locals from enclosing scopes instead of allocating new ones. It also simplifies pop validation in IRBuilder::makePop and adds comprehensive tests for block tunneling and misplaced pop parse errors. The review feedback points out a critical correctness bug in pushScope where isInputGet fails to verify that the LocalGet index matches the parent local's index, which could trigger an assertion failure or cause incorrect optimization. Additionally, the reviewer suggests wrapping the parameter matching loop in an if (hasInput) block to prevent potential out-of-bounds indexing of Type::none when hasInput is false.
# Conflicts: # src/wasm/wasm-ir-builder.cpp
|
It looks this also contains changes in #9336. Are you going to rebase? |
# Conflicts: # src/wasm/wasm-ir-builder.cpp # test/lit/control-flow-input.wast # test/lit/control-flow-input.wast.wasm
|
Yes, merged latest changes now. |
|
Friendly ping @aheejin |
There was a problem hiding this comment.
-
Can we split the pop handling code and the scratch local tunneling code? They don't share much other than
pushSyntheticat the end, and to me merging the two code paths makes it harder to read. -
Currently this code is accepted without an error:
(module
(tag $e (param i64))
(func $test
try
catch $e
block (param i32) ;; This should error out because the tag type is i64
drop
end
end
)
)- Can we have a test case that tests double tunneling too, so that we can confirm we only create a single scratch local for the below?
(func $block-double-tunnel (result i32)
i32.const 0
block (param i32) (result i32)
block (param i32) (result i32)
block (param i32) (result i32)
end
end
end
)
Yes, this makes things much simpler. Good idea.
Good catch, fixed.
Done, and added some other interesting test cases as well. |
When entering a nested control flow scope whose input parameters are scratch local.gets from the enclosing scope's inputs, reuse the enclosing scope's scratch locals directly instead of allocating new scratch locals. Share the movement logic in pushScope with moving legacy EH pops into nested unnamed blocks.