;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.

;; RUN: foreach %s %t wasm-opt --duplicate-function-elimination --all-features -S -o - | filecheck %s

;; Test that we merge functions even if they differ in branch hints. This is
;; good for code size, and follows what LLVM does.

;; The functions here differ in branch hints (but we still merge).
(module
 ;; CHECK:      (type $0 (func (param i32)))

 ;; CHECK:      (export "a" (func $a))

 ;; CHECK:      (export "b" (func $a))

 ;; CHECK:      (func $a (type $0) (param $x i32)
 ;; CHECK-NEXT:  (@metadata.code.branch_hint "\00")
 ;; CHECK-NEXT:  (if
 ;; CHECK-NEXT:   (local.get $x)
 ;; CHECK-NEXT:   (then
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $a (export "a") (param $x i32)
  (@metadata.code.branch_hint "\00")
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )

 (func $b (export "b") (param $x i32)
  (@metadata.code.branch_hint "\01")
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )
)

;; These also differ, now one is missing a hint (but we still merge).
(module
 ;; CHECK:      (type $0 (func (param i32)))

 ;; CHECK:      (export "a" (func $a))

 ;; CHECK:      (export "b" (func $a))

 ;; CHECK:      (func $a (type $0) (param $x i32)
 ;; CHECK-NEXT:  (@metadata.code.branch_hint "\00")
 ;; CHECK-NEXT:  (if
 ;; CHECK-NEXT:   (local.get $x)
 ;; CHECK-NEXT:   (then
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $a (export "a") (param $x i32)
  (@metadata.code.branch_hint "\00")
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )

 (func $b (export "b") (param $x i32)
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )
)

;; Flipped case of the above, now the other one is the only one with a hint,
;; and that hint is flipped (but we still merge).
(module
 ;; CHECK:      (type $0 (func (param i32)))

 ;; CHECK:      (export "a" (func $a))

 ;; CHECK:      (export "b" (func $a))

 ;; CHECK:      (func $a (type $0) (param $x i32)
 ;; CHECK-NEXT:  (if
 ;; CHECK-NEXT:   (local.get $x)
 ;; CHECK-NEXT:   (then
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $a (export "a") (param $x i32)
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )

 (func $b (export "b") (param $x i32)
  (@metadata.code.branch_hint "\01")
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )
)

;; Identical branch hints: We can definitely merge here.
(module
 ;; CHECK:      (type $0 (func (param i32)))

 ;; CHECK:      (export "a" (func $a))

 ;; CHECK:      (export "b" (func $a))

 ;; CHECK:      (func $a (type $0) (param $x i32)
 ;; CHECK-NEXT:  (@metadata.code.branch_hint "\00")
 ;; CHECK-NEXT:  (if
 ;; CHECK-NEXT:   (local.get $x)
 ;; CHECK-NEXT:   (then
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $a (export "a") (param $x i32)
  (@metadata.code.branch_hint "\00")
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )

 (func $b (export "b") (param $x i32)
  (@metadata.code.branch_hint "\00")
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )
)

;; Ditto, with identical hints of 1.
(module
 ;; CHECK:      (type $0 (func (param i32)))

 ;; CHECK:      (export "a" (func $a))

 ;; CHECK:      (export "b" (func $a))

 ;; CHECK:      (func $a (type $0) (param $x i32)
 ;; CHECK-NEXT:  (@metadata.code.branch_hint "\01")
 ;; CHECK-NEXT:  (if
 ;; CHECK-NEXT:   (local.get $x)
 ;; CHECK-NEXT:   (then
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $a (export "a") (param $x i32)
  (@metadata.code.branch_hint "\01")
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )

 (func $b (export "b") (param $x i32)
  (@metadata.code.branch_hint "\01")
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )
)

;; Source file location (debug info) does not prevent optimization (and has
;; even less reason to do so than branch hints, as we prioritize optimization
;; over debug info quality).
(module
 ;; CHECK:      (type $0 (func (param i32)))

 ;; CHECK:      (export "a" (func $a))

 ;; CHECK:      (export "b" (func $a))

 ;; CHECK:      (func $a (type $0) (param $x i32)
 ;; CHECK-NEXT:  ;;@ src.cpp:10:1
 ;; CHECK-NEXT:  (if
 ;; CHECK-NEXT:   (local.get $x)
 ;; CHECK-NEXT:   (then
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $a (export "a") (param $x i32)
  ;; After we merge, this hint will remain in the single function.
  ;;@ src.cpp:10:1
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )

 (func $b (export "b") (param $x i32)
  ;;@ src.cpp:20:1
  (if
   (local.get $x)
   (then
    (unreachable)
   )
  )
 )
)

