// RUN: %target-swift-frontend  -primary-file %s -O -sil-verify-all -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test -emit-sil -enforce-exclusivity=unchecked | %FileCheck %s

// Also do an end-to-end test to check all components, including IRGen.
// RUN: %empty-directory(%t) 
// RUN: %target-build-swift -O -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test %s -o %t/a.out
// RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT
// REQUIRES: executable_test,swift_stdlib_no_asserts,optimized_stdlib

// Check if the optimizer is able to convert array literals to statically initialized arrays.

// CHECK-LABEL: outlined variable #0 of arrayLookup(_:)
// CHECK-NEXT:  sil_global private @{{.*}}arrayLookup{{.*}} = {
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 10
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 11
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 12
// CHECK:         object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}}, {{[^,]*}})
// CHECK-NEXT:  }

// CHECK-LABEL: outlined variable #0 of returnArray()
// CHECK-NEXT:  sil_global private @{{.*}}returnArray{{.*}} = {
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 20
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 21
// CHECK:         object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}})
// CHECK-NEXT:  }

// CHECK-LABEL: outlined variable #0 of returnStaticStringArray()
// CHECK-NEXT:  sil_global private @{{.*}}returnStaticStringArray{{.*}} = {
// CHECK-DAG:     string_literal utf8 "a"
// CHECK-DAG:     string_literal utf8 "b"
// CHECK:         object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}})
// CHECK-NEXT:  }

// CHECK-LABEL: outlined variable #0 of passArray()
// CHECK-NEXT:  sil_global private @{{.*}}passArray{{.*}} = {
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 27
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 28
// CHECK:         object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}})
// CHECK-NEXT:  }

// CHECK-LABEL: outlined variable #1 of passArray()
// CHECK-NEXT:  sil_global private @{{.*}}passArray{{.*}} = {
// CHECK:         integer_literal $Builtin.Int{{[0-9]+}}, 29
// CHECK:         object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}})
// CHECK-NEXT:  }

// CHECK-LABEL: outlined variable #0 of storeArray()
// CHECK-NEXT:  sil_global private @{{.*}}storeArray{{.*}} = {
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 227
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 228
// CHECK:         object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}})
// CHECK-NEXT:  }

// CHECK-LABEL: sil_global private @{{.*}}main{{.*}} = {
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 100
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 101
// CHECK-DAG:     integer_literal $Builtin.Int{{[0-9]+}}, 102
// CHECK:         object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}}, {{[^,]*}})
// CHECK-NEXT:  }

// CHECK-LABEL: sil @main
// CHECK:   global_value @{{.*}}main{{.*}}
// CHECK:   return
public let globalVariable = [ 100, 101, 102 ]

// CHECK-LABEL: sil {{.*}}arrayLookup{{.*}} : $@convention(thin) (Int) -> Int {
// CHECK:   global_value @{{.*}}arrayLookup{{.*}}
// CHECK:   return
@inline(never)
public func arrayLookup(_ i: Int) -> Int {
  let lookupTable = [10, 11, 12]
  return lookupTable[i]
}

// CHECK-LABEL: sil {{.*}}returnArray{{.*}} : $@convention(thin) () -> @owned Array<Int> {
// CHECK:   global_value @{{.*}}returnArray{{.*}}
// CHECK:   return
@inline(never)
public func returnArray() -> [Int] {
  return [20, 21]
}

// CHECK-LABEL: sil {{.*}}returnStaticStringArray{{.*}} : $@convention(thin) () -> @owned Array<StaticString> {
// CHECK:   global_value @{{.*}}returnStaticStringArray{{.*}}
// CHECK:   return
@inline(never)
public func returnStaticStringArray() -> [StaticString] {
  return ["a", "b"]
}

public var gg: [Int]?

@inline(never)
public func receiveArray(_ a: [Int]) {
  gg = a
}

// CHECK-LABEL: sil {{.*}}passArray{{.*}} : $@convention(thin) () -> () {
// CHECK:   global_value @{{.*}}passArray{{.*}}
// CHECK:   global_value @{{.*}}passArray{{.*}}
// CHECK:   return
@inline(never)
public func passArray() {
  receiveArray([27, 28])
  receiveArray([29])
}

// CHECK-LABEL: sil {{.*}}storeArray{{.*}} : $@convention(thin) () -> () {
// CHECK:   global_value @{{.*}}storeArray{{.*}}
// CHECK:   return
@inline(never)
public func storeArray() {
  gg = [227, 228]
}

struct Empty { }

// CHECK-LABEL: sil {{.*}}arrayWithEmptyElements{{.*}} : $@convention(thin) () -> @owned Array<Empty> {
func arrayWithEmptyElements() -> [Empty] {
  // CHECK:    global_value @{{.*}}arrayWithEmptyElements{{.*}}
  // CHECK:    return
  return [Empty()]
}

// CHECK-OUTPUT:      [100, 101, 102]
print(globalVariable)
// CHECK-OUTPUT-NEXT: 11
print(arrayLookup(1))
// CHECK-OUTPUT-NEXT: [20, 21]
print(returnArray())
// CHECK-OUTPUT-NEXT: ["a", "b"]
print(returnStaticStringArray())
passArray()
// CHECK-OUTPUT-NEXT: [29]
print(gg!)
storeArray()
// CHECK-OUTPUT-NEXT: [227, 228]
print(gg!)






public class SwiftClass {}

@inline(never)
func takeUnsafePointer(ptr : UnsafePointer<SwiftClass>, len: Int) {
  print(ptr, len)  // Use the arguments somehow so they don't get removed.
}

// This should be a single basic block, and the array should end up being stack
// allocated.
//
// CHECK-LABEL: sil @{{.*}}passArrayOfClasses
// CHECK: bb0(%0 : $SwiftClass, %1 : $SwiftClass, %2 : $SwiftClass):
// CHECK-NOT: bb1(
// CHECK: alloc_ref {{.*}}[tail_elems $SwiftClass *
// CHECK-NOT: bb1(
// CHECK:   return
public func passArrayOfClasses(a: SwiftClass, b: SwiftClass, c: SwiftClass) {
  let arr = [a, b, c]
  takeUnsafePointer(ptr: arr, len: arr.count)
}




