summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-12-05 12:41:21 -0800
committerGitHub <noreply@github.com>2023-12-05 12:41:21 -0800
commit66277f9b767cb1b45ce12b77109c2538b6cb9c12 (patch)
tree31dc89d2894fdd8805ba6b1e8db11aa3b6703555 /test
parent42cddbf88ebe74d17490e2dd13826e6da9104b15 (diff)
downloadbinaryen-66277f9b767cb1b45ce12b77109c2538b6cb9c12.tar.gz
binaryen-66277f9b767cb1b45ce12b77109c2538b6cb9c12.tar.bz2
binaryen-66277f9b767cb1b45ce12b77109c2538b6cb9c12.zip
Inlining: Inline trivial calls (#6143)
A trivial call is something like a function that just calls another immediately, function foo(x, y) { return bar(y, 15); } We can inline those and expect to benefit in most cases, though we might increase code size slightly. Hence it makes sense to inline such cases, even though in general we are careful and do not inline functions with calls in them; a "trampoline" like that likely has most of the work in the call itself, which we can avoid by inlining. Suggested based on findings in Java.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/inlining-optimizing_optimize-level=3.wast19
-rw-r--r--test/lit/passes/inlining_optimize-level=3.wast155
2 files changed, 161 insertions, 13 deletions
diff --git a/test/lit/passes/inlining-optimizing_optimize-level=3.wast b/test/lit/passes/inlining-optimizing_optimize-level=3.wast
index fd646d5b4..a44429688 100644
--- a/test/lit/passes/inlining-optimizing_optimize-level=3.wast
+++ b/test/lit/passes/inlining-optimizing_optimize-level=3.wast
@@ -16,10 +16,10 @@
;; CHECK: (type $FUNCSIG$i (func (result i32)))
- ;; CHECK: (type $5 (func (param i32 i32 i32 i32) (result i32)))
-
;; CHECK: (type $FUNCSIG$vii (func (param i32 i32)))
+ ;; CHECK: (type $6 (func (param i32 i32 i32 i32) (result i32)))
+
;; CHECK: (type $FUNCSIG$v (func))
(type $FUNCSIG$v (func))
(type $FUNCSIG$i (func (result i32)))
@@ -6487,11 +6487,12 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $12
- ;; CHECK-NEXT: (call $___udivdi3
+ ;; CHECK-NEXT: (call $___udivmoddi4
;; CHECK-NEXT: (local.get $12)
;; CHECK-NEXT: (local.get $20)
;; CHECK-NEXT: (i32.const 1000000000)
;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br_if $while-in66
@@ -14813,11 +14814,12 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
- ;; CHECK-NEXT: (call $___udivdi3
+ ;; CHECK-NEXT: (call $___udivmoddi4
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
@@ -30696,15 +30698,6 @@
)
(local.get $3)
)
- ;; CHECK: (func $___udivdi3 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
- ;; CHECK-NEXT: (call $___udivmoddi4
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
(func $___udivdi3 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
(call $___udivmoddi4
(local.get $0)
diff --git a/test/lit/passes/inlining_optimize-level=3.wast b/test/lit/passes/inlining_optimize-level=3.wast
index b993137c1..c03f7f117 100644
--- a/test/lit/passes/inlining_optimize-level=3.wast
+++ b/test/lit/passes/inlining_optimize-level=3.wast
@@ -563,3 +563,158 @@
(unreachable)
)
)
+
+;; Inlining of trivial calls in the middle.
+(module
+ (table 10 funcref)
+
+ ;; Refer to the middle functions so that we do not inline them as single-use
+ ;; functions (which would be a trivial case, not related to trivial calls).
+ (elem (i32.const 0) $middle1 $middle2 $middle3)
+
+ ;; CHECK: (type $0 (func (param i32 i32 i32)))
+
+ ;; CHECK: (type $1 (func))
+
+ ;; CHECK: (table $0 10 funcref)
+
+ ;; CHECK: (elem $0 (i32.const 0) $middle1 $middle2 $middle3)
+
+ ;; CHECK: (func $top (param $x i32) (param $y i32) (param $z i32)
+ ;; CHECK-NEXT: (loop $loop
+ ;; CHECK-NEXT: (br $loop)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $top (param $x i32) (param $y i32) (param $z i32)
+ ;; This top function will not be inlined.
+ (loop $loop
+ (br $loop)
+ )
+ ;; Add to the size so it isn't inlined as a tiny function.
+ (nop)
+ (nop)
+ )
+
+ ;; CHECK: (func $middle1 (param $x i32) (param $y i32) (param $z i32)
+ ;; CHECK-NEXT: (call $top
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (local.get $z)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $middle1 (param $x i32) (param $y i32) (param $z i32)
+ ;; This function is a trivial call, which we can inline to the bottom.
+ (call $top
+ (local.get $x)
+ (local.get $y)
+ (local.get $z)
+ )
+ )
+
+ ;; CHECK: (func $middle2 (param $x i32) (param $y i32) (param $z i32)
+ ;; CHECK-NEXT: (call $top
+ ;; CHECK-NEXT: (local.get $z)
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $middle2 (param $x i32) (param $y i32) (param $z i32)
+ ;; Also trivial, even though the order of params is different and we have a
+ ;; const.
+ (call $top
+ (local.get $z)
+ (i32.const 42)
+ (local.get $x)
+ )
+ )
+
+ ;; CHECK: (func $middle3 (param $x i32) (param $y i32) (param $z i32)
+ ;; CHECK-NEXT: (call $top
+ ;; CHECK-NEXT: (local.get $z)
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $middle3 (param $x i32) (param $y i32) (param $z i32)
+ ;; Not trivial, becaues of the eqz.
+ (call $top
+ (local.get $z)
+ (i32.eqz
+ (i32.const 42)
+ )
+ (local.get $x)
+ )
+ )
+
+ ;; CHECK: (func $bottom
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (local $4 i32)
+ ;; CHECK-NEXT: (local $5 i32)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block $__inlined_func$middle1
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $top
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block $__inlined_func$middle2$1
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $4
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $5
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $top
+ ;; CHECK-NEXT: (local.get $5)
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $middle3
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $bottom
+ ;; The first two will be inlined.
+ (call $middle1
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ )
+ (call $middle2
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ )
+ (call $middle3
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+)