;; 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 $0 (func)) ;; CHECK: (type $1 (func (param i32))) ;; CHECK: (type $2 (func (param anyref) (result anyref))) ;; CHECK: (type $3 (func (param anyref))) ;; CHECK: (type $struct (struct )) (type $struct (struct)) ;; CHECK: (type $5 (func (param i64 i32 f64))) ;; CHECK: (import "out" "func" (func $import (type $0))) (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) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-maybe-work-hard (type $0) ;; 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: (then ;; 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: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$maybe-work-hard$1 ;; 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: (then ;; 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: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$maybe-work-hard$2 ;; 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: (then ;; 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: ) ;; 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) (then (loop $l (call $import) (br_if $l (local.get $x) ) ) ) ) ) ;; CHECK: (func $call-just-if (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$just-if$3 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-B$just-if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$just-if$4 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-B$just-if ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; 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 (type $1) (param $x i32) ;; CHECK-NEXT: (block $toplevel ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $toplevel) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $br-to-toplevel (param $x i32) (block $toplevel (if (local.get $x) (then (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. (then (br $toplevel) ) (else (call $import) ) ) ) ) ) ) ) ;; CHECK: (func $call-br-to-toplevel (type $0) ;; 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)) ) (func $nondefaultable-param (param $x i32) (param $y (ref $struct)) ;; We can inline despite the non-initial, non-defaultable param. (if (local.get $x) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-nondefaultable-param (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 (ref $struct)) ;; CHECK-NEXT: (block $__inlined_func$nondefaultable-param$5 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$nondefaultable-param$5) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (loop $l ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: (br $l) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-nondefaultable-param (call $nondefaultable-param (i32.const 0) (struct.new $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) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-many-params (type $0) ;; 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$6 ;; 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: (then ;; 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: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$many-params$7 ;; 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: (then ;; 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: ) ;; 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) ) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-condition-eqz (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-eqz$8 ;; 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: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$condition-eqz ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-eqz$9 ;; 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: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$condition-eqz ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; 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) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-condition-global (type $0) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-global$10 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $glob) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$condition-global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-global$11 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $glob) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$condition-global) ;; CHECK-NEXT: ) ;; 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) ) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-condition-ref.is (type $0) ;; 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$12 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (ref.null none) ;; 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: (then ;; 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: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-ref.is$13 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (ref.null none) ;; 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: (then ;; 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: ) ;; 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 (type $1) (param $x i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) ;; 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) ) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-condition-disallow-binary (type $0) ;; 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 (type $1) (param $x i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) ;; 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) ) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-condition-disallow-unreachable (type $0) ;; 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 (type $0) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (global.get $glob) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) ;; 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) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-start-used-globally (type $0) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$start-used-globally$14 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $glob) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$start-used-globally) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$start-used-globally$15 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $glob) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$start-used-globally) ;; CHECK-NEXT: ) ;; 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) (then (return) ) ) ) ;; CHECK: (func $call-inlineable (type $0) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$inlineable$16 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (global.get $glob) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$inlineable$16) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$inlineable$17 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (global.get $glob) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$inlineable$17) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-inlineable (call $inlineable) (call $inlineable) ) ;; CHECK: (func $if-not-first (type $1) (param $x i32) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) ;; 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) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-if-not-first (type $0) ;; 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 (type $1) (param $x i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; 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) (then (return) ) (else (nop) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-if-else (type $0) ;; 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 (type $1) (param $x i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; 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) (then (unreachable) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-if-non-return (type $0) ;; 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) (then (return) ) ) (loop $l (call $import) (br $l) ) ) ;; CHECK: (func $call-colliding-name (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$colliding-name$18 ;; 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: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$colliding-name_67 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$colliding-name$19 ;; 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: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$colliding-name_67 ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; 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 (type $0) ;; 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) ) (then (block (call $import) (unreachable) ) ) ) (local.get $x) ) ;; CHECK: (func $call-error-if-null (type $0) ;; 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$20 (result anyref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$byn-split-inlineable-B$error-if-null$20 ;; CHECK-NEXT: (call $byn-split-outlined-B$error-if-null ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; 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-null$21 (result anyref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$byn-split-inlineable-B$error-if-null$21 ;; CHECK-NEXT: (call $byn-split-outlined-B$error-if-null ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; 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 (type $2) (param $x anyref) (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; 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) ) (then (block (call $import) (unreachable) ) ) ) (nop) ;; An extra operation here prevents us from identifying the pattern. (local.get $x) ) ;; CHECK: (func $call-too-many (type $0) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $too-many ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $too-many ;; CHECK-NEXT: (ref.null none) ;; 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 (type $2) (param $x anyref) (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; 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) ) (then (block (call $import) (unreachable) ) ) ) (unreachable) ;; This prevents us from optimizing ) ;; CHECK: (func $call-tail-not-simple (type $0) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $tail-not-simple ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $tail-not-simple ;; CHECK-NEXT: (ref.null none) ;; 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. (then (block ;; We need to have a loop here to avoid normal inlining from kicking in ;; on the outlined code. (loop $loop (call $import) ) ) ) ) (local.get $x) ) ;; CHECK: (func $call-reachable-if-body (type $0) ;; 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$reachable-if-body$22 (result anyref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-B$reachable-if-body ;; 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$reachable-if-body$23 (result anyref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-B$reachable-if-body ;; 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-reachable-if-body (drop (call $reachable-if-body (ref.null any))) (drop (call $reachable-if-body (ref.null any))) ) (func $reachable-if-body-noloop (param $x anyref) (result anyref) ;; As above, but without a loop. (if (ref.is_null (local.get $x) ) (then (call $import) ) ) (local.get $x) ) ;; CHECK: (func $call-reachable-if-body-noloop (type $0) ;; CHECK-NEXT: (local $0 anyref) ;; CHECK-NEXT: (local $1 anyref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (block $__inlined_func$reachable-if-body-noloop$24 (result anyref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; 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$reachable-if-body-noloop$25 (result anyref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; 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-noloop ;; As above, but the called function has no loop. In that case, even though ;; it fits the pattern for partial inlining we can just inline the entire ;; thing normally. (drop (call $reachable-if-body-noloop (ref.null any))) (drop (call $reachable-if-body-noloop (ref.null any))) ) ;; CHECK: (func $reachable-if-body-return (type $2) (param $x anyref) (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) (then (if (i32.const 1) ;; The return here prevents the optimization. (then (return (local.get $x) ) ) (else (call $import) ) ) ) ) (local.get $x) ) ;; CHECK: (func $call-reachable-if-body-return (type $0) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $reachable-if-body-return ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $reachable-if-body-return ;; CHECK-NEXT: (ref.null none) ;; 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. (then (block (call $import) (unreachable) ) ) ) ) ;; CHECK: (func $call-unreachable-if-body-no-result (type $0) ;; 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$26 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; 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: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$unreachable-if-body-no-result$27 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; 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: ) ;; 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) ) (then (call $import) ) ) ;; A second if. We can outline both if bodies. (if (ref.is_null (local.get $x) ) (then (loop $x (call $import) (br_if $x (global.get $glob) ) ) ) ) (local.get $x) ) ;; CHECK: (func $call-multi-if (type $0) ;; 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$28 (result anyref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-B$multi-if$30 ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_76 ;; 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$multi-if$29 (result anyref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-B$multi-if$31 ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_76 ;; 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-multi-if (drop (call $multi-if (ref.null none))) (drop (call $multi-if (ref.null none))) ) ;; CHECK: (func $too-many-ifs (type $2) (param $x anyref) (result anyref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; 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) ) (then (call $import) ) ) (if (ref.is_null (local.get $x) ) (then (call $import) ) ) (if (ref.is_null (local.get $x) ) (then (call $import) ) ) (if (ref.is_null (local.get $x) ) (then (call $import) ) ) (if (ref.is_null (local.get $x) ) (then (call $import) ) ) (local.get $x) ) ;; CHECK: (func $call-too-many-ifs (type $0) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $too-many-ifs ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $too-many-ifs ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-too-many-ifs (drop (call $too-many-ifs (ref.null none))) (drop (call $too-many-ifs (ref.null none))) ) ) ;; CHECK: (func $byn-split-outlined-A$maybe-work-hard (type $1) (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 (type $1) (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 (type $5) (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 (type $1) (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 (type $0) ;; 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 (type $3) (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 (type $0) ;; CHECK-NEXT: (loop $l ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: (br $l) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK: (func $byn-split-outlined-A$colliding-name_67 (type $1) (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 (type $2) (param $x anyref) (result anyref) ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK: (func $byn-split-outlined-B$reachable-if-body (type $3) (param $x anyref) ;; CHECK-NEXT: (loop $loop ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK: (func $byn-split-outlined-B$unreachable-if-body-no-result (type $3) (param $x anyref) ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK: (func $byn-split-outlined-B$multi-if_76 (type $3) (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 (type $none_=>_none) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (global.get $global$0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) ;; 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$1$1 ;; 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) (then (return) ) ) (call $1) (call $1) ) ;; CHECK: (func $1 (type $none_=>_none) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$0$2 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $global$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-A$0$3 ;; 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$0$4 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $global$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; 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: (block ;; CHECK-NEXT: (block $__inlined_func$1$1 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$0$5 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $global$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; 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: ) ;; 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 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $2 (nop) ) ;; CHECK: (func $3 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $3 (nop) ) ;; CHECK: (func $4 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $4 (nop) ) ;; CHECK: (func $5 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $5 (nop) ) ;; CHECK: (func $6 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $6 (nop) ) ;; CHECK: (func $7 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $7 (nop) ) ;; CHECK: (func $8 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $8 (nop) ) ;; CHECK: (func $9 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $9 (nop) ) ;; CHECK: (func $10 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $10 (nop) ) ;; CHECK: (func $11 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $11 (nop) ) ;; CHECK: (func $12 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $12 (nop) ) ;; CHECK: (func $13 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $13 (nop) ) ;; CHECK: (func $14 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $14 (nop) ) ;; CHECK: (func $15 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $15 (nop) ) ;; CHECK: (func $16 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $16 (nop) ) ;; CHECK: (func $17 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $17 (nop) ) ;; CHECK: (func $18 (type $none_=>_none) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $18 (nop) ) ) ;; CHECK: (func $byn-split-outlined-A$0 (type $none_=>_none) ;; 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$6 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $global$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$0_21) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$1$1 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$0$7 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $global$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$0_21) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK: (func $byn-split-outlined-A$0_21 (type $none_=>_none) ;; 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$8 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $global$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$0_22) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$1$1 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$0$9 ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (global.get $global$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$0_22) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK: (func $byn-split-outlined-A$0_22 (type $none_=>_none) ;; 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$1$1 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (call $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (module (func $middle-size-A (param $x i32) ;; This function is too big for normal inlining with the default size limit. ;; However, if we partially inline it then the outlined code becomes small ;; enough to be normally inlined. We should just inline it normally in that ;; case, to avoid wasted work. (if (local.get $x) (then (return) ) ) ;; 6x3 = 18 items, close to the default size limit of 20. With the if, we ;; hit that limit and are too big. But if we did partial inlining then the ;; lines below us are small enough to then be inlined normally. (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) ) ;; CHECK: (type $0 (func)) ;; CHECK: (type $1 (func (param i32))) ;; CHECK: (type $2 (func (param i32) (result i32))) ;; CHECK: (func $call-$middle-size-A (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$middle-size-A ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$middle-size-A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$middle-size-A$1 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$middle-size-A$1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-$middle-size-A ;; This will be normally inlined, see the comment in the above function. ;; We can see it is normally inlined and not partially from the string ;; "__inlined_func" in the code (instead of "split" appearing anywhere). (call $middle-size-A (i32.const 0) ) (call $middle-size-A (i32.const 1) ) ) (func $big-size-A (param $x i32) ;; As above, but a little larger - so large that we won't normally inline ;; it. (if (local.get $x) (then (return) ) ) ;; 6x4 = 24 items, which is more than the inlining limit. (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) ) ;; CHECK: (func $call-$big-size-A (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$big-size-A$2 ;; 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: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$big-size-A ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$big-size-A$3 ;; 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: (then ;; CHECK-NEXT: (call $byn-split-outlined-A$big-size-A ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-$big-size-A ;; Normal inlining can't work here, so we'll just do partial inlining. (call $big-size-A (i32.const 0) ) (call $big-size-A (i32.const 1) ) ) (func $middle-size-B (param $x i32) (result i32) ;; As above, but for pattern B and not A. (if (local.get $x) (then (block (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (unreachable) ) ) ) (local.get $x) ) ;; CHECK: (func $call-$middle-size-B (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (block $__inlined_func$middle-size-B$4 (result i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (block $__inlined_func$middle-size-B$5 (result i32) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-$middle-size-B ;; We will normally inline here. (drop (call $middle-size-B (i32.const 0) ) ) (drop (call $middle-size-B (i32.const 1) ) ) ) (func $big-size-B (param $x i32) (result i32) ;; As above, but a little larger - so large that we won't normally inline ;; it. (if (local.get $x) (then (block (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0)) (unreachable) ) ) ) (local.get $x) ) ;; CHECK: (func $call-$big-size-B (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$big-size-B$6 (result i32) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$byn-split-inlineable-B$big-size-B$6 ;; CHECK-NEXT: (call $byn-split-outlined-B$big-size-B ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; 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 i32) ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$big-size-B$7 (result i32) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (br $__inlined_func$byn-split-inlineable-B$big-size-B$7 ;; CHECK-NEXT: (call $byn-split-outlined-B$big-size-B ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-$big-size-B ;; We'll partially inline here. (drop (call $big-size-B (i32.const 0) ) ) (drop (call $big-size-B (i32.const 1) ) ) ) ) ;; CHECK: (func $byn-split-outlined-A$big-size-A (type $1) (param $x i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK: (func $byn-split-outlined-B$big-size-B (type $2) (param $x i32) (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: )