diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/cfp.wast | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/test/lit/passes/cfp.wast b/test/lit/passes/cfp.wast index e3bd4b049..38e17c578 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -2292,3 +2292,327 @@ ) ) ) + +;; A type with two subtypes. A copy on the parent can affect either child. +(module + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) + (type $A (sub (struct (field (mut i32))))) + + ;; CHECK: (type $B1 (sub $A (struct (field (mut i32))))) + (type $B1 (sub $A (struct (field (mut i32))))) + + ;; CHECK: (type $B2 (sub $A (struct (field (mut i32))))) + (type $B2 (sub $A (struct (field (mut i32))))) + ) + + ;; CHECK: (type $3 (func (param (ref null $A) (ref null $B1) (ref null $B2)))) + + ;; CHECK: (func $test (type $3) (param $A (ref null $A)) (param $B1 (ref null $B1)) (param $B2 (ref null $B2)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $A + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $B1 + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $B2 + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get $B1 0 + ;; CHECK-NEXT: (local.get $B1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get $B2 0 + ;; CHECK-NEXT: (local.get $B2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test (param $A (ref null $A)) (param $B1 (ref null $B1)) (param $B2 (ref null $B2)) + ;; A and B1 agree on their value in their construction. + (drop + (struct.new $A + (i32.const 10) + ) + ) + (drop + (struct.new $B1 + (i32.const 10) + ) + ) + (drop + (struct.new $B2 + (i32.const 20) ;; this value is different from the others + ) + ) + + ;; Copy on $A + (struct.set $A 0 + (local.get $A) + (struct.get $A 0 + (local.get $A) + ) + ) + + ;; $A might read either child, so we can't infer. + (drop + (struct.get $A 0 + (local.get $A) + ) + ) + ;; $B1 should be only able to read 10, but the copy opens the possibility + ;; of 20, so we can't optimize. + (drop + (struct.get $B1 0 + (local.get $B1) + ) + ) + ;; As with $B1, the copy stops us. + (drop + (struct.get $B2 0 + (local.get $B2) + ) + ) + ) +) + +;; As above, but now the copy is on B1. +(module + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) + (type $A (sub (struct (field (mut i32))))) + + ;; CHECK: (type $B1 (sub $A (struct (field (mut i32))))) + (type $B1 (sub $A (struct (field (mut i32))))) + + ;; CHECK: (type $B2 (sub $A (struct (field (mut i32))))) + (type $B2 (sub $A (struct (field (mut i32))))) + ) + + ;; CHECK: (type $3 (func (param (ref null $A) (ref null $B1) (ref null $B2)))) + + ;; CHECK: (func $test (type $3) (param $A (ref null $A)) (param $B1 (ref null $B1)) (param $B2 (ref null $B2)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $A + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $B1 + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $B2 + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $B1 0 + ;; CHECK-NEXT: (local.get $B1) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $B1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $B1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get $B2 0 + ;; CHECK-NEXT: (local.get $B2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test (param $A (ref null $A)) (param $B1 (ref null $B1)) (param $B2 (ref null $B2)) + (drop + (struct.new $A + (i32.const 10) + ) + ) + (drop + (struct.new $B1 + (i32.const 10) + ) + ) + (drop + (struct.new $B2 + (i32.const 20) + ) + ) + + ;; This changed from $A to $B1. + (struct.set $B1 0 + (local.get $B1) + (struct.get $B1 0 + (local.get $B1) + ) + ) + + ;; This might still read $B1 or $B2, with different values, so we can't + ;; optimize. + (drop + (struct.get $A 0 + (local.get $A) + ) + ) + ;; The copy can only refer to $B1, so we can optimize here. + (drop + (struct.get $B1 0 + (local.get $B1) + ) + ) + ;; The copy can't refer to a $B2, so we can optimize here. TODO + (drop + (struct.get $B2 0 + (local.get $B2) + ) + ) + ) +) + +;; As above, but now the copy is on B2. +(module + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) + (type $A (sub (struct (field (mut i32))))) + + ;; CHECK: (type $B1 (sub $A (struct (field (mut i32))))) + (type $B1 (sub $A (struct (field (mut i32))))) + + ;; CHECK: (type $B2 (sub $A (struct (field (mut i32))))) + (type $B2 (sub $A (struct (field (mut i32))))) + ) + + ;; CHECK: (type $3 (func (param (ref null $A) (ref null $B1) (ref null $B2)))) + + ;; CHECK: (func $test (type $3) (param $A (ref null $A)) (param $B1 (ref null $B1)) (param $B2 (ref null $B2)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $A + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $B1 + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.new $B2 + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $B2 0 + ;; CHECK-NEXT: (local.get $B2) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $B2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get $B1 0 + ;; CHECK-NEXT: (local.get $B1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $B2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test (param $A (ref null $A)) (param $B1 (ref null $B1)) (param $B2 (ref null $B2)) + (drop + (struct.new $A + (i32.const 10) + ) + ) + (drop + (struct.new $B1 + (i32.const 10) + ) + ) + (drop + (struct.new $B2 + (i32.const 20) + ) + ) + + ;; This changed from $A to $B2. + (struct.set $B2 0 + (local.get $B2) + (struct.get $B2 0 + (local.get $B2) + ) + ) + + ;; This might still read $B1 or $B2, with different values, so we can't + ;; optimize. + (drop + (struct.get $A 0 + (local.get $A) + ) + ) + ;; The copy can't refer to a $B1, so we can optimize here. TODO + (drop + (struct.get $B1 0 + (local.get $B1) + ) + ) + ;; $B2 is copied to itself, and nothing else, so we can optimize here. + (drop + (struct.get $B2 0 + (local.get $B2) + ) + ) + ) +) |