blob: e00502dd0aac4d37d2453cb7e55b5e136d9ae819 [file]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; Test that optimize-instructions turns resumptions of continuations that never
;; suspend into direct calls.
;; RUN: wasm-opt %s --all-features --generate-global-effects --optimize-instructions -S -o - | filecheck %s --check-prefix NO-TNH
;; RUN: wasm-opt %s --all-features --generate-global-effects --traps-never-happen --optimize-instructions -S -o - | filecheck %s --check-prefix TNH
;; RUN: wasm-opt %s --all-features --generate-global-effects --optimize-instructions --vacuum -S -o - | filecheck %s --check-prefix VACUUM
(module
;; NO-TNH: (type $sig-none (func))
;; NO-TNH: (type $cont-none (cont $sig-none))
;; NO-TNH: (type $sig-binary (func (param i32 i32) (result i32)))
;; NO-TNH: (type $cont-binary (cont $sig-binary))
;; NO-TNH: (type $sig-unary (func (param i32) (result i32)))
;; NO-TNH: (type $sig-any (func (param (ref any)) (result (ref any))))
;; NO-TNH: (import "env" "imported" (func $imported (type $sig-none)))
;; TNH: (type $sig-none (func))
;; TNH: (type $cont-none (cont $sig-none))
;; TNH: (type $sig-binary (func (param i32 i32) (result i32)))
;; TNH: (type $cont-binary (cont $sig-binary))
;; TNH: (type $sig-unary (func (param i32) (result i32)))
;; TNH: (type $sig-any (func (param (ref any)) (result (ref any))))
;; TNH: (import "env" "imported" (func $imported (type $sig-none)))
;; VACUUM: (type $sig-none (func))
;; VACUUM: (type $cont-none (cont $sig-none))
;; VACUUM: (type $sig-binary (func (param i32 i32) (result i32)))
;; VACUUM: (type $cont-binary (cont $sig-binary))
;; VACUUM: (type $sig-unary (func (param i32) (result i32)))
;; VACUUM: (type $sig-any (func (param (ref any)) (result (ref any))))
;; VACUUM: (import "env" "imported" (func $imported (type $sig-none)))
(import "env" "imported" (func $imported (type $sig-none)))
;; NO-TNH: (global $counter (mut i32) (i32.const 0))
;; NO-TNH: (tag $tag (type $sig-none))
;; TNH: (global $counter (mut i32) (i32.const 0))
;; TNH: (tag $tag (type $sig-none))
;; VACUUM: (global $counter (mut i32) (i32.const 0))
;; VACUUM: (tag $tag (type $sig-none))
(tag $tag)
;; NO-TNH: (tag $tag-i32 (type $7) (param i32))
;; TNH: (tag $tag-i32 (type $7) (param i32))
;; VACUUM: (tag $tag-i32 (type $7) (param i32))
(tag $tag-i32 (param i32))
(type $sig-none (func))
(type $sig-binary (func (param i32 i32) (result i32)))
(type $sig-unary (func (param i32) (result i32)))
(type $sig-any (func (param (ref any)) (result (ref any))))
(type $cont-none (cont $sig-none))
(type $cont-binary (cont $sig-binary))
(type $cont-unary (cont $sig-unary))
(type $cont-any (cont $sig-any))
(global $counter (mut i32) (i32.const 0))
;; NO-TNH: (func $pure (type $sig-none)
;; NO-TNH-NEXT: (nop)
;; NO-TNH-NEXT: )
;; TNH: (func $pure (type $sig-none)
;; TNH-NEXT: (nop)
;; TNH-NEXT: )
;; VACUUM: (func $pure (type $sig-none)
;; VACUUM-NEXT: (nop)
;; VACUUM-NEXT: )
(func $pure (type $sig-none)
(nop)
)
;; NO-TNH: (func $pure-binary (type $sig-binary) (param $x i32) (param $y i32) (result i32)
;; NO-TNH-NEXT: (i32.add
;; NO-TNH-NEXT: (local.get $x)
;; NO-TNH-NEXT: (local.get $y)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $pure-binary (type $sig-binary) (param $x i32) (param $y i32) (result i32)
;; TNH-NEXT: (i32.add
;; TNH-NEXT: (local.get $x)
;; TNH-NEXT: (local.get $y)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $pure-binary (type $sig-binary) (param $x i32) (param $y i32) (result i32)
;; VACUUM-NEXT: (i32.add
;; VACUUM-NEXT: (local.get $x)
;; VACUUM-NEXT: (local.get $y)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $pure-binary (type $sig-binary) (param $x i32) (param $y i32) (result i32)
(i32.add (local.get $x) (local.get $y))
)
;; NO-TNH: (func $pure-any (type $sig-any) (param $x (ref any)) (result (ref any))
;; NO-TNH-NEXT: (local.get $x)
;; NO-TNH-NEXT: )
;; TNH: (func $pure-any (type $sig-any) (param $x (ref any)) (result (ref any))
;; TNH-NEXT: (local.get $x)
;; TNH-NEXT: )
;; VACUUM: (func $pure-any (type $sig-any) (param $x (ref any)) (result (ref any))
;; VACUUM-NEXT: (local.get $x)
;; VACUUM-NEXT: )
(func $pure-any (type $sig-any) (param $x (ref any)) (result (ref any))
(local.get $x)
)
;; NO-TNH: (func $suspending (type $sig-none)
;; NO-TNH-NEXT: (suspend $tag)
;; NO-TNH-NEXT: )
;; TNH: (func $suspending (type $sig-none)
;; TNH-NEXT: (suspend $tag)
;; TNH-NEXT: )
;; VACUUM: (func $suspending (type $sig-none)
;; VACUUM-NEXT: (suspend $tag)
;; VACUUM-NEXT: )
(func $suspending (type $sig-none)
(suspend $tag)
)
;; NO-TNH: (func $caller-of-suspending (type $sig-none)
;; NO-TNH-NEXT: (call $suspending)
;; NO-TNH-NEXT: )
;; TNH: (func $caller-of-suspending (type $sig-none)
;; TNH-NEXT: (call $suspending)
;; TNH-NEXT: )
;; VACUUM: (func $caller-of-suspending (type $sig-none)
;; VACUUM-NEXT: (call $suspending)
;; VACUUM-NEXT: )
(func $caller-of-suspending (type $sig-none)
(call $suspending)
)
;; NO-TNH: (func $same-sig-pure (type $sig-unary) (param $x i32) (result i32)
;; NO-TNH-NEXT: (local.get $x)
;; NO-TNH-NEXT: )
;; TNH: (func $same-sig-pure (type $sig-unary) (param $x i32) (result i32)
;; TNH-NEXT: (local.get $x)
;; TNH-NEXT: )
;; VACUUM: (func $same-sig-pure (type $sig-unary) (param $x i32) (result i32)
;; VACUUM-NEXT: (local.get $x)
;; VACUUM-NEXT: )
(func $same-sig-pure (type $sig-unary) (param $x i32) (result i32)
(local.get $x)
)
;; NO-TNH: (func $same-sig-suspending (type $sig-unary) (param $x i32) (result i32)
;; NO-TNH-NEXT: (suspend $tag-i32
;; NO-TNH-NEXT: (local.get $x)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (local.get $x)
;; NO-TNH-NEXT: )
;; TNH: (func $same-sig-suspending (type $sig-unary) (param $x i32) (result i32)
;; TNH-NEXT: (suspend $tag-i32
;; TNH-NEXT: (local.get $x)
;; TNH-NEXT: )
;; TNH-NEXT: (local.get $x)
;; TNH-NEXT: )
;; VACUUM: (func $same-sig-suspending (type $sig-unary) (param $x i32) (result i32)
;; VACUUM-NEXT: (suspend $tag-i32
;; VACUUM-NEXT: (local.get $x)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (local.get $x)
;; VACUUM-NEXT: )
(func $same-sig-suspending (type $sig-unary) (param $x i32) (result i32)
(suspend $tag-i32 (local.get $x))
(local.get $x)
)
;; NO-TNH: (func $side-effect-1 (type $2) (result i32)
;; NO-TNH-NEXT: (global.set $counter
;; NO-TNH-NEXT: (i32.add
;; NO-TNH-NEXT: (global.get $counter)
;; NO-TNH-NEXT: (i32.const 1)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (i32.const 10)
;; NO-TNH-NEXT: )
;; TNH: (func $side-effect-1 (type $2) (result i32)
;; TNH-NEXT: (global.set $counter
;; TNH-NEXT: (i32.add
;; TNH-NEXT: (global.get $counter)
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (i32.const 10)
;; TNH-NEXT: )
;; VACUUM: (func $side-effect-1 (type $2) (result i32)
;; VACUUM-NEXT: (global.set $counter
;; VACUUM-NEXT: (i32.add
;; VACUUM-NEXT: (global.get $counter)
;; VACUUM-NEXT: (i32.const 1)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (i32.const 10)
;; VACUUM-NEXT: )
(func $side-effect-1 (result i32)
(global.set $counter (i32.add (global.get $counter) (i32.const 1)))
(i32.const 10)
)
;; NO-TNH: (func $side-effect-2 (type $2) (result i32)
;; NO-TNH-NEXT: (global.set $counter
;; NO-TNH-NEXT: (i32.add
;; NO-TNH-NEXT: (global.get $counter)
;; NO-TNH-NEXT: (i32.const 2)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (i32.const 20)
;; NO-TNH-NEXT: )
;; TNH: (func $side-effect-2 (type $2) (result i32)
;; TNH-NEXT: (global.set $counter
;; TNH-NEXT: (i32.add
;; TNH-NEXT: (global.get $counter)
;; TNH-NEXT: (i32.const 2)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (i32.const 20)
;; TNH-NEXT: )
;; VACUUM: (func $side-effect-2 (type $2) (result i32)
;; VACUUM-NEXT: (global.set $counter
;; VACUUM-NEXT: (i32.add
;; VACUUM-NEXT: (global.get $counter)
;; VACUUM-NEXT: (i32.const 2)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (i32.const 20)
;; VACUUM-NEXT: )
(func $side-effect-2 (result i32)
(global.set $counter (i32.add (global.get $counter) (i32.const 2)))
(i32.const 20)
)
;; NO-TNH: (func $side-effect-3 (type $sig-none)
;; NO-TNH-NEXT: (global.set $counter
;; NO-TNH-NEXT: (i32.add
;; NO-TNH-NEXT: (global.get $counter)
;; NO-TNH-NEXT: (i32.const 3)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $side-effect-3 (type $sig-none)
;; TNH-NEXT: (global.set $counter
;; TNH-NEXT: (i32.add
;; TNH-NEXT: (global.get $counter)
;; TNH-NEXT: (i32.const 3)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $side-effect-3 (type $sig-none)
;; VACUUM-NEXT: (global.set $counter
;; VACUUM-NEXT: (i32.add
;; VACUUM-NEXT: (global.get $counter)
;; VACUUM-NEXT: (i32.const 3)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $side-effect-3
(global.set $counter (i32.add (global.get $counter) (i32.const 3)))
)
;; NO-TNH: (func $test-resume-null (type $sig-none)
;; NO-TNH-NEXT: (unreachable)
;; NO-TNH-NEXT: )
;; TNH: (func $test-resume-null (type $sig-none)
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; VACUUM: (func $test-resume-null (type $sig-none)
;; VACUUM-NEXT: (unreachable)
;; VACUUM-NEXT: )
(func $test-resume-null
;; Resume of null traps: replaced with unreachable.
(resume $cont-none
(ref.null $cont-none)
)
)
;; NO-TNH: (func $test-resume-null-operands (type $sig-none)
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (block
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (call $side-effect-1)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (call $side-effect-2)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (unreachable)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-resume-null-operands (type $sig-none)
;; TNH-NEXT: (drop
;; TNH-NEXT: (block
;; TNH-NEXT: (drop
;; TNH-NEXT: (call $side-effect-1)
;; TNH-NEXT: )
;; TNH-NEXT: (drop
;; TNH-NEXT: (call $side-effect-2)
;; TNH-NEXT: )
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-resume-null-operands (type $sig-none)
;; VACUUM-NEXT: (drop
;; VACUUM-NEXT: (block
;; VACUUM-NEXT: (drop
;; VACUUM-NEXT: (call $side-effect-1)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (drop
;; VACUUM-NEXT: (call $side-effect-2)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (unreachable)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-resume-null-operands
;; Operands are evaluated and dropped before the null trap.
(resume $cont-binary
(call $side-effect-1)
(call $side-effect-2)
(ref.null $cont-binary)
)
(drop)
)
;; NO-TNH: (func $test-resume-skip-non-null-cast (type $9) (param $c (ref null $cont-none))
;; NO-TNH-NEXT: (resume $cont-none
;; NO-TNH-NEXT: (local.get $c)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-resume-skip-non-null-cast (type $9) (param $c (ref null $cont-none))
;; TNH-NEXT: (resume $cont-none
;; TNH-NEXT: (local.get $c)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-resume-skip-non-null-cast (type $9) (param $c (ref null $cont-none))
;; VACUUM-NEXT: (resume $cont-none
;; VACUUM-NEXT: (local.get $c)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-resume-skip-non-null-cast (param $c (ref null $cont-none))
;; Redundant ref.as_non_null on continuation is stripped because resume
;; traps on null.
(resume $cont-none
(ref.as_non_null
(local.get $c)
)
)
)
;; NO-TNH: (func $test-resume-null-arm-tnh (type $6) (param $cond i32) (param $c (ref $cont-none))
;; NO-TNH-NEXT: (resume $cont-none
;; NO-TNH-NEXT: (if (result (ref null $cont-none))
;; NO-TNH-NEXT: (local.get $cond)
;; NO-TNH-NEXT: (then
;; NO-TNH-NEXT: (ref.null nocont)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (else
;; NO-TNH-NEXT: (local.get $c)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-resume-null-arm-tnh (type $6) (param $cond i32) (param $c (ref $cont-none))
;; TNH-NEXT: (resume $cont-none
;; TNH-NEXT: (block (result (ref $cont-none))
;; TNH-NEXT: (drop
;; TNH-NEXT: (local.get $cond)
;; TNH-NEXT: )
;; TNH-NEXT: (local.get $c)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-resume-null-arm-tnh (type $6) (param $cond i32) (param $c (ref $cont-none))
;; VACUUM-NEXT: (resume $cont-none
;; VACUUM-NEXT: (if (result (ref null $cont-none))
;; VACUUM-NEXT: (local.get $cond)
;; VACUUM-NEXT: (then
;; VACUUM-NEXT: (ref.null nocont)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (else
;; VACUUM-NEXT: (local.get $c)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-resume-null-arm-tnh (param $cond i32) (param $c (ref $cont-none))
;; Under TNH, if-arms that flow out null are assumed never taken.
(resume $cont-none
(if (result (ref null $cont-none))
(local.get $cond)
(then
(ref.null $cont-none)
)
(else
(local.get $c)
)
)
)
)
;; NO-TNH: (func $test-resume-null-select-tnh (type $6) (param $cond i32) (param $c (ref $cont-none))
;; NO-TNH-NEXT: (resume $cont-none
;; NO-TNH-NEXT: (select (result (ref null $cont-none))
;; NO-TNH-NEXT: (ref.null nocont)
;; NO-TNH-NEXT: (local.get $c)
;; NO-TNH-NEXT: (local.get $cond)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-resume-null-select-tnh (type $6) (param $cond i32) (param $c (ref $cont-none))
;; TNH-NEXT: (resume $cont-none
;; TNH-NEXT: (block (result (ref $cont-none))
;; TNH-NEXT: (drop
;; TNH-NEXT: (ref.null nocont)
;; TNH-NEXT: )
;; TNH-NEXT: (block (result (ref $cont-none))
;; TNH-NEXT: (drop
;; TNH-NEXT: (local.get $cond)
;; TNH-NEXT: )
;; TNH-NEXT: (local.get $c)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-resume-null-select-tnh (type $6) (param $cond i32) (param $c (ref $cont-none))
;; VACUUM-NEXT: (resume $cont-none
;; VACUUM-NEXT: (select (result (ref null $cont-none))
;; VACUUM-NEXT: (ref.null nocont)
;; VACUUM-NEXT: (local.get $c)
;; VACUUM-NEXT: (local.get $cond)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-resume-null-select-tnh (param $cond i32) (param $c (ref $cont-none))
;; Under TNH, select branches that flow out null are assumed never taken.
(resume $cont-none
(select (result (ref null $cont-none))
(ref.null $cont-none)
(local.get $c)
(local.get $cond)
)
)
)
;; NO-TNH: (func $test-basic (type $sig-none)
;; NO-TNH-NEXT: (call $pure)
;; NO-TNH-NEXT: )
;; TNH: (func $test-basic (type $sig-none)
;; TNH-NEXT: (call $pure)
;; TNH-NEXT: )
;; VACUUM: (func $test-basic (type $sig-none)
;; VACUUM-NEXT: (nop)
;; VACUUM-NEXT: )
(func $test-basic
;; Basic rewrite: resume of non-suspending continuation becomes direct
;; call.
(resume $cont-none
(cont.new $cont-none (ref.func $pure))
)
)
;; NO-TNH: (func $test-binary (type $2) (result i32)
;; NO-TNH-NEXT: (call $pure-binary
;; NO-TNH-NEXT: (i32.const 1)
;; NO-TNH-NEXT: (i32.const 2)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-binary (type $2) (result i32)
;; TNH-NEXT: (call $pure-binary
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: (i32.const 2)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-binary (type $2) (result i32)
;; VACUUM-NEXT: (call $pure-binary
;; VACUUM-NEXT: (i32.const 1)
;; VACUUM-NEXT: (i32.const 2)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-binary (result i32)
;; Operands and results: passed cleanly to the direct call.
(resume $cont-binary
(i32.const 1)
(i32.const 2)
(cont.new $cont-binary (ref.func $pure-binary))
)
)
;; NO-TNH: (func $test-fallthrough-block (type $sig-none)
;; NO-TNH-NEXT: (call $pure)
;; NO-TNH-NEXT: )
;; TNH: (func $test-fallthrough-block (type $sig-none)
;; TNH-NEXT: (call $pure)
;; TNH-NEXT: )
;; VACUUM: (func $test-fallthrough-block (type $sig-none)
;; VACUUM-NEXT: (nop)
;; VACUUM-NEXT: )
(func $test-fallthrough-block
;; Fallthrough cases: straight-line blocks and ref.cast.
(resume $cont-none
(block (result (ref $cont-none))
(cont.new $cont-none
(block (result (ref $sig-none))
(ref.func $pure)
)
)
)
)
)
;; NO-TNH: (func $test-fallthrough-cast (type $sig-none)
;; NO-TNH-NEXT: (call $pure)
;; NO-TNH-NEXT: )
;; TNH: (func $test-fallthrough-cast (type $sig-none)
;; TNH-NEXT: (call $pure)
;; TNH-NEXT: )
;; VACUUM: (func $test-fallthrough-cast (type $sig-none)
;; VACUUM-NEXT: (nop)
;; VACUUM-NEXT: )
(func $test-fallthrough-cast
(resume $cont-none
(cont.new $cont-none
(ref.cast (ref $sig-none)
(ref.func $pure)
)
)
)
)
;; NO-TNH: (func $test-tee (type $10) (result (ref $cont-none))
;; NO-TNH-NEXT: (local $c (ref null $cont-none))
;; NO-TNH-NEXT: (resume $cont-none
;; NO-TNH-NEXT: (local.tee $c
;; NO-TNH-NEXT: (cont.new $cont-none
;; NO-TNH-NEXT: (ref.func $pure)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (ref.as_non_null
;; NO-TNH-NEXT: (local.get $c)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-tee (type $10) (result (ref $cont-none))
;; TNH-NEXT: (local $c (ref null $cont-none))
;; TNH-NEXT: (local $1 (ref null $cont-none))
;; TNH-NEXT: (block
;; TNH-NEXT: (local.set $1
;; TNH-NEXT: (local.tee $c
;; TNH-NEXT: (cont.new $cont-none
;; TNH-NEXT: (ref.func $pure)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (call $pure)
;; TNH-NEXT: )
;; TNH-NEXT: (ref.as_non_null
;; TNH-NEXT: (local.get $c)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-tee (type $10) (result (ref $cont-none))
;; VACUUM-NEXT: (local $c (ref null $cont-none))
;; VACUUM-NEXT: (resume $cont-none
;; VACUUM-NEXT: (local.tee $c
;; VACUUM-NEXT: (cont.new $cont-none
;; VACUUM-NEXT: (ref.func $pure)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (ref.as_non_null
;; VACUUM-NEXT: (local.get $c)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-tee (result (ref $cont-none))
;; trapsNeverHappen: local.tee is only looked through with TNH.
(local $c (ref null $cont-none))
(resume $cont-none
(local.tee $c
(cont.new $cont-none (ref.func $pure))
)
)
(ref.as_non_null (local.get $c))
)
;; NO-TNH: (func $test-tee-params (type $11) (result (ref $cont-binary))
;; NO-TNH-NEXT: (local $c (ref null $cont-binary))
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (resume $cont-binary
;; NO-TNH-NEXT: (i32.const 1)
;; NO-TNH-NEXT: (i32.const 2)
;; NO-TNH-NEXT: (local.tee $c
;; NO-TNH-NEXT: (cont.new $cont-binary
;; NO-TNH-NEXT: (ref.func $pure-binary)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (ref.as_non_null
;; NO-TNH-NEXT: (local.get $c)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-tee-params (type $11) (result (ref $cont-binary))
;; TNH-NEXT: (local $c (ref null $cont-binary))
;; TNH-NEXT: (local $1 (ref null $cont-binary))
;; TNH-NEXT: (drop
;; TNH-NEXT: (block (result i32)
;; TNH-NEXT: (local.set $1
;; TNH-NEXT: (local.tee $c
;; TNH-NEXT: (cont.new $cont-binary
;; TNH-NEXT: (ref.func $pure-binary)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (call $pure-binary
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: (i32.const 2)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (ref.as_non_null
;; TNH-NEXT: (local.get $c)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-tee-params (type $11) (result (ref $cont-binary))
;; VACUUM-NEXT: (local $c (ref null $cont-binary))
;; VACUUM-NEXT: (drop
;; VACUUM-NEXT: (resume $cont-binary
;; VACUUM-NEXT: (i32.const 1)
;; VACUUM-NEXT: (i32.const 2)
;; VACUUM-NEXT: (local.tee $c
;; VACUUM-NEXT: (cont.new $cont-binary
;; VACUUM-NEXT: (ref.func $pure-binary)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (ref.as_non_null
;; VACUUM-NEXT: (local.get $c)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-tee-params (result (ref $cont-binary))
;; trapsNeverHappen: local.tee with operands is only looked through with
;; TNH.
(local $c (ref null $cont-binary))
(drop
(resume $cont-binary
(i32.const 1)
(i32.const 2)
(local.tee $c
(cont.new $cont-binary (ref.func $pure-binary))
)
)
)
(ref.as_non_null (local.get $c))
)
;; NO-TNH: (func $test-tee-func (type $12) (result (ref $sig-none))
;; NO-TNH-NEXT: (local $f (ref null $sig-none))
;; NO-TNH-NEXT: (local $1 (ref (exact $cont-none)))
;; NO-TNH-NEXT: (block
;; NO-TNH-NEXT: (local.set $1
;; NO-TNH-NEXT: (cont.new $cont-none
;; NO-TNH-NEXT: (local.tee $f
;; NO-TNH-NEXT: (ref.func $pure)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (call $pure)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (ref.as_non_null
;; NO-TNH-NEXT: (local.get $f)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-tee-func (type $12) (result (ref $sig-none))
;; TNH-NEXT: (local $f (ref null $sig-none))
;; TNH-NEXT: (local $1 (ref (exact $cont-none)))
;; TNH-NEXT: (block
;; TNH-NEXT: (local.set $1
;; TNH-NEXT: (cont.new $cont-none
;; TNH-NEXT: (local.tee $f
;; TNH-NEXT: (ref.func $pure)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (call $pure)
;; TNH-NEXT: )
;; TNH-NEXT: (ref.as_non_null
;; TNH-NEXT: (local.get $f)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-tee-func (type $12) (result (ref $sig-none))
;; VACUUM-NEXT: (local $f (ref null $sig-none))
;; VACUUM-NEXT: (local $1 (ref (exact $cont-none)))
;; VACUUM-NEXT: (local.set $1
;; VACUUM-NEXT: (cont.new $cont-none
;; VACUUM-NEXT: (local.tee $f
;; VACUUM-NEXT: (ref.func $pure)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (ref.as_non_null
;; VACUUM-NEXT: (local.get $f)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-tee-func (result (ref $sig-none))
;; Now the tee is on the ref.func. We can look through it with or without
;; TNH.
(local $f (ref null $sig-none))
(resume $cont-none
(cont.new $cont-none
(local.tee $f (ref.func $pure))
)
)
(ref.as_non_null (local.get $f))
)
;; NO-TNH: (func $test-negative-suspend (type $sig-none)
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (block $on-suspend (result (ref $cont-none))
;; NO-TNH-NEXT: (resume $cont-none (on $tag $on-suspend)
;; NO-TNH-NEXT: (cont.new $cont-none
;; NO-TNH-NEXT: (ref.func $suspending)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (unreachable)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-negative-suspend (type $sig-none)
;; TNH-NEXT: (drop
;; TNH-NEXT: (block $on-suspend (result (ref $cont-none))
;; TNH-NEXT: (resume $cont-none (on $tag $on-suspend)
;; TNH-NEXT: (cont.new $cont-none
;; TNH-NEXT: (ref.func $suspending)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-negative-suspend (type $sig-none)
;; VACUUM-NEXT: (drop
;; VACUUM-NEXT: (block $on-suspend (result (ref $cont-none))
;; VACUUM-NEXT: (resume $cont-none (on $tag $on-suspend)
;; VACUUM-NEXT: (cont.new $cont-none
;; VACUUM-NEXT: (ref.func $suspending)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (unreachable)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-negative-suspend
;; Negative test: continuation function that suspends cannot be converted.
(block $on-suspend (result (ref $cont-none))
(resume $cont-none (on $tag $on-suspend)
(cont.new $cont-none (ref.func $suspending))
)
(unreachable)
)
(drop)
)
;; NO-TNH: (func $test-negative-transitive-suspend (type $sig-none)
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (block $on-suspend (result (ref $cont-none))
;; NO-TNH-NEXT: (resume $cont-none (on $tag $on-suspend)
;; NO-TNH-NEXT: (cont.new $cont-none
;; NO-TNH-NEXT: (ref.func $caller-of-suspending)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (unreachable)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-negative-transitive-suspend (type $sig-none)
;; TNH-NEXT: (drop
;; TNH-NEXT: (block $on-suspend (result (ref $cont-none))
;; TNH-NEXT: (resume $cont-none (on $tag $on-suspend)
;; TNH-NEXT: (cont.new $cont-none
;; TNH-NEXT: (ref.func $caller-of-suspending)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-negative-transitive-suspend (type $sig-none)
;; VACUUM-NEXT: (drop
;; VACUUM-NEXT: (block $on-suspend (result (ref $cont-none))
;; VACUUM-NEXT: (resume $cont-none (on $tag $on-suspend)
;; VACUUM-NEXT: (cont.new $cont-none
;; VACUUM-NEXT: (ref.func $caller-of-suspending)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (unreachable)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-negative-transitive-suspend
;; Negative test: continuation function calling a suspending function.
(block $on-suspend (result (ref $cont-none))
(resume $cont-none (on $tag $on-suspend)
(cont.new $cont-none (ref.func $caller-of-suspending))
)
(unreachable)
)
(drop)
)
;; NO-TNH: (func $test-same-sig (type $2) (result i32)
;; NO-TNH-NEXT: (call $same-sig-pure
;; NO-TNH-NEXT: (i32.const 42)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-same-sig (type $2) (result i32)
;; TNH-NEXT: (call $same-sig-pure
;; TNH-NEXT: (i32.const 42)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-same-sig (type $2) (result i32)
;; VACUUM-NEXT: (call $same-sig-pure
;; VACUUM-NEXT: (i32.const 42)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-same-sig (result i32)
;; Precision test: function $f does not suspend, but another function with
;; the same signature does. Verify $f is still converted.
(resume $cont-unary
(i32.const 42)
(cont.new $cont-unary (ref.func $same-sig-pure))
)
)
;; NO-TNH: (func $test-eval-order (type $2) (result i32)
;; NO-TNH-NEXT: (local $0 i32)
;; NO-TNH-NEXT: (local $1 i32)
;; NO-TNH-NEXT: (local $2 (ref $cont-binary))
;; NO-TNH-NEXT: (local.set $0
;; NO-TNH-NEXT: (call $side-effect-1)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (local.set $1
;; NO-TNH-NEXT: (call $side-effect-2)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (local.set $2
;; NO-TNH-NEXT: (block (result (ref $cont-binary))
;; NO-TNH-NEXT: (call $side-effect-3)
;; NO-TNH-NEXT: (cont.new $cont-binary
;; NO-TNH-NEXT: (ref.func $pure-binary)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (call $pure-binary
;; NO-TNH-NEXT: (local.get $0)
;; NO-TNH-NEXT: (local.get $1)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-eval-order (type $2) (result i32)
;; TNH-NEXT: (local $0 i32)
;; TNH-NEXT: (local $1 i32)
;; TNH-NEXT: (local $2 (ref $cont-binary))
;; TNH-NEXT: (local.set $0
;; TNH-NEXT: (call $side-effect-1)
;; TNH-NEXT: )
;; TNH-NEXT: (local.set $1
;; TNH-NEXT: (call $side-effect-2)
;; TNH-NEXT: )
;; TNH-NEXT: (local.set $2
;; TNH-NEXT: (block (result (ref $cont-binary))
;; TNH-NEXT: (call $side-effect-3)
;; TNH-NEXT: (cont.new $cont-binary
;; TNH-NEXT: (ref.func $pure-binary)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (call $pure-binary
;; TNH-NEXT: (local.get $0)
;; TNH-NEXT: (local.get $1)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-eval-order (type $2) (result i32)
;; VACUUM-NEXT: (local $0 i32)
;; VACUUM-NEXT: (local $1 i32)
;; VACUUM-NEXT: (local $2 (ref $cont-binary))
;; VACUUM-NEXT: (local.set $0
;; VACUUM-NEXT: (call $side-effect-1)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (local.set $1
;; VACUUM-NEXT: (call $side-effect-2)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (local.set $2
;; VACUUM-NEXT: (block (result (ref (exact $cont-binary)))
;; VACUUM-NEXT: (call $side-effect-3)
;; VACUUM-NEXT: (cont.new $cont-binary
;; VACUUM-NEXT: (ref.func $pure-binary)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (call $pure-binary
;; VACUUM-NEXT: (local.get $0)
;; VACUUM-NEXT: (local.get $1)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-eval-order (result i32)
;; Evaluation order test: side effects in continuation expression execute
;; after operands and before the direct call.
(resume $cont-binary
(call $side-effect-1)
(call $side-effect-2)
(block (result (ref $cont-binary))
(call $side-effect-3)
(cont.new $cont-binary (ref.func $pure-binary))
)
)
)
;; NO-TNH: (func $test-handler-elimination (type $sig-none)
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (block $handler (result (ref $cont-none))
;; NO-TNH-NEXT: (block
;; NO-TNH-NEXT: (call $pure)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (return)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-handler-elimination (type $sig-none)
;; TNH-NEXT: (drop
;; TNH-NEXT: (block $handler (result (ref $cont-none))
;; TNH-NEXT: (block
;; TNH-NEXT: (call $pure)
;; TNH-NEXT: )
;; TNH-NEXT: (return)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-handler-elimination (type $sig-none)
;; VACUUM-NEXT: (nop)
;; VACUUM-NEXT: )
(func $test-handler-elimination
;; Handler elimination test: dead handler blocks are removed in full
;; pipeline.
(block $handler (result (ref $cont-none))
(resume $cont-none (on $tag $handler)
(cont.new $cont-none (ref.func $pure))
)
(return)
)
(drop)
)
;; NO-TNH: (func $test-unreachable-operand (type $sig-none)
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (resume $cont-binary
;; NO-TNH-NEXT: (unreachable)
;; NO-TNH-NEXT: (i32.const 1)
;; NO-TNH-NEXT: (cont.new $cont-binary
;; NO-TNH-NEXT: (ref.func $pure-binary)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-unreachable-operand (type $sig-none)
;; TNH-NEXT: (drop
;; TNH-NEXT: (resume $cont-binary
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: (cont.new $cont-binary
;; TNH-NEXT: (ref.func $pure-binary)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-unreachable-operand (type $sig-none)
;; VACUUM-NEXT: (drop
;; VACUUM-NEXT: (resume $cont-binary
;; VACUUM-NEXT: (unreachable)
;; VACUUM-NEXT: (i32.const 1)
;; VACUUM-NEXT: (cont.new $cont-binary
;; VACUUM-NEXT: (ref.func $pure-binary)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-unreachable-operand
;; Unreachable operands or continuation: resume is unreachable, left for
;; DCE.
(resume $cont-binary
(unreachable)
(i32.const 1)
(cont.new $cont-binary (ref.func $pure-binary))
)
(drop)
)
;; NO-TNH: (func $test-unreachable-cont (type $sig-none)
;; NO-TNH-NEXT: (block ;; (replaces unreachable Resume we can't emit)
;; NO-TNH-NEXT: (drop
;; NO-TNH-NEXT: (unreachable)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (unreachable)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-unreachable-cont (type $sig-none)
;; TNH-NEXT: (block ;; (replaces unreachable Resume we can't emit)
;; TNH-NEXT: (drop
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-unreachable-cont (type $sig-none)
;; VACUUM-NEXT: (block ;; (replaces unreachable Resume we can't emit)
;; VACUUM-NEXT: (drop
;; VACUUM-NEXT: (unreachable)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: (unreachable)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-unreachable-cont
;; Unreachable continuation: resume is unreachable, left for DCE.
(resume $cont-none
(unreachable)
)
)
;; NO-TNH: (func $test-negative-imported (type $sig-none)
;; NO-TNH-NEXT: (resume $cont-none
;; NO-TNH-NEXT: (cont.new $cont-none
;; NO-TNH-NEXT: (ref.func $imported)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; TNH: (func $test-negative-imported (type $sig-none)
;; TNH-NEXT: (resume $cont-none
;; TNH-NEXT: (cont.new $cont-none
;; TNH-NEXT: (ref.func $imported)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; VACUUM: (func $test-negative-imported (type $sig-none)
;; VACUUM-NEXT: (resume $cont-none
;; VACUUM-NEXT: (cont.new $cont-none
;; VACUUM-NEXT: (ref.func $imported)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-negative-imported
;; Negative test: continuation function is imported and cannot be proven
;; non-suspending.
(resume $cont-none
(cont.new $cont-none (ref.func $imported))
)
)
;; NO-TNH: (func $test-handler-switch (type $sig-none)
;; NO-TNH-NEXT: (call $pure)
;; NO-TNH-NEXT: )
;; TNH: (func $test-handler-switch (type $sig-none)
;; TNH-NEXT: (call $pure)
;; TNH-NEXT: )
;; VACUUM: (func $test-handler-switch (type $sig-none)
;; VACUUM-NEXT: (nop)
;; VACUUM-NEXT: )
(func $test-handler-switch
;; Handler elimination test: switch handlers are also eliminated when
;; directizing.
(resume $cont-none (on $tag switch)
(cont.new $cont-none (ref.func $pure))
)
)
;; NO-TNH: (func $test-eval-order-no-operands (type $sig-none)
;; NO-TNH-NEXT: (local $0 (ref $cont-none))
;; NO-TNH-NEXT: (local.set $0
;; NO-TNH-NEXT: (block (result (ref $cont-none))
;; NO-TNH-NEXT: (call $side-effect-3)
;; NO-TNH-NEXT: (cont.new $cont-none
;; NO-TNH-NEXT: (ref.func $pure)
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: )
;; NO-TNH-NEXT: (call $pure)
;; NO-TNH-NEXT: )
;; TNH: (func $test-eval-order-no-operands (type $sig-none)
;; TNH-NEXT: (local $0 (ref $cont-none))
;; TNH-NEXT: (local.set $0
;; TNH-NEXT: (block (result (ref $cont-none))
;; TNH-NEXT: (call $side-effect-3)
;; TNH-NEXT: (cont.new $cont-none
;; TNH-NEXT: (ref.func $pure)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (call $pure)
;; TNH-NEXT: )
;; VACUUM: (func $test-eval-order-no-operands (type $sig-none)
;; VACUUM-NEXT: (local $0 (ref $cont-none))
;; VACUUM-NEXT: (local.set $0
;; VACUUM-NEXT: (block (result (ref (exact $cont-none)))
;; VACUUM-NEXT: (call $side-effect-3)
;; VACUUM-NEXT: (cont.new $cont-none
;; VACUUM-NEXT: (ref.func $pure)
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
;; VACUUM-NEXT: )
(func $test-eval-order-no-operands
;; Evaluation order test: side effects in continuation expression execute
;; before the direct call even when there are no operands.
(resume $cont-none
(block (result (ref $cont-none))
(call $side-effect-3)
(cont.new $cont-none (ref.func $pure))
)
)
)
)