Skip to content

Commit f778170

Browse files
authored
Merge pull request #79351 from jckarter/lifetime-dependence-lowering
SIL: Lower lifetime dependencies when lowering function types.
2 parents 2852c59 + c654756 commit f778170

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
@@ -4011,10 +4011,10 @@ namespace {
40114011
/*isImmortal*/ true);
40124012
if (const auto *funDecl = dyn_cast<FuncDecl>(result))
40134013
if (hasUnsafeAPIAttr(decl) && !funDecl->getResultInterfaceType()->isEscapable()) {
4014+
lifetimeDependencies.push_back(immortalLifetime);
40144015
Impl.SwiftContext.evaluator.cacheOutput(
40154016
LifetimeDependenceInfoRequest{result},
40164017
Impl.SwiftContext.AllocateCopy(lifetimeDependencies));
4017-
lifetimeDependencies.push_back(immortalLifetime);
40184018
return;
40194019
}
40204020

lib/Parse/ParseDecl.cpp

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

0 commit comments

Comments
 (0)