blob: c4902b0c542be5289600e21582ab606ea83348b9 [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 -all --dae2 --closed-world -S -o - | filecheck %s
;; TODO: Analyze and optimize stack switching instructions.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $k (cont $f))
;; CHECK: (type $1 (func))
;; CHECK: (type $f (func))
(type $f (func (param i32)))
(type $k (cont $f))
(type $f-unused (func (param i32)))
(type $k-unused (cont $f-unused))
)
;; CHECK: (elem declare func $f)
;; CHECK: (func $f (type $f)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $f (type $f) (param i32)
;; This function is used in a continuation, but not in a way that it ever
;; receives parameters, so it can be optimized.
(nop)
)
;; CHECK: (func $cont-new (type $1)
;; CHECK-NEXT: (local $k (ref null $k))
;; CHECK-NEXT: (local.set $k
;; CHECK-NEXT: (block (result (ref null $k))
;; CHECK-NEXT: (local.get $k)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (cont.new $k
;; CHECK-NEXT: (ref.func $f)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cont-new
;; Having a local that uses a continuation type, and even moving values into
;; and out of that local, is not enough to inhibit optimization.
(local $k (ref null $k))
(local.set $k
(block (result (ref null $k))
(local.get $k)
)
)
;; A cont.new is not enough to inhibit optimizations, either.
(drop
(cont.new $k
(ref.func $f)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $k-sent (cont $f-sent))
;; CHECK: (type $k (cont $f))
;; CHECK: (type $2 (func))
;; CHECK: (type $f-sent (func))
;; CHECK: (type $f (func (param i32)))
(type $f (func (param i32)))
(type $k (cont $f))
(type $f-sent (func (param i64)))
(type $k-sent (cont $f-sent))
;; CHECK: (type $5 (func))
;; CHECK: (type $6 (func (param i32 (ref $k))))
;; CHECK: (elem declare func $f $f-sent)
;; CHECK: (tag $e (type $5))
(tag $e)
;; CHECK: (func $f (type $f) (param $0 i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $f)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $f (type $f) (param i32)
;; This referenced function will not be optimized.
(drop
(ref.func $f)
)
)
;; CHECK: (func $unreferenced (type $2)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $unreferenced (type $f) (param i32)
;; This unreferenced function with the same type can still be optimized.
(nop)
)
;; CHECK: (func $f-sent (type $f-sent)
;; CHECK-NEXT: (local $0 i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $f-sent)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $f-sent (type $f-sent) (param i64)
;; This can be optimized.
(drop
(ref.func $f-sent)
)
)
;; CHECK: (func $resume (type $6) (param $x i32) (param $k (ref $k))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $l (result (ref null $k-sent))
;; CHECK-NEXT: (resume $k (on $e $l)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (local.get $k)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $resume (param $x i32) (param $k (ref $k))
;; resume inhibits optimizations for the resumed continuation type, but not
;; the continuation types it sends.
(drop
(block $l (result (ref null $k-sent))
(resume $k (on $e $l)
(local.get $x)
(local.get $k)
)
(unreachable)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $k-sent (cont $f-sent))
;; CHECK: (type $k (cont $f))
;; CHECK: (type $2 (func))
;; CHECK: (type $f-sent (func))
;; CHECK: (type $f (func (param i32)))
(type $f (func (param i32)))
(type $k (cont $f))
(type $f-sent (func (param i64)))
(type $k-sent (cont $f-sent))
;; CHECK: (type $5 (func))
;; CHECK: (type $6 (func (param (ref $k))))
;; CHECK: (elem declare func $f $f-sent)
;; CHECK: (tag $e (type $5))
(tag $e)
;; CHECK: (func $f (type $f) (param $0 i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $f)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $f (type $f) (param i32)
;; This referenced function will not be optimized.
(drop
(ref.func $f)
)
)
;; CHECK: (func $f-sent (type $f-sent)
;; CHECK-NEXT: (local $0 i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $f-sent)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $f-sent (type $f-sent) (param i64)
;; This can be optimized.
(drop
(ref.func $f-sent)
)
)
;; CHECK: (func $resume-throw (type $6) (param $k (ref $k))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $l (result (ref null $k-sent))
;; CHECK-NEXT: (resume_throw $k $e (on $e $l)
;; CHECK-NEXT: (local.get $k)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $resume-throw (param $k (ref $k))
;; resume_throw inhibits optimizations for the resumed continuation type,
;; but not the continuation types it sends.
(drop
(block $l (result (ref null $k-sent))
(resume_throw $k $e (on $e $l)
(local.get $k)
)
(unreachable)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $k-ret (cont $f-ret))
;; CHECK: (type $k (cont $f))
;; CHECK: (type $2 (func))
;; CHECK: (type $f-ret (func (param i64 (ref null $k))))
(type $f-ret (func (param i64 (ref null $k))))
(type $k-ret (cont $f-ret))
;; CHECK: (type $f (func (param i32 (ref null $k-ret))))
(type $f (func (param i32 (ref null $k-ret))))
(type $k (cont $f))
)
;; CHECK: (type $5 (func))
;; CHECK: (type $6 (func (param i32 (ref $k))))
;; CHECK: (elem declare func $f $f-ret)
;; CHECK: (tag $e (type $5))
(tag $e)
;; CHECK: (func $f (type $f) (param $0 i32) (param $1 (ref null $k-ret))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $f)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $f (type $f) (param i32) (param (ref null $k-ret))
;; This referenced function will not be optimized.
(drop
(ref.func $f)
)
)
;; CHECK: (func $f-ret (type $f-ret) (param $0 i64) (param $1 (ref null $k))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $f-ret)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $f-ret (type $f-ret) (param i64) (param (ref null $k))
;; This cannot be optimized either.
(drop
(ref.func $f-ret)
)
)
;; CHECK: (func $switch (type $6) (param $x i32) (param $k (ref $k))
;; CHECK-NEXT: (tuple.drop 2
;; CHECK-NEXT: (switch $k $e
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (local.get $k)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable StackSwitch we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $switch (param $x i32) (param $k (ref $k))
;; switch inhibits optimizations for both the target and return continuation
;; types.
(tuple.drop 2
(switch $k $e
(local.get $x)
(local.get $k)
)
)
;; Do not get confused when the continuation is unreachable.
(switch $k $e
(local.get $x)
(unreachable)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $k2 (cont $f2))
;; CHECK: (type $k1 (cont $f1))
;; CHECK: (type $2 (func))
;; CHECK: (type $f2 (func (param i64)))
;; CHECK: (type $f1 (func (param i32 i64)))
(type $f1 (func (param i32 i64)))
(type $k1 (cont $f1))
(type $f2 (func (param i64)))
(type $k2 (cont $f2))
;; CHECK: (type $5 (func))
;; CHECK: (type $6 (func (param i32 (ref $k1))))
;; CHECK: (elem declare func $f1 $f2)
;; CHECK: (tag $e (type $5))
(tag $e)
;; CHECK: (func $f1 (type $f1) (param $0 i32) (param $1 i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $f1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $f1 (type $f1) (param i32) (param i64)
;; This referenced function will not be optimized.
(drop
(ref.func $f1)
)
)
;; CHECK: (func $f2 (type $f2) (param $0 i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $f2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $f2 (type $f2) (param i64)
;; This will not be optimized either.
(drop
(ref.func $f2)
)
)
;; CHECK: (func $cont-bind (type $6) (param $x i32) (param $k1 (ref $k1))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (cont.bind $k1 $k2
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (local.get $k1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cont-bind (param $x i32) (param $k1 (ref $k1))
;; cont.bind inhibits optimizations for both the input and output types.
(drop
(cont.bind $k1 $k2
(local.get $x)
(local.get $k1)
)
)
)
)