| ;; NOTE: Assertions have been generated by update_lit_checks.py --output=fuzz-exec and should not be edited. |
| |
| ;; RUN: foreach %s %t wasm-opt -all --fuzz-exec-before -q -o /dev/null 2>&1 | filecheck %s |
| |
| (module |
| (type $f (func)) |
| (type $k (cont $f)) |
| |
| (type $f-i32 (func (result i32))) |
| (type $k-i32 (cont $f-i32)) |
| |
| (type $f-get-i32 (func (param i32))) |
| (type $k-get-i32 (cont $f-get-i32)) |
| |
| (import "fuzzing-support" "log" (func $log (param i32))) |
| |
| (tag $more) |
| (tag $more-i32 (result i32)) |
| |
| (func $run (param $k (ref $k)) |
| ;; Run a coroutine, continuing to resume it until it is complete. |
| (call $log (i32.const 100)) ;; start |
| (loop $loop |
| (block $on (result (ref $k)) |
| (resume $k (on $more $on) |
| (local.get $k) |
| ) |
| (call $log (i32.const 300)) ;; stop |
| (return) |
| ) |
| (call $log (i32.const 200)) ;; continue |
| (local.set $k) |
| (br $loop) |
| ) |
| (unreachable) |
| ) |
| |
| ;; A coroutine with only control flow in a single basic block (no locals, no |
| ;; params, no branching, no value stack). When $run-block, below, runs this, |
| ;; the result should be to log -1, -2, -3 (with interleaved logging from |
| ;; $run itself, above, 100, 200, 200, 300). |
| (func $block |
| (call $log (i32.const -1)) |
| (suspend $more) |
| (call $log (i32.const -2)) |
| (suspend $more) |
| (call $log (i32.const -3)) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-block |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -2] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -3] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-block (export "run-block") |
| (call $run |
| (cont.new $k (ref.func $block)) |
| ) |
| ) |
| |
| ;; Nested blocks, so when we suspend/resume we must traverse that stack |
| ;; properly. |
| (func $block-nested |
| (block $a |
| (call $log (i32.const -1)) |
| (suspend $more) |
| (block $b |
| (block $c |
| (call $log (i32.const -2)) |
| (suspend $more) |
| (call $log (i32.const -3)) |
| ) |
| (call $log (i32.const -4)) |
| ) |
| (suspend $more) |
| (call $log (i32.const -5)) |
| (suspend $more) |
| ) |
| (call $log (i32.const -6)) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-block-nested |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -2] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -3] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -4] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -5] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -6] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-block-nested (export "run-block-nested") |
| (call $run |
| (cont.new $k (ref.func $block-nested)) |
| ) |
| ) |
| |
| ;; The local's state must be saved and restored. |
| (func $local |
| (local $x i32) |
| (local.set $x (i32.const 42)) |
| (suspend $more) |
| (call $log (local.get $x)) |
| (local.set $x (i32.const 1337)) |
| (suspend $more) |
| (call $log (local.get $x)) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-local |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 42] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 1337] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-local (export "run-local") |
| (call $run |
| (cont.new $k (ref.func $local)) |
| ) |
| ) |
| |
| (func $multi-locals |
| (local $i32 i32) |
| (local $f64 f64) |
| (local.set $i32 (i32.const 42)) |
| (local.set $f64 (f64.const 3.14159)) |
| (suspend $more) |
| (call $log |
| (local.get $i32) |
| ) |
| (call $log |
| (i32.trunc_f64_s |
| (local.get $f64) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-multi-locals |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 42] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 3] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-multi-locals (export "run-multi-locals") |
| (call $run |
| (cont.new $k (ref.func $multi-locals)) |
| ) |
| ) |
| |
| ;; This loop should suspend 4 times and log 3, 2, 1, 0. |
| (func $loop |
| (local $x i32) |
| (local.set $x (i32.const 4)) |
| (loop $loop |
| (local.set $x |
| (i32.sub |
| (local.get $x) |
| (i32.const 1) |
| ) |
| ) |
| (call $log (local.get $x)) |
| (suspend $more) |
| (br_if $loop |
| (local.get $x) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-loop |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 3] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 2] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 0] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-loop (export "run-loop") |
| (call $run |
| (cont.new $k (ref.func $loop)) |
| ) |
| ) |
| |
| ;; We should log -1, -2, -3, -4 |
| (func $if |
| (local $x i32) |
| (if |
| (local.get $x) |
| (then |
| (unreachable) |
| ) |
| (else |
| ;; We should get here. |
| (call $log (i32.const -1)) |
| (local.set $x (i32.const 1)) |
| (suspend $more) |
| ;; A nested if. |
| (if |
| (local.get $x) |
| (then |
| ;; We should get here |
| (suspend $more) |
| (call $log (i32.const -2)) |
| ) |
| (else |
| (unreachable) |
| ) |
| ) |
| ) |
| ) |
| ;; If with one arm. |
| (if |
| (local.get $x) |
| (then |
| ;; We should get here. |
| (call $log (i32.const -3)) |
| (suspend $more) |
| (call $log (i32.const -4)) |
| ) |
| ) |
| (if |
| (i32.eqz |
| (local.get $x) |
| ) |
| (then |
| (unreachable) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-if |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -2] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -3] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -4] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-if (export "run-if") |
| (call $run |
| (cont.new $k (ref.func $if)) |
| ) |
| ) |
| |
| ;; Suspend in the if's condition. |
| (func $if-condition |
| (if |
| (block (result i32) |
| (call $log (i32.const -1)) |
| (suspend $more) |
| (call $log (i32.const -2)) |
| (i32.const 1) |
| ) |
| (then |
| (call $log (i32.const -3)) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-if-condition |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -2] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -3] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-if-condition (export "run-if-condition") |
| (call $run |
| (cont.new $k (ref.func $if-condition)) |
| ) |
| ) |
| |
| ;; Check that we properly stash things on the value stack. |
| (func $value-stack |
| ;; Suspend on the left. No value is actually saved on the stack, as we |
| ;; resume before we execute the right side. |
| (call $log |
| (i32.sub ;; 1 - 2 => -1 |
| (block (result i32) |
| (suspend $more) |
| (i32.const 1) |
| ) |
| (i32.const 2) |
| ) |
| ) |
| ;; On the right. Now we save the 2 when we suspend. |
| (call $log |
| (i32.sub ;; 2 - 4 => -2 |
| (i32.const 2) |
| (block (result i32) |
| (suspend $more) |
| (i32.const 4) |
| ) |
| ) |
| ) |
| ;; Both sides suspend. |
| (call $log |
| (i32.sub ;; 3 - 6 => -3 |
| (block (result i32) |
| (suspend $more) |
| (i32.const 3) |
| ) |
| (block (result i32) |
| (suspend $more) |
| (i32.const 6) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-value-stack |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -2] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -3] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-value-stack (export "run-value-stack") |
| (call $run |
| (cont.new $k (ref.func $value-stack)) |
| ) |
| ) |
| |
| (func $nested-unary |
| ;; Suspend at the top. |
| (call $log |
| (i32.eqz |
| (i32.eqz |
| (i32.eqz |
| (block (result i32) |
| (suspend $more) |
| (i32.const 1) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ;; Suspend everywhere. |
| (call $log |
| (block (result i32) |
| (suspend $more) |
| (i32.eqz |
| (block (result i32) |
| (suspend $more) |
| (i32.eqz |
| (block (result i32) |
| (suspend $more) |
| (i32.eqz |
| (block (result i32) |
| (suspend $more) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-nested-unary |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 0] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-nested-unary (export "run-nested-unary") |
| (call $run |
| (cont.new $k (ref.func $nested-unary)) |
| ) |
| ) |
| |
| (func $nested-unary-more |
| (local $temp i32) |
| ;; Suspend before and after each operation. |
| (call $log |
| (block (result i32) |
| i32.const 0 |
| suspend $more |
| i32.eqz |
| suspend $more |
| i32.eqz |
| suspend $more |
| i32.eqz |
| suspend $more |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-nested-unary-more |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-nested-unary-more (export "run-nested-unary-more") |
| (call $run |
| (cont.new $k (ref.func $nested-unary-more)) |
| ) |
| ) |
| |
| (func $nested-binary |
| (local $temp i32) |
| ;; Both sides suspend, in different places. |
| (call $log ;; (2 + 1) - (4 + 2) => -3 |
| (i32.sub |
| (block (result i32) |
| (i32.add |
| (block (result i32) |
| (suspend $more) |
| (i32.const 2) |
| ) |
| (i32.const 1) |
| ) |
| ) |
| (block (result i32) |
| (suspend $more) |
| (i32.add |
| (i32.const 4) |
| (i32.const 2) |
| ) |
| ) |
| ) |
| ) |
| ;; Ditto, but with suspensions moved in the arms, and others on the |
| ;; outside. Also add 1. |
| (call $log |
| (block (result i32) |
| (suspend $more) |
| (local.set $temp |
| (i32.sub |
| (block (result i32) |
| (suspend $more) |
| (i32.add |
| (i32.const 3) |
| (i32.const 1) |
| ) |
| ) |
| (block (result i32) |
| (i32.add |
| (i32.const 4) |
| (block (result i32) |
| (suspend $more) |
| (i32.const 2) |
| ) |
| ) |
| ) |
| ) |
| ) |
| (suspend $more) |
| (local.get $temp) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-nested-binary |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -3] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging -2] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-nested-binary (export "run-nested-binary") |
| (call $run |
| (cont.new $k (ref.func $nested-binary)) |
| ) |
| ) |
| |
| (func $trinary |
| ;; Suspend in one of the arms. |
| (call $log |
| (select |
| (block (result i32) |
| (suspend $more) |
| (i32.const 1) |
| ) |
| (i32.const 2) |
| (i32.const 3) |
| ) |
| ) |
| (call $log |
| (select |
| (i32.const 4) |
| (block (result i32) |
| (suspend $more) |
| (i32.const 5) |
| ) |
| (i32.const 6) |
| ) |
| ) |
| (call $log |
| (select |
| (i32.const 7) |
| (i32.const 8) |
| (block (result i32) |
| (suspend $more) |
| (i32.const 9) |
| ) |
| ) |
| ) |
| ;; Suspend in them all. |
| (call $log |
| (select |
| (block (result i32) |
| (suspend $more) |
| (i32.const 10) |
| ) |
| (block (result i32) |
| (suspend $more) |
| (i32.const 11) |
| ) |
| (block (result i32) |
| (suspend $more) |
| (i32.const 12) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-trinary |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 1] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 4] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 7] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 10] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-trinary (export "run-trinary") |
| (call $run |
| (cont.new $k (ref.func $trinary)) |
| ) |
| ) |
| |
| (func $run-i32 (param $k-i32 (ref $k-i32)) (result i32) |
| ;; As $run, but the coroutine returns an i32. |
| (call $log (i32.const 100)) ;; start |
| (loop $loop |
| (block $on (result (ref $k-i32)) |
| (resume $k-i32 (on $more $on) |
| (local.get $k-i32) |
| ) |
| (call $log (i32.const 300)) ;; stop |
| (return) |
| ) |
| (call $log (i32.const 200)) ;; continue |
| (local.set $k-i32) |
| (br $loop) |
| ) |
| (unreachable) |
| ) |
| |
| (func $ret-i32 (result i32) |
| ;; Just immediately return. |
| (i32.const 42) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-ret-i32 |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| ;; CHECK-NEXT: [fuzz-exec] note result: run-ret-i32 => 42 |
| (func $run-ret-i32 (export "run-ret-i32") (result i32) |
| (call $run-i32 |
| (cont.new $k-i32 (ref.func $ret-i32)) |
| ) |
| ) |
| |
| (func $pause-i32 (result i32) |
| (local $x i32) |
| ;; Pause before returning. |
| (local.set $x |
| (i32.const 1336) |
| ) |
| (suspend $more) |
| (i32.add |
| (local.get $x) |
| (i32.const 1) |
| ) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-pause-i32 |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| ;; CHECK-NEXT: [fuzz-exec] note result: run-pause-i32 => 1337 |
| (func $run-pause-i32 (export "run-pause-i32") (result i32) |
| (call $run-i32 |
| (cont.new $k-i32 (ref.func $pause-i32)) |
| ) |
| ) |
| |
| (func $run-get-i32 (param $x i32) (param $k-get-i32 (ref $k-get-i32)) |
| ;; As $run, but the coroutine receives an i32. |
| (call $log (i32.const 100)) ;; start |
| (loop $loop |
| (block $on (result (ref $k-get-i32)) |
| (resume $k-get-i32 (on $more-i32 $on) |
| (local.get $x) |
| (local.get $k-get-i32) |
| ) |
| (call $log (i32.const 300)) ;; stop |
| (return) |
| ) |
| (call $log (i32.const 200)) ;; continue |
| ;; Modify $x, so we can see differences in the loggings. |
| (local.set $x |
| (i32.sub |
| (local.get $x) |
| (i32.const 1) |
| ) |
| ) |
| (local.set $k-get-i32) |
| (br $loop) |
| ) |
| (unreachable) |
| ) |
| |
| (func $param (param $x i32) |
| (call $log (local.get $x)) |
| (local.set $x |
| (i32.add |
| (local.get $x) |
| (i32.const 1295) |
| ) |
| ) |
| (call $log (suspend $more-i32)) |
| (call $log (local.get $x)) |
| (call $log (suspend $more-i32)) |
| ) |
| |
| ;; CHECK: [fuzz-exec] calling run-param |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 100] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 42] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 41] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 1337] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 200] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 40] |
| ;; CHECK-NEXT: [LoggingExternalInterface logging 300] |
| (func $run-param (export "run-param") |
| (call $run-get-i32 |
| (i32.const 42) |
| (cont.new $k-get-i32 (ref.func $param)) |
| ) |
| ) |
| ) |