diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/cfp.wast | 297 |
1 files changed, 266 insertions, 31 deletions
diff --git a/test/lit/passes/cfp.wast b/test/lit/passes/cfp.wast index 684e5cf98..fce78d126 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -553,9 +553,7 @@ ;; Subtyping: Create a supertype and get a subtype. As we never create a ;; subtype, the get must trap anyhow (the reference it receives can -;; only by null in this closed world). Since the only possible writes -;; to the field are of the value 10, we will optimize to that. (But -;; as it will trap anyhow, that doesn't really matter.) +;; only be null in this closed world). (module ;; CHECK: (type $none_=>_none (func)) @@ -582,6 +580,61 @@ ) ;; CHECK: (func $get ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null $substruct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $get + (drop + (struct.get $substruct 0 + (ref.null $substruct) + ) + ) + ) +) + +;; As above, but in addition to a new of $struct also add a set. The set could +;; in principle be relevant for the get as far as this pass knows, and so we +;; will optimize the result to the only possible value. (In practice, though, +;; it will trap anyhow.) +(module + ;; CHECK: (type $struct (struct (field (mut i32)))) + (type $struct (struct (mut i32))) + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $substruct (struct (field (mut i32))) (extends $struct)) + (type $substruct (struct (mut i32)) (extends $struct)) + + ;; CHECK: (func $create + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new_with_rtt $struct + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (rtt.canon $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $create + (drop + (struct.new_with_rtt $struct + (i32.const 10) + (rtt.canon $struct) + ) + ) + (struct.set $struct 0 + (ref.null $struct) + (i32.const 10) + ) + ) + ;; CHECK: (func $get + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null @@ -771,17 +824,15 @@ ) ;; Subtyping: Create both a subtype and a supertype, with different constants -;; for the shared field, but get from the subtype. As the field is -;; shared between the types, we cannot optimize here: we model the -;; struct.new as a set, and if there is a set of the supertype, then -;; it might be to a reference of the subtype. -;; TODO: model new and set separately +;; for the shared field, but get from the subtype. The field is +;; shared between the types, but we only create the substruct with +;; one value, so we can optimize. (module + ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $substruct (struct (field i32) (field f64)) (extends $struct)) (type $substruct (struct i32 f64) (extends $struct)) - ;; CHECK: (type $none_=>_none (func)) - ;; CHECK: (type $struct (struct (field i32))) (type $struct (struct i32)) @@ -817,6 +868,75 @@ ) ;; CHECK: (func $get ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null $substruct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $get + (drop + (struct.get $substruct 0 + (ref.null $substruct) + ) + ) + ) +) + +;; As above, but add a set of $struct. The set prevents the optimization. +(module + ;; CHECK: (type $struct (struct (field (mut i32)))) + (type $struct (struct (mut i32))) + + ;; CHECK: (type $substruct (struct (field (mut i32)) (field f64)) (extends $struct)) + (type $substruct (struct (mut i32) f64) (extends $struct)) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (func $create + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new_with_rtt $struct + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (rtt.canon $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new_with_rtt $substruct + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: (rtt.canon $substruct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $create + (drop + (struct.new_with_rtt $struct + (i32.const 10) + (rtt.canon $struct) + ) + ) + (struct.set $struct 0 + (ref.null $struct) + (i32.const 10) + ) + (drop + (struct.new_with_rtt $substruct + (i32.const 20) + (f64.const 3.14159) + (rtt.canon $substruct) + ) + ) + ) + ;; CHECK: (func $get + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $substruct 0 ;; CHECK-NEXT: (ref.null $substruct) ;; CHECK-NEXT: ) @@ -967,22 +1087,17 @@ ;; Multi-level subtyping with conflicts. The even-numbered fields will get ;; different values in the sub-most type. Create the top and bottom types, but -;; not the middle one. Any field which receives more than one value, no matter -;; where, cannot be optimized, which leaves the odd fields as optimizable, as -;; well as fields only present in the sub-most class anyhow (if they have a -;; constant value in the single construction there). -;; (See notes earlier on the limitations of our modeling new and set in the same -;; way.) +;; not the middle one. (module ;; CHECK: (type $struct3 (struct (field i32) (field i32) (field f64) (field f64) (field anyref) (field anyref)) (extends $struct2)) (type $struct3 (struct i32 i32 f64 f64 anyref anyref) (extends $struct2)) - ;; CHECK: (type $struct2 (struct (field i32) (field i32) (field f64) (field f64)) (extends $struct1)) - (type $struct2 (struct i32 i32 f64 f64) (extends $struct1)) - ;; CHECK: (type $struct1 (struct (field i32) (field i32))) (type $struct1 (struct i32 i32)) + ;; CHECK: (type $struct2 (struct (field i32) (field i32) (field f64) (field f64)) (extends $struct1)) + (type $struct2 (struct i32 i32 f64 f64) (extends $struct1)) + ;; CHECK: (type $anyref_=>_none (func (param anyref))) ;; CHECK: (type $none_=>_none (func)) @@ -1055,8 +1170,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct2 1 - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -1090,8 +1210,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct3 1 - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -1196,15 +1321,116 @@ ) ;; Multi-level subtyping with a different value in the middle of the chain. We -;; cannot optimize any of these (for the very last field in the subtype, if we -;; modeled new separately from set then we could, as mentioned earlier). +;; can only optimize $struct3. (module - ;; CHECK: (type $struct1 (struct (field i32))) - (type $struct1 (struct i32)) - ;; CHECK: (type $struct2 (struct (field i32) (field f64)) (extends $struct1)) - (type $struct2 (struct i32 f64) (extends $struct1)) - ;; CHECK: (type $struct3 (struct (field i32) (field f64) (field anyref)) (extends $struct2)) - (type $struct3 (struct i32 f64 anyref) (extends $struct2)) + ;; CHECK: (type $struct1 (struct (field (mut i32)))) + (type $struct1 (struct (mut i32))) + ;; CHECK: (type $struct2 (struct (field (mut i32)) (field f64)) (extends $struct1)) + (type $struct2 (struct (mut i32) f64) (extends $struct1)) + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $struct3 (struct (field (mut i32)) (field f64) (field anyref)) (extends $struct2)) + (type $struct3 (struct (mut i32) f64 anyref) (extends $struct2)) + + ;; CHECK: (func $create + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new_with_rtt $struct1 + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (rtt.canon $struct1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new_with_rtt $struct2 + ;; CHECK-NEXT: (i32.const 9999) + ;; CHECK-NEXT: (f64.const 0) + ;; CHECK-NEXT: (rtt.canon $struct2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new_with_rtt $struct3 + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (f64.const 0) + ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (rtt.canon $struct3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $create + (drop + (struct.new_with_rtt $struct1 + (i32.const 10) + (rtt.canon $struct1) + ) + ) + (drop + (struct.new_with_rtt $struct2 + (i32.const 9999) ;; use a different value here + (f64.const 0) + (rtt.canon $struct2) + ) + ) + (drop + (struct.new_with_rtt $struct3 + (i32.const 10) + (f64.const 0) + (ref.null any) + (rtt.canon $struct3) + ) + ) + ) + ;; CHECK: (func $get + ;; 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: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $get + ;; Get field 0 in all the types. + (drop + (struct.get $struct1 0 + (ref.null $struct1) + ) + ) + (drop + (struct.get $struct2 0 + (ref.null $struct2) + ) + ) + (drop + (struct.get $struct3 0 + (ref.null $struct3) + ) + ) + ) +) + +;; As above, but add not just a new of the middle class with a different value +;; but also a set. That prevents all optimizations. +(module + ;; CHECK: (type $struct2 (struct (field (mut i32)) (field f64)) (extends $struct1)) + (type $struct2 (struct (mut i32) f64) (extends $struct1)) + + ;; CHECK: (type $struct1 (struct (field (mut i32)))) + (type $struct1 (struct (mut i32))) + + ;; CHECK: (type $struct3 (struct (field (mut i32)) (field f64) (field anyref)) (extends $struct2)) + (type $struct3 (struct (mut i32) f64 anyref) (extends $struct2)) ;; CHECK: (type $none_=>_none (func)) @@ -1222,6 +1448,10 @@ ;; CHECK-NEXT: (rtt.canon $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct2 0 + ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (i32.const 9999) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_with_rtt $struct3 ;; CHECK-NEXT: (i32.const 10) @@ -1245,6 +1475,11 @@ (rtt.canon $struct2) ) ) + (struct.set $struct2 0 + (ref.null $struct2) + (i32.const 9999) ;; use a different value here + (f64.const 0) + ) (drop (struct.new_with_rtt $struct3 (i32.const 10) |