diff options
Diffstat (limited to 'test/lit/ctor-eval')
-rw-r--r-- | test/lit/ctor-eval/gc-cycle-multi.wast | 144 | ||||
-rw-r--r-- | test/lit/ctor-eval/gc-cycle.wast | 1297 | ||||
-rw-r--r-- | test/lit/ctor-eval/partial-global.wat | 39 |
3 files changed, 1480 insertions, 0 deletions
diff --git a/test/lit/ctor-eval/gc-cycle-multi.wast b/test/lit/ctor-eval/gc-cycle-multi.wast new file mode 100644 index 000000000..62a888dbd --- /dev/null +++ b/test/lit/ctor-eval/gc-cycle-multi.wast @@ -0,0 +1,144 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: foreach %s %t wasm-ctor-eval --ctors=test1,test2,test3 --kept-exports=test1,test2,test3 --quiet -all -S -o - | filecheck %s + +;; Similar to gc-cycle.wast, but now there are three exported ctors that we +;; call. + +(module + ;; Multiple independent cycles. + ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) + (type $A (struct (field (mut (ref null $A))) (field i32))) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_8 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 30) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $c (mut (ref null $A)) (global.get $ctor-eval$global_8)) + + ;; CHECK: (global $ctor-eval$global_7 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7)) + (global $a (mut (ref null $A)) (ref.null $A)) + ;; CHECK: (global $ctor-eval$global_6 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $b (mut (ref null $A)) (global.get $ctor-eval$global_6)) + (global $b (mut (ref null $A)) (ref.null $A)) + (global $c (mut (ref null $A)) (ref.null $A)) + + (func $makeCycle (param $i i32) (result (ref $A)) + (local $x (ref $A)) + (local.set $x + (struct.new $A + (ref.null $A) + (local.get $i) + ) + ) + (struct.set $A 0 + (local.get $x) + (local.get $x) + ) + (local.get $x) + ) + + (func $test1 (export "test1") + (global.set $a + (call $makeCycle + (i32.const 10) + ) + ) + ) + + (func $test2 (export "test2") + (global.set $b + (call $makeCycle + (i32.const 20) + ) + ) + ) + + (func $test3 (export "test3") + (global.set $c + (call $makeCycle + (i32.const 30) + ) + ) + ) + + ;; CHECK: (export "test1" (func $test1_6)) + + ;; CHECK: (export "test2" (func $test2_7)) + + ;; CHECK: (export "test3" (func $test3_8)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $c) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (i32.add + (struct.get $A 1 + (global.get $a) + ) + (i32.add + (struct.get $A 1 + (global.get $b) + ) + (struct.get $A 1 + (global.get $c) + ) + ) + ) + ) +) +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_6) +;; CHECK-NEXT: (global.get $ctor-eval$global_6) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test1_6 (type $none_=>_none) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) + +;; CHECK: (func $test2_7 (type $none_=>_none) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) + +;; CHECK: (func $test3_8 (type $none_=>_none) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) diff --git a/test/lit/ctor-eval/gc-cycle.wast b/test/lit/ctor-eval/gc-cycle.wast new file mode 100644 index 000000000..a6edc28aa --- /dev/null +++ b/test/lit/ctor-eval/gc-cycle.wast @@ -0,0 +1,1297 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: foreach %s %t wasm-ctor-eval --ctors=test --kept-exports=test --quiet -all -S -o - | filecheck %s + +(module + ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) + (type $A (struct (field (mut (ref null $A))) (field i32))) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_3 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_3)) + (global $a (mut (ref null $A)) (ref.null $A)) + + (func $test (export "test") + (local $a (ref $A)) + ;; This generates a self-cycle where the global $a's ref field points to + ;; itself. To handle this, wasm-ctor-eval will emit a new global with a null + ;; in the ref field, and add a start function that adds the self-reference. + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $A) + (i32.const 42) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (local.get $a) + ) + ) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + ;; Getting $A.0.1 (reading from the reference in the global's first field) + ;; checks that we have a proper reference there. If we could do --fuzz-exec + ;; here we could validate that (but atm we can't use --output=fuzz-exec at the + ;; same time as --all-items in the update_lit_checks.py note). + (struct.get $A 1 + (struct.get $A 0 + (global.get $a) + ) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; As above, but with $A's fields reversed. This verifies we use the right + ;; field index in the start function. + + ;; CHECK: (type $A (struct (field i32) (field (mut (ref null $A))))) + (type $A (struct (field i32) (field (mut (ref null $A))))) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_3 (ref $A) (struct.new $A + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_3)) + (global $a (mut (ref null $A)) (ref.null $A)) + + (func $test (export "test") + (local $a (ref $A)) + (global.set $a + (local.tee $a + (struct.new $A + (i32.const 42) + (ref.null $A) + ) + ) + ) + (struct.set $A 1 + (local.get $a) + (local.get $a) + ) + ) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (struct.get $A 0 + (struct.get $A 1 + (global.get $a) + ) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 1 +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; A cycle between two globals. + + ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) + (type $A (struct (field (mut (ref null $A))) (field i32))) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_8 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_8)) + (global $a (mut (ref null $A)) (ref.null $A)) + + ;; CHECK: (global $ctor-eval$global_7 (ref $A) (struct.new $A + ;; CHECK-NEXT: (global.get $ctor-eval$global_8) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $b (mut (ref null $A)) (global.get $ctor-eval$global_7)) + (global $b (mut (ref null $A)) (ref.null $A)) + + (func $test (export "test") + (local $a (ref $A)) + (local $b (ref $A)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $A) + (i32.const 42) + ) + ) + ) + (global.set $b + (local.tee $b + (struct.new $A + (global.get $a) ;; $b can refer to $a since we've created $a already. + (i32.const 1337) + ) + ) + ) + ;; $a needs a set to allow us to create the cycle. + (struct.set $A 0 + (local.get $a) + (local.get $b) + ) + ) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (i32.add + (struct.get $A 1 + (global.get $a) + ) + (struct.get $A 1 + (global.get $b) + ) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (local $b (ref $A)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; A cycle between two globals of different types. One of them has an + ;; immutable field in the cycle. + + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (struct (field (mut (ref null $B))) (field i32))) + (type $A (struct (field (mut (ref null $B))) (field i32))) + + ;; CHECK: (type $B (struct (field (ref null $A)) (field i32))) + (type $B (struct (field (ref null $A)) (field i32))) + ) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_8 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_8)) + (global $a (mut (ref null $A)) (ref.null $A)) + + ;; CHECK: (global $ctor-eval$global_7 (ref $B) (struct.new $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_8) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_7)) + (global $b (mut (ref null $B)) (ref.null $B)) + + (func $test (export "test") + (local $a (ref $A)) + (local $b (ref $B)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $A) + (i32.const 42) + ) + ) + ) + (global.set $b + (local.tee $b + (struct.new $B + (global.get $a) + (i32.const 1337) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (local.get $b) + ) + ) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $B 1 + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (i32.add + (struct.get $A 1 + (global.get $a) + ) + (struct.get $B 1 + (global.get $b) + ) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (local $b (ref $B)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; As above, but with the order of globals reversed. + + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (struct (field (mut (ref null $B))) (field i32))) + (type $A (struct (field (mut (ref null $B))) (field i32))) + + ;; CHECK: (type $B (struct (field (ref null $A)) (field i32))) + (type $B (struct (field (ref null $A)) (field i32))) + ) + + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_8 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_8)) + + ;; CHECK: (global $ctor-eval$global_7 (ref $B) (struct.new $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_8) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_7)) + (global $b (mut (ref null $B)) (ref.null $B)) + + (global $a (mut (ref null $A)) (ref.null $A)) + + (func $test (export "test") + (local $a (ref $A)) + (local $b (ref $B)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $A) + (i32.const 42) + ) + ) + ) + (global.set $b + (local.tee $b + (struct.new $B + (global.get $a) + (i32.const 1337) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (local.get $b) + ) + ) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $B 1 + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (i32.add + (struct.get $A 1 + (global.get $a) + ) + (struct.get $B 1 + (global.get $b) + ) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (local $b (ref $B)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; A cycle as above, but with non-nullability rather than immutability. + + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (struct (field (mut (ref null $B))) (field i32))) + (type $A (struct (field (mut (ref null $B))) (field i32))) + + ;; CHECK: (type $B (struct (field (mut (ref $A))) (field i32))) + (type $B (struct (field (mut (ref $A))) (field i32))) + ) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_8 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_8)) + (global $a (mut (ref null $A)) (ref.null $A)) + + (global $b (mut (ref null $B)) (ref.null $B)) + + (func $test (export "test") + (local $a (ref $A)) + (local $b (ref $B)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $A) + (i32.const 42) + ) + ) + ) + (global.set $b + (local.tee $b + (struct.new $B + (local.get $a) + (i32.const 1337) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (local.get $b) + ) + ) + + ;; CHECK: (global $ctor-eval$global_7 (ref $B) (struct.new $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_8) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (struct.get $A 1 + (global.get $a) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (local $b (ref $B)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; A cycle as above, but with globals in reverse order and with both non- + ;; nullability and immutability. + + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (struct (field (mut (ref null $B))) (field i32))) + (type $A (struct (field (mut (ref null $B))) (field i32))) + + ;; CHECK: (type $B (struct (field (ref $A)) (field i32))) + (type $B (struct (field (ref $A)) (field i32))) + ) + + + (global $b (mut (ref null $B)) (ref.null $B)) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_8 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_8)) + (global $a (mut (ref null $A)) (ref.null $A)) + + (func $test (export "test") + (local $a (ref $A)) + (local $b (ref $B)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $A) + (i32.const 42) + ) + ) + ) + (global.set $b + (local.tee $b + (struct.new $B + (local.get $a) + (i32.const 1337) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (local.get $b) + ) + ) + + ;; CHECK: (global $ctor-eval$global_7 (ref $B) (struct.new $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_8) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (struct.get $A 1 + (global.get $a) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (local $b (ref $B)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; A cycle between three globals. + + ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) + (type $A (struct (field (mut (ref null $A))) (field i32))) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_13 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_14 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_14)) + (global $a (mut (ref null $A)) (ref.null $A)) + + (global $b (mut (ref null $A)) (ref.null $A)) + + (global $c (mut (ref null $A)) (ref.null $A)) + + (func $test (export "test") + (local $a (ref $A)) + (local $b (ref $A)) + (local $c (ref $A)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $A) + (i32.const 42) + ) + ) + ) + (global.set $b + (local.tee $b + (struct.new $A + (global.get $a) + (i32.const 1337) + ) + ) + ) + (global.set $c + (local.tee $c + (struct.new $A + (global.get $b) + (i32.const 99999) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (local.get $c) + ) + ) + + ;; CHECK: (global $ctor-eval$global_12 (ref $A) (struct.new $A + ;; CHECK-NEXT: (global.get $ctor-eval$global_13) + ;; CHECK-NEXT: (i32.const 99999) + ;; CHECK-NEXT: )) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (struct.get $A 1 + (global.get $a) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_13) +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (global.get $ctor-eval$global_12) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (local $b (ref $A)) +;; CHECK-NEXT: (local $c (ref $A)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; A cycle between three globals as above, but now using different types and + ;; also both structs and arrays. Also reverse the order of globals, make + ;; one array immutable and one non-nullable, and make one array refer to the + ;; other two. + + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (struct (field (mut (ref null $C))) (field i32))) + (type $A (struct (field (mut (ref null $C))) (field i32))) + ;; CHECK: (type $B (array (ref null $A))) + (type $B (array (ref null $A))) + ;; CHECK: (type $C (array (mut (ref any)))) + (type $C (array (mut (ref any)))) + ) + + (global $c (mut (ref null $C)) (ref.null $C)) + + (global $b (mut (ref null $B)) (ref.null $B)) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_14 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_13 (ref $B) (array.new_fixed $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_14)) + (global $a (mut (ref null $A)) (ref.null $A)) + + (func $test (export "test") + (local $a (ref $A)) + (local $b (ref $B)) + (local $c (ref $C)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $C) + (i32.const 42) + ) + ) + ) + (global.set $b + (local.tee $b + (array.new $B + (global.get $a) + (i32.const 10) + ) + ) + ) + (global.set $c + (local.tee $c + (array.new_fixed $C + (local.get $b) + (local.get $a) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (global.get $c) + ) + ) + + ;; CHECK: (global $ctor-eval$global_12 (ref $C) (array.new_fixed $C + ;; CHECK-NEXT: (global.get $ctor-eval$global_13) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: )) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (struct.get $A 1 + (global.get $a) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (global.get $ctor-eval$global_12) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (local $b (ref $B)) +;; CHECK-NEXT: (local $c (ref $C)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; As above but with the order of globals reversed once more. + + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (struct (field (mut (ref null $C))) (field i32))) + (type $A (struct (field (mut (ref null $C))) (field i32))) + ;; CHECK: (type $B (array (ref null $A))) + (type $B (array (ref null $A))) + ;; CHECK: (type $C (array (mut (ref any)))) + (type $C (array (mut (ref any)))) + ) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_14 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_13 (ref $B) (array.new_fixed $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_14)) + (global $a (mut (ref null $A)) (ref.null $A)) + + (global $b (mut (ref null $B)) (ref.null $B)) + + (global $c (mut (ref null $C)) (ref.null $C)) + + (func $test (export "test") + (local $a (ref $A)) + (local $b (ref $B)) + (local $c (ref $C)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $C) + (i32.const 42) + ) + ) + ) + (global.set $b + (local.tee $b + (array.new $B + (global.get $a) + (i32.const 10) + ) + ) + ) + (global.set $c + (local.tee $c + (array.new_fixed $C + (local.get $b) + (local.get $a) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (global.get $c) + ) + ) + + ;; CHECK: (global $ctor-eval$global_12 (ref $C) (array.new_fixed $C + ;; CHECK-NEXT: (global.get $ctor-eval$global_13) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: )) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (struct.get $A 1 + (global.get $a) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (global.get $ctor-eval$global_12) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (local $b (ref $B)) +;; CHECK-NEXT: (local $c (ref $C)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; A cycle between two globals, where some of the fields participate in the + ;; cycle and some do not. + + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (struct (field (mut (ref null $B))) (field (mut (ref null $B))) (field (mut (ref null $B))))) + (type $A (struct (field (mut (ref null $B))) (field (mut (ref null $B))) (field (mut (ref null $B))))) + ;; CHECK: (type $B (array (ref null $A))) + (type $B (array (ref null $A))) + ) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_anyref (func (result anyref))) + + ;; CHECK: (global $ctor-eval$global_16 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_16)) + (global $a (mut (ref null $A)) (ref.null $A)) + (global $b (mut (ref null $B)) (ref.null $B)) + + (func $test (export "test") + (local $a (ref $A)) + (global.set $a + (local.tee $a + (struct.new $A + (array.new_default $B + (i32.const 0) + ) + (ref.null $B) + (array.new_default $B + (i32.const 0) + ) + ) + ) + ) + (global.set $b + (array.new_fixed $B + (struct.new_default $A) + (global.get $a) + (struct.new_default $A) + ) + ) + (struct.set $A 1 + (local.get $a) + (global.get $b) + ) + ) + + ;; CHECK: (global $ctor-eval$global_19 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_15 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_14 (ref $B) (array.new_fixed $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_15) + ;; CHECK-NEXT: (global.get $ctor-eval$global_16) + ;; CHECK-NEXT: (global.get $ctor-eval$global_19) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_17 (ref $B) (array.new_fixed $B)) + + ;; CHECK: (global $ctor-eval$global_18 (ref $B) (array.new_fixed $B)) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_anyref) (result anyref) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result (ref null any)) + (struct.get $A 1 + (global.get $a) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_16) +;; CHECK-NEXT: (global.get $ctor-eval$global_17) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 1 +;; CHECK-NEXT: (global.get $ctor-eval$global_16) +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 2 +;; CHECK-NEXT: (global.get $ctor-eval$global_16) +;; CHECK-NEXT: (global.get $ctor-eval$global_18) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; As above, with the cycle creation logic reversed. + + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (struct (field (ref null $B)) (field (ref null $B)) (field (ref null $B)))) + (type $A (struct (field (ref null $B)) (field (ref null $B)) (field (ref null $B)))) + ;; CHECK: (type $B (array (mut (ref null $A)))) + (type $B (array (mut (ref null $A)))) + ) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_anyref (func (result anyref))) + + ;; CHECK: (global $ctor-eval$global_16 (ref $B) (array.new_fixed $B + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_19 (ref $B) (array.new_fixed $B)) + + ;; CHECK: (global $ctor-eval$global_15 (ref $B) (array.new_fixed $B)) + + ;; CHECK: (global $ctor-eval$global_14 (ref $A) (struct.new $A + ;; CHECK-NEXT: (global.get $ctor-eval$global_15) + ;; CHECK-NEXT: (global.get $ctor-eval$global_16) + ;; CHECK-NEXT: (global.get $ctor-eval$global_19) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_14)) + (global $a (mut (ref null $A)) (ref.null $A)) + (global $b (mut (ref null $B)) (ref.null $B)) + + (func $test (export "test") + (local $b (ref $B)) + (global.set $b + (local.tee $b + (array.new_fixed $B + (struct.new_default $A) + (ref.null $A) + (struct.new_default $A) + ) + ) + ) + (global.set $a + (struct.new $A + (array.new_default $B + (i32.const 0) + ) + (global.get $b) + (array.new_default $B + (i32.const 0) + ) + ) + ) + (array.set $B + (local.get $b) + (i32.const 1) + (global.get $a) + ) + ) + + ;; CHECK: (global $ctor-eval$global_17 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_18 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $none_=>_anyref) (result anyref) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result (ref null any)) + (struct.get $A 1 + (global.get $a) + ) + ) +) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (array.set $B +;; CHECK-NEXT: (global.get $ctor-eval$global_16) +;; CHECK-NEXT: (i32.const 0) +;; CHECK-NEXT: (global.get $ctor-eval$global_17) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (array.set $B +;; CHECK-NEXT: (global.get $ctor-eval$global_16) +;; CHECK-NEXT: (i32.const 1) +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (array.set $B +;; CHECK-NEXT: (global.get $ctor-eval$global_16) +;; CHECK-NEXT: (i32.const 2) +;; CHECK-NEXT: (global.get $ctor-eval$global_18) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $b (ref $B)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; The start function already exists here. We must prepend to it. + + ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) + (type $A (struct (field (mut (ref null $A))) (field i32))) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (global $ctor-eval$global_4 (ref $A) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_4)) + (global $a (mut (ref null $A)) (ref.null $A)) + + ;; CHECK: (global $b (mut (ref null $A)) (ref.null none)) + (global $b (mut (ref null $A)) (ref.null $A)) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + (start $start) + + (func $test (export "test") + (local $a (ref $A)) + (global.set $a + (local.tee $a + (struct.new $A + (ref.null $A) + (i32.const 42) + ) + ) + ) + (struct.set $A 0 + (local.get $a) + (local.get $a) + ) + ) + + ;; CHECK: (func $keepalive (type $none_=>_i32) (result i32) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + (i32.add + (struct.get $A 1 + (global.get $a) + ) + (struct.get $A 1 + (global.get $b) + ) + ) + ) + + ;; CHECK: (func $start (type $none_=>_none) + ;; CHECK-NEXT: (struct.set $A 0 + ;; CHECK-NEXT: (global.get $ctor-eval$global_4) + ;; CHECK-NEXT: (global.get $ctor-eval$global_4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.set $b + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $start + (global.set $b + (global.get $a) + ) + ) +) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (local $a (ref $A)) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) +(module + ;; CHECK: (type $A (struct (field (mut (ref null $A))))) + (type $A (struct (field (mut (ref null $A))))) + + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $anyref_=>_none (func (param anyref))) + + ;; CHECK: (import "a" "b" (func $import (param anyref))) + (import "a" "b" (func $import (param anyref))) + + (func $test (export "test") + (local $a (ref $A)) + (struct.set $A 0 + (local.tee $a + (struct.new_default $A) + ) + (local.get $a) + ) + ;; The previous instructions created a cycle, which we now send to an import. + ;; The import will block us from evalling the entire function, and we will + ;; only partially eval it, removing the statements before the call. Note that + ;; the cycle only exists in local state - there is no global it is copied to - + ;; and so this test verifies that we handle cycles in local state. + (call $import + (local.get $a) + ) + ) +) +;; CHECK: (global $ctor-eval$global (ref $A) (struct.new $A +;; CHECK-NEXT: (ref.null none) +;; CHECK-NEXT: )) + +;; CHECK: (export "test" (func $test_3)) + +;; CHECK: (start $start) + +;; CHECK: (func $start (type $none_=>_none) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global) +;; CHECK-NEXT: (global.get $ctor-eval$global) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $none_=>_none) +;; CHECK-NEXT: (call $import +;; CHECK-NEXT: (global.get $ctor-eval$global) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) diff --git a/test/lit/ctor-eval/partial-global.wat b/test/lit/ctor-eval/partial-global.wat new file mode 100644 index 000000000..fdd196d02 --- /dev/null +++ b/test/lit/ctor-eval/partial-global.wat @@ -0,0 +1,39 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: wasm-ctor-eval %s --ctors=test --kept-exports=test --quiet -all -S -o - | filecheck %s + +(module + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (global $global (mut i32) (i32.const 0)) + (global $global (mut i32) (i32.const 0)) + + (func $test (export "test") + ;; The nop can be evalled away, but not the loop. We should not apply any + ;; partial results from the loop - in particular, the global must remain at + ;; 0. That is, the global.set of 999 below must not be applied to the global. + ;; + ;; (It is true that in this simple module it would be ok to set 999 to the + ;; global, but if the global were exported for example then that would not + ;; be the case, nor would it be the case if the code did $global = $global + 1 + ;; or such. That is, since the global.set is not evalled away, its effects + ;; must not be applied; we do both atomically or neither, so that the + ;; global.set's execution only happens once.) + + (nop) + (loop + (global.set $global + (i32.const 999) + ) + (unreachable) + ) + ) +) + +;; CHECK: (export "test" (func $test_1)) + +;; CHECK: (func $test_1 (type $none_=>_none) +;; CHECK-NEXT: (global.set $global +;; CHECK-NEXT: (i32.const 999) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (unreachable) +;; CHECK-NEXT: ) |