Skip to content

Commit ae93e60

Browse files
committed
SIL: add a lazy_property_getter flag to SILFunction
It is set on getter-functions for lazy properties.
1 parent 0be8357 commit ae93e60

File tree

15 files changed

+88
-24
lines changed

15 files changed

+88
-24
lines changed

docs/SIL.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,19 @@ This is currently true if the function is an addressor that was lazily
936936
generated from a global variable access. Note that the initialization
937937
function itself does not need this attribute. It is private and only
938938
called within the addressor.
939+
::
940+
941+
sil-function-purpose ::= 'lazy_getter'
942+
943+
The function is a getter of a lazy property for which the backing storage is
944+
an ``Optional`` of the property's type. The getter contains a top-level
945+
``switch_enum`` (or ``switch_enum_addr``), which tests if the lazy property
946+
is already computed. In the ``None``-case, the property is computed and stored
947+
to the backing storage of the property.
948+
949+
After the first call of a lazy property getter, it is guaranteed that the
950+
property is computed and consecutive calls always execute the ``Some``-case of
951+
the top-level ``switch_enum``.
939952
::
940953

941954
sil-function-attribute ::= '[weak_imported]'

include/swift/SIL/SILFunction.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ class SILFunction
118118
public:
119119
using BlockListType = llvm::iplist<SILBasicBlock>;
120120

121+
// For more information see docs/SIL.rst
122+
enum class Purpose : uint8_t {
123+
None,
124+
GlobalInit,
125+
LazyPropertyGetter
126+
};
127+
121128
private:
122129
friend class SILBasicBlock;
123130
friend class SILModule;
@@ -183,6 +190,8 @@ class SILFunction
183190
/// should use weak linking.
184191
AvailabilityContext Availability;
185192

193+
Purpose specialPurpose = Purpose::None;
194+
186195
/// This is the number of uses of this SILFunction inside the SIL.
187196
/// It does not include references from debug scopes.
188197
unsigned RefCount = 0;
@@ -806,6 +815,8 @@ class SILFunction
806815
void setEffectsKind(EffectsKind E) {
807816
EffectsKindAttr = unsigned(E);
808817
}
818+
819+
Purpose getSpecialPurpose() const { return specialPurpose; }
809820

810821
/// Get this function's global_init attribute.
811822
///
@@ -819,8 +830,13 @@ class SILFunction
819830
/// generated from a global variable access. Note that the initialization
820831
/// function itself does not need this attribute. It is private and only
821832
/// called within the addressor.
822-
bool isGlobalInit() const { return GlobalInitFlag; }
823-
void setGlobalInit(bool isGI) { GlobalInitFlag = isGI; }
833+
bool isGlobalInit() const { return specialPurpose == Purpose::GlobalInit; }
834+
835+
bool isLazyPropertyGetter() const {
836+
return specialPurpose == Purpose::LazyPropertyGetter;
837+
}
838+
839+
void setSpecialPurpose(Purpose purpose) { specialPurpose = purpose; }
824840

825841
/// Return whether this function has a foreign implementation which can
826842
/// be emitted on demand.

