-
Notifications
You must be signed in to change notification settings - Fork 837
OnceReduction: Optimize idempotent functions #8369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3d7a3ac
3b2faa5
3747c0e
360e531
31834a4
18a545c
23be382
be17f9c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. | ||
| ;; RUN: foreach %s %t wasm-opt --once-reduction -all -S -o - | filecheck %s | ||
|
|
||
| (module | ||
| ;; CHECK: (type $0 (func)) | ||
|
|
||
| ;; CHECK: (import "a" "b" (func $import (type $0))) | ||
| (import "a" "b" (func $import)) | ||
|
|
||
| ;; CHECK: (@binaryen.idempotent) | ||
| ;; CHECK-NEXT: (func $idempotent (type $0) | ||
| ;; CHECK-NEXT: (call $import) | ||
| ;; CHECK-NEXT: ) | ||
| (@binaryen.idempotent) | ||
| (func $idempotent | ||
| ;; This function has side effects, but is marked idempotent. | ||
| (call $import) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $potent (type $0) | ||
| ;; CHECK-NEXT: (call $import) | ||
| ;; CHECK-NEXT: ) | ||
| (func $potent | ||
| ;; As above, but not marked as idempotent. | ||
| (call $import) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $basics (type $0) | ||
| ;; CHECK-NEXT: (call $idempotent) | ||
| ;; CHECK-NEXT: (nop) | ||
| ;; CHECK-NEXT: (call $potent) | ||
| ;; CHECK-NEXT: (call $potent) | ||
| ;; CHECK-NEXT: ) | ||
| (func $basics | ||
| ;; We can optimize here, using idempotency. The second call goes away. | ||
| (call $idempotent) | ||
| (call $idempotent) | ||
|
|
||
| ;; We can't optimize here. | ||
| (call $potent) | ||
| (call $potent) | ||
| ) | ||
|
|
||
| ;; CHECK: (@binaryen.idempotent) | ||
| ;; CHECK-NEXT: (func $idempotent2 (type $0) | ||
| ;; CHECK-NEXT: (call $import) | ||
| ;; CHECK-NEXT: ) | ||
| (@binaryen.idempotent) | ||
| (func $idempotent2 | ||
| ;; A second idempotent function. | ||
| (call $import) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $mix (type $0) | ||
| ;; CHECK-NEXT: (call $idempotent) | ||
| ;; CHECK-NEXT: (call $idempotent2) | ||
| ;; CHECK-NEXT: ) | ||
| (func $mix | ||
| ;; We can't optimize here: these are idempotent, but different. | ||
| (call $idempotent) | ||
| (call $idempotent2) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $mix2 (type $0) | ||
| ;; CHECK-NEXT: (call $idempotent2) | ||
| ;; CHECK-NEXT: (call $idempotent) | ||
| ;; CHECK-NEXT: ) | ||
| (func $mix2 | ||
| ;; As above, reverse order. We can't optimize here. | ||
| (call $idempotent2) | ||
| (call $idempotent) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $mix3 (type $0) | ||
| ;; CHECK-NEXT: (call $idempotent) | ||
| ;; CHECK-NEXT: (call $idempotent2) | ||
| ;; CHECK-NEXT: (nop) | ||
| ;; CHECK-NEXT: (nop) | ||
| ;; CHECK-NEXT: (nop) | ||
| ;; CHECK-NEXT: (nop) | ||
| ;; CHECK-NEXT: ) | ||
| (func $mix3 | ||
| (call $idempotent) | ||
| (call $idempotent2) | ||
|
|
||
| ;; We can remove both of these second calls. | ||
| (call $idempotent) | ||
| (call $idempotent2) | ||
|
Comment on lines
+86
to
+88
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I commented on the discussion to get feedback:
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.) |
||
|
|
||
| ;; These as well, which are reordered. | ||
| (call $idempotent2) | ||
| (call $idempotent) | ||
| ) | ||
| ) | ||
|
|
||
| (module | ||
| ;; CHECK: (type $0 (func)) | ||
|
|
||
| ;; CHECK: (type $1 (func (param i32))) | ||
|
|
||
| ;; CHECK: (import "a" "b" (func $import (type $0))) | ||
| (import "a" "b" (func $import)) | ||
|
|
||
| ;; CHECK: (@binaryen.idempotent) | ||
| ;; CHECK-NEXT: (func $idempotent (type $1) (param $x i32) | ||
| ;; CHECK-NEXT: (call $import) | ||
| ;; CHECK-NEXT: ) | ||
| (@binaryen.idempotent) | ||
| (func $idempotent (param $x i32) | ||
| ;; As above, but now with a param. | ||
| (call $import) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $basics (type $0) | ||
| ;; CHECK-NEXT: (call $idempotent | ||
| ;; CHECK-NEXT: (i32.const 10) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (call $idempotent | ||
| ;; CHECK-NEXT: (i32.const 10) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: ) | ||
| (func $basics | ||
| ;; We could optimize here in theory, but the pass does not handle params | ||
| ;; yet. It could compare them for equality, check generativity, etc. | ||
| (call $idempotent (i32.const 10)) | ||
| (call $idempotent (i32.const 10)) | ||
| ) | ||
| ) | ||
|
|
||
| (module | ||
| ;; CHECK: (type $0 (func)) | ||
|
|
||
| ;; CHECK: (type $1 (func (result i32))) | ||
|
|
||
| ;; CHECK: (import "a" "b" (func $import (type $0))) | ||
| (import "a" "b" (func $import)) | ||
|
|
||
| ;; CHECK: (@binaryen.idempotent) | ||
| ;; CHECK-NEXT: (func $idempotent (type $1) (result i32) | ||
| ;; CHECK-NEXT: (call $import) | ||
| ;; CHECK-NEXT: (i32.const 42) | ||
| ;; CHECK-NEXT: ) | ||
| (@binaryen.idempotent) | ||
| (func $idempotent (result i32) | ||
| ;; As above, but now with a result. | ||
| (call $import) | ||
| (i32.const 42) | ||
| ) | ||
|
|
||
| ;; CHECK: (func $basics (type $0) | ||
| ;; CHECK-NEXT: (drop | ||
| ;; CHECK-NEXT: (call $idempotent) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (drop | ||
| ;; CHECK-NEXT: (call $idempotent) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: ) | ||
| (func $basics | ||
| ;; We could optimize here in theory, but the pass does not handle results | ||
| ;; yet. | ||
| (drop | ||
| (call $idempotent) | ||
| ) | ||
| (drop | ||
| (call $idempotent) | ||
| ) | ||
| ) | ||
| ) | ||
There was a problem hiding this comment.
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.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, done.