diff options
Diffstat (limited to 'test/lit/passes')
-rw-r--r-- | test/lit/passes/precompute-gc.wast | 359 |
1 files changed, 358 insertions, 1 deletions
diff --git a/test/lit/passes/precompute-gc.wast b/test/lit/passes/precompute-gc.wast index 9402aa068..0cd6d2c2c 100644 --- a/test/lit/passes/precompute-gc.wast +++ b/test/lit/passes/precompute-gc.wast @@ -1,8 +1,13 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. -;; RUN: wasm-opt %s --remove-unused-names --precompute-propagate -all -S -o - \ +;; RUN: wasm-opt %s --remove-unused-names --precompute-propagate --fuzz-exec -all -S -o - \ ;; RUN: | filecheck %s (module + (type $struct (struct (mut i32))) + (type $empty (struct)) + + (import "fuzzing-support" "log-i32" (func $log (param i32))) + ;; CHECK: (func $test-fallthrough (result i32) ;; CHECK-NEXT: (local $x funcref) ;; CHECK-NEXT: (local.set $x @@ -34,4 +39,356 @@ (local.get $x) ) ) + + ;; CHECK: (func $load-from-struct + ;; CHECK-NEXT: (local $x (ref null $struct)) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (struct.new_with_rtt $struct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (rtt.canon $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (struct.new_with_rtt $struct + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (rtt.canon $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $load-from-struct + (local $x (ref null $struct)) + (local.set $x + (struct.new_with_rtt $struct + (i32.const 1) + (rtt.canon $struct) + ) + ) + ;; we don't precompute these, as we don't know if the GC data was modified + ;; elsewhere (we'd need immutability or escape analysis) + (call $log + (struct.get $struct 0 (local.get $x)) + ) + ;; Assign a new struct + (local.set $x + (struct.new_with_rtt $struct + (i32.const 2) + (rtt.canon $struct) + ) + ) + (call $log + (struct.get $struct 0 (local.get $x)) + ) + ;; Assign a new value + (struct.set $struct 0 + (local.get $x) + (i32.const 3) + ) + (call $log + (struct.get $struct 0 (local.get $x)) + ) + ) + ;; CHECK: (func $load-from-struct-bad-merge (param $i i32) + ;; CHECK-NEXT: (local $x (ref null $struct)) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $i) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (struct.new_with_rtt $struct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (rtt.canon $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (struct.new_with_rtt $struct + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (rtt.canon $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $load-from-struct-bad-merge (param $i i32) + (local $x (ref null $struct)) + ;; a merge of two different $x values cannot be precomputed + (if + (local.get $i) + (local.set $x + (struct.new_with_rtt $struct + (i32.const 1) + (rtt.canon $struct) + ) + ) + (local.set $x + (struct.new_with_rtt $struct + (i32.const 2) + (rtt.canon $struct) + ) + ) + ) + (call $log + (struct.get $struct 0 (local.get $x)) + ) + ) + ;; CHECK: (func $modify-gc-heap (param $x (ref null $struct)) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $modify-gc-heap (param $x (ref null $struct)) + (struct.set $struct 0 + (local.get $x) + (i32.add + (struct.get $struct 0 + (local.get $x) + ) + (i32.const 1) + ) + ) + ) + ;; --fuzz-exec verifies the output of this function, checking that the change + ;; makde in modify-gc-heap is not ignored + ;; CHECK: (func $load-from-struct-bad-escape + ;; CHECK-NEXT: (local $x (ref null $struct)) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (struct.new_with_rtt $struct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (rtt.canon $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $modify-gc-heap + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $load-from-struct-bad-escape (export "test") + (local $x (ref null $struct)) + (local.set $x + (struct.new_with_rtt $struct + (i32.const 1) + (rtt.canon $struct) + ) + ) + (call $modify-gc-heap + (local.get $x) + ) + (call $log + (struct.get $struct 0 (local.get $x)) + ) + ) + ;; CHECK: (func $load-from-struct-bad-arrive (param $x (ref null $struct)) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $load-from-struct-bad-arrive (param $x (ref null $struct)) + ;; a parameter cannot be precomputed + (call $log + (struct.get $struct 0 (local.get $x)) + ) + ) + ;; CHECK: (func $ref-comparisons (param $x (ref null $struct)) (param $y (ref null $struct)) + ;; CHECK-NEXT: (local $z (ref null $struct)) + ;; CHECK-NEXT: (local $w (ref null $struct)) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $log + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $ref-comparisons + (param $x (ref null $struct)) + (param $y (ref null $struct)) + (local $z (ref null $struct)) + (local $w (ref null $struct)) + ;; incoming parameters are unknown + (call $log + (ref.eq + (local.get $x) + (local.get $y) + ) + ) + (call $log + (ref.eq + (local.get $x) + ;; locals are ref.null which are known, and will be propagated + (local.get $z) + ) + ) + (call $log + (ref.eq + (local.get $x) + (local.get $w) + ) + ) + ;; null-initialized locals are known and can be compared + (call $log + (ref.eq + (local.get $z) + (local.get $w) + ) + ) + ) + ;; CHECK: (func $new-ref-comparisons (result i32) + ;; CHECK-NEXT: (local $x (ref null $struct)) + ;; CHECK-NEXT: (local $y (ref null $struct)) + ;; CHECK-NEXT: (local $tempresult i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (struct.new_with_rtt $struct + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (rtt.canon $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $tempresult + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $tempresult) + ;; CHECK-NEXT: ) + (func $new-ref-comparisons (result i32) + (local $x (ref null $struct)) + (local $y (ref null $struct)) + (local $tempresult i32) + (local.set $x + (struct.new_with_rtt $struct + (i32.const 1) + (rtt.canon $struct) + ) + ) + (local.set $y + (local.get $x) + ) + ;; assign the result, so that propagate calculates the ref.eq + (local.set $tempresult + (ref.eq + (local.get $x) + (local.get $y) + ) + ) + ;; this value could be precomputed in principle, however, we currently do not + ;; precompute GC references, and so nothing will be done. + (local.get $tempresult) + ) + ;; CHECK: (func $propagate-equal (result i32) + ;; CHECK-NEXT: (local $tempresult i32) + ;; CHECK-NEXT: (local $tempref (ref null $empty)) + ;; CHECK-NEXT: (local.set $tempresult + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (local.tee $tempref + ;; CHECK-NEXT: (struct.new_default_with_rtt $empty + ;; CHECK-NEXT: (rtt.canon $empty) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $tempref) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $tempresult) + ;; CHECK-NEXT: ) + (func $propagate-equal (result i32) + (local $tempresult i32) + (local $tempref (ref null $empty)) + ;; assign the result, so that propagate calculates the ref.eq + (local.set $tempresult + (ref.eq + ;; allocate one struct + (local.tee $tempref + (struct.new_with_rtt $empty + (rtt.canon $empty) + ) + ) + (local.get $tempref) + ) + ) + ;; this value could be precomputed in principle, however, we currently do not + ;; precompute GC references, and so nothing will be done. + (local.get $tempresult) + ) + ;; CHECK: (func $propagate-unequal (result i32) + ;; CHECK-NEXT: (local $tempresult i32) + ;; CHECK-NEXT: (local $tempref (ref null $empty)) + ;; CHECK-NEXT: (local.set $tempresult + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (struct.new_default_with_rtt $empty + ;; CHECK-NEXT: (rtt.canon $empty) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default_with_rtt $empty + ;; CHECK-NEXT: (rtt.canon $empty) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $tempresult) + ;; CHECK-NEXT: ) + (func $propagate-unequal (result i32) + (local $tempresult i32) + (local $tempref (ref null $empty)) + ;; assign the result, so that propagate calculates the ref.eq + (local.set $tempresult + ;; allocate two different structs + (ref.eq + (struct.new_with_rtt $empty + (rtt.canon $empty) + ) + (struct.new_with_rtt $empty + (rtt.canon $empty) + ) + ) + ) + ;; this value could be precomputed in principle, however, we currently do not + ;; precompute GC references, and so nothing will be done. + (local.get $tempresult) + ) ) |