Skip to content

Commit 1621393

Browse files
committed
IRGen: support read-only statically initialized arrays in embedded swift
Arrays buffers need to be initialized with a (minimal) metatype and with an immortal reference count.
1 parent 09d2e8f commit 1621393

File tree

4 files changed

+142
-25
lines changed

4 files changed

+142
-25
lines changed

lib/IRGen/GenConstant.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -456,22 +456,37 @@ llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI,
456456

457457
if (IGM.canMakeStaticObjectReadOnly(OI->getType())) {
458458
if (!IGM.swiftImmortalRefCount) {
459-
auto *var = new llvm::GlobalVariable(IGM.Module, IGM.Int8Ty,
460-
/*constant*/ true, llvm::GlobalValue::ExternalLinkage,
461-
/*initializer*/ nullptr, "_swiftImmortalRefCount");
462-
IGM.swiftImmortalRefCount = var;
459+
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
460+
// = HeapObject.immortalRefCount
461+
IGM.swiftImmortalRefCount = llvm::ConstantInt::get(IGM.IntPtrTy, -1);
462+
} else {
463+
IGM.swiftImmortalRefCount = llvm::ConstantExpr::getPtrToInt(
464+
new llvm::GlobalVariable(IGM.Module, IGM.Int8Ty,
465+
/*constant*/ true, llvm::GlobalValue::ExternalLinkage,
466+
/*initializer*/ nullptr, "_swiftImmortalRefCount"),
467+
IGM.IntPtrTy);
468+
}
463469
}
464470
if (!IGM.swiftStaticArrayMetadata) {
465471
auto *classDecl = IGM.getStaticArrayStorageDecl();
466472
assert(classDecl && "no __StaticArrayStorage in stdlib");
467473
CanType classTy = CanType(ClassType::get(classDecl, Type(), IGM.Context));
468-
LinkEntity entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint);
469-
auto *metatype = IGM.getAddrOfLLVMVariable(entity, NotForDefinition, DebugTypeInfo());
470-
IGM.swiftStaticArrayMetadata = cast<llvm::GlobalVariable>(metatype);
474+
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
475+
LinkEntity entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint,
476+
/*forceShared=*/ true);
477+
// In embedded swift, the metadata for the array buffer class only needs to be very minimal:
478+
// No vtable needed, because the object is never destructed. It only contains the null super-
479+
// class pointer.
480+
llvm::Constant *superClass = llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
481+
IGM.swiftStaticArrayMetadata = IGM.getAddrOfLLVMVariable(entity, superClass, DebugTypeInfo());
482+
} else {
483+
LinkEntity entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint);
484+
IGM.swiftStaticArrayMetadata = IGM.getAddrOfLLVMVariable(entity, NotForDefinition, DebugTypeInfo());
485+
}
471486
}
472487
elements[0].add(llvm::ConstantStruct::get(ObjectHeaderTy, {
473488
IGM.swiftStaticArrayMetadata,
474-
llvm::ConstantExpr::getPtrToInt(IGM.swiftImmortalRefCount, IGM.IntPtrTy)}));
489+
IGM.swiftImmortalRefCount }));
475490
} else {
476491
elements[0].add(llvm::Constant::getNullValue(ObjectHeaderTy));
477492
}

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -837,8 +837,8 @@ class IRGenModule {
837837

838838
llvm::GlobalVariable *TheTrivialPropertyDescriptor = nullptr;
839839

840-
llvm::GlobalVariable *swiftImmortalRefCount = nullptr;
841-
llvm::GlobalVariable *swiftStaticArrayMetadata = nullptr;
840+
llvm::Constant *swiftImmortalRefCount = nullptr;
841+
llvm::Constant *swiftStaticArrayMetadata = nullptr;
842842

843843
/// Used to create unique names for class layout types with tail allocated
844844
/// elements.

stdlib/public/core/EmbeddedRuntime.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public struct HeapObject {
4646
static let refcountMask = Int(bitPattern: 0x7fff_ffff)
4747
#endif
4848

49+
// Note: The immortalRefCount value of -1 is also hard-coded in IRGen in `irgen::emitConstantObject`.
4950
static let immortalRefCount = -1
5051
}
5152

test/embedded/static-object.swift

Lines changed: 116 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,128 @@
1-
// RUN: %target-swift-frontend -O -emit-irgen %s -module-name main -parse-as-library -enable-experimental-feature Embedded | %FileCheck %s --check-prefix CHECK-IR
2-
// RUN: %target-run-simple-swift(-O -enable-experimental-feature Embedded -parse-as-library -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s
1+
// RUN: %target-swift-frontend -parse-as-library -enable-experimental-feature Embedded %s -O -wmo -sil-verify-all -module-name=test -emit-ir | %FileCheck %s
32

4-
// REQUIRES: swift_in_compiler
5-
// REQUIRES: executable_test
6-
// REQUIRES: optimized_stdlib
7-
// REQUIRES: OS=macosx || OS=linux-gnu
3+
// Also do an end-to-end test to check all components, including IRGen.
4+
// RUN: %empty-directory(%t)
5+
// RUN: %target-build-swift -parse-as-library -enable-experimental-feature Embedded -O -wmo -module-name=test %s -o %t/a.out
6+
// RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT
7+
8+
// REQUIRES: executable_test,swift_stdlib_no_asserts,optimized_stdlib
9+
10+
// Check if the optimizer is able to convert array literals to constant statically initialized arrays.
11+
12+
// CHECK-DAG: @"$s4test11arrayLookupyS2iFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1
13+
// CHECK-DAG: @"$s4test11returnArraySaySiGyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1
14+
// CHECK-DAG: @"$s4test9passArrayyyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1
15+
// CHECK-DAG: @"$s4test9passArrayyyFTv0_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1
16+
// CHECK-DAG: @"$s4test10storeArrayyyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1
17+
// CHECK-DAG: @"$s4test3StrV9staticLet_WZTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1
18+
// CHECK-DAG: @"$s4test3StrV9staticVar_WZTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} -1
19+
// CHECK-DAG: @"$s4test3StrV9staticVarSaySiGvpZ" = global {{.*}} ptr @"$s4test3StrV9staticVar_WZTv_r"
20+
// CHECK-DAG: @"$s4test3StrV14twoDimensionalSaySaySiGGvpZ" = global {{.*}} ptr @"$s4test3StrV14twoDimensional_WZTv{{[0-9]*}}_r"
21+
22+
// Currently, constant static arrays only work on Darwin platforms.
23+
// REQUIRES: VENDOR=apple
24+
25+
26+
public struct Str {
27+
public static let staticLet = [ 200, 201, 202 ]
28+
public static var staticVar = [ 300, 301, 302 ]
29+
public static var twoDimensional = [[1, 2], [3, 4], [5, 6]]
30+
}
31+
32+
@inline(never)
33+
public func arrayLookup(_ i: Int) -> Int {
34+
let lookupTable = [10, 11, 12]
35+
return lookupTable[i]
36+
}
37+
38+
@inline(never)
39+
public func returnArray() -> [Int] {
40+
return [20, 21]
41+
}
42+
43+
@inline(never)
44+
public func modifyArray() -> [Int] {
45+
var a = returnArray()
46+
a[1] = 27
47+
return a
48+
}
49+
50+
public var gg: [Int]?
51+
52+
@inline(never)
53+
public func receiveArray(_ a: [Int]) {
54+
gg = a
55+
}
56+
57+
@inline(never)
58+
public func passArray() {
59+
receiveArray([27, 28])
60+
receiveArray([29])
61+
}
62+
63+
@inline(never)
64+
public func storeArray() {
65+
gg = [227, 228]
66+
}
867

968
public func stringArray() -> [StaticString] {
1069
return ["a", "b", "c", "d"]
1170
}
12-
// CHECK-IR: define {{.*}}@"$s4main11stringArraySays12StaticStringVGyF"
13-
// CHECK-IR-NEXT: entry:
14-
// CHECK-IR-NEXT: call {{.*}}@swift_initStaticObject
1571

16-
@main
17-
struct Main {
72+
@main struct Main {
1873
static func main() {
74+
75+
// CHECK-OUTPUT: [200, 201, 202]
76+
printArray(Str.staticLet)
77+
78+
// CHECK-OUTPUT: [300, 301, 302]
79+
printArray(Str.staticVar)
80+
81+
// CHECK-OUTPUT: [1, 2]
82+
// CHECK-OUTPUT-NEXT: [3, 4]
83+
// CHECK-OUTPUT-NEXT: [5, 6]
84+
for x in Str.twoDimensional {
85+
printArray(x)
86+
}
87+
88+
// CHECK-OUTPUT-NEXT: 11
89+
print(arrayLookup(1))
90+
91+
// CHECK-OUTPUT-NEXT: [20, 21]
92+
printArray(returnArray())
93+
94+
// CHECK-OUTPUT-NEXT: [20, 27]
95+
// CHECK-OUTPUT-NEXT: [20, 27]
96+
// CHECK-OUTPUT-NEXT: [20, 27]
97+
// CHECK-OUTPUT-NEXT: [20, 27]
98+
// CHECK-OUTPUT-NEXT: [20, 27]
99+
for _ in 0..<5 {
100+
printArray(modifyArray())
101+
}
102+
103+
passArray()
104+
// CHECK-OUTPUT-NEXT: [29]
105+
printArray(gg!)
106+
107+
storeArray()
108+
// CHECK-OUTPUT-NEXT: [227, 228]
109+
printArray(gg!)
110+
19111
for c in stringArray() {
112+
// CHECK-OUTPUT-NEXT: a
113+
// CHECK-OUTPUT-NEXT: b
114+
// CHECK-OUTPUT-NEXT: c
115+
// CHECK-OUTPUT-NEXT: d
20116
print(c)
21-
// CHECK: a
22-
// CHECK: b
23-
// CHECK: c
24-
// CHECK: d
25117
}
26118
}
27119
}
120+
121+
func printArray(_ a: [Int]) {
122+
print("[", terminator: "")
123+
for (i, x) in a.enumerated() {
124+
print(x, terminator: i == a.count - 1 ? "" : ", ")
125+
}
126+
print("]")
127+
}
128+

0 commit comments

Comments
 (0)