Skip to content

[IRBuilder] Tunnel block inputs into nested scopes - #9337

Open
tlively wants to merge 11 commits into
mainfrom
ir-builder-tunnel-params
Open

tlively wants to merge 11 commits into
mainfrom
ir-builder-tunnel-params

Conversation

@tlively

@tlively tlively commented Nov 1, 2026

Copy link
Copy Markdown
Member

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.

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.
@tlively
tlively requested a review from a team as a code owner November 1, 2026 07:30
@tlively
tlively requested review from aheejin and removed request for a team November 1, 2026 07:30

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/wasm/wasm-ir-builder.cpp Resolved

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Google Antigravity Code Review

I have reviewed the changes in this Pull Request and left inline feedback.

Comment thread src/wasm/wasm-ir-builder.cpp Resolved
Comment thread src/wasm/wasm-ir-builder.cpp Resolved
Base automatically changed from ir-builder-input-locals to main November 3, 2026 19:39
@aheejin

aheejin commented Nov 4, 2026

Copy link
Copy Markdown
Member

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
@tlively

tlively commented Nov 5, 2026

Copy link
Copy Markdown
Member Author

Yes, merged latest changes now.

@tlively

tlively commented Nov 6, 2026

Copy link
Copy Markdown
Member Author

Friendly ping @aheejin

@aheejin aheejin left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Can we split the pop handling code and the scratch local tunneling code? They don't share much other than pushSynthetic at the end, and to me merging the two code paths makes it harder to read.

  2. 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
  )
)
  1. 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                                                                                                                                                                                                                             
)    

@tlively

tlively commented Nov 11, 2026

Copy link
Copy Markdown
Member Author
  1. Can we split the pop handling code and the scratch local tunneling code? They don't share much other than pushSynthetic at the end, and to me merging the two code paths makes it harder to read.

Yes, this makes things much simpler. Good idea.

  1. 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
    )
    )

Good catch, fixed.

  1. 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
)

Done, and added some other interesting test cases as well.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants