blob: 710be00b7b364a602f7a2f1e553878ce33eae301 [file] [log] [blame] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt --remove-unused-module-elements --closed-world -all -S -o - | filecheck %s
;; RUN: foreach %s %t wasm-opt --remove-unused-module-elements -all -S -o - | filecheck %s --check-prefix OPEN_WORLD
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $foo (func))
;; OPEN_WORLD: (rec
;; OPEN_WORLD-NEXT: (type $foo (func))
(type $foo (func))
;; CHECK: (type $bar (func))
;; OPEN_WORLD: (type $bar (func))
(type $bar (func))
)
;; CHECK: (type $2 (func))
;; CHECK: (table $table 10 funcref)
;; OPEN_WORLD: (type $2 (func))
;; OPEN_WORLD: (table $table 10 funcref)
(table $table 10 funcref)
;; CHECK: (elem $table (i32.const 0) $foo-in-table $bar)
;; OPEN_WORLD: (elem $table (i32.const 0) $foo-in-table $bar)
(elem $table (i32.const 0) $foo-in-table $bar)
;; CHECK: (elem declare func $foo-not-in-table)
;; CHECK: (export "export" (func $export))
;; CHECK: (func $export (type $2)
;; CHECK-NEXT: (call_indirect $table (type $foo)
;; CHECK-NEXT: (i32.const 5)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $foo-not-in-table)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPEN_WORLD: (elem declare func $foo-not-in-table)
;; OPEN_WORLD: (export "export" (func $export))
;; OPEN_WORLD: (func $export (type $2)
;; OPEN_WORLD-NEXT: (call_indirect $table (type $foo)
;; OPEN_WORLD-NEXT: (i32.const 5)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (ref.func $foo-not-in-table)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $export (export "export")
;; Call type $foo and nothing else.
(call_indirect $table (type $foo)
;; TODO: we could track indexes in the table.
(i32.const 5)
)
;; Refer to $foo-not-in-table.
(drop
(ref.func $foo-not-in-table)
)
)
;; CHECK: (func $foo-in-table (type $foo)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $foo-in-table (type $foo)
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (i32.const 10)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $foo-in-table (type $foo)
;; This should not change: type $foo is called, and this is in the table.
(drop (i32.const 10))
)
;; CHECK: (func $foo-not-in-table (type $foo)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $foo-not-in-table (type $foo)
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (i32.const 20)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $foo-not-in-table (type $foo)
;; This can be made unreachable: its type is called, but it is not in the
;; table, and we can see the table's contents: no table.set etc. can put us
;; there, and it is not imported/exported. That we are referred to is not
;; enough to keep our contents alive, at least not in closed world (in open
;; world, our reference might escape and be called outside).
(drop (i32.const 20))
)
;; CHECK: (func $bar (type $bar)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $bar (type $bar)
;; OPEN_WORLD-NEXT: (unreachable)
;; OPEN_WORLD-NEXT: )
(func $bar (type $bar)
;; This can be made unreachable: its type is not even called, even though it
;; is in the table.
(drop (i32.const 30))
)
)
;; As above, but now the table is exported. It might be written to from the
;; outside, preventing some opts.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $foo (func))
;; OPEN_WORLD: (rec
;; OPEN_WORLD-NEXT: (type $foo (func))
(type $foo (func))
;; CHECK: (type $bar (func))
;; OPEN_WORLD: (type $bar (func))
(type $bar (func))
)
;; CHECK: (type $2 (func))
;; CHECK: (table $table 10 funcref)
;; OPEN_WORLD: (type $2 (func))
;; OPEN_WORLD: (table $table 10 funcref)
(table $table 10 funcref)
;; CHECK: (elem $table (i32.const 0) $foo-in-table $bar)
;; OPEN_WORLD: (elem $table (i32.const 0) $foo-in-table $bar)
(elem $table (i32.const 0) $foo-in-table $bar)
;; CHECK: (elem declare func $foo-not-in-table)
;; CHECK: (export "export" (func $export))
;; CHECK: (export "table" (table $table))
;; OPEN_WORLD: (elem declare func $foo-not-in-table)
;; OPEN_WORLD: (export "export" (func $export))
;; OPEN_WORLD: (export "table" (table $table))
(export "table" (table $table)) ;; this was added
;; CHECK: (func $export (type $2)
;; CHECK-NEXT: (call_indirect $table (type $foo)
;; CHECK-NEXT: (i32.const 5)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $foo-not-in-table)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $export (type $2)
;; OPEN_WORLD-NEXT: (call_indirect $table (type $foo)
;; OPEN_WORLD-NEXT: (i32.const 5)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (ref.func $foo-not-in-table)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $export (export "export")
(call_indirect $table (type $foo)
(i32.const 5)
)
(drop
(ref.func $foo-not-in-table)
)
)
;; CHECK: (func $foo-in-table (type $foo)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $foo-in-table (type $foo)
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (i32.const 10)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $foo-in-table (type $foo)
;; As above.
(drop (i32.const 10))
)
;; CHECK: (func $foo-not-in-table (type $foo)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $foo-not-in-table (type $foo)
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (i32.const 20)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $foo-not-in-table (type $foo)
;; Optimization changes here: the table is public, so we must assume this
;; could be in the table, written there from outside. Even in closed world,
;; we change nothing here.
(drop (i32.const 20))
)
;; CHECK: (func $bar (type $bar)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $bar (type $bar)
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (i32.const 30)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $bar (type $bar)
;; This changes too: In open world, we cannot assume this is not called, and
;; leave it alone.
(drop (i32.const 30))
)
)
;; As above, but now the table has a table.set.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $foo (func))
;; OPEN_WORLD: (rec
;; OPEN_WORLD-NEXT: (type $foo (func))
(type $foo (func))
;; CHECK: (type $bar (func))
;; OPEN_WORLD: (type $bar (func))
(type $bar (func))
)
;; CHECK: (type $2 (func))
;; CHECK: (table $table 10 funcref)
;; OPEN_WORLD: (type $2 (func))
;; OPEN_WORLD: (table $table 10 funcref)
(table $table 10 funcref)
;; CHECK: (elem $table (i32.const 0) $foo-in-table $bar)
;; OPEN_WORLD: (elem $table (i32.const 0) $foo-in-table $bar)
(elem $table (i32.const 0) $foo-in-table $bar)
;; CHECK: (elem declare func $foo-not-in-table)
;; CHECK: (export "export" (func $export))
;; CHECK: (func $export (type $2)
;; CHECK-NEXT: (call_indirect $table (type $foo)
;; CHECK-NEXT: (i32.const 5)
;; CHECK-NEXT: )
;; CHECK-NEXT: (table.set $table
;; CHECK-NEXT: (i32.const 7)
;; CHECK-NEXT: (ref.null nofunc)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $foo-not-in-table)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPEN_WORLD: (elem declare func $foo-not-in-table)
;; OPEN_WORLD: (export "export" (func $export))
;; OPEN_WORLD: (func $export (type $2)
;; OPEN_WORLD-NEXT: (call_indirect $table (type $foo)
;; OPEN_WORLD-NEXT: (i32.const 5)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: (table.set $table
;; OPEN_WORLD-NEXT: (i32.const 7)
;; OPEN_WORLD-NEXT: (ref.null nofunc)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (ref.func $foo-not-in-table)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $export (export "export")
(call_indirect $table (type $foo)
(i32.const 5)
)
(table.set $table
(i32.const 7)
(ref.null func)
)
;; Take the reference of $foo-not-in-table, so that it is referred to but
;; not in the table. The table.set will make our analysis believe it might
;; be there (we do not track the flow of values precisely).
(drop
(ref.func $foo-not-in-table)
)
)
;; CHECK: (func $foo-in-table (type $foo)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $foo-in-table (type $foo)
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (i32.const 10)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $foo-in-table (type $foo)
;; As above.
(drop (i32.const 10))
)
;; CHECK: (func $foo-not-in-table (type $foo)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $foo-not-in-table (type $foo)
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (i32.const 20)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $foo-not-in-table (type $foo)
;; The reference taken of this function might be table.set'ed, so we can do
;; nothing here.
(drop (i32.const 20))
)
;; CHECK: (func $bar (type $bar)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; OPEN_WORLD: (func $bar (type $bar)
;; OPEN_WORLD-NEXT: (drop
;; OPEN_WORLD-NEXT: (i32.const 30)
;; OPEN_WORLD-NEXT: )
;; OPEN_WORLD-NEXT: )
(func $bar (type $bar)
;; As above.
(drop (i32.const 30))
)
)