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

;; RUN: wasm-opt %s --precompute-propagate -all -S -o - | filecheck %s

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

 ;; CHECK:      (type $array16 (array (mut i16)))
 (type $array16 (array (mut i16)))

 (type $array16-imm (array i16))

 ;; CHECK:      (type $2 (func (result (ref string))))

 ;; CHECK:      (type $3 (func (result externref)))

 ;; CHECK:      (type $4 (func (result (ref any))))

 ;; CHECK:      (export "get_codepoint-unicode" (func $get_codepoint-unicode))

 ;; CHECK:      (export "get_codepoint-surrogate" (func $get_codepoint-surrogate))

 ;; CHECK:      (export "test" (func $encode-stashed))

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

 ;; CHECK:      (export "slice-unicode" (func $slice-unicode))

 ;; CHECK:      (export "slice-invalid-unicode-end" (func $slice-invalid-unicode-end))

 ;; CHECK:      (export "slice-invalid-unicode-begin" (func $slice-invalid-unicode-begin))

 ;; CHECK:      (func $eq-no (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 0)
 ;; CHECK-NEXT: )
 (func $eq-no (result i32)
  (string.eq
   (string.const "ab")
   (string.const "cdefg")
  )
 )

 ;; CHECK:      (func $eq-yes (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 1)
 ;; CHECK-NEXT: )
 (func $eq-yes (result i32)
  (string.eq
   (string.const "ab")
   (string.const "ab")
  )
 )

 ;; CHECK:      (func $concat (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 1)
 ;; CHECK-NEXT: )
 (func $concat (result i32)
  (string.eq
   (string.concat (string.const "a") (string.const "b"))
   (string.const "ab")
  )
 )

 ;; CHECK:      (func $concat-surrogates (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 1)
 ;; CHECK-NEXT: )
 (func $concat-surrogates (result i32)
  (string.eq
   ;; Concatenating these surrogates creates '𐍈', which has a different UTF-8 encoding.
   (string.concat (string.const "\ED\A0\80") (string.const "\ED\BD\88"))
   (string.const "\F0\90\8D\88")
  )
 )

 ;; CHECK:      (func $length (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 7)
 ;; CHECK-NEXT: )
 (func $length (result i32)
  (string.measure_wtf16
   (string.const "1234567")
  )
 )

 ;; CHECK:      (func $length-unicode (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 8)
 ;; CHECK-NEXT: )
 (func $length-unicode (result i32)
  (string.measure_wtf16
   ;; $_£_€_𐍈 (the last character is encoded as a surrogate pair)
   (string.const "$_\C2\A3_\E2\82\AC_\F0\90\8D\88")
  )
 )

 ;; CHECK:      (func $get_codepoint (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 95)
 ;; CHECK-NEXT: )
 (func $get_codepoint (result i32)
  ;; Returns 95 ('_').
  (stringview_wtf16.get_codeunit
   ;; $_£_€_𐍈
   (string.const "$_\C2\A3_\E2\82\AC_\F0\90\8D\88")
   (i32.const 1)
  )
 )

 ;; CHECK:      (func $get_codepoint-unicode (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 8364)
 ;; CHECK-NEXT: )
 (func $get_codepoint-unicode (export "get_codepoint-unicode") (result i32)
  ;; Returns 8364 ('€')
  (stringview_wtf16.get_codeunit
   ;; $_£_€_𐍈
   (string.const "$_\C2\A3_\E2\82\AC_\F0\90\8D\88")
   (i32.const 4)
  )
 )

 ;; CHECK:      (func $get_codepoint-surrogate (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 55296)
 ;; CHECK-NEXT: )
 (func $get_codepoint-surrogate (export "get_codepoint-surrogate") (result i32)
  ;; Returns 0xd800 (the high surrogate in '𐍈')
  (stringview_wtf16.get_codeunit
   ;; $_£_€_𐍈
   (string.const "$_\C2\A3_\E2\82\AC_\F0\90\8D\88")
   (i32.const 6)
  )
 )

 ;; CHECK:      (func $encode (type $0) (result i32)
 ;; CHECK-NEXT:  (string.encode_wtf16_array
 ;; CHECK-NEXT:   (string.const "$_")
 ;; CHECK-NEXT:   (array.new_default $array16
 ;; CHECK-NEXT:    (i32.const 20)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $encode (result i32)
  ;; We could optimize away the encode operation here as the reference does not
  ;; escape, but we do not do escape analysis here.
  (string.encode_wtf16_array
   (string.const "$_")
   (array.new_default $array16
    (i32.const 20)
   )
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $encode-unicode (type $0) (result i32)
 ;; CHECK-NEXT:  (string.encode_wtf16_array
 ;; CHECK-NEXT:   (string.const "$_\c2\a3_\e2\82\ac_\f0\90\8d\88")
 ;; CHECK-NEXT:   (array.new_default $array16
 ;; CHECK-NEXT:    (i32.const 20)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $encode-unicode (result i32)
  (string.encode_wtf16_array
   ;; $_£_€_𐍈
   (string.const "$_\C2\A3_\E2\82\AC_\F0\90\8D\88")
   (array.new_default $array16
    (i32.const 20)
   )
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $encode-stashed (type $4) (result (ref any))
 ;; CHECK-NEXT:  (local $1 (ref $array16))
 ;; CHECK-NEXT:  (local.set $1
 ;; CHECK-NEXT:   (array.new_default $array16
 ;; CHECK-NEXT:    (i32.const 10)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (string.encode_wtf16_array
 ;; CHECK-NEXT:    (string.const "0123456789")
 ;; CHECK-NEXT:    (local.get $1)
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.get $1)
 ;; CHECK-NEXT: )
 (func $encode-stashed (export "test") (result (ref any))
  (local $1 (ref $array16))
  ;; Create a zero-filled array.
  (local.set $1
   (array.new_default $array16
    (i32.const 10)
   )
  )
  ;; Fill it with some string data.
  (drop
   (string.encode_wtf16_array
    (string.const "0123456789")
    (local.get $1)
    (i32.const 0)
   )
  )
  ;; Return the modified array. We must not have removed the encode operation
  ;; above us (it has the side effect of modifying the array, just like an
  ;; array.copy does).
  (local.get $1)
 )

 ;; CHECK:      (func $slice (type $2) (result (ref string))
 ;; CHECK-NEXT:  (string.const "def")
 ;; CHECK-NEXT: )
 (func $slice (export "slice") (result (ref string))
  ;; Slicing [3:6] here should definitely output "def".
  (stringview_wtf16.slice
   (string.const "abcdefgh")
   (i32.const 3)
   (i32.const 6)
  )
 )

 ;; CHECK:      (func $slice-unicode (type $2) (result (ref string))
 ;; CHECK-NEXT:  (string.const "d\c2\a3f")
 ;; CHECK-NEXT: )
 (func $slice-unicode (export "slice-unicode") (result (ref string))
  (stringview_wtf16.slice
   ;; abcd£fgh
   (string.const "abcd\C2\A3fgh")
   (i32.const 3)
   (i32.const 6)
  )
 )

 ;; CHECK:      (func $slice-invalid-unicode-end (type $2) (result (ref string))
 ;; CHECK-NEXT:  (stringview_wtf16.slice
 ;; CHECK-NEXT:   (string.const "a\f0\90\8d\86b")
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (i32.const 2)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $slice-invalid-unicode-end (export "slice-invalid-unicode-end") (result (ref string))
  (stringview_wtf16.slice
   ;; a𐍆b
   (string.const "a\f0\90\8d\86b")
   (i32.const 0)
   (i32.const 2)
  )
 )

 ;; CHECK:      (func $slice-invalid-unicode-begin (type $2) (result (ref string))
 ;; CHECK-NEXT:  (stringview_wtf16.slice
 ;; CHECK-NEXT:   (string.const "a\f0\90\8d\86b")
 ;; CHECK-NEXT:   (i32.const 2)
 ;; CHECK-NEXT:   (i32.const 4)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $slice-invalid-unicode-begin (export "slice-invalid-unicode-begin") (result (ref string))
  (stringview_wtf16.slice
   ;; a𐍆b
   (string.const "a\f0\90\8d\86b")
   (i32.const 2)
   (i32.const 4)
  )
 )


 ;; CHECK:      (func $string.new-mutable (type $3) (result externref)
 ;; CHECK-NEXT:  (string.const "ABCD")
 ;; CHECK-NEXT: )
 (func $string.new-mutable (result externref)
  ;; We can precompute this only because the allocation is the immediate child.
  (string.new_wtf16_array
   (array.new_fixed $array16 4
    (i32.const 65)
    (i32.const 66)
    (i32.const 67)
    (i32.const 68)
   )
   (i32.const 0)
   (i32.const 4)
  )
 )

 ;; CHECK:      (func $string.new-mutable-indirect (type $3) (result externref)
 ;; CHECK-NEXT:  (string.new_wtf16_array
 ;; CHECK-NEXT:   (block (result (ref (exact $array16)))
 ;; CHECK-NEXT:    (array.new_fixed $array16 4
 ;; CHECK-NEXT:     (i32.const 65)
 ;; CHECK-NEXT:     (i32.const 66)
 ;; CHECK-NEXT:     (i32.const 67)
 ;; CHECK-NEXT:     (i32.const 68)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (i32.const 4)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $string.new-mutable-indirect (result externref)
  ;; Now the allocation is not the immediate child, so we do not precompute.
  ;; TODO: be smarter and optimize this.
  (string.new_wtf16_array
   (block (result (ref $array16))
    (array.new_fixed $array16 4
     (i32.const 65)
     (i32.const 66)
     (i32.const 67)
     (i32.const 68)
    )
   )
   (i32.const 0)
   (i32.const 4)
  )
 )
)