lib/ParseSIL/ParseSIL.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ static bool parseDeclSILOptional(bool *isTransparent,
910910
IsExactSelfClass_t *isExactSelfClass,
911911
SILFunction **dynamicallyReplacedFunction,
912912
Identifier *objCReplacementFor,
913-
bool *isGlobalInit,
913+
SILFunction::Purpose *specialPurpose,
914914
Inline_t *inlineStrategy,
915915
OptimizationMode *optimizationMode,
916916
bool *isLet,
@@ -955,8 +955,10 @@ static bool parseDeclSILOptional(bool *isTransparent,
955955
else if (isWithoutActuallyEscapingThunk
956956
&& SP.P.Tok.getText() == "without_actually_escaping")
957957
*isWithoutActuallyEscapingThunk = true;
958-
else if (isGlobalInit && SP.P.Tok.getText() == "global_init")
959-
*isGlobalInit = true;
958+
else if (specialPurpose && SP.P.Tok.getText() == "global_init")
959+
*specialPurpose = SILFunction::Purpose::GlobalInit;
960+
else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter")
961+
*specialPurpose = SILFunction::Purpose::LazyPropertyGetter;
960962
else if (isWeakImported && SP.P.Tok.getText() == "weak_imported") {
961963
if (M.getASTContext().LangOpts.Target.isOSBinFormatCOFF())
962964
SP.P.diagnose(SP.P.Tok, diag::attr_unsupported_on_target,
@@ -5462,7 +5464,8 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
54625464
IsExactSelfClass_t isExactSelfClass = IsNotExactSelfClass;
54635465
bool hasOwnershipSSA = false;
54645466
IsThunk_t isThunk = IsNotThunk;
5465-
bool isGlobalInit = false, isWeakImported = false;
5467+
SILFunction::Purpose specialPurpose = SILFunction::Purpose::None;
5468+
bool isWeakImported = false;
54665469
AvailabilityContext availability = AvailabilityContext::alwaysAvailable();
54675470
bool isWithoutActuallyEscapingThunk = false;
54685471
Inline_t inlineStrategy = InlineDefault;
@@ -5477,8 +5480,9 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
54775480
parseDeclSILOptional(
54785481
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
54795482
&isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction,
5480-
&objCReplacementFor, &isGlobalInit, &inlineStrategy, &optimizationMode, nullptr,
5481-
&isWeakImported, &availability, &isWithoutActuallyEscapingThunk, &Semantics,
5483+
&objCReplacementFor, &specialPurpose, &inlineStrategy,
5484+
&optimizationMode, nullptr, &isWeakImported, &availability,
5485+
&isWithoutActuallyEscapingThunk, &Semantics,
54825486
&SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
54835487
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
54845488
P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) ||
@@ -5512,7 +5516,7 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
55125516
DynamicallyReplacedFunction);
55135517
if (!objCReplacementFor.empty())
55145518
FunctionState.F->setObjCReplacement(objCReplacementFor);
5515-
FunctionState.F->setGlobalInit(isGlobalInit);
5519+
FunctionState.F->setSpecialPurpose(specialPurpose);
55165520
FunctionState.F->setAlwaysWeakImported(isWeakImported);
55175521
FunctionState.F->setAvailabilityForLinkage(availability);
55185522
FunctionState.F->setWithoutActuallyEscapingThunk(

lib/SIL/SILFunctionBuilder.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction(
157157
inlineStrategy, EK);
158158
F->setDebugScope(new (mod) SILDebugScope(loc, F));
159159

160-
F->setGlobalInit(constant.isGlobal());
160+
if (constant.isGlobal())
161+
F->setSpecialPurpose(SILFunction::Purpose::GlobalInit);
162+
161163
if (constant.hasDecl()) {
162164
auto decl = constant.getDecl();
163165

@@ -172,6 +174,12 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction(
172174
// Add attributes for e.g. computed properties.
173175
addFunctionAttributes(F, storage->getAttrs(), mod,
174176
getOrCreateDeclaration);
177+
178+
auto *varDecl = dyn_cast<VarDecl>(storage);
179+
if (varDecl && varDecl->getAttrs().hasAttribute<LazyAttr>() &&
180+
accessor->getAccessorKind() == AccessorKind::Get) {
181+
F->setSpecialPurpose(SILFunction::Purpose::LazyPropertyGetter);
182+
}
175183
}
176184
addFunctionAttributes(F, decl->getAttrs(), mod, getOrCreateDeclaration,
177185
constant);

lib/SIL/SILPrinter.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2444,8 +2444,16 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
24442444
if (isWithoutActuallyEscapingThunk())
24452445
OS << "[without_actually_escaping] ";
24462446

2447-
if (isGlobalInit())
2447+
switch (getSpecialPurpose()) {
2448+
case SILFunction::Purpose::None:
2449+
break;
2450+
case SILFunction::Purpose::GlobalInit:
24482451
OS << "[global_init] ";
2452+
break;
2453+
case SILFunction::Purpose::LazyPropertyGetter:
2454+
OS << "[lazy_getter] ";
2455+
break;
2456+
}
24492457
if (isAlwaysWeakImported())
24502458
OS << "[weak_imported] ";
24512459
auto availability = getAvailabilityForLinkage();

lib/Serialization/DeserializeSIL.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -511,14 +511,14 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
511511
IdentifierID replacedFunctionID;
512512
GenericSignatureID genericSigID;
513513
unsigned rawLinkage, isTransparent, isSerialized, isThunk,
514-
isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
514+
isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy,
515515
optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
516516
isWeakImported, LIST_VER_TUPLE_PIECES(available),
517517
isDynamic, isExactSelfClass;
518518
ArrayRef<uint64_t> SemanticsIDs;
519519
SILFunctionLayout::readRecord(
520520
scratch, rawLinkage, isTransparent, isSerialized, isThunk,
521-
isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
521+
isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy,
522522
optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
523523
isWeakImported, LIST_VER_TUPLE_PIECES(available),
524524
isDynamic, isExactSelfClass,
@@ -630,7 +630,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
630630
fn->setThunk(IsThunk_t(isThunk));
631631
fn->setWithoutActuallyEscapingThunk(bool(isWithoutactuallyEscapingThunk));
632632
fn->setInlineStrategy(Inline_t(inlineStrategy));
633-
fn->setGlobalInit(isGlobal == 1);
633+
fn->setSpecialPurpose(SILFunction::Purpose(specialPurpose));
634634
fn->setEffectsKind(EffectsKind(effect));
635635
fn->setOptimizationMode(OptimizationMode(optimizationMode));
636636
fn->setAlwaysWeakImported(isWeakImported);

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t SWIFTMODULE_VERSION_MINOR = 546; // Avoid conflict with downstream bump
58+
const uint16_t SWIFTMODULE_VERSION_MINOR = 547; // lazyPropertyGetter flag
5959

6060
/// A standard hash seed used for all string hashes in a serialized module.
6161
///

lib/Serialization/SILFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ namespace sil_block {
273273
BCFixed<2>, // serialized
274274
BCFixed<2>, // thunks: signature optimized/reabstraction
275275
BCFixed<1>, // without_actually_escaping
276-
BCFixed<1>, // global_init
276+
BCFixed<3>, // specialPurpose
277277
BCFixed<2>, // inlineStrategy
278278
BCFixed<2>, // optimizationMode
279279
BCFixed<3>, // side effect info.

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) {
434434
Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage),
435435
(unsigned)F.isTransparent(), (unsigned)F.isSerialized(),
436436
(unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(),
437-
(unsigned)F.isGlobalInit(), (unsigned)F.getInlineStrategy(),
437+
(unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(),
438438
(unsigned)F.getOptimizationMode(), (unsigned)F.getEffectsKind(),
439439
(unsigned)numSpecAttrs, (unsigned)F.hasOwnership(),
440440
F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available),

test/SIL/Parser/basic.sil

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,13 @@ bb0:
16511651
return %0 : $()
16521652
}
16531653

1654+
// CHECK-LABEL: sil [lazy_getter] @test_lazy_getter
1655+
sil [lazy_getter] @test_lazy_getter : $@convention(thin) () -> () {
1656+
bb0:
1657+
%0 = tuple ()
1658+
return %0 : $()
1659+
}
1660+
16541661
struct EmptyStruct {}
16551662

16561663
sil @test_empty_destructure : $@convention(thin) () -> () {

0 commit comments

Comments
 (0)