diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/help/wasm-opt.test | 2 | ||||
-rw-r--r-- | test/lit/help/wasm2js.test | 2 | ||||
-rw-r--r-- | test/lit/passes/gsi.wast | 806 |
3 files changed, 810 insertions, 0 deletions
diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test index d786bfdfc..1985d70ec 100644 --- a/test/lit/help/wasm-opt.test +++ b/test/lit/help/wasm-opt.test @@ -166,6 +166,8 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --global-refining refine the types of globals ;; CHECK-NEXT: +;; CHECK-NEXT: --gsi globally optimize struct values +;; CHECK-NEXT: ;; CHECK-NEXT: --gto globally optimize GC types ;; CHECK-NEXT: ;; CHECK-NEXT: --heap2local replace GC allocations with diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test index 504e08726..5c0f249e3 100644 --- a/test/lit/help/wasm2js.test +++ b/test/lit/help/wasm2js.test @@ -128,6 +128,8 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --global-refining refine the types of globals ;; CHECK-NEXT: +;; CHECK-NEXT: --gsi globally optimize struct values +;; CHECK-NEXT: ;; CHECK-NEXT: --gto globally optimize GC types ;; CHECK-NEXT: ;; CHECK-NEXT: --heap2local replace GC allocations with diff --git a/test/lit/passes/gsi.wast b/test/lit/passes/gsi.wast new file mode 100644 index 000000000..9b54a98ca --- /dev/null +++ b/test/lit/passes/gsi.wast @@ -0,0 +1,806 @@ +;; 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) + ) + ) + ) +) + +;; 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) + ) + ) + ) +) |