Skip to content

OnceReduction: Optimize idempotent functions#8369

Merged
kripken merged 8 commits intoWebAssembly:mainfrom
kripken:idempotent.once
Feb 25, 2026
Merged

OnceReduction: Optimize idempotent functions#8369
kripken merged 8 commits intoWebAssembly:mainfrom
kripken:idempotent.once

Conversation

@kripken
Copy link
Member

@kripken kripken commented Feb 24, 2026

OnceReduction finds functions that execute once, then removes later
calls to them,

initJavaClass();
initJavaClass();

=>

initJavaClass();
; // optimized out

This PR makes it do the same for idempotent-marked calls.

So far this only handles the simple case of no params or results.

@kripken kripken requested a review from tlively February 24, 2026 18:27
Copy link
Member

@tlively tlively left a comment

Choose a reason for hiding this comment

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

I wonder how complicated it would be to do a proper interprocedural control flow analysis that would let us find all idempotent operations (e.g. idempotent function calls, sets of globals that are only ever set to a single value, etc.) dominated by previous copies of the same operation. That would let us uniformly optimize all the idempotent operations we could want without special-casing "once" functions or being limited to single basic blocks.

Comment on lines +85 to +90
// When we see an idempotent-marked function, which as mentioned above is
// effectively "once" but does not have an explicit global controlling it, we
// create a fake global name for it to use here. That gives each function we
// can optimize a unique global name for our optimizer to track. That is, the
// global name is a real global for ones we found a global for, and for
// idempotent functions, it is a unique name that is not an actual global.
Copy link
Member

Choose a reason for hiding this comment

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

As a drive-by, it might be nice to rename this to onceFuncGlobals, since the values are globals.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea, done.

Comment on lines +86 to +88
;; We can remove both of these second calls.
(call $idempotent)
(call $idempotent2)
Copy link
Member

Choose a reason for hiding this comment

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

It's not clear to me that we should allow removing calls to idempotent functions when there are arbitrary side effects between the calls and their preceding calls. For example, gcc's pure annotation does not allow optimization when there are intervening side effects.

Copy link
Member Author

Choose a reason for hiding this comment

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

I commented on the discussion to get feedback:

#7574 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

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

If we can't optimize like this, then the OnceReduction pass may not be the right place to do this, as "once" functions can be optimized in this way.

Copy link
Member Author

Choose a reason for hiding this comment

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

I added a comment to clarify that in the linked discussion we are leaning towards allowing this optimization.

(We can reconsider later if this is a problem, and perhaps add a parameter to this intrinsic, as both use cases might matter.)

@kripken
Copy link
Member Author

kripken commented Feb 24, 2026

I wonder how complicated it would be to do a proper interprocedural control flow analysis that would let us find all idempotent operations (e.g. idempotent function calls, sets of globals that are only ever set to a single value, etc.) dominated by previous copies of the same operation. That would let us uniformly optimize all the idempotent operations we could want without special-casing "once" functions or being limited to single basic blocks.

OnceReduction already does that: it uses a DomTree to find all dominated second calls, and removes them.

Maybe you're thinking of LocalCSE which is limited to a single basic block? It is worth improving that one.

@kripken kripken merged commit 72cd1b3 into WebAssembly:main Feb 25, 2026
17 checks passed
@kripken kripken deleted the idempotent.once branch February 25, 2026 19:26
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