Skip to content

Commit 4009814

Browse files
committed
[IRGen] Lazily emit SIL global variables
Delay the emission of SIL global variables that aren't externally visible until they are actually used. This is the same lazy emission approach that we use for a number of other entities, such as SIL functions. Part of rdar://158363967.
1 parent bee2369 commit 4009814

File tree

8 files changed

+106
-13
lines changed

8 files changed

+106
-13
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,26 @@ static bool isLazilyEmittedFunction(SILFunction &f, SILModule &m) {
11741174
return true;
11751175
}
11761176

1177+
// Eagerly emit global variables that are externally visible.
1178+
static bool isLazilyEmittedGlobalVariable(SILGlobalVariable &v, SILModule &m) {
1179+
// FIXME: Eagerly emit statically-initialized objects due to an issue I
1180+
// have yet to debug.
1181+
if (v.isInitializedObject())
1182+
return false;
1183+
1184+
if (v.isPossiblyUsedExternally()) {
1185+
// Under the embedded linkage model, if it has a non-unique definition,
1186+
// treat it lazily.
1187+
if (v.hasNonUniqueDefinition() && !v.markedAsUsed()) {
1188+
return true;
1189+
}
1190+
1191+
return false;
1192+
}
1193+
1194+
return true;
1195+
}
1196+
11771197
void IRGenerator::emitGlobalTopLevel(
11781198
const std::vector<std::string> &linkerDirectives) {
11791199
if (PrimaryIGM->getSILModule().getOptions().StopOptimizationAfterSerialization) {
@@ -1207,6 +1227,9 @@ void IRGenerator::emitGlobalTopLevel(
12071227
createLinkerDirectiveVariable(*PrimaryIGM, directive);
12081228
}
12091229
for (SILGlobalVariable &v : PrimaryIGM->getSILModule().getSILGlobals()) {
1230+
if (isLazilyEmittedGlobalVariable(v, PrimaryIGM->getSILModule()))
1231+
continue;
1232+
12101233
Decl *decl = v.getDecl();
12111234
CurrentIGMPtr IGM = getGenModule(decl ? decl->getDeclContext() : nullptr);
12121235
IGM->emitSILGlobalVariable(&v);
@@ -1368,6 +1391,7 @@ void IRGenerator::emitLazyDefinitions() {
13681391
!LazyExtensionDescriptors.empty() ||
13691392
!LazyFieldDescriptors.empty() ||
13701393
!LazyFunctionDefinitions.empty() || !LazyWitnessTables.empty() ||
1394+
!LazyGlobalVariables.empty() ||
13711395
!LazyCanonicalSpecializedMetadataAccessors.empty() ||
13721396
!LazyMetadataAccessors.empty() ||
13731397
!LazyClassMetadata.empty() ||
@@ -1456,6 +1480,13 @@ void IRGenerator::emitLazyDefinitions() {
14561480
IGM->emitSILFunction(f);
14571481
}
14581482

1483+
// Emit any lazy global variables we require.
1484+
while (!LazyGlobalVariables.empty()) {
1485+
SILGlobalVariable *v = LazyGlobalVariables.pop_back_val();
1486+
CurrentIGMPtr IGM = getGenModule(v);
1487+
IGM->emitSILGlobalVariable(v);
1488+
}
1489+
14591490
while (!LazyCanonicalSpecializedMetadataAccessors.empty()) {
14601491
CanType theType =
14611492
LazyCanonicalSpecializedMetadataAccessors.pop_back_val();
@@ -1529,6 +1560,26 @@ void IRGenerator::addLazyFunction(SILFunction *f) {
15291560
DefaultIGMForFunction.insert(std::make_pair(f, CurrentIGM));
15301561
}
15311562

1563+
void IRGenerator::addLazyGlobalVariable(SILGlobalVariable *v) {
1564+
// Add it to the queue if it hasn't already been put there.
1565+
if (!LazilyEmittedGlobalVariables.insert(v).second)
1566+
return;
1567+
1568+
assert(!FinishedEmittingLazyDefinitions);
1569+
LazyGlobalVariables.push_back(v);
1570+
1571+
if (auto decl = v->getDecl()) {
1572+
if (decl->getDeclContext()->getParentSourceFile())
1573+
return;
1574+
}
1575+
1576+
if (CurrentIGM == nullptr)
1577+
return;
1578+
1579+
// Don't update the map if we already have an entry.
1580+
DefaultIGMForGlobalVariable.insert(std::make_pair(v, CurrentIGM));
1581+
}
1582+
15321583
bool IRGenerator::hasLazyMetadata(TypeDecl *type) {
15331584
assert(isa<NominalTypeDecl>(type) ||
15341585
isa<OpaqueTypeDecl>(type));
@@ -2714,6 +2765,9 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
27142765
auto alignment =
27152766
Alignment(getClangASTContext().getDeclAlign(clangDecl).getQuantity());
27162767
return Address(addr, ti.getStorageType(), alignment);
2768+
} else if (!forDefinition &&
2769+
isLazilyEmittedGlobalVariable(*var, getSILModule())) {
2770+
IRGen.addLazyGlobalVariable(var);
27172771
}
27182772

27192773
ResilienceExpansion expansion = getResilienceExpansionForLayout(var);

lib/IRGen/IRGenModule.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,6 +2300,22 @@ IRGenModule *IRGenerator::getGenModule(SILFunction *f) {
23002300
return getPrimaryIGM();
23012301
}
23022302

2303+
IRGenModule *IRGenerator::getGenModule(SILGlobalVariable *v) {
2304+
if (GenModules.size() == 1) {
2305+
return getPrimaryIGM();
2306+
}
2307+
2308+
auto found = DefaultIGMForGlobalVariable.find(v);
2309+
if (found != DefaultIGMForGlobalVariable.end())
2310+
return found->second;
2311+
2312+
if (auto decl = v->getDecl()) {
2313+
return getGenModule(decl->getDeclContext());
2314+
}
2315+
2316+
return getPrimaryIGM();
2317+
}
2318+
23032319
uint32_t swift::irgen::getSwiftABIVersion() {
23042320
return IRGenModule::swiftVersion;
23052321
}

lib/IRGen/IRGenModule.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ class IRGenerator {
228228
// It is used if a function has no source-file association.
229229
llvm::DenseMap<SILFunction *, IRGenModule *> DefaultIGMForFunction;
230230

231+
// Stores the IGM from which a global variable is referenced the first time.
232+
// It is used if a global variable has no source-file association.
233+
llvm::DenseMap<SILGlobalVariable *, IRGenModule *> DefaultIGMForGlobalVariable;
234+
231235
// The IGMs where specializations of functions are emitted. The key is the
232236
// non-specialized function.
233237
// Storing all specializations of a function in the same IGM increases the
@@ -327,6 +331,13 @@ class IRGenerator {
327331
/// The queue of SIL functions to emit.
328332
llvm::SmallVector<SILFunction *, 4> LazyFunctionDefinitions;
329333

334+
/// SIL global variables that have already been lazily emitted, or are
335+
/// queued up.
336+
llvm::SmallPtrSet<SILGlobalVariable *, 4> LazilyEmittedGlobalVariables;
337+
338+
/// The queue of SIL global variables to emit.
339+
llvm::SmallVector<SILGlobalVariable *, 4> LazyGlobalVariables;
340+
330341
/// Witness tables that have already been lazily emitted, or are queued up.
331342
llvm::SmallPtrSet<SILWitnessTable *, 4> LazilyEmittedWitnessTables;
332343

@@ -388,6 +399,12 @@ class IRGenerator {
388399
/// first time.
389400
IRGenModule *getGenModule(SILFunction *f);
390401

402+
/// Get an IRGenModule for a global variable.
403+
/// Returns the IRGenModule of the containing source file, or if this cannot
404+
/// be determined, returns the IGM from which the global variable is
405+
/// referenced the first time.
406+
IRGenModule *getGenModule(SILGlobalVariable *v);
407+
391408
/// Returns the primary IRGenModule. This is the first added IRGenModule.
392409
/// It is used for everything which cannot be correlated to a specific source
393410
/// file. And of course, in single-threaded compilation there is only the
@@ -454,6 +471,8 @@ class IRGenerator {
454471

455472
void addLazyFunction(SILFunction *f);
456473

474+
void addLazyGlobalVariable(SILGlobalVariable *v);
475+
457476
void addDynamicReplacement(SILFunction *f) { DynamicReplacements.insert(f); }
458477

459478
void forceLocalEmitOfLazyFunction(SILFunction *f) {

lib/SIL/IR/SILGlobalVariable.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ bool SILGlobalVariable::isPossiblyUsedExternally() const {
8484
if (shouldBePreservedForDebugger())
8585
return true;
8686

87+
if (markedAsUsed())
88+
return true;
89+
8790
SILLinkage linkage = getLinkage();
8891
return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
8992
}

test/IRGen/constant_struct_with_padding.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct T {
1111
}
1212

1313
// CHECK: @global = hidden global %T4main1TV <{ i1 false, [3 x i8] undef, i32 0 }>, align 4
14-
sil_global hidden @global : $T = {
14+
sil_global hidden [used] @global : $T = {
1515
%2 = integer_literal $Builtin.Int1, 0
1616
%3 = integer_literal $Builtin.Int32, 0
1717
%initval = struct $T (%2 : $Builtin.Int1, %3 : $Builtin.Int32)

test/IRGen/global_resilience.sil

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,6 @@ public struct LargeResilientStruct {
3939
// CHECK: @largeGlobal = {{(dllexport )?}}{{(protected )?}}global [[BUFFER]] zeroinitializer
4040
sil_global [let] @largeGlobal : $LargeResilientStruct
4141

42-
//
43-
// Size is known in this resilience domain, and global is hidden,
44-
// so allocate it directly.
45-
//
46-
47-
// CHECK: @fixedGlobal = hidden global %T17global_resilience20LargeResilientStructV zeroinitializer
48-
sil_global hidden @fixedGlobal : $LargeResilientStruct
49-
5042
//
5143
// Unknown size -- must call value witness functions for buffer
5244
// management.
@@ -55,6 +47,14 @@ sil_global hidden @fixedGlobal : $LargeResilientStruct
5547
// CHECK: @otherGlobal = {{(dllexport )?}}{{(protected )?}}global [[BUFFER]] zeroinitializer
5648
sil_global [let] @otherGlobal : $Size
5749

50+
//
51+
// Size is known in this resilience domain, and global is hidden,
52+
// so allocate it directly.
53+
//
54+
55+
// CHECK: @fixedGlobal = hidden global %T17global_resilience20LargeResilientStructV zeroinitializer
56+
sil_global hidden @fixedGlobal : $LargeResilientStruct
57+
5858
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i32 @testSmallGlobal()
5959
sil @testSmallGlobal : $@convention(thin) () -> Int32 {
6060
bb0:

test/embedded/linkage/leaf_application.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121

2222
//--- Library.swift
2323

24-
// TODO: Once global variables can be emitted lazily, these should be -NOT
25-
// again, then show up in the application binary if we use them.
26-
// LIBRARY-IR: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = weak_odr {{(protected |dllexport )?}}global
24+
// Never referenced.
25+
// LIBRARY-IR-NOT: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = weak_odr {{(protected |dllexport )?}}global
26+
27+
// Note: referenced by swift_allocEmptyBox.
2728
// LIBRARY-IR: @"$es16_emptyBoxStorageSi_Sitvp" = weak_odr {{(protected |dllexport )?}}global
2829

2930
// LIBRARY-IR-NOT: define {{.*}}@"$e7Library5helloSaySiGyF"()

test/embedded/modules-globals.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ public func main() {
3333
// CHECK: @"$e4Main022global_in_client_used_c1_D0Sivp" = {{.*}}global %TSi zeroinitializer
3434
// CHECK: @"$e4Main024global_in_client_unused_c1_D0Sivp" = {{.*}}global %TSi zeroinitializer
3535
// CHECK: @"$e8MyModule022global_in_module_used_d1_E0Sivp" = {{.*}}global %TSi zeroinitializer
36-
// CHECK: @"$e8MyModule024global_in_module_unused_d1_E0Sivp" = {{.*}}global %TSi zeroinitializer
36+
// CHECK-NOT: @"$e8MyModule024global_in_module_unused_d1_E0Sivp" = {{.*}}global %TSi zeroinitializer

0 commit comments

Comments
 (0)