;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: foreach %s %t wasm-opt -all --instrument-branch-hints -S -o - | filecheck %s

(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (type $1 (func (param i32)))

  ;; CHECK:      (type $2 (func (result f64)))

  ;; CHECK:      (type $3 (func (param anyref)))

  ;; CHECK:      (type $4 (func (param i32 i32 i32)))

  ;; CHECK:      (import "fuzzing-support" "log-branch" (func $log-branch (type $4) (param i32 i32 i32)))

  ;; CHECK:      (tag $i32 (type $1) (param i32))
  (tag $i32 (param i32))

  ;; CHECK:      (func $if (type $0)
  ;; CHECK-NEXT:  (local $0 i32)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (local.set $0
  ;; CHECK-NEXT:     (i32.const 42)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $log-branch
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1337)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 99)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (local.set $1
  ;; CHECK-NEXT:     (i32.const 142)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $log-branch
  ;; CHECK-NEXT:     (i32.const 2)
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:     (local.get $1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 11337)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 199)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if
    ;; An if with a 0 hint and another with a 1 hint.
    (@metadata.code.branch_hint "\00")
    (if
      (i32.const 42)
      (then
        (drop (i32.const 1337))
      )
      (else
        (drop (i32.const 99))
      )
    )
    (@metadata.code.branch_hint "\01")
    (if
      (i32.const 142)
      (then
        (drop (i32.const 11337))
      )
      (else
        (drop (i32.const 199))
      )
    )
  )

  ;; CHECK:      (func $if-2 (type $0)
  ;; CHECK-NEXT:  (local $0 i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (i32.const 242)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 21337)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 299)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (local.set $0
  ;; CHECK-NEXT:     (i32.const 342)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $log-branch
  ;; CHECK-NEXT:     (i32.const 3)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 31337)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 399)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-2
    ;; An if with no hint, and another with 0 for more coverage.
    (if
      (i32.const 242)
      (then
        (drop (i32.const 21337))
      )
      (else
        (drop (i32.const 299))
      )
    )
    (@metadata.code.branch_hint "\00")
    (if
      (i32.const 342)
      (then
        (drop (i32.const 31337))
      )
      (else
        (drop (i32.const 399))
      )
    )
  )

  ;; CHECK:      (func $br (type $0)
  ;; CHECK-NEXT:  (local $0 i32)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:   (br_if $out
  ;; CHECK-NEXT:    (block (result i32)
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (i32.const 42)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (call $log-branch
  ;; CHECK-NEXT:      (i32.const 4)
  ;; CHECK-NEXT:      (i32.const 0)
  ;; CHECK-NEXT:      (local.get $0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (i32.const 1337)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block $out1
  ;; CHECK-NEXT:   (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:   (br_if $out1
  ;; CHECK-NEXT:    (block (result i32)
  ;; CHECK-NEXT:     (local.set $1
  ;; CHECK-NEXT:      (i32.const 142)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (call $log-branch
  ;; CHECK-NEXT:      (i32.const 5)
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:      (local.get $1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.get $1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (i32.const 11337)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br
    ;; As above, with br_if, hints of 0 and 1.
    (block $out
      (@metadata.code.branch_hint "\00")
      (br_if $out
        (i32.const 42)
      )
      (drop (i32.const 1337))
    )
    (block $out1
      (@metadata.code.branch_hint "\01")
      (br_if $out1
        (i32.const 142)
      )
      (drop (i32.const 11337))
    )
  )

  ;; CHECK:      (func $br-no (type $0)
  ;; CHECK-NEXT:  (block $out2
  ;; CHECK-NEXT:   (br_if $out2
  ;; CHECK-NEXT:    (i32.const 242)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (i32.const 21337)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br-no
    ;; A br_if with no hint.
    (block $out2
      (br_if $out2
        (i32.const 242)
      )
      (drop (i32.const 21337))
    )
  )

  ;; CHECK:      (func $br_value (type $2) (result f64)
  ;; CHECK-NEXT:  (local $scratch f64)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (block $out (result f64)
  ;; CHECK-NEXT:   (local.set $scratch
  ;; CHECK-NEXT:    (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:    (br_if $out
  ;; CHECK-NEXT:     (f64.const 3.14159)
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (local.set $1
  ;; CHECK-NEXT:       (i32.const 42)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (call $log-branch
  ;; CHECK-NEXT:       (i32.const 6)
  ;; CHECK-NEXT:       (i32.const 0)
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (local.get $1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (i32.const 1337)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (local.get $scratch)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br_value (result f64)
    ;; As above, but now with a value.
    (block $out (result f64)
      (@metadata.code.branch_hint "\00")
      (br_if $out
        (f64.const 3.14159)
        (i32.const 42)
      )
      (drop (i32.const 1337))
    )
  )

  ;; CHECK:      (func $nested (type $0)
  ;; CHECK-NEXT:  (local $0 i32)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (local $2 i32)
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (local.set $2
  ;; CHECK-NEXT:     (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:     (if (result i32)
  ;; CHECK-NEXT:      (block (result i32)
  ;; CHECK-NEXT:       (local.set $0
  ;; CHECK-NEXT:        (i32.const 42)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (call $log-branch
  ;; CHECK-NEXT:        (i32.const 7)
  ;; CHECK-NEXT:        (i32.const 1)
  ;; CHECK-NEXT:        (local.get $0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (local.get $0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (then
  ;; CHECK-NEXT:       (i32.const 142)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (else
  ;; CHECK-NEXT:       (i32.const 242)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $log-branch
  ;; CHECK-NEXT:     (i32.const 9)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (local.get $2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $2)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (local.set $1
  ;; CHECK-NEXT:       (i32.const 342)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (call $log-branch
  ;; CHECK-NEXT:       (i32.const 8)
  ;; CHECK-NEXT:       (i32.const 0)
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (local.get $1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (i32.const 1337)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $nested
    ;; We should instrument all these, even the nested ones.
    (@metadata.code.branch_hint "\00")
    (if
      (@metadata.code.branch_hint "\01")
      (if (result i32)
        (i32.const 42)
        (then
          (i32.const 142)
        )
        (else
          (i32.const 242)
        )
      )
      (then
        (@metadata.code.branch_hint "\00")
        (if
          (i32.const 342)
          (then
            (drop (i32.const 1337))
          )
        )
      )
    )
  )

  ;; CHECK:      (func $br_on (type $3) (param $x anyref)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:    (br_on_null $out
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br_on (param $x anyref)
    ;; We do not instrument BrOn yet: the condition is not an i32 in this case,
    ;; so logging is trickier. TODO
    (block $out
      (drop
        (@metadata.code.branch_hint "\00")
        (br_on_null $out
          (local.get $x)
        )
      )
    )
  )

  ;; CHECK:      (func $eh-pop (type $0)
  ;; CHECK-NEXT:  (local $0 i32)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (block $label
  ;; CHECK-NEXT:   (try
  ;; CHECK-NEXT:    (do
  ;; CHECK-NEXT:     (nop)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (catch $i32
  ;; CHECK-NEXT:     (local.set $1
  ;; CHECK-NEXT:      (pop i32)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:     (br_if $label
  ;; CHECK-NEXT:      (block (result i32)
  ;; CHECK-NEXT:       (local.set $0
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (call $log-branch
  ;; CHECK-NEXT:        (i32.const 10)
  ;; CHECK-NEXT:        (i32.const 0)
  ;; CHECK-NEXT:        (local.get $0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (local.get $0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $eh-pop
    (block $label
      (try
        (do
          (nop)
        )
        (catch $i32
          (@metadata.code.branch_hint "\00")
          (br_if $label
            ;; This pop will end up in a block after our instrumentation, which
            ;; requires fixups.
            (pop i32)
          )
        )
      )
    )
  )
)

;; This module has an existing import with our module and base names. We nop it
;; and create a fresh one, to avoid confusion.
(module
  (import "fuzzing-support" "log-branch" (func $existing (param i32 i32 i32)))

  ;; CHECK:      (type $0 (func (param i32 i32 i32)))

  ;; CHECK:      (type $1 (func))

  ;; CHECK:      (import "fuzzing-support" "log-branch" (func $log-branch (type $0) (param i32 i32 i32)))

  ;; CHECK:      (func $existing (type $0) (param $0 i32) (param $1 i32) (param $2 i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )

  ;; CHECK:      (func $if (type $1)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (local.set $1
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (local.set $x
  ;; CHECK-NEXT:       (i32.const 42)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (call $existing
  ;; CHECK-NEXT:       (i32.const 42)
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:       (local.get $x)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (local.get $x)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $log-branch
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:     (local.get $1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1337)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if
    (local $x i32)
    (@metadata.code.branch_hint "\01")
    (if
      (block (result i32)
        (local.set $x
          (i32.const 42)
        )
        (call $existing
          (i32.const 42)
          (i32.const 1)
          (local.get $x)
        )
        (local.get $x)
      )
      (then
        (drop (i32.const 1337))
      )
    )
  )
)
