forked from WebAssembly/binaryen
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix global effect computation with -O flags (WebAssembly#6211)
We tested --generate-global-effects --vacuum and such, but not --generate-global-effects -O3 or the other -O flags. Unfortunately, our targeted testing missed a bug because of that. Specifically, we have special logic for -O flags to make sure the passes they expand into run with the proper opt and shrink levels, but that logic happened to also interfere with global effect computation. It would also interfere with allowing GUFA info or other things to be stored on the side, which we've proposed. This PR fixes that + future issues. The fix is to just allow a pass runner to execute more than once. We thought to avoid that and assert against it to keep the model "hermetic" (you create a pass runner, you run the passes, and you throw it out), which feels nice in a way, but it led to the bug here, and I'm not sure it would prevent any other ones really. It is also more code. It is simpler to allow a runner to execute more than once, and add a method to clear it. With that, the logic for -O3 execution is both simpler and does not interfere with anything but the opt and shrink level flags: we create a single runner, give it the proper options, and then keep using that runner + those options as we go, normally.
- Loading branch information
1 parent
a11727f
commit 8f12e5f
Showing
4 changed files
with
229 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. | ||
|
||
;; RUN: foreach %s %t wasm-opt -all -S -o - --generate-global-effects | filecheck %s --check-prefix CHECK_0 | ||
;; RUN: foreach %s %t wasm-opt -all -S -o - --generate-global-effects -O1 | filecheck %s --check-prefix CHECK_1 | ||
;; RUN: foreach %s %t wasm-opt -all -S -o - --generate-global-effects -O3 | filecheck %s --check-prefix CHECK_3 | ||
;; RUN: foreach %s %t wasm-opt -all -S -o - --generate-global-effects -Os | filecheck %s --check-prefix CHECK_s | ||
;; RUN: foreach %s %t wasm-opt -all -S -o - --generate-global-effects -O | filecheck %s --check-prefix CHECK_O | ||
|
||
;; Test that global effects benefit -O1 and related modes. | ||
|
||
(module | ||
;; CHECK_0: (type $0 (func)) | ||
|
||
;; CHECK_0: (type $1 (func (result i32))) | ||
|
||
;; CHECK_0: (export "main" (func $main)) | ||
;; CHECK_1: (type $0 (func)) | ||
|
||
;; CHECK_1: (type $1 (func (result i32))) | ||
|
||
;; CHECK_1: (export "main" (func $main)) | ||
;; CHECK_3: (type $0 (func)) | ||
|
||
;; CHECK_3: (type $1 (func (result i32))) | ||
|
||
;; CHECK_3: (export "main" (func $main)) | ||
;; CHECK_s: (type $0 (func)) | ||
|
||
;; CHECK_s: (type $1 (func (result i32))) | ||
|
||
;; CHECK_s: (export "main" (func $main)) | ||
;; CHECK_O: (type $0 (func)) | ||
|
||
;; CHECK_O: (type $1 (func (result i32))) | ||
|
||
;; CHECK_O: (export "main" (func $main)) | ||
(export "main" (func $main)) | ||
|
||
;; CHECK_0: (export "pointless-work" (func $pointless-work)) | ||
;; CHECK_1: (export "pointless-work" (func $pointless-work)) | ||
;; CHECK_3: (export "pointless-work" (func $pointless-work)) | ||
;; CHECK_s: (export "pointless-work" (func $pointless-work)) | ||
;; CHECK_O: (export "pointless-work" (func $pointless-work)) | ||
(export "pointless-work" (func $pointless-work)) | ||
|
||
;; CHECK_0: (func $main (type $0) | ||
;; CHECK_0-NEXT: (if | ||
;; CHECK_0-NEXT: (call $pointless-work) | ||
;; CHECK_0-NEXT: (then | ||
;; CHECK_0-NEXT: (drop | ||
;; CHECK_0-NEXT: (call $pointless-work) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_1: (func $main (type $0) | ||
;; CHECK_1-NEXT: (nop) | ||
;; CHECK_1-NEXT: ) | ||
;; CHECK_3: (func $main (type $0) (; has Stack IR ;) | ||
;; CHECK_3-NEXT: (nop) | ||
;; CHECK_3-NEXT: ) | ||
;; CHECK_s: (func $main (type $0) (; has Stack IR ;) | ||
;; CHECK_s-NEXT: (nop) | ||
;; CHECK_s-NEXT: ) | ||
;; CHECK_O: (func $main (type $0) (; has Stack IR ;) | ||
;; CHECK_O-NEXT: (nop) | ||
;; CHECK_O-NEXT: ) | ||
(func $main | ||
;; This calls a function that does pointless work. After generating global | ||
;; effects we can see that it is pointless and remove this entire if (except | ||
;; for -O0). | ||
(if | ||
(call $pointless-work) | ||
(then | ||
(drop | ||
(call $pointless-work) | ||
) | ||
) | ||
) | ||
) | ||
|
||
;; CHECK_0: (func $pointless-work (type $1) (result i32) | ||
;; CHECK_0-NEXT: (local $x i32) | ||
;; CHECK_0-NEXT: (loop $loop | ||
;; CHECK_0-NEXT: (local.set $x | ||
;; CHECK_0-NEXT: (i32.add | ||
;; CHECK_0-NEXT: (local.get $x) | ||
;; CHECK_0-NEXT: (i32.const 1) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: (if | ||
;; CHECK_0-NEXT: (i32.ge_u | ||
;; CHECK_0-NEXT: (local.get $x) | ||
;; CHECK_0-NEXT: (i32.const 12345678) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: (then | ||
;; CHECK_0-NEXT: (return | ||
;; CHECK_0-NEXT: (local.get $x) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: (br $loop) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_0-NEXT: ) | ||
;; CHECK_1: (func $pointless-work (type $1) (result i32) | ||
;; CHECK_1-NEXT: (local $0 i32) | ||
;; CHECK_1-NEXT: (loop $loop (result i32) | ||
;; CHECK_1-NEXT: (br_if $loop | ||
;; CHECK_1-NEXT: (i32.lt_u | ||
;; CHECK_1-NEXT: (local.tee $0 | ||
;; CHECK_1-NEXT: (i32.add | ||
;; CHECK_1-NEXT: (local.get $0) | ||
;; CHECK_1-NEXT: (i32.const 1) | ||
;; CHECK_1-NEXT: ) | ||
;; CHECK_1-NEXT: ) | ||
;; CHECK_1-NEXT: (i32.const 12345678) | ||
;; CHECK_1-NEXT: ) | ||
;; CHECK_1-NEXT: ) | ||
;; CHECK_1-NEXT: (local.get $0) | ||
;; CHECK_1-NEXT: ) | ||
;; CHECK_1-NEXT: ) | ||
;; CHECK_3: (func $pointless-work (type $1) (; has Stack IR ;) (result i32) | ||
;; CHECK_3-NEXT: (local $0 i32) | ||
;; CHECK_3-NEXT: (loop $loop (result i32) | ||
;; CHECK_3-NEXT: (br_if $loop | ||
;; CHECK_3-NEXT: (i32.lt_u | ||
;; CHECK_3-NEXT: (local.tee $0 | ||
;; CHECK_3-NEXT: (i32.add | ||
;; CHECK_3-NEXT: (local.get $0) | ||
;; CHECK_3-NEXT: (i32.const 1) | ||
;; CHECK_3-NEXT: ) | ||
;; CHECK_3-NEXT: ) | ||
;; CHECK_3-NEXT: (i32.const 12345678) | ||
;; CHECK_3-NEXT: ) | ||
;; CHECK_3-NEXT: ) | ||
;; CHECK_3-NEXT: (local.get $0) | ||
;; CHECK_3-NEXT: ) | ||
;; CHECK_3-NEXT: ) | ||
;; CHECK_s: (func $pointless-work (type $1) (; has Stack IR ;) (result i32) | ||
;; CHECK_s-NEXT: (local $0 i32) | ||
;; CHECK_s-NEXT: (loop $loop (result i32) | ||
;; CHECK_s-NEXT: (br_if $loop | ||
;; CHECK_s-NEXT: (i32.lt_u | ||
;; CHECK_s-NEXT: (local.tee $0 | ||
;; CHECK_s-NEXT: (i32.add | ||
;; CHECK_s-NEXT: (local.get $0) | ||
;; CHECK_s-NEXT: (i32.const 1) | ||
;; CHECK_s-NEXT: ) | ||
;; CHECK_s-NEXT: ) | ||
;; CHECK_s-NEXT: (i32.const 12345678) | ||
;; CHECK_s-NEXT: ) | ||
;; CHECK_s-NEXT: ) | ||
;; CHECK_s-NEXT: (local.get $0) | ||
;; CHECK_s-NEXT: ) | ||
;; CHECK_s-NEXT: ) | ||
;; CHECK_O: (func $pointless-work (type $1) (; has Stack IR ;) (result i32) | ||
;; CHECK_O-NEXT: (local $0 i32) | ||
;; CHECK_O-NEXT: (loop $loop (result i32) | ||
;; CHECK_O-NEXT: (br_if $loop | ||
;; CHECK_O-NEXT: (i32.lt_u | ||
;; CHECK_O-NEXT: (local.tee $0 | ||
;; CHECK_O-NEXT: (i32.add | ||
;; CHECK_O-NEXT: (local.get $0) | ||
;; CHECK_O-NEXT: (i32.const 1) | ||
;; CHECK_O-NEXT: ) | ||
;; CHECK_O-NEXT: ) | ||
;; CHECK_O-NEXT: (i32.const 12345678) | ||
;; CHECK_O-NEXT: ) | ||
;; CHECK_O-NEXT: ) | ||
;; CHECK_O-NEXT: (local.get $0) | ||
;; CHECK_O-NEXT: ) | ||
;; CHECK_O-NEXT: ) | ||
(func $pointless-work (result i32) | ||
(local $x i32) | ||
;; Some pointless work, with no side effects, that cannot be inlined. (The | ||
;; changes here are not important for this test.) | ||
(loop $loop | ||
(local.set $x | ||
(i32.add | ||
(local.get $x) | ||
(i32.const 1) | ||
) | ||
) | ||
(if | ||
(i32.ge_u | ||
(local.get $x) | ||
(i32.const 12345678) | ||
) | ||
(then | ||
(return | ||
(local.get $x) | ||
) | ||
) | ||
) | ||
(br $loop) | ||
) | ||
) | ||
) |