summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorRoberto Lublinerman <rluble@google.com>2024-05-09 14:05:53 -0700
committerGitHub <noreply@github.com>2024-05-09 14:05:53 -0700
commita816627051c67ae14f6defc8fc5c616ba427a29e (patch)
treec7f861c41915279052667e674d4a7811ea9b7c78 /test
parent712ad9d83953101abec01e5017e306fcb4bf7f70 (diff)
downloadbinaryen-a816627051c67ae14f6defc8fc5c616ba427a29e.tar.gz
binaryen-a816627051c67ae14f6defc8fc5c616ba427a29e.tar.bz2
binaryen-a816627051c67ae14f6defc8fc5c616ba427a29e.zip
[J2Cl] Make J2clOpts more effective with transitive deps in constant intialization (#6571)
Constants that need to be hoisted sometimes are initialized by calling getters of other constants that need to be hoisted. These getters are non-trivial, e.g. (func $getConst1_<once>_@X (result (ref null $A)) (block (result (ref null $A)) (if (i32.eqz (ref.is_null (global.get $$const1@X))) (then (return (global.get $$const1@X)) ) ) (global.set $$const1@X (struct.new $A (i32.const 2))) (global.get $$const1@X) ) (func $getConst2_<once>_@X (result (ref null $A)) (block (result (ref null $A)) (if (i32.eqz (ref.is_null (global.get $$const2@X))) (then (return (global.get $$const2@X)) ) ) (global.set $$const2@X .... expression with (call $getConst1_<once>_@X) ....)) (global.get $$const2@X) ) and can only be simplified after the constants they initialize are hoisted. After the constant is hoisted the getter can be inlined and constants that depend on it for their initialization can now be hoisted. Before this pass, inlining would happen after the pass was run by a subsequent run of the inliner (likely as part of -O3), requiring as many runs of this pass, interleaved with the inliner, as the depth in the call sequence. By having a simpler inliner run as part of the loop in this pass, the pass becomes more effective and more independent of the call depths.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/j2cl-inline.wast4
-rw-r--r--test/lit/passes/j2cl.wast194
2 files changed, 176 insertions, 22 deletions
diff --git a/test/lit/passes/j2cl-inline.wast b/test/lit/passes/j2cl-inline.wast
index 9b6d4127b..9148b5378 100644
--- a/test/lit/passes/j2cl-inline.wast
+++ b/test/lit/passes/j2cl-inline.wast
@@ -1,8 +1,6 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; NOTE: In real world example no-inline would use _<once>_ but there is escaping problem in a multi-platform
-;; way in lit so we are working around it by using no-inline with a different pattern that matches same method.
-;; RUN: foreach %s %t wasm-opt --no-inline=*clinit* --optimize-j2cl --inlining --vacuum --optimize-level=3 -all -S -o - | filecheck %s
+;; RUN: foreach %s %t wasm-opt --optimize-j2cl --vacuum -all -S -o - | filecheck %s
;; Only trivial once functions are inlined
(module
diff --git a/test/lit/passes/j2cl.wast b/test/lit/passes/j2cl.wast
index 50fe807c0..1963203a8 100644
--- a/test/lit/passes/j2cl.wast
+++ b/test/lit/passes/j2cl.wast
@@ -152,22 +152,23 @@
)
)
-
+;; Getters are transitively inlined and their constants hoisted.
(module
;; CHECK: (type $0 (func (result i32)))
- ;; CHECK: (global $$var2@Zoo (mut i32) (i32.const 0))
+ ;; CHECK: (global $$var3@Zoo i32 (i32.const 2))
+
+ ;; CHECK: (global $$var2@Zoo i32 (i32.const 2))
;; CHECK: (global $$var1@Zoo i32 (i32.const 2))
(global $$var1@Zoo (mut i32) (i32.const 0))
(global $$var2@Zoo (mut i32) (i32.const 0))
-
- ;; CHECK: (export "getVar1_<once>_@Zoo" (func $getVar1_<once>_@Zoo))
+ (global $$var3@Zoo (mut i32) (i32.const 0))
;; CHECK: (func $getVar1_<once>_@Zoo (type $0) (result i32)
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
- (func $getVar1_<once>_@Zoo (export "getVar1_<once>_@Zoo") (result i32)
+ (func $getVar1_<once>_@Zoo (result i32)
(if (global.get $$var1@Zoo)
(then
(return (global.get $$var1@Zoo))
@@ -178,20 +179,7 @@
)
;; CHECK: (func $getVar2_<once>_@Zoo (type $0) (result i32)
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (global.get $$var2@Zoo)
- ;; CHECK-NEXT: (then
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (global.get $$var2@Zoo)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (global.set $$var2@Zoo
- ;; CHECK-NEXT: (call $getVar1_<once>_@Zoo)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (global.get $$var2@Zoo)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
(func $getVar2_<once>_@Zoo (result i32)
(if (global.get $$var2@Zoo)
@@ -202,4 +190,172 @@
(global.set $$var2@Zoo (call $getVar1_<once>_@Zoo))
(return (global.get $$var2@Zoo))
)
+
+ ;; CHECK: (func $getVar3_<once>_@Zoo (type $0) (result i32)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ (func $getVar3_<once>_@Zoo (result i32)
+ (if (global.get $$var3@Zoo)
+ (then
+ (return (global.get $$var3@Zoo))
+ )
+ )
+ (global.set $$var3@Zoo (call $getVar2_<once>_@Zoo))
+ (return (global.get $$var3@Zoo))
+ )
+)
+
+;; Simple once functions are inlined
+(module
+ ;; CHECK: (type $0 (func))
+
+ ;; CHECK: (type $1 (func (result i32)))
+
+ ;; CHECK: (global $$var2@Zoo (mut i32) (i32.const 3))
+
+ ;; CHECK: (global $$var1@Zoo (mut i32) (i32.const 2))
+ (global $$var1@Zoo (mut i32) (i32.const 2))
+ (global $$var2@Zoo (mut i32) (i32.const 3))
+
+
+ ;; CHECK: (func $notOnceFunction@Zoo (type $0)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $notOnceFunction@Zoo
+ )
+
+ ;; CHECK: (func $nop_<once>_@Zoo (type $0)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $nop_<once>_@Zoo
+ (nop)
+ )
+
+ ;; CHECK: (func $empty_<once>_@Zoo (type $0)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $empty_<once>_@Zoo
+ )
+
+ ;; CHECK: (func $simpleCall_<once>_@Zoo (type $0)
+ ;; CHECK-NEXT: (call $notOnceFunction@Zoo)
+ ;; CHECK-NEXT: )
+ (func $simpleCall_<once>_@Zoo
+ (call $notOnceFunction@Zoo)
+ )
+
+ ;; CHECK: (func $globalGet_<once>_@Zoo (type $1) (result i32)
+ ;; CHECK-NEXT: (global.get $$var1@Zoo)
+ ;; CHECK-NEXT: )
+ (func $globalGet_<once>_@Zoo (result i32)
+ (global.get $$var1@Zoo)
+ )
+
+ ;; CHECK: (func $globalSet_<once>_@Zoo (type $0)
+ ;; CHECK-NEXT: (global.set $$var2@Zoo
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $globalSet_<once>_@Zoo
+ (global.set $$var2@Zoo (i32.const 3))
+ )
+
+ ;; CHECK: (func $caller_@Zoo (type $1) (result i32)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: (call $notOnceFunction@Zoo)
+ ;; CHECK-NEXT: (global.set $$var2@Zoo
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (global.get $$var1@Zoo)
+ ;; CHECK-NEXT: )
+ (func $caller_@Zoo (result i32)
+ (call $nop_<once>_@Zoo)
+ (call $empty_<once>_@Zoo)
+ (call $simpleCall_<once>_@Zoo)
+ (call $globalSet_<once>_@Zoo)
+ (call $globalGet_<once>_@Zoo)
+ )
+)
+
+;; Simple once functions that would be inlined if cleaned up.
+(module
+ ;; CHECK: (type $0 (func (result i32)))
+
+ ;; CHECK: (type $1 (func))
+
+ ;; CHECK: (global $$var1@Zoo (mut i32) (i32.const 2))
+ (global $$var1@Zoo (mut i32) (i32.const 2))
+
+
+ ;; CHECK: (func $justReturn_<once>_@Zoo (type $1)
+ ;; CHECK-NEXT: (return)
+ ;; CHECK-NEXT: )
+ (func $justReturn_<once>_@Zoo
+ (return)
+ )
+
+ ;; CHECK: (func $returnGlobalGet_<once>_@Zoo (type $0) (result i32)
+ ;; CHECK-NEXT: (return
+ ;; CHECK-NEXT: (global.get $$var1@Zoo)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $returnGlobalGet_<once>_@Zoo (result i32)
+ (return (global.get $$var1@Zoo))
+ )
+
+ ;; CHECK: (func $caller_@Zoo (type $0) (result i32)
+ ;; CHECK-NEXT: (call $justReturn_<once>_@Zoo)
+ ;; CHECK-NEXT: (call $returnGlobalGet_<once>_@Zoo)
+ ;; CHECK-NEXT: )
+ (func $caller_@Zoo (result i32)
+ (call $justReturn_<once>_@Zoo)
+ (call $returnGlobalGet_<once>_@Zoo)
+ )
+)
+
+;; Hoist constants for getters that have transitive dependencies.
+(module
+ ;; CHECK: (type $A (struct (field i32)))
+ (type $A (struct (field i32)))
+
+ ;; CHECK: (type $1 (func (result (ref null $A))))
+
+ ;; CHECK: (global $$class@X (ref null $A) (struct.new $A
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: ))
+ (global $$class@X (mut (ref null $A)) (ref.null $A))
+ ;; CHECK: (global $$class@Y (ref null $A) (global.get $$class@X))
+ (global $$class@Y (mut (ref null $A)) (ref.null $A))
+
+ ;; CHECK: (func $f_<once>_@X (type $1) (result (ref null $A))
+ ;; CHECK-NEXT: (global.get $$class@X)
+ ;; CHECK-NEXT: )
+ (func $f_<once>_@X (result (ref null $A))
+ (block (result (ref null $A))
+ (if (i32.eqz (ref.is_null (global.get $$class@X)))
+ (then
+ (return (global.get $$class@X))
+ )
+ )
+ (global.set $$class@X (struct.new $A (i32.const 2)))
+ (global.get $$class@X)
+ )
+ )
+
+ ;; CHECK: (func $f_<once>_@Y (type $1) (result (ref null $A))
+ ;; CHECK-NEXT: (global.get $$class@Y)
+ ;; CHECK-NEXT: )
+ (func $f_<once>_@Y (result (ref null $A))
+ (block (result (ref null $A))
+ (if
+ (i32.eqz (ref.is_null (global.get $$class@Y)))
+ (then
+ (return (global.get $$class@Y))
+ )
+ )
+ (global.set $$class@Y (call $f_<once>_@X))
+ (global.get $$class@Y)
+ )
+ )
)