@ 261106.8
current
;; 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))

  (type $f-switch (func (param i32 (ref null $k))))
  (type $k-switch (cont $f-switch))

  (rec
    (type $f-swap (func (param i32 (ref null $k-swap)) (result i32)))
    (type $k-swap (cont $f-swap))
  )

  (import "fuzzing-support" "log-i32" (func $log (param i32)))

  (tag $more)
  (tag $more-i32 (result i32))

  (table $table 10 10 funcref)

  (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] export 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] export 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] export 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] export 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] export 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] export 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] export 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] export 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] export 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] export 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] export 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] export 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] export 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] export 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] export 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))
    )
  )

  (func $calls
    ;; Suspend before and after calling a child, who also suspends.
    (local $x i32)
    ;; Set a value here to check that we do not get confused between locals in
    ;; different scopes.
    (local.set $x (i32.const -1))
    (suspend $more)
    (call $calls-child (i32.const 41))
    (suspend $more)
    (call $calls-child (i32.const 1336))
    (suspend $more)
    (call $log (local.get $x))
  )

  (func $calls-child (param $x i32)
    (suspend $more)
    (local.set $x
      (i32.add
        (local.get $x)
        (i32.const 1)
      )
    )
    (suspend $more)
    (call $log (local.get $x))
    (suspend $more)
  )

  ;; CHECK:      [fuzz-exec] export run-calls
  ;; CHECK-NEXT: [LoggingExternalInterface logging 100]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 1337]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging -1]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 300]
  (func $run-calls (export "run-calls")
    (call $run
      (cont.new $k (ref.func $calls))
    )
  )

  (func $call_indirect
    ;; Test that indirect calls go to the right place, even if we modify the
    ;; table in between.
    (table.set $table
      (i32.const 7)
      (ref.func $call_indirect-child)
    )
    (call $log (i32.const -1))
    (call_indirect (type $f)
      (i32.const 7)
    )
    (call $log (i32.const -2))
  )

  (func $call_indirect-child
    ;; When we resume the suspend below, the table entry will have null, but we
    ;; should still rewind the stack properly.
    (call $log (i32.const -10))
    (call $log
      (ref.is_null
        (table.get $table
          (i32.const 7)
        )
      )
    )
    (table.set $table
      (i32.const 7)
      (ref.null func)
    )
    (suspend $more)
    (call $log (i32.const -20))
    (call $log
      (ref.is_null
        (table.get $table
          (i32.const 7)
        )
      )
    )
    (suspend $more)
  )

  ;; CHECK:      [fuzz-exec] export run-call_indirect
  ;; CHECK-NEXT: [LoggingExternalInterface logging 100]
  ;; CHECK-NEXT: [LoggingExternalInterface logging -1]
  ;; CHECK-NEXT: [LoggingExternalInterface logging -10]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging -20]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging -2]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 300]
  (func $run-call_indirect (export "run-call_indirect")
    (call $run
      (cont.new $k (ref.func $call_indirect))
    )
  )

  (func $call_ref
    (suspend $more)
    (call_ref $f
      (ref.func $call_ref-child)
    )
    (suspend $more)
  )

  (func $call_ref-child
    (suspend $more)
    (call $log (i32.const -20))
    (suspend $more)
  )

  ;; CHECK:      [fuzz-exec] export run-call_ref
  ;; CHECK-NEXT: [LoggingExternalInterface logging 100]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging -20]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 300]
  (func $run-call_ref (export "run-call_ref")
    (call $run
      (cont.new $k (ref.func $call_ref))
    )
  )

  (func $bind (param $x i32)
    ;; Test that cont.bind works when used on this.
    (suspend $more)
    (call $log (local.get $x))
    (suspend $more)
    ;; Test that the bound arguments do not get applied to child calls.
    (call $bind-child
      (i32.const 1337)
    )
    (suspend $more)
  )

  (func $bind-child (param $x i32)
    (suspend $more)
    (call $log (local.get $x))
    (suspend $more)
  )

  ;; CHECK:      [fuzz-exec] export run-bind
  ;; CHECK-NEXT: [LoggingExternalInterface logging 100]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 1337]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 200]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 300]
  (func $run-bind (export "run-bind")
    (call $run
      (cont.bind $k-get-i32 $k
        (i32.const 42)
        (cont.new $k-get-i32 (ref.func $bind))
      )
    )
  )

  (func $never
    ;; This will be resume_throw'd on the first execution, so this code is never
    ;; reached.
    (call $log (i32.const 1337))
  )

  ;; CHECK:      [fuzz-exec] export resume_throw-never
  ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
  (func $resume_throw-never (export "resume_throw-never")
    (block $more
      (try_table (catch $more $more)
        (resume_throw $k $more
          (cont.new $k (ref.func $never))
        )
      )
    )
    ;; This will be reached.
    (call $log (i32.const 42))
  )

  ;; CHECK:      [fuzz-exec] export suspend-unhandled-block
  ;; CHECK-NEXT: [exception thrown: unhandled suspend]
  (func $suspend-unhandled-block (export "suspend-unhandled-block")
    ;; The nop here means that we are inside a block. The block will try to save
    ;; resume data, but we should skip that without erroring, and just report an
    ;; unhandled suspend.
    (suspend $more)
    (nop)
  )

  (func $switch-target (param $x i32) (param $k (ref null $k)))

  ;; CHECK:      [fuzz-exec] export switch-null
  ;; CHECK-NEXT: [LoggingExternalInterface logging 10]
  ;; CHECK-NEXT: [trap null ref]
  (func $switch-null (export "switch-null")
    ;; Operands should be evaluated before trapping on a null continuation.
    (switch $k-switch $more
      (block (result i32)
        (call $log (i32.const 10))
        (i32.const 20)
      )
      (ref.null $k-switch)
    )
  )

  ;; CHECK:      [fuzz-exec] export switch-unhandled
  ;; CHECK-NEXT: [LoggingExternalInterface logging 30]
  ;; CHECK-NEXT: [exception thrown: unhandled suspend]
  (func $switch-unhandled (export "switch-unhandled")
    ;; Switching without an enclosing switch handler should report an unhandled
    ;; suspend.
    (switch $k-switch $more
      (block (result i32)
        (call $log (i32.const 30))
        (i32.const 40)
      )
      (cont.new $k-switch
        (ref.func $switch-target)
      )
    )
  )

  (func $swap-first (type $f-swap) (param $x i32) (param $next (ref null $k-swap)) (result i32)
    (call $log (local.get $x))
    (local.set $next
      (switch $k-swap $more-i32
        (i32.add (local.get $x) (i32.const 1))
        (local.get $next)
      )
    )
    (local.set $x)
    (call $log (local.get $x))
    (drop
      (switch $k-swap $more-i32
        (i32.add (local.get $x) (i32.const 1))
        (local.get $next)
      )
    )
    (unreachable)
  )

  (func $swap-second (type $f-swap) (param $x i32) (param $next (ref null $k-swap)) (result i32)
    (call $log (local.get $x))
    (local.set $next
      (switch $k-swap $more-i32
        (i32.add (local.get $x) (i32.const 10))
        (local.get $next)
      )
    )
    (local.set $x)
    (call $log (local.get $x))
    (i32.add (local.get $x) (i32.const 100))
  )

  ;; CHECK:      [fuzz-exec] export run-switch
  ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 2]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 12]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 13]
  ;; CHECK-NEXT: [fuzz-exec] note result: run-switch => 113
  (func $run-switch (export "run-switch") (result i32)
    ;; Switch back and forth between two continuations.
    (resume $k-swap (on $more-i32 switch)
      (i32.const 1)
      (cont.new $k-swap (ref.func $swap-second))
      (cont.new $k-swap (ref.func $swap-first))
    )
  )

  (func $switch-twice (type $f-swap) (param $x i32) (param $next (ref null $k-swap)) (result i32)
    ;; Try switching to the same continuation twice, which traps the second
    ;; time because the first continuation was already executed.
    (drop
      (switch $k-swap $more-i32
        (local.get $x)
        (local.get $next)
      )
    )
    (drop)
    (drop
      (switch $k-swap $more-i32
        (local.get $x)
        (local.get $next)
      )
    )
    (drop)
    (i32.const 0)
  )

  (func $switch-back-once (type $f-swap) (param $x i32) (param $next (ref null $k-swap)) (result i32)
    (drop
      (switch $k-swap $more-i32
        (local.get $x)
        (local.get $next)
      )
    )
    (drop)
    (i32.const 0)
  )

  ;; CHECK:      [fuzz-exec] export switch-already-executed
  ;; CHECK-NEXT: [trap continuation already executed]
  (func $switch-already-executed (export "switch-already-executed") (result i32)
    ;; Switching to an already-executed continuation should trap.
    (resume $k-swap (on $more-i32 switch)
      (i32.const 1)
      (cont.new $k-swap (ref.func $switch-back-once))
      (cont.new $k-swap (ref.func $switch-twice))
    )
  )

  (func $switch-thrower (param $x i32) (param $k (ref null $k))
    (call $log (local.get $x))
    (resume_throw $k $more
      (local.get $k)
    )
  )

  (func $switch-catcher
    (block $caught
      (try_table (catch $more $caught)
        (switch $k-switch $more
          (i32.const 55)
          (cont.new $k-switch (ref.func $switch-thrower))
        )
        (unreachable)
      )
    )
    (call $log (i32.const 66))
  )

  ;; CHECK:      [fuzz-exec] export run-switch-resume-throw
  ;; CHECK-NEXT: [LoggingExternalInterface logging 55]
  ;; CHECK-NEXT: [LoggingExternalInterface logging 66]
  (func $run-switch-resume-throw (export "run-switch-resume-throw")
    ;; Resume a switched-from continuation with resume_throw and catch it.
    (resume $k (on $more switch)
      (cont.new $k (ref.func $switch-catcher))
    )
  )
)