// RUN: %target-swift-frontend -primary-file %s -O -sil-verify-all -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test -emit-sil | %FileCheck %s // RUN: %target-swift-frontend -primary-file %s -O -sil-verify-all -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test -emit-ir | %FileCheck %s -check-prefix=CHECK-LLVM // 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 // REQUIRES: CPU=arm64 || CPU=x86_64 // REQUIRES: swift_in_compiler // Check if the optimizer is able to convert array literals to statically initialized arrays. // CHECK-LABEL: sil_global @$s4test4FStrV10globalFuncyS2icvpZ : $@callee_guaranteed (Int) -> Int = { // CHECK: %0 = function_ref @$s4test3fooyS2iF : $@convention(thin) (Int) -> Int // CHECK-NEXT: %initval = thin_to_thick_function %0 // CHECK-NEXT: } // CHECK-LABEL: outlined variable #0 of arrayLookup(_:) // CHECK-NEXT: sil_global private [let] @{{.*}}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 [let] @{{.*}}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 [let] @{{.*}}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 [let] @{{.*}}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 [let] @{{.*}}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 [let] @{{.*}}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: outlined variable #0 of functionArray() // CHECK-NEXT: sil_global private [let] @{{.*functionArray.*}} = { // CHECK: function_ref // CHECK: thin_to_thick_function // CHECK: convert_function // CHECK: function_ref // CHECK: thin_to_thick_function // CHECK: convert_function // CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] // CHECK-NEXT: } // CHECK-LABEL: outlined variable #0 of returnDictionary() // CHECK-NEXT: sil_global private [let] @{{.*}}returnDictionary{{.*}} = { // CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 5 // CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 4 // CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 2 // CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 1 // CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 6 // CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 3 // CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] // CHECK-NEXT: } // CHECK-LABEL: outlined variable #0 of returnStringDictionary() // CHECK-NEXT: sil_global private [let] @{{.*}}returnStringDictionary{{.*}} = { // CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] // CHECK-NEXT: } // CHECK-LABEL: sil_global private [let] @{{.*}}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 [noinline] @$s4test11arrayLookupyS2iF // CHECK: global_value [bare] @$s4test11arrayLookupyS2iFTv_ // CHECK-NOT: retain // CHECK-NOT: release // CHECK: } // end sil function '$s4test11arrayLookupyS2iF' // CHECK-LLVM-LABEL: define {{.*}} @"$s4test11arrayLookupyS2iF" // CHECK-LLVM-NOT: call // CHECK-LLVM: [[E:%[0-9]+]] = getelementptr {{.*}} @"$s4test11arrayLookupyS2iFTv_{{r*}}" // CHECK-LLVM-NEXT: [[L:%[0-9]+]] = load {{.*}} [[E]] // CHECK-LLVM-NEXT: ret {{.*}} [[L]] // CHECK-LLVM: } @inline(never) public func arrayLookup(_ i: Int) -> Int { let lookupTable = [10, 11, 12] return lookupTable[i] } // CHECK-LABEL: sil {{.*}}returnArray{{.*}} : $@convention(thin) () -> @owned Array { // CHECK: global_value @{{.*}}returnArray{{.*}} // CHECK: return @inline(never) public func returnArray() -> [Int] { return [20, 21] } // CHECK-LABEL: sil {{.*}}returnStaticStringArray{{.*}} : $@convention(thin) () -> @owned Array { // 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 { func arrayWithEmptyElements() -> [Empty] { // CHECK: global_value @{{.*}}arrayWithEmptyElements{{.*}} // CHECK: return return [Empty()] } // CHECK-LABEL: sil hidden [noinline] @$s4test13arrayOfTuplesSaySi_SbtGyF : // CHECK: global_value @$s4test13arrayOfTuplesSaySi_SbtGyFTv_ : // CHECK-NOT: store // CHECK-NOT: apply // CHECK: } // end sil function '$s4test13arrayOfTuplesSaySi_SbtGyF' @inline(never) func arrayOfTuples() -> [(Int, Bool)] { return [(1, false), (2, true), (3, false)] } // CHECK-LABEL: sil {{.*}}returnDictionary{{.*}} : $@convention(thin) () -> @owned Dictionary { // CHECK: global_value @{{.*}}returnDictionary{{.*}} // CHECK: return @inline(never) public func returnDictionary() -> [Int:Int] { return [1:2, 3:4, 5:6] } // CHECK-LABEL: sil {{.*}}returnStringDictionary{{.*}} : $@convention(thin) () -> @owned Dictionary { // CHECK: global_value @{{.*}}returnStringDictionary{{.*}} // CHECK: return @inline(never) public func returnStringDictionary() -> [String:String] { return ["1":"2", "3":"4", "5":"6"] } func foo(_ i: Int) -> Int { return i } // CHECK-LABEL: sil {{.*functionArray.*}} : $@convention(thin) () -> @owned Array<(Int) -> Int> { // CHECK: global_value @{{.*functionArray.*}} // CHECK: } // end sil function '{{.*functionArray.*}}' @inline(never) func functionArray() -> [(Int) -> Int] { func bar(_ i: Int) -> Int { return i + 1 } return [foo, bar, { $0 + 10 }] } var g1 = 1 var g2 = 2 // CHECK-LABEL: sil {{.*arrayOfGlobalPointers.*}} : $@convention(thin) () -> @owned Array> { // CHECK: global_value @{{.*arrayOfGlobalPointers.*}} // CHECK: } // end sil function '{{.*arrayOfGlobalPointers.*}}' @inline(never) public func arrayOfGlobalPointers() -> [UnsafePointer] { return [UnsafePointer(&g1), UnsafePointer(&g2)] } public struct FStr { // Not an array, but also tested here. public static var globalFunc = foo } @inline(never) func testit() { // 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!) // CHECK-OUTPUT-NEXT: 311 print(functionArray()[0](100) + functionArray()[1](100) + functionArray()[2](100)) // CHECK-OUTPUT-NEXT: 27 print(FStr.globalFunc(27)) let tuples = arrayOfTuples() // CHECK-OUTPUT-NEXT: tuples [(1, false), (2, true), (3, false)] print("tuples \(tuples)") let dict = returnDictionary() // CHECK-OUTPUT-NEXT: dict 3: 2, 4, 6 print("dict \(dict.count): \(dict[1]!), \(dict[3]!), \(dict[5]!)") let sdict = returnStringDictionary() // CHECK-OUTPUT-NEXT: sdict 3: 2, 4, 6 print("sdict \(sdict.count): \(sdict["1"]!), \(sdict["3"]!), \(sdict["5"]!)") // CHECK-OUTPUT-NEXT: globalpointers: [1, 2] print("globalpointers: \(arrayOfGlobalPointers().map { $0.pointee })") } testit() public class SwiftClass {} @inline(never) func takeUnsafePointer(ptr : UnsafePointer, 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 [noinline] @$s4test18passArrayOfClasses1a1b1cyAA10SwiftClassC_A2GtF : $@convention(thin) (@guaranteed SwiftClass, @guaranteed SwiftClass, @guaranteed SwiftClass) -> () { // CHECK: bb0(%0 : $SwiftClass, %1 : $SwiftClass, %2 : $SwiftClass): // CHECK-NOT: bb1 // CHECK: alloc_ref{{.*}}[stack] [tail_elems $SwiftClass * // CHECK-NOT: bb1 // CHECK: } // end sil function '$s4test18passArrayOfClasses1a1b1cyAA10SwiftClassC_A2GtF' @inline(never) public func passArrayOfClasses(a: SwiftClass, b: SwiftClass, c: SwiftClass) { let arr = [a, b, c] takeUnsafePointer(ptr: arr, len: arr.count) }