blob: 4db5d7aec83ccfc9f3ee21f30343b88b3fba064f [file] [log] [blame]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt --inlining --optimize-level=3 --partial-inlining-ifs=4 --all-features -S -o - | filecheck %s
(module
;; CHECK: (type $func.0 (func))
;; CHECK: (type $func.1 (func (param i32)))
;; CHECK: (type $func.2 (func (param anyref) (result anyref)))
;; CHECK: (type $func.3 (func (param anyref)))
;; CHECK: (type $struct (struct))
(type $struct (struct))
;; CHECK: (type $func.4 (func (param i32 (rtt $struct))))
;; CHECK: (type $func.5 (func (param i64 i32 f64)))
;; CHECK: (import "out" "func" (func $import))
(import "out" "func" (func $import))
;; CHECK: (global $glob i32 (i32.const 1))
(global $glob i32 (i32.const 1))
;; CHECK: (start $start-used-globally)
(start $start-used-globally)
;; Pattern A: functions beginning with
;;
;; if (simple) return;
(func $maybe-work-hard (param $x i32)
;; A function that does a quick check before any heavy work. We can outline
;; the heavy work, so that the condition can be inlined.
;;
;; This function (and others lower down that we also optimize) will vanish
;; in the output. Part of it will be inlined into its caller, below, and
;; the rest will be outlined into a new function with suffix "outlined".
(if
(local.get $x)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-maybe-work-hard
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (local $2 i32)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$maybe-work-hard
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$maybe-work-hard
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$maybe-work-hard0
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$maybe-work-hard
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$maybe-work-hard1
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$maybe-work-hard
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-maybe-work-hard
;; Call the above function to verify that we can in fact inline it after
;; splitting. We should see each of these three calls replaced by inlined
;; code performing the if from $maybe-work-hard, and depending on that
;; result they each call the outlined code that must *not* be inlined.
;;
;; Note that we must call more than once, otherwise given a single use we
;; will always inline the entire thing.
(call $maybe-work-hard (i32.const 1))
(call $maybe-work-hard (i32.const 2))
(call $maybe-work-hard (i32.const 3))
)
(func $just-if (param $x i32)
;; As above, but all we have is an if.
(if
(local.get $x)
(loop $l
(call $import)
(br_if $l
(local.get $x)
)
)
)
)
;; CHECK: (func $call-just-if
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$just-if
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (call $byn-split-outlined-B$just-if
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$just-if0
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: (call $byn-split-outlined-B$just-if
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-just-if
(call $just-if (i32.const 1))
(call $just-if (i32.const 2))
)
;; CHECK: (func $br-to-toplevel (param $x i32)
;; CHECK-NEXT: (block $toplevel
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (br $toplevel)
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-to-toplevel (param $x i32)
(block $toplevel
(if
(local.get $x)
(block
(if
(local.get $x)
;; A br to the toplevel block prevents us from outlining this code,
;; as we can't outline a br without its target.
(br $toplevel)
(call $import)
)
)
)
)
)
;; CHECK: (func $call-br-to-toplevel
;; CHECK-NEXT: (call $br-to-toplevel
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $br-to-toplevel
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-br-to-toplevel
(call $br-to-toplevel (i32.const 1))
(call $br-to-toplevel (i32.const 2))
)
;; CHECK: (func $nondefaultable-param (param $x i32) (param $y (rtt $struct))
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $nondefaultable-param (param $x i32) (param $y (rtt $struct))
;; The RTT param here prevents us from even being inlined, even with
;; splitting.
(if
(local.get $x)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-nondefaultable-param
;; CHECK-NEXT: (call $nondefaultable-param
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (rtt.canon $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-nondefaultable-param
(call $nondefaultable-param (i32.const 0) (rtt.canon $struct))
)
(func $many-params (param $x i64) (param $y i32) (param $z f64)
;; Test that we can optimize this function even though it has multiple
;; parameters, and it is not the very first one that we use in the
;; condition.
(if
(local.get $y)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-many-params
;; CHECK-NEXT: (local $0 i64)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (local $2 f64)
;; CHECK-NEXT: (local $3 i64)
;; CHECK-NEXT: (local $4 i32)
;; CHECK-NEXT: (local $5 f64)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$many-params
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (f64.const 3.14159)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$many-params
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$many-params0
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $4
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $5
;; CHECK-NEXT: (f64.const 3.14159)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$many-params
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: (local.get $5)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-many-params
;; Call the above function to verify that we can in fact inline it after
;; splitting. We should see each of these three calls replaced by inlined
;; code performing the if from $maybe-work-hard, and depending on that
;; result they each call the outlined code that must *not* be inlined.
(call $many-params (i64.const 0) (i32.const 1) (f64.const 3.14159))
(call $many-params (i64.const 0) (i32.const 1) (f64.const 3.14159))
)
(func $condition-eqz (param $x i32)
(if
;; More work in the condition, but work that we still consider worth
;; optimizing: a unary op.
(i32.eqz
(local.get $x)
)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-condition-eqz
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-eqz
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$condition-eqz
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-eqz0
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$condition-eqz
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-condition-eqz
(call $condition-eqz (i32.const 0))
(call $condition-eqz (i32.const 1))
)
(func $condition-global
(if
;; A global read, also worth splitting.
(global.get $glob)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-condition-global
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-global
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $glob)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$condition-global)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-global0
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $glob)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$condition-global)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-condition-global
(call $condition-global)
(call $condition-global)
)
(func $condition-ref.is (param $x anyref)
(if
;; A ref.is operation.
(ref.is_null
(local.get $x)
)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-condition-ref.is
;; CHECK-NEXT: (local $0 anyref)
;; CHECK-NEXT: (local $1 anyref)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-ref.is
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$condition-ref.is
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-ref.is0
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$condition-ref.is
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-condition-ref.is
(call $condition-ref.is (ref.null any))
(call $condition-ref.is (ref.null any))
)
;; CHECK: (func $condition-disallow-binary (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $condition-disallow-binary (param $x i32)
(if
;; Work we do *not* allow (at least for now), a binary.
(i32.add
(local.get $x)
(local.get $x)
)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-condition-disallow-binary
;; CHECK-NEXT: (call $condition-disallow-binary
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $condition-disallow-binary
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-condition-disallow-binary
(call $condition-disallow-binary (i32.const 0))
(call $condition-disallow-binary (i32.const 1))
)
;; CHECK: (func $condition-disallow-unreachable (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $condition-disallow-unreachable (param $x i32)
(if
;; Work we do *not* allow (at least for now), an unreachable.
(i32.eqz
(unreachable)
)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-condition-disallow-unreachable
;; CHECK-NEXT: (call $condition-disallow-unreachable
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $condition-disallow-unreachable
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-condition-disallow-unreachable
(call $condition-disallow-unreachable (i32.const 0))
(call $condition-disallow-unreachable (i32.const 1))
)
;; CHECK: (func $start-used-globally
;; CHECK-NEXT: (if
;; CHECK-NEXT: (global.get $glob)
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $start-used-globally
;; This is optimizable even though it is the start function, that is is,
;; having global uses of a function are not a problem for partial inlining
;; (since we do not modify this function - we create new split pieces of
;; it).
(if
(global.get $glob)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-start-used-globally
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$start-used-globally
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $glob)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$start-used-globally)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$start-used-globally0
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $glob)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$start-used-globally)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-start-used-globally
(call $start-used-globally)
(call $start-used-globally)
)
(func $inlineable
;; This looks optimizable, but it is also inlineable - so we do not need to
;; split it. It will just be inlined directly, without any $outlined part
;; that is split out.
(if
(global.get $glob)
(return)
)
)
;; CHECK: (func $call-inlineable
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$inlineable
;; CHECK-NEXT: (if
;; CHECK-NEXT: (global.get $glob)
;; CHECK-NEXT: (br $__inlined_func$inlineable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$inlineable0
;; CHECK-NEXT: (if
;; CHECK-NEXT: (global.get $glob)
;; CHECK-NEXT: (br $__inlined_func$inlineable0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-inlineable
(call $inlineable)
(call $inlineable)
)
;; CHECK: (func $if-not-first (param $x i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $if-not-first (param $x i32)
;; Except for the initial nop, we should outline this. As the if is not
;; first any more, we ignore it.
(nop)
(if
(local.get $x)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-if-not-first
;; CHECK-NEXT: (call $if-not-first
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $if-not-first
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-if-not-first
(call $if-not-first (i32.const 0))
(call $if-not-first (i32.const 1))
)
;; CHECK: (func $if-else (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (return)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $if-else (param $x i32)
;; An else in the if prevents us from recognizing the pattern we want.
(if
(local.get $x)
(return)
(nop)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-if-else
;; CHECK-NEXT: (call $if-else
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $if-else
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-if-else
(call $if-else (i32.const 0))
(call $if-else (i32.const 1))
)
;; CHECK: (func $if-non-return (param $x i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $if-non-return (param $x i32)
;; Something other than a return in the if body prevents us from outlining.
(if
(local.get $x)
(unreachable)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-if-non-return
;; CHECK-NEXT: (call $if-non-return
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $if-non-return
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-if-non-return
(call $if-non-return (i32.const 0))
(call $if-non-return (i32.const 1))
)
(func $colliding-name (param $x i32)
;; When we outline this, the name should not collide with that of the
;; function after us.
(if
(local.get $x)
(return)
)
(loop $l
(call $import)
(br $l)
)
)
;; CHECK: (func $call-colliding-name
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$colliding-name
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$colliding-name_0
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$colliding-name0
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$colliding-name_0
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-colliding-name
(call $colliding-name (i32.const 0))
(call $colliding-name (i32.const 1))
)
;; CHECK: (func $byn-split-outlined-A$colliding-name
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $byn-split-outlined-A$colliding-name
;; This function's name might collide with the split function we create for
;; the above function; the split function's name must be fixed up.
)
;; Pattern B: functions containing
;;
;; if (simple1) heavy-work-that-is-unreachable;
;; if (simple..) heavy-work-that-is-unreachable;
;; simplek
(func $error-if-null (param $x anyref) (result anyref)
;; A "as non null" function: If the input is null, issue an error somehow
;; (here, by calling an import, but could also be a throwing of an
;; exception). If not null, return the value.
(if
(ref.is_null
(local.get $x)
)
(block
(call $import)
(unreachable)
)
)
(local.get $x)
)
;; CHECK: (func $call-error-if-null
;; CHECK-NEXT: (local $0 anyref)
;; CHECK-NEXT: (local $1 anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$error-if-null (result anyref)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $__inlined_func$byn-split-inlineable-B$error-if-null
;; CHECK-NEXT: (call $byn-split-outlined-B$error-if-null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$error-if-null0 (result anyref)
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $__inlined_func$byn-split-inlineable-B$error-if-null0
;; CHECK-NEXT: (call $byn-split-outlined-B$error-if-null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-error-if-null
(drop (call $error-if-null (ref.null any)))
(drop (call $error-if-null (ref.null any)))
)
;; CHECK: (func $too-many (param $x anyref) (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $too-many (param $x anyref) (result anyref)
(if
(ref.is_null
(local.get $x)
)
(block
(call $import)
(unreachable)
)
)
(nop) ;; An extra operation here prevents us from identifying the pattern.
(local.get $x)
)
;; CHECK: (func $call-too-many
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $too-many
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $too-many
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-too-many
(drop (call $too-many (ref.null any)))
(drop (call $too-many (ref.null any)))
)
;; CHECK: (func $tail-not-simple (param $x anyref) (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $tail-not-simple (param $x anyref) (result anyref)
(if
(ref.is_null
(local.get $x)
)
(block
(call $import)
(unreachable)
)
)
(unreachable) ;; This prevents us from optimizing
)
;; CHECK: (func $call-tail-not-simple
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $tail-not-simple
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $tail-not-simple
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-tail-not-simple
(drop (call $tail-not-simple (ref.null any)))
(drop (call $tail-not-simple (ref.null any)))
)
(func $reachable-if-body (param $x anyref) (result anyref)
(if
(ref.is_null
(local.get $x)
)
;; It is ok if the body is not unreachable (so long as it contains no
;; returns). We will optimize this, and just do a call to the outlined
;; code, without a return of a value here.
(call $import)
)
(local.get $x)
)
;; CHECK: (func $call-reachable-if-body
;; CHECK-NEXT: (local $0 anyref)
;; CHECK-NEXT: (local $1 anyref)
;; CHECK-NEXT: (local $2 anyref)
;; CHECK-NEXT: (local $3 anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$reachable-if-body (result anyref)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-B$reachable-if-body
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$reachable-if-body0 (result anyref)
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-B$reachable-if-body0
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-reachable-if-body
;; Note that the above contains
;;
;; (block $__inlined_func$byn-split-outlined-B$reachable-if-body
;;
;; which indicates that we've inlined the outlined function. That seems odd,
;; but it is the result of the if's body being just a call. When we outline,
;; we end up with a function that all it does is make that call - which is
;; worth inlining in the normal way (to avoid two calls). As a result of all
;; that, we end up inlining *all* of $reachable-if-body, just by a
;; roundabout way (split, outline, then inline). While this seems odd, each
;; step along the way makes sense, and the result is a good one (might be a
;; little hard to see before opts remove the extra block cruft etc.).
;;
;; We could avoid this if we detected that the if body is just a call, and
;; not done any outlining - just done that call. That would be more
;; efficient, but it would make the code more complicated, and the result is
;; the same.
(drop (call $reachable-if-body (ref.null any)))
(drop (call $reachable-if-body (ref.null any)))
)
;; CHECK: (func $reachable-if-body-return (param $x anyref) (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: (return
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $reachable-if-body-return (param $x anyref) (result anyref)
(if
(ref.is_null
(local.get $x)
)
(if
(i32.const 1)
;; The return here prevents the optimization.
(return
(local.get $x)
)
(call $import)
)
)
(local.get $x)
)
;; CHECK: (func $call-reachable-if-body-return
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $reachable-if-body-return
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $reachable-if-body-return
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-reachable-if-body-return
(drop (call $reachable-if-body-return (ref.null any)))
(drop (call $reachable-if-body-return (ref.null any)))
)
(func $unreachable-if-body-no-result (param $x anyref)
(if
(ref.is_null
(local.get $x)
)
;; The if body is unreachable, but the function has no returned value.
;; When we outline this code, we should not try to return a value.
(block
(call $import)
(unreachable)
)
)
)
;; CHECK: (func $call-unreachable-if-body-no-result
;; CHECK-NEXT: (local $0 anyref)
;; CHECK-NEXT: (local $1 anyref)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$unreachable-if-body-no-result
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-B$unreachable-if-body-no-result
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$unreachable-if-body-no-result0
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-B$unreachable-if-body-no-result
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-unreachable-if-body-no-result
(call $unreachable-if-body-no-result (ref.null any))
(call $unreachable-if-body-no-result (ref.null any))
)
(func $multi-if (param $x anyref) (result anyref)
(if
(ref.is_null
(local.get $x)
)
(call $import)
)
;; A second if. We can outline both if bodies.
(if
(ref.is_func
(local.get $x)
)
(loop $x
(call $import)
(br_if $x
(global.get $glob)
)
)
)
(local.get $x)
)
;; CHECK: (func $call-multi-if
;; CHECK-NEXT: (local $0 anyref)
;; CHECK-NEXT: (local $1 anyref)
;; CHECK-NEXT: (local $2 anyref)
;; CHECK-NEXT: (local $3 anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$multi-if (result anyref)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-B$multi-if
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_func
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_0
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$multi-if0 (result anyref)
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (ref.null func)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-B$multi-if0
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_func
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_0
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-multi-if
(drop (call $multi-if (ref.null any)))
(drop (call $multi-if (ref.null func)))
)
;; CHECK: (func $too-many-ifs (param $x anyref) (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $too-many-ifs (param $x anyref) (result anyref)
;; 5 ifs, which is too many.
(if
(ref.is_null
(local.get $x)
)
(call $import)
)
(if
(ref.is_null
(local.get $x)
)
(call $import)
)
(if
(ref.is_null
(local.get $x)
)
(call $import)
)
(if
(ref.is_null
(local.get $x)
)
(call $import)
)
(if
(ref.is_null
(local.get $x)
)
(call $import)
)
(local.get $x)
)
;; CHECK: (func $call-too-many-ifs
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $too-many-ifs
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $too-many-ifs
;; CHECK-NEXT: (ref.null func)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-too-many-ifs
(drop (call $too-many-ifs (ref.null any)))
(drop (call $too-many-ifs (ref.null func)))
)
)
;; CHECK: (func $byn-split-outlined-A$maybe-work-hard (param $x i32)
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-B$just-if (param $x i32)
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br_if $l
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-A$many-params (param $x i64) (param $y i32) (param $z f64)
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-A$condition-eqz (param $x i32)
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-A$condition-global
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-A$condition-ref.is (param $x anyref)
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-A$start-used-globally
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-A$colliding-name_0 (param $x i32)
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-B$error-if-null (param $x anyref) (result anyref)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-B$unreachable-if-body-no-result (param $x anyref)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-B$multi-if_0 (param $x anyref)
;; CHECK-NEXT: (loop $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br_if $x
;; CHECK-NEXT: (global.get $glob)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; CHECK: (type $none_=>_none (func))
(type $none_=>_none (func))
;; CHECK: (global $global$0 (mut i32) (i32.const 10))
(global $global$0 (mut i32) (i32.const 10))
;; CHECK: (export "0" (func $0))
(export "0" (func $0))
;; CHECK: (export "1" (func $1))
(export "1" (func $1))
;; CHECK: (func $0
;; CHECK-NEXT: (if
;; CHECK-NEXT: (global.get $global$0)
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$1
;; CHECK-NEXT: (block
;; CHECK-NEXT: (call $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$10
;; CHECK-NEXT: (block
;; CHECK-NEXT: (call $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $0
;; A function that is a good candidate to partially inline.
(if
(global.get $global$0)
(return)
)
(call $1)
(call $1)
)
;; CHECK: (func $1
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$0
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-A$0
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$1
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$00
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$10
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$01
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $1
;; This and the previous function are mutually recursive. As a result, we
;; can keep partially inlining between them, creating new functions as we
;; go, even though that is not very useful.
(call $0)
)
;; Add a lot more functions, so the # of functions is high which would
;; otherwise limit the # of iterations that we run.
;; CHECK: (func $2
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $2
(nop)
)
;; CHECK: (func $3
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $3
(nop)
)
;; CHECK: (func $4
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $4
(nop)
)
;; CHECK: (func $5
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $5
(nop)
)
;; CHECK: (func $6
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $6
(nop)
)
;; CHECK: (func $7
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $7
(nop)
)
;; CHECK: (func $8
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $8
(nop)
)
;; CHECK: (func $9
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $9
(nop)
)
;; CHECK: (func $10
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $10
(nop)
)
;; CHECK: (func $11
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $11
(nop)
)
;; CHECK: (func $12
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $12
(nop)
)
;; CHECK: (func $13
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $13
(nop)
)
;; CHECK: (func $14
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $14
(nop)
)
;; CHECK: (func $15
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $15
(nop)
)
;; CHECK: (func $16
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $16
(nop)
)
;; CHECK: (func $17
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $17
(nop)
)
;; CHECK: (func $18
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $18
(nop)
)
)
;; CHECK: (func $byn-split-outlined-A$0
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$1
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$0
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$0_0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$10
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$00
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$0_0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-A$0_0
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$1
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$0
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$0_1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$10
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$00
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global$0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-A$0_1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $byn-split-outlined-A$0_1
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$1
;; CHECK-NEXT: (block
;; CHECK-NEXT: (call $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$10
;; CHECK-NEXT: (block
;; CHECK-NEXT: (call $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )