diff --git a/lib/IRGen/GenConstant.cpp b/lib/IRGen/GenConstant.cpp index e897a0e2ef7..df18be6e11d 100644 --- a/lib/IRGen/GenConstant.cpp +++ b/lib/IRGen/GenConstant.cpp @@ -456,22 +456,37 @@ llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI, if (IGM.canMakeStaticObjectReadOnly(OI->getType())) { if (!IGM.swiftImmortalRefCount) { - auto *var = new llvm::GlobalVariable(IGM.Module, IGM.Int8Ty, - /*constant*/ true, llvm::GlobalValue::ExternalLinkage, - /*initializer*/ nullptr, "_swiftImmortalRefCount"); - IGM.swiftImmortalRefCount = var; + if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) { + // = HeapObject.immortalRefCount + IGM.swiftImmortalRefCount = llvm::ConstantInt::get(IGM.IntPtrTy, -1); + } else { + IGM.swiftImmortalRefCount = llvm::ConstantExpr::getPtrToInt( + new llvm::GlobalVariable(IGM.Module, IGM.Int8Ty, + /*constant*/ true, llvm::GlobalValue::ExternalLinkage, + /*initializer*/ nullptr, "_swiftImmortalRefCount"), + IGM.IntPtrTy); + } } if (!IGM.swiftStaticArrayMetadata) { auto *classDecl = IGM.getStaticArrayStorageDecl(); assert(classDecl && "no __StaticArrayStorage in stdlib"); CanType classTy = CanType(ClassType::get(classDecl, Type(), IGM.Context)); - LinkEntity entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint); - auto *metatype = IGM.getAddrOfLLVMVariable(entity, NotForDefinition, DebugTypeInfo()); - IGM.swiftStaticArrayMetadata = cast(metatype); + if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) { + LinkEntity entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint, + /*forceShared=*/ true); + // In embedded swift, the metadata for the array buffer class only needs to be very minimal: + // No vtable needed, because the object is never destructed. It only contains the null super- + // class pointer. + llvm::Constant *superClass = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); + IGM.swiftStaticArrayMetadata = IGM.getAddrOfLLVMVariable(entity, superClass, DebugTypeInfo()); + } else { + LinkEntity entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint); + IGM.swiftStaticArrayMetadata = IGM.getAddrOfLLVMVariable(entity, NotForDefinition, DebugTypeInfo()); + } } elements[0].add(llvm::ConstantStruct::get(ObjectHeaderTy, { IGM.swiftStaticArrayMetadata, - llvm::ConstantExpr::getPtrToInt(IGM.swiftImmortalRefCount, IGM.IntPtrTy)})); + IGM.swiftImmortalRefCount })); } else { elements[0].add(llvm::Constant::getNullValue(ObjectHeaderTy)); } diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 7c89a169466..9b1e8bf8386 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -837,8 +837,8 @@ public: llvm::GlobalVariable *TheTrivialPropertyDescriptor = nullptr; - llvm::GlobalVariable *swiftImmortalRefCount = nullptr; - llvm::GlobalVariable *swiftStaticArrayMetadata = nullptr; + llvm::Constant *swiftImmortalRefCount = nullptr; + llvm::Constant *swiftStaticArrayMetadata = nullptr; /// Used to create unique names for class layout types with tail allocated /// elements. diff --git a/stdlib/public/core/EmbeddedRuntime.swift b/stdlib/public/core/EmbeddedRuntime.swift index b3c7a5238c9..2a9a2561e0d 100644 --- a/stdlib/public/core/EmbeddedRuntime.swift +++ b/stdlib/public/core/EmbeddedRuntime.swift @@ -46,6 +46,7 @@ public struct HeapObject { static let refcountMask = Int(bitPattern: 0x7fff_ffff) #endif + // Note: The immortalRefCount value of -1 is also hard-coded in IRGen in `irgen::emitConstantObject`. static let immortalRefCount = -1 } diff --git a/test/embedded/static-object.swift b/test/embedded/static-object.swift index 429b118db20..4b98e91c74f 100644 --- a/test/embedded/static-object.swift +++ b/test/embedded/static-object.swift @@ -1,27 +1,128 @@ -// RUN: %target-swift-frontend -O -emit-irgen %s -module-name main -parse-as-library -enable-experimental-feature Embedded | %FileCheck %s --check-prefix CHECK-IR -// RUN: %target-run-simple-swift(-O -enable-experimental-feature Embedded -parse-as-library -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s +// RUN: %target-swift-frontend -parse-as-library -enable-experimental-feature Embedded %s -O -wmo -sil-verify-all -module-name=test -emit-ir | %FileCheck %s -// REQUIRES: swift_in_compiler -// REQUIRES: executable_test -// REQUIRES: optimized_stdlib -// REQUIRES: OS=macosx || OS=linux-gnu +// Also do an end-to-end test to check all components, including IRGen. +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -parse-as-library -enable-experimental-feature Embedded -O -wmo -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 constant statically initialized arrays. + +// CHECK-DAG: @"$s4test11arrayLookupyS2iFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1 +// CHECK-DAG: @"$s4test11returnArraySaySiGyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1 +// CHECK-DAG: @"$s4test9passArrayyyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1 +// CHECK-DAG: @"$s4test9passArrayyyFTv0_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1 +// CHECK-DAG: @"$s4test10storeArrayyyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1 +// CHECK-DAG: @"$s4test3StrV9staticLet_WZTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1 +// CHECK-DAG: @"$s4test3StrV9staticVar_WZTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1 +// CHECK-DAG: @"$s4test3StrV9staticVarSaySiGvpZ" = global {{.*}} ptr @"$s4test3StrV9staticVar_WZTv_r" +// CHECK-DAG: @"$s4test3StrV14twoDimensionalSaySaySiGGvpZ" = global {{.*}} ptr @"$s4test3StrV14twoDimensional_WZTv{{[0-9]*}}_r" + +// Currently, constant static arrays only work on Darwin platforms. +// REQUIRES: VENDOR=apple + + +public struct Str { + public static let staticLet = [ 200, 201, 202 ] + public static var staticVar = [ 300, 301, 302 ] + public static var twoDimensional = [[1, 2], [3, 4], [5, 6]] +} + +@inline(never) +public func arrayLookup(_ i: Int) -> Int { + let lookupTable = [10, 11, 12] + return lookupTable[i] +} + +@inline(never) +public func returnArray() -> [Int] { + return [20, 21] +} + +@inline(never) +public func modifyArray() -> [Int] { + var a = returnArray() + a[1] = 27 + return a +} + +public var gg: [Int]? + +@inline(never) +public func receiveArray(_ a: [Int]) { + gg = a +} + +@inline(never) +public func passArray() { + receiveArray([27, 28]) + receiveArray([29]) +} + +@inline(never) +public func storeArray() { + gg = [227, 228] +} public func stringArray() -> [StaticString] { return ["a", "b", "c", "d"] } -// CHECK-IR: define {{.*}}@"$s4main11stringArraySays12StaticStringVGyF" -// CHECK-IR-NEXT: entry: -// CHECK-IR-NEXT: call {{.*}}@swift_initStaticObject -@main -struct Main { +@main struct Main { static func main() { + + // CHECK-OUTPUT: [200, 201, 202] + printArray(Str.staticLet) + + // CHECK-OUTPUT: [300, 301, 302] + printArray(Str.staticVar) + + // CHECK-OUTPUT: [1, 2] + // CHECK-OUTPUT-NEXT: [3, 4] + // CHECK-OUTPUT-NEXT: [5, 6] + for x in Str.twoDimensional { + printArray(x) + } + + // CHECK-OUTPUT-NEXT: 11 + print(arrayLookup(1)) + + // CHECK-OUTPUT-NEXT: [20, 21] + printArray(returnArray()) + + // CHECK-OUTPUT-NEXT: [20, 27] + // CHECK-OUTPUT-NEXT: [20, 27] + // CHECK-OUTPUT-NEXT: [20, 27] + // CHECK-OUTPUT-NEXT: [20, 27] + // CHECK-OUTPUT-NEXT: [20, 27] + for _ in 0..<5 { + printArray(modifyArray()) + } + + passArray() + // CHECK-OUTPUT-NEXT: [29] + printArray(gg!) + + storeArray() + // CHECK-OUTPUT-NEXT: [227, 228] + printArray(gg!) + for c in stringArray() { + // CHECK-OUTPUT-NEXT: a + // CHECK-OUTPUT-NEXT: b + // CHECK-OUTPUT-NEXT: c + // CHECK-OUTPUT-NEXT: d print(c) - // CHECK: a - // CHECK: b - // CHECK: c - // CHECK: d } } } + +func printArray(_ a: [Int]) { + print("[", terminator: "") + for (i, x) in a.enumerated() { + print(x, terminator: i == a.count - 1 ? "" : ", ") + } + print("]") +} +