| ;; 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 |
| |
| ;; The global.get of $global is the descriptor, not a field of the struct. |
| ;; We should not try to optimize it away and error. |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (descriptor $desc) (struct)) |
| (type $struct (descriptor $desc) (struct)) |
| ;; CHECK: (type $desc (describes $struct) (struct)) |
| (type $desc (describes $struct) (struct)) |
| ) |
| |
| ;; CHECK: (type $2 (func)) |
| |
| ;; CHECK: (global $desc (ref (exact $desc)) (struct.new_default $desc)) |
| (global $desc (ref (exact $desc)) (struct.new $desc)) |
| |
| ;; CHECK: (export "export" (func $export)) |
| |
| ;; CHECK: (func $export (type $2) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $export (export "export") |
| (drop |
| (struct.new_desc $struct |
| (global.get $desc) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; We cannot optimize out globals whose initializers might trap due to a null |
| ;; descriptor (or conservatively even just a nullable descriptor). |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (descriptor $desc) (struct)) |
| (type $struct (descriptor $desc) (struct)) |
| ;; CHECK: (type $desc (describes $struct) (struct)) |
| (type $desc (describes $struct) (struct)) |
| ;; CHECK: (type $list (struct (field (ref $struct)) (field (ref null $list)))) |
| (type $list (struct (field (ref $struct)) (field (ref null $list)))) |
| ) |
| |
| ;; CHECK: (global $null nullref (ref.null none)) |
| (global $null nullref (ref.null none)) |
| ;; CHECK: (global $nullable-desc (ref null (exact $desc)) (struct.new_default $desc)) |
| (global $nullable-desc (ref null (exact $desc)) (struct.new $desc)) |
| ;; CHECK: (global $desc (ref (exact $desc)) (struct.new_default $desc)) |
| (global $desc (ref (exact $desc)) (struct.new $desc)) |
| |
| ;; Trapping globals must be kept, but non-trapping globals can be removed. |
| ;; CHECK: (global $trap (ref $struct) (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (ref.null none) |
| ;; CHECK-NEXT: )) |
| (global $trap (ref $struct) (struct.new_desc $struct (ref.null none))) |
| (global $no-trap (ref $struct) (struct.new_desc $struct (struct.new $desc))) |
| |
| ;; CHECK: (global $trap-get-null (ref $struct) (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (global.get $null) |
| ;; CHECK-NEXT: )) |
| (global $trap-get-null (ref $struct) (struct.new_desc $struct (global.get $null))) |
| ;; CHECK: (global $trap-get-nullable (ref $struct) (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (global.get $nullable-desc) |
| ;; CHECK-NEXT: )) |
| (global $trap-get-nullable (ref $struct) (struct.new_desc $struct (global.get $nullable-desc))) |
| (global $no-trap-get (ref $struct) (struct.new_desc $struct (global.get $desc))) |
| |
| ;; CHECK: (global $trap-nested (ref $list) (struct.new $list |
| ;; CHECK-NEXT: (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (struct.new_default $desc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.new $list |
| ;; CHECK-NEXT: (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.new $list |
| ;; CHECK-NEXT: (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (ref.null none) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (ref.null none) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: )) |
| (global $trap-nested (ref $list) |
| (struct.new $list |
| (struct.new_desc $struct (struct.new $desc)) |
| (struct.new $list |
| (struct.new_desc $struct (global.get $desc)) |
| (struct.new $list |
| (struct.new_desc $struct (ref.null none)) |
| (ref.null none) |
| ) |
| ) |
| ) |
| ) |
| |
| (global $no-trap-nested (ref $list) |
| (struct.new $list |
| (struct.new_desc $struct (struct.new $desc)) |
| (struct.new $list |
| (struct.new_desc $struct (global.get $desc)) |
| (ref.null none) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (elem $trap anyref (item (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (ref.null none) |
| ;; CHECK-NEXT: ))) |
| (elem $trap anyref (item (struct.new_desc $struct (ref.null none)))) |
| (elem $no-trap anyref (item (struct.new_desc $struct (struct.new $desc)))) |
| ;; CHECK: (elem $trap-get-null anyref (item (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (global.get $null) |
| ;; CHECK-NEXT: ))) |
| (elem $trap-get-null anyref (item (struct.new_desc $struct (global.get $null)))) |
| ;; CHECK: (elem $trap-get-nullable anyref (item (struct.new_default_desc $struct |
| ;; CHECK-NEXT: (global.get $nullable-desc) |
| ;; CHECK-NEXT: ))) |
| (elem $trap-get-nullable anyref (item (struct.new_desc $struct (global.get $nullable-desc)))) |
| (elem $no-trap-get anyref (item (struct.new_desc $struct (global.get $desc)))) |
| ) |
| |
| (module |
| ;; CHECK: (type $void (func)) |
| (type $void (func)) |
| |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $vtable (sub (descriptor $vtable.desc) (struct (field (ref $void))))) |
| (type $vtable (sub (descriptor $vtable.desc) (struct (field (ref $void))))) |
| ;; CHECK: (type $vtable.desc (sub (describes $vtable) (struct (field (ref $void))))) |
| (type $vtable.desc (sub (describes $vtable) (struct (field (ref $void))))) |
| ) |
| |
| ;; CHECK: (global $vtable (ref $vtable) (struct.new_desc $vtable |
| ;; CHECK-NEXT: (ref.func $a) |
| ;; CHECK-NEXT: (struct.new $vtable.desc |
| ;; CHECK-NEXT: (ref.func $b) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: )) |
| (global $vtable (ref $vtable) (struct.new_desc $vtable |
| (ref.func $a) |
| (struct.new $vtable.desc |
| (ref.func $b) |
| ) |
| )) |
| |
| ;; CHECK: (export "export" (func $export)) |
| |
| ;; CHECK: (func $export (type $void) |
| ;; CHECK-NEXT: (call_ref $void |
| ;; CHECK-NEXT: (struct.get $vtable 0 |
| ;; CHECK-NEXT: (global.get $vtable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $export (export "export") |
| ;; Read $a and call it. $b, in the descriptor, should not be callable. |
| (call_ref $void |
| (struct.get $vtable 0 |
| (global.get $vtable) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $a (type $void) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 42) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $a (type $void) |
| ;; This is reached from above. |
| (drop (i32.const 42)) |
| ) |
| |
| ;; CHECK: (func $b (type $void) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| (func $b (type $void) |
| ;; This is not reached: We never read the descriptor, so we never read field 0 |
| ;; in it, leaving this as dead (in closed world). That it itself seems to read |
| ;; the descriptor should not confuse us. |
| (call_ref $void |
| (struct.get $vtable.desc 0 |
| (ref.get_desc $vtable |
| (global.get $vtable) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |