Skip to content

Commit c654756

Browse files
committed
SIL: Lower lifetime dependencies when lowering function types.
Map the lifetime dependencies described in terms of the formal AST-level parameters to the correct parameter(s) in the lowered SIL function type. There can be 0, 1, or many SIL parameters per formal parameter because of tuple exploding. Also, record which dependencies are on addressable parameters (meaning that the dependency includes not only the value of the parameter, but its specific memory location).
1 parent 3ce2449 commit c654756

File tree

10 files changed

+381
-57
lines changed

10 files changed

+381
-57
lines changed

include/swift/AST/LifetimeDependence.h

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,12 @@ struct LifetimeDescriptor {
5151
} Named;
5252
struct {
5353
unsigned index;
54+
bool isAddress;
5455
} Ordered;
5556
struct {
5657
} Self;
5758
Value(StringRef name) : Named({name}) {}
58-
Value(unsigned index) : Ordered({index}) {}
59+
Value(unsigned index, bool isAddress) : Ordered({index, isAddress}) {}
5960
Value() : Self() {}
6061
} value;
6162

@@ -71,10 +72,10 @@ struct LifetimeDescriptor {
7172
SourceLoc loc)
7273
: value{name}, kind(DescriptorKind::Named),
7374
parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {}
74-
LifetimeDescriptor(unsigned index,
75+
LifetimeDescriptor(unsigned index, bool isAddress,
7576
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
7677
SourceLoc loc)
77-
: value{index}, kind(DescriptorKind::Ordered),
78+
: value{index, isAddress}, kind(DescriptorKind::Ordered),
7879
parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {}
7980
LifetimeDescriptor(ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
8081
SourceLoc loc)
@@ -91,8 +92,9 @@ struct LifetimeDescriptor {
9192
static LifetimeDescriptor
9293
forOrdered(unsigned index,
9394
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
94-
SourceLoc loc) {
95-
return {index, parsedLifetimeDependenceKind, loc};
95+
SourceLoc loc,
96+
bool isAddress = false) {
97+
return {index, isAddress, parsedLifetimeDependenceKind, loc};
9698
}
9799
static LifetimeDescriptor
98100
forSelf(ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
@@ -113,6 +115,12 @@ struct LifetimeDescriptor {
113115
assert(kind == DescriptorKind::Ordered);
114116
return value.Ordered.index;
115117
}
118+
119+
bool isAddressable() const {
120+
return kind == DescriptorKind::Ordered
121+
? value.Ordered.isAddress
122+
: false;
123+
}
116124

117125
DescriptorKind getDescriptorKind() const { return kind; }
118126

@@ -206,8 +214,9 @@ class LifetimeEntry final
206214
class LifetimeDependenceInfo {
207215
IndexSubset *inheritLifetimeParamIndices;
208216
IndexSubset *scopeLifetimeParamIndices;
217+
llvm::PointerIntPair<IndexSubset *, 1, bool>
218+
addressableParamIndicesAndImmortal;
209219
unsigned targetIndex;
210-
bool immortal;
211220

212221
static LifetimeDependenceInfo getForIndex(AbstractFunctionDecl *afd,
213222
unsigned targetIndex,
@@ -238,11 +247,14 @@ class LifetimeDependenceInfo {
238247
public:
239248
LifetimeDependenceInfo(IndexSubset *inheritLifetimeParamIndices,
240249
IndexSubset *scopeLifetimeParamIndices,
241-
unsigned targetIndex, bool isImmortal)
250+
unsigned targetIndex, bool isImmortal,
251+
// set during SIL type lowering
252+
IndexSubset *addressableParamIndices = nullptr)
242253
: inheritLifetimeParamIndices(inheritLifetimeParamIndices),
243254
scopeLifetimeParamIndices(scopeLifetimeParamIndices),
244-
targetIndex(targetIndex), immortal(isImmortal) {
245-
assert(isImmortal || inheritLifetimeParamIndices ||
255+
addressableParamIndicesAndImmortal(addressableParamIndices, isImmortal),
256+
targetIndex(targetIndex) {
257+
assert(this->isImmortal() || inheritLifetimeParamIndices ||
246258
scopeLifetimeParamIndices);
247259
assert(!inheritLifetimeParamIndices ||
248260
!inheritLifetimeParamIndices->isEmpty());
@@ -252,11 +264,11 @@ class LifetimeDependenceInfo {
252264
operator bool() const { return !empty(); }
253265

254266
bool empty() const {
255-
return !immortal && inheritLifetimeParamIndices == nullptr &&
267+
return !isImmortal() && inheritLifetimeParamIndices == nullptr &&
256268
scopeLifetimeParamIndices == nullptr;
257269
}
258270

259-
bool isImmortal() const { return immortal; }
271+
bool isImmortal() const { return addressableParamIndicesAndImmortal.getInt(); }
260272

261273
unsigned getTargetIndex() const { return targetIndex; }
262274

@@ -266,11 +278,18 @@ class LifetimeDependenceInfo {
266278
bool hasScopeLifetimeParamIndices() const {
267279
return scopeLifetimeParamIndices != nullptr;
268280
}
281+
bool hasAddressableParamIndices() const {
282+
return addressableParamIndicesAndImmortal.getPointer() != nullptr;
283+
}
269284

270285
IndexSubset *getInheritIndices() const { return inheritLifetimeParamIndices; }
271286

272287
IndexSubset *getScopeIndices() const { return scopeLifetimeParamIndices; }
273288

289+
IndexSubset *getAddressableIndices() const {
290+
return addressableParamIndicesAndImmortal.getPointer();
291+
}
292+
274293
bool checkInherit(int index) const {
275294
return inheritLifetimeParamIndices
276295
&& inheritLifetimeParamIndices->contains(index);
@@ -300,15 +319,15 @@ class LifetimeDependenceInfo {
300319
return this->isImmortal() == other.isImmortal() &&
301320
this->getTargetIndex() == other.getTargetIndex() &&
302321
this->getInheritIndices() == other.getInheritIndices() &&
322+
this->getAddressableIndices() == other.getAddressableIndices() &&
303323
this->getScopeIndices() == other.getScopeIndices();
304324
}
305325

306326
bool operator!=(const LifetimeDependenceInfo &other) const {
307-
return this->isImmortal() != other.isImmortal() &&
308-
this->getTargetIndex() != other.getTargetIndex() &&
309-
this->getInheritIndices() != other.getInheritIndices() &&
310-
this->getScopeIndices() != other.getScopeIndices();
327+
return !(*this == other);
311328
}
329+
330+
SWIFT_DEBUG_DUMPER(dump());
312331
};
313332

314333
std::optional<LifetimeDependenceInfo>

lib/AST/LifetimeDependence.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ getLifetimeDependenceFor(ArrayRef<LifetimeDependenceInfo> lifetimeDependencies,
4848

4949
std::string LifetimeDependenceInfo::getString() const {
5050
std::string lifetimeDependenceString = "@lifetime(";
51-
auto getSourceString = [](IndexSubset *bitvector, StringRef kind) {
51+
auto addressable = getAddressableIndices();
52+
53+
auto getSourceString = [&](IndexSubset *bitvector, StringRef kind) {
5254
std::string result;
5355
bool isFirstSetBit = true;
5456
for (unsigned i = 0; i < bitvector->getCapacity(); i++) {
@@ -57,6 +59,9 @@ std::string LifetimeDependenceInfo::getString() const {
5759
result += ", ";
5860
}
5961
result += kind;
62+
if (addressable && addressable->contains(i)) {
63+
result += "address ";
64+
}
6065
result += std::to_string(i);
6166
isFirstSetBit = false;
6267
}
@@ -84,6 +89,8 @@ std::string LifetimeDependenceInfo::getString() const {
8489
}
8590

8691
void LifetimeDependenceInfo::Profile(llvm::FoldingSetNodeID &ID) const {
92+
ID.AddBoolean(addressableParamIndicesAndImmortal.getInt());
93+
ID.AddInteger(targetIndex);
8794
if (inheritLifetimeParamIndices) {
8895
ID.AddInteger((uint8_t)LifetimeDependenceKind::Inherit);
8996
inheritLifetimeParamIndices->Profile(ID);
@@ -92,6 +99,12 @@ void LifetimeDependenceInfo::Profile(llvm::FoldingSetNodeID &ID) const {
9299
ID.AddInteger((uint8_t)LifetimeDependenceKind::Scope);
93100
scopeLifetimeParamIndices->Profile(ID);
94101
}
102+
if (addressableParamIndicesAndImmortal.getPointer()) {
103+
ID.AddBoolean(true);
104+
addressableParamIndicesAndImmortal.getPointer()->Profile(ID);
105+
} else {
106+
ID.AddBoolean(false);
107+
}
95108
}
96109

97110
static LifetimeDependenceKind
@@ -196,6 +209,9 @@ void LifetimeDependenceInfo::getConcatenatedData(
196209
if (hasScopeLifetimeParamIndices()) {
197210
pushData(scopeLifetimeParamIndices);
198211
}
212+
if (hasAddressableParamIndices()) {
213+
pushData(addressableParamIndicesAndImmortal.getPointer());
214+
}
199215
}
200216

201217
static Type getResultOrYield(AbstractFunctionDecl *afd) {
@@ -434,6 +450,7 @@ std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromDependsOn(
434450

435451
SmallBitVector inheritLifetimeParamIndices(capacity);
436452
SmallBitVector scopeLifetimeParamIndices(capacity);
453+
SmallBitVector addressableLifetimeParamIndices(capacity);
437454

438455
auto updateLifetimeDependenceInfo = [&](LifetimeDescriptor descriptor,
439456
unsigned paramIndexToSet,
@@ -476,6 +493,9 @@ std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromDependsOn(
476493
if (updateLifetimeDependenceInfo(source, index, paramConvention)) {
477494
return std::nullopt;
478495
}
496+
if (source.isAddressable()) {
497+
addressableLifetimeParamIndices.set(index);
498+
}
479499
break;
480500
}
481501
case LifetimeDescriptor::DescriptorKind::Named: {
@@ -499,7 +519,10 @@ std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromDependsOn(
499519
? IndexSubset::get(ctx, scopeLifetimeParamIndices)
500520
: nullptr,
501521
targetIndex,
502-
/*isImmortal*/ false);
522+
/*isImmortal*/ false,
523+
addressableLifetimeParamIndices.any()
524+
? IndexSubset::get(ctx, addressableLifetimeParamIndices)
525+
: nullptr);
503526
}
504527

505528
std::optional<LifetimeDependenceInfo>
@@ -745,4 +768,23 @@ LifetimeDependenceInfo::get(FunctionTypeRepr *funcRepr,
745768
return dc->getASTContext().AllocateCopy(lifetimeDependencies);
746769
}
747770

771+
void LifetimeDependenceInfo::dump() const {
772+
llvm::errs() << "target: " << getTargetIndex() << '\n';
773+
if (isImmortal()) {
774+
llvm::errs() << " immortal\n";
775+
}
776+
if (auto scoped = getScopeIndices()) {
777+
llvm::errs() << " scoped: ";
778+
scoped->dump();
779+
}
780+
if (auto inherited = getInheritIndices()) {
781+
llvm::errs() << " inherited: ";
782+
inherited->dump();
783+
}
784+
if (auto addressable = getAddressableIndices()) {
785+
llvm::errs() << " addressable: ";
786+
addressable->dump();
787+
}
788+
}
789+
748790
} // namespace swift

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4009,10 +4009,10 @@ namespace {
40094009
/*isImmortal*/ true);
40104010
if (const auto *funDecl = dyn_cast<FuncDecl>(result))
40114011
if (hasUnsafeAPIAttr(decl) && !funDecl->getResultInterfaceType()->isEscapable()) {
4012+
lifetimeDependencies.push_back(immortalLifetime);
40124013
Impl.SwiftContext.evaluator.cacheOutput(
40134014
LifetimeDependenceInfoRequest{result},
40144015
Impl.SwiftContext.AllocateCopy(lifetimeDependencies));
4015-
lifetimeDependencies.push_back(immortalLifetime);
40164016
return;
40174017
}
40184018

lib/Parse/ParseDecl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2484,6 +2484,23 @@ parseLifetimeDescriptor(Parser &P,
24842484
case tok::identifier: {
24852485
Identifier name;
24862486
auto loc = P.consumeIdentifier(name, /*diagnoseDollarPrefix=*/false);
2487+
2488+
// In SIL, lifetimes explicitly state whether they are dependent on a
2489+
// memory location in addition to the value stored at that location.
2490+
if (P.isInSILMode()
2491+
&& name.str() == "address"
2492+
&& P.Tok.is(tok::integer_literal)) {
2493+
SourceLoc orderedLoc;
2494+
unsigned index;
2495+
2496+
if (P.parseUnsignedInteger(
2497+
index, loc, diag::expected_param_index_lifetime_dependence)) {
2498+
return std::nullopt;
2499+
}
2500+
return LifetimeDescriptor::forOrdered(index, lifetimeDependenceKind, loc,
2501+
/*addressable*/ true);
2502+
}
2503+
24872504
return LifetimeDescriptor::forNamed(name.str(), lifetimeDependenceKind,
24882505
loc);
24892506
}

0 commit comments

Comments
 (0)