diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/cfp.wast | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/test/lit/passes/cfp.wast b/test/lit/passes/cfp.wast index 99fd9d209..90eecf01b 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -1872,3 +1872,301 @@ ) ) ) + +(module + ;; CHECK: (type $struct (struct_subtype (field i32) data)) + (type $struct (struct i32)) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (global $global i32 (i32.const 42)) + (global $global i32 (i32.const 42)) + + ;; CHECK: (func $test + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test + ;; An immutable global is the only thing written to this field, so we can + ;; propagate the value to the struct.get and replace it with a global.get. + (drop + (struct.new $struct + (global.get $global) + ) + ) + (drop + (struct.get $struct 0 + (ref.null $struct) + ) + ) + ) +) + +(module + ;; CHECK: (type $struct (struct_subtype (field i32) data)) + (type $struct (struct i32)) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (global $global (mut i32) (i32.const 42)) + (global $global (mut i32) (i32.const 42)) + + ;; CHECK: (func $test + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (global.get $global) + ;; 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 + ;; As above, but the global is *not* immutable, so we cannot optimize. + (drop + (struct.new $struct + (global.get $global) + ) + ) + (drop + (struct.get $struct 0 + (ref.null $struct) + ) + ) + ) +) + +(module + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) + (type $struct (struct (mut i32))) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (global $global i32 (i32.const 42)) + (global $global i32 (i32.const 42)) + + ;; CHECK: (func $test + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test + (drop + (struct.new $struct + (global.get $global) + ) + ) + ;; As above, but there is another set of the field. It is the same, though, + ;; so that is fine. Also, the struct's field is now mutable as well to allow + ;; that, and that also does not prevent optimization. + (struct.set $struct 0 + (ref.null $struct) + (global.get $global) + ) + (drop + (struct.get $struct 0 + (ref.null $struct) + ) + ) + ) +) + +(module + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) + (type $struct (struct (mut i32))) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (global $global i32 (i32.const 42)) + (global $global i32 (i32.const 42)) + ;; CHECK: (global $global-2 i32 (i32.const 1337)) + (global $global-2 i32 (i32.const 1337)) + + ;; CHECK: (func $test + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (global.get $global-2) + ;; 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 + (global.get $global) + ) + ) + ;; As above, but set a different global, which prevents optimization. + (struct.set $struct 0 + (ref.null $struct) + (global.get $global-2) + ) + (drop + (struct.get $struct 0 + (ref.null $struct) + ) + ) + ) +) + +(module + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) + (type $struct (struct (mut i32))) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (global $global i32 (i32.const 42)) + (global $global i32 (i32.const 42)) + ;; CHECK: (global $global-2 i32 (i32.const 1337)) + (global $global-2 i32 (i32.const 1337)) + + ;; CHECK: (func $test + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (i32.const 1337) + ;; 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 + (global.get $global) + ) + ) + ;; As above, but set a constant, which means we are mixing constants with + ;; globals, which prevents the optimization. + (struct.set $struct 0 + (ref.null $struct) + (i32.const 1337) + ) + (drop + (struct.get $struct 0 + (ref.null $struct) + ) + ) + ) +) + +(module + ;; Test a global type other than i32. Arrays of structs are a realistic case + ;; as they are used to implement itables. + + ;; CHECK: (type $vtable (struct_subtype (field funcref) data)) + (type $vtable (struct funcref)) + + ;; CHECK: (type $itable (array_subtype (ref $vtable) data)) + (type $itable (array (ref $vtable))) + + ;; CHECK: (type $object (struct_subtype (field $itable (ref $itable)) data)) + (type $object (struct (field $itable (ref $itable)))) + + ;; CHECK: (type $none_=>_funcref (func_subtype (result funcref) func)) + + ;; CHECK: (global $global (ref $itable) (array.init_static $itable + ;; CHECK-NEXT: (struct.new $vtable + ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $vtable + ;; CHECK-NEXT: (ref.func $test) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: )) + (global $global (ref $itable) (array.init_static $itable + (struct.new $vtable + (ref.null func) + ) + (struct.new $vtable + (ref.func $test) + ) + )) + + ;; CHECK: (func $test (result funcref) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $object + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $vtable 0 + ;; CHECK-NEXT: (array.get $itable + ;; CHECK-NEXT: (block (result (ref $itable)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null $object) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test (result funcref) + (drop + (struct.new $object + (global.get $global) + ) + ) + ;; Realistic usage of an itable: read an item from it, then a func from + ;; that, and return the value (all verifying that the types are correct + ;; after optimization). Note how after optimization everything is lined up + ;; so that precompute-propagate can infer from the global.get the specific + ;; object the array.get is on, allowing us to emit a constant value for the + ;; outer struct.get in principle. + (struct.get $vtable 0 + (array.get $itable + (struct.get $object $itable + (ref.null $object) + ) + (i32.const 1) + ) + ) + ) +) + |