blob: e378fa262819e33e830b66aab6809f7515a92309 [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 --nominal --gsi -all -S -o - | filecheck %s
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; A non-reference global does not confuse us.
;; CHECK: (global $global-other i32 (i32.const 123456))
(global $global-other i32 (i32.const 123456))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
;; We can infer that this get can reference either $global1 or $global2,
;; and nothing else (aside from a null), and can emit a select between
;; those values.
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; As above, but now the field is mutable, so we cannot optimize.
(module
;; CHECK: (type $struct (struct_subtype (field (mut i32)) data))
(type $struct (struct (mut i32)))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; Just one global. We do not optimize here - we let other passes do that.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; Three globals. For now, we do not optimize here.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global3 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 99999)
;; CHECK-NEXT: ))
(global $global3 (ref $struct) (struct.new $struct
(i32.const 99999)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; Three globals, as above, but now two agree on their values. We can optimize
;; by comparing to the one that has a single value.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global3 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global3 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; As above, but move the different value of the three to the middle.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global3 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global3 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; As above, but move the different value of the three to the end.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global3 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global3 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; Four values, two pairs of equal ones. We do not optimize this.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global3 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global3 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global4 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global4 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; Four values, three equal and one unique. We can optimize this with a single
;; comparison on the unique one.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global3 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global3 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global4 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global4 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; A struct.new inside a function stops us from optimizing.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $struct
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.new $struct
(i32.const 1)
)
)
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; We ignore imports, as we assume a closed world, but that might change in the
;; future. For now, we will optimize here.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (import "a" "b" (global $global-import (ref $struct)))
(import "a" "b" (global $global-import (ref $struct)))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; A struct.new in a non-toplevel position in a global stops us from
;; optimizing.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $tuple (struct_subtype (field anyref) (field anyref) data))
(type $tuple (struct anyref anyref))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global-tuple (ref $tuple) (struct.new $tuple
;; CHECK-NEXT: (struct.new $struct
;; CHECK-NEXT: (i32.const 999999)
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: ))
(global $global-tuple (ref $tuple) (struct.new $tuple
(struct.new $struct
(i32.const 999999)
)
(ref.null any)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; As above, but remove the struct.new in a nested position, while keeping all
;; the other stuff in the above test. Now we should optimize.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $tuple (struct_subtype (field anyref) (field anyref) data))
(type $tuple (struct anyref anyref))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (global $global-tuple (ref $tuple) (struct.new $tuple
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: (ref.null any)
;; CHECK-NEXT: ))
(global $global-tuple (ref $tuple) (struct.new $tuple
(ref.null any)
(ref.null any)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; When one of the globals is mutable, we cannot optimize.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (mut (ref $struct)) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (mut (ref $struct)) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; A subtype is not optimizable, which prevents $struct from being optimized.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct_subtype i32 data))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (type $sub-struct (struct_subtype (field i32) $struct))
(type $sub-struct (struct_subtype i32 $struct))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub-struct
;; CHECK-NEXT: (i32.const 999999)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.new $sub-struct
(i32.const 999999)
)
)
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; A *super*-type is not optimizable, but that does not block us, and we can
;; optimize.
(module
;; CHECK: (type $super-struct (struct_subtype (field i32) data))
(type $super-struct (struct_subtype i32 data))
;; CHECK: (type $struct (struct_subtype (field i32) $super-struct))
(type $struct (struct_subtype i32 $super-struct))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $super-struct
;; CHECK-NEXT: (i32.const 999999)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.new $super-struct
(i32.const 999999)
)
)
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; One global for each of the type and the subtype. The optimization will pick
;; between their 2 values.
(module
;; CHECK: (type $super-struct (struct_subtype (field i32) data))
(type $super-struct (struct_subtype i32 data))
;; CHECK: (type $struct (struct_subtype (field i32) $super-struct))
(type $struct (struct_subtype i32 $super-struct))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $super-struct) (struct.new $super-struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global1 (ref $super-struct) (struct.new $super-struct
(i32.const 42)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $super-struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
;; We cannot optimize the first - it has just one global - but the second
;; will consider the struct and sub-struct, find 2 possible values, and
;; optimize.
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
(drop
(struct.get $super-struct 0
(ref.null $super-struct)
)
)
)
)
;; One global has a non-constant field, so we cannot optimize.
(module
;; CHECK: (type $struct (struct_subtype (field i32) data))
(type $struct (struct i32))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global1 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (i32.const 41)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: ))
(global $global1 (ref $struct) (struct.new $struct
(i32.add
(i32.const 41)
(i32.const 1)
)
))
;; CHECK: (global $global2 (ref $struct) (struct.new $struct
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: ))
(global $global2 (ref $struct) (struct.new $struct
(i32.const 1337)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (ref.null $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(drop
(struct.get $struct 0
(ref.null $struct)
)
)
)
)
;; One global each for two subtypes of a common supertype, and one for the
;; supertype.
(module
;; CHECK: (type $super-struct (struct_subtype (field i32) data))
(type $super-struct (struct_subtype i32 data))
;; CHECK: (type $struct1 (struct_subtype (field i32) (field f32) $super-struct))
(type $struct1 (struct_subtype i32 f32 $super-struct))
;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $super-struct))
(type $struct2 (struct_subtype i32 f64 $super-struct))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global0 (ref $super-struct) (struct.new $super-struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global0 (ref $super-struct) (struct.new $super-struct
(i32.const 42)
))
;; CHECK: (global $global1 (ref $struct1) (struct.new $struct1
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (f32.const 3.141590118408203)
;; CHECK-NEXT: ))
(global $global1 (ref $struct1) (struct.new $struct1
(i32.const 1337)
(f32.const 3.14159)
))
;; CHECK: (global $global2 (ref $struct2) (struct.new $struct2
;; CHECK-NEXT: (i32.const 99999)
;; CHECK-NEXT: (f64.const 2.71828)
;; CHECK-NEXT: ))
(global $global2 (ref $struct2) (struct.new $struct2
(i32.const 99999)
(f64.const 2.71828)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super-struct 0
;; CHECK-NEXT: (ref.null $super-struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct1 0
;; CHECK-NEXT: (ref.null $struct1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct2 0
;; CHECK-NEXT: (ref.null $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
;; This has three possible values due to the two children, so we do not
;; optimize.
(drop
(struct.get $super-struct 0
(ref.null $super-struct)
)
)
;; These each have one possible value, so we also do not optimize.
(drop
(struct.get $struct1 0
(ref.null $struct1)
)
)
(drop
(struct.get $struct2 0
(ref.null $struct2)
)
)
)
)
;; As above, but now the subtypes each have 2 values, and we can optimize.
(module
;; CHECK: (type $super-struct (struct_subtype (field i32) data))
(type $super-struct (struct_subtype i32 data))
;; CHECK: (type $struct1 (struct_subtype (field i32) (field f32) $super-struct))
(type $struct1 (struct_subtype i32 f32 $super-struct))
;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $super-struct))
(type $struct2 (struct_subtype i32 f64 $super-struct))
;; CHECK: (type $none_=>_none (func_subtype func))
;; CHECK: (global $global0 (ref $super-struct) (struct.new $super-struct
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: ))
(global $global0 (ref $super-struct) (struct.new $super-struct
(i32.const 42)
))
;; CHECK: (global $global1 (ref $struct1) (struct.new $struct1
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (f32.const 3.141590118408203)
;; CHECK-NEXT: ))
(global $global1 (ref $struct1) (struct.new $struct1
(i32.const 1337)
(f32.const 3.14159)
))
;; CHECK: (global $global1b (ref $struct1) (struct.new $struct1
;; CHECK-NEXT: (i32.const 1338)
;; CHECK-NEXT: (f32.const 3.141590118408203)
;; CHECK-NEXT: ))
(global $global1b (ref $struct1) (struct.new $struct1
(i32.const 1338)
(f32.const 3.14159)
))
;; CHECK: (global $global2 (ref $struct2) (struct.new $struct2
;; CHECK-NEXT: (i32.const 99999)
;; CHECK-NEXT: (f64.const 2.71828)
;; CHECK-NEXT: ))
(global $global2 (ref $struct2) (struct.new $struct2
(i32.const 99999)
(f64.const 2.71828)
))
;; CHECK: (global $global2b (ref $struct2) (struct.new $struct2
;; CHECK-NEXT: (i32.const 99998)
;; CHECK-NEXT: (f64.const 2.71828)
;; CHECK-NEXT: ))
(global $global2b (ref $struct2) (struct.new $struct2
(i32.const 99998)
(f64.const 2.71828)
))
;; CHECK: (func $test (type $none_=>_none)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super-struct 0
;; CHECK-NEXT: (ref.null $super-struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (i32.const 1338)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select
;; CHECK-NEXT: (i32.const 99999)
;; CHECK-NEXT: (i32.const 99998)
;; CHECK-NEXT: (ref.eq
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (ref.null $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $global2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
;; This still cannot be optimized.
(drop
(struct.get $super-struct 0
(ref.null $super-struct)
)
)
;; These can be optimized, and will be different from one another.
(drop
(struct.get $struct1 0
(ref.null $struct1)
)
)
(drop
(struct.get $struct2 0
(ref.null $struct2)
)
)
)
)