Skip to content

Commit 24a91bb

Browse files
authored
Merge pull request #80038 from jckarter/addressable-for-deps-lowering
SIL: Lower fields that are conditionally addressable because of a dependency.
2 parents f9e5517 + c949e62 commit 24a91bb

File tree

6 files changed

+101
-27
lines changed

6 files changed

+101
-27
lines changed

include/swift/AST/LifetimeDependence.h

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,25 @@ enum class ParsedLifetimeDependenceKind : uint8_t {
4545
enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope };
4646

4747
struct LifetimeDescriptor {
48+
enum IsAddressable_t {
49+
IsNotAddressable,
50+
IsConditionallyAddressable,
51+
IsAddressable,
52+
};
53+
4854
union Value {
4955
struct {
5056
Identifier name;
5157
} Named;
5258
struct {
5359
unsigned index;
54-
bool isAddress;
60+
IsAddressable_t isAddress;
5561
} Ordered;
5662
struct {
5763
} Self;
5864
Value(Identifier name) : Named({name}) {}
59-
Value(unsigned index, bool isAddress) : Ordered({index, isAddress}) {}
65+
Value(unsigned index, IsAddressable_t isAddress)
66+
: Ordered({index, isAddress}) {}
6067
Value() : Self() {}
6168
} value;
6269

@@ -72,7 +79,7 @@ struct LifetimeDescriptor {
7279
SourceLoc loc)
7380
: value{name}, kind(DescriptorKind::Named),
7481
parsedLifetimeDependenceKind(parsedLifetimeDependenceKind), loc(loc) {}
75-
LifetimeDescriptor(unsigned index, bool isAddress,
82+
LifetimeDescriptor(unsigned index, IsAddressable_t isAddress,
7683
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
7784
SourceLoc loc)
7885
: value{index, isAddress}, kind(DescriptorKind::Ordered),
@@ -93,7 +100,7 @@ struct LifetimeDescriptor {
93100
forOrdered(unsigned index,
94101
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind,
95102
SourceLoc loc,
96-
bool isAddress = false) {
103+
IsAddressable_t isAddress = IsNotAddressable) {
97104
return {index, isAddress, parsedLifetimeDependenceKind, loc};
98105
}
99106
static LifetimeDescriptor
@@ -116,10 +123,10 @@ struct LifetimeDescriptor {
116123
return value.Ordered.index;
117124
}
118125

119-
bool isAddressable() const {
126+
IsAddressable_t isAddressable() const {
120127
return kind == DescriptorKind::Ordered
121128
? value.Ordered.isAddress
122-
: false;
129+
: IsNotAddressable;
123130
}
124131

125132
DescriptorKind getDescriptorKind() const { return kind; }
@@ -216,6 +223,8 @@ class LifetimeDependenceInfo {
216223
IndexSubset *scopeLifetimeParamIndices;
217224
llvm::PointerIntPair<IndexSubset *, 1, bool>
218225
addressableParamIndicesAndImmortal;
226+
IndexSubset *conditionallyAddressableParamIndices;
227+
219228
unsigned targetIndex;
220229

221230
static LifetimeDependenceInfo getForIndex(AbstractFunctionDecl *afd,
@@ -249,16 +258,23 @@ class LifetimeDependenceInfo {
249258
IndexSubset *scopeLifetimeParamIndices,
250259
unsigned targetIndex, bool isImmortal,
251260
// set during SIL type lowering
252-
IndexSubset *addressableParamIndices = nullptr)
261+
IndexSubset *addressableParamIndices = nullptr,
262+
IndexSubset *conditionallyAddressableParamIndices = nullptr)
253263
: inheritLifetimeParamIndices(inheritLifetimeParamIndices),
254264
scopeLifetimeParamIndices(scopeLifetimeParamIndices),
255265
addressableParamIndicesAndImmortal(addressableParamIndices, isImmortal),
266+
conditionallyAddressableParamIndices(conditionallyAddressableParamIndices),
256267
targetIndex(targetIndex) {
257268
assert(this->isImmortal() || inheritLifetimeParamIndices ||
258269
scopeLifetimeParamIndices);
259270
assert(!inheritLifetimeParamIndices ||
260271
!inheritLifetimeParamIndices->isEmpty());
261272
assert(!scopeLifetimeParamIndices || !scopeLifetimeParamIndices->isEmpty());
273+
assert((!conditionallyAddressableParamIndices
274+
|| (addressableParamIndices
275+
&& conditionallyAddressableParamIndices
276+
->isSubsetOf(addressableParamIndices)))
277+
&& "conditionally-addressable params not a subset of addressable params?");
262278
}
263279

264280
operator bool() const { return !empty(); }
@@ -286,9 +302,26 @@ class LifetimeDependenceInfo {
286302

287303
IndexSubset *getScopeIndices() const { return scopeLifetimeParamIndices; }
288304

305+
/// Return the set of parameters which have addressable dependencies.
306+
///
307+
/// This indicates that any dependency on the parameter value is dependent
308+
/// not only on the value, but the memory location of a particular instance
309+
/// of the value.
289310
IndexSubset *getAddressableIndices() const {
290311
return addressableParamIndicesAndImmortal.getPointer();
291312
}
313+
/// Return the set of parameters which may have addressable dependencies
314+
/// depending on the type of the parameter.
315+
///
316+
/// Generic parameters need to be conservatively treated as addressable in
317+
/// situations where the substituted type may end up being addressable-for-
318+
/// dependencies. If substitution at a call site or specialization results
319+
/// in the type becoming concretely non-addressable-for-dependencies,
320+
/// then the lifetime dependency can be considered a normal value
321+
/// dependency.
322+
IndexSubset *getConditionallyAddressableIndices() const {
323+
return conditionallyAddressableParamIndices;
324+
}
292325

293326
bool checkInherit(int index) const {
294327
return inheritLifetimeParamIndices

lib/AST/LifetimeDependence.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ getLifetimeDependenceFor(ArrayRef<LifetimeDependenceInfo> lifetimeDependencies,
5050
std::string LifetimeDependenceInfo::getString() const {
5151
std::string lifetimeDependenceString = "@lifetime(";
5252
auto addressable = getAddressableIndices();
53+
auto condAddressable = getConditionallyAddressableIndices();
5354

5455
auto getSourceString = [&](IndexSubset *bitvector, StringRef kind) {
5556
std::string result;
@@ -61,7 +62,11 @@ std::string LifetimeDependenceInfo::getString() const {
6162
}
6263
result += kind;
6364
if (addressable && addressable->contains(i)) {
64-
result += "address ";
65+
if (condAddressable && condAddressable->contains(i)) {
66+
result += "address_for_deps ";
67+
} else {
68+
result += "address ";
69+
}
6570
}
6671
result += std::to_string(i);
6772
isFirstSetBit = false;
@@ -452,6 +457,7 @@ std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromDependsOn(
452457
SmallBitVector inheritLifetimeParamIndices(capacity);
453458
SmallBitVector scopeLifetimeParamIndices(capacity);
454459
SmallBitVector addressableLifetimeParamIndices(capacity);
460+
SmallBitVector conditionallyAddressableLifetimeParamIndices(capacity);
455461

456462
auto updateLifetimeDependenceInfo = [&](LifetimeDescriptor descriptor,
457463
unsigned paramIndexToSet,
@@ -494,8 +500,16 @@ std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromDependsOn(
494500
if (updateLifetimeDependenceInfo(source, index, paramConvention)) {
495501
return std::nullopt;
496502
}
497-
if (source.isAddressable()) {
503+
switch (source.isAddressable()) {
504+
case LifetimeDescriptor::IsNotAddressable:
505+
break;
506+
case LifetimeDescriptor::IsConditionallyAddressable:
507+
conditionallyAddressableLifetimeParamIndices.set(index);
508+
addressableLifetimeParamIndices.set(index);
509+
break;
510+
case LifetimeDescriptor::IsAddressable:
498511
addressableLifetimeParamIndices.set(index);
512+
break;
499513
}
500514
break;
501515
}
@@ -523,6 +537,9 @@ std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromDependsOn(
523537
/*isImmortal*/ false,
524538
addressableLifetimeParamIndices.any()
525539
? IndexSubset::get(ctx, addressableLifetimeParamIndices)
540+
: nullptr,
541+
conditionallyAddressableLifetimeParamIndices.any()
542+
? IndexSubset::get(ctx, conditionallyAddressableLifetimeParamIndices)
526543
: nullptr);
527544
}
528545

lib/Parse/ParseDecl.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,7 +2524,7 @@ parseLifetimeDescriptor(Parser &P,
25242524
// In SIL, lifetimes explicitly state whether they are dependent on a
25252525
// memory location in addition to the value stored at that location.
25262526
if (P.isInSILMode()
2527-
&& name.str() == "address"
2527+
&& (name.str() == "address" || name.str() == "address_for_deps")
25282528
&& P.Tok.is(tok::integer_literal)) {
25292529
SourceLoc orderedLoc;
25302530
unsigned index;
@@ -2534,7 +2534,9 @@ parseLifetimeDescriptor(Parser &P,
25342534
return std::nullopt;
25352535
}
25362536
return LifetimeDescriptor::forOrdered(index, lifetimeDependenceKind, loc,
2537-
/*addressable*/ true);
2537+
name.str() == "address_for_deps"
2538+
? LifetimeDescriptor::IsConditionallyAddressable
2539+
: LifetimeDescriptor::IsAddressable);
25382540
}
25392541

25402542
return LifetimeDescriptor::forNamed(name, lifetimeDependenceKind, loc);

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,7 @@ class DestructureInputs {
15781578
SmallVectorImpl<SILParameterInfo> &Inputs;
15791579
SmallVectorImpl<int> &ParameterMap;
15801580
SmallBitVector &AddressableLoweredParameters;
1581+
SmallBitVector &ConditionallyAddressableLoweredParameters;
15811582
unsigned NextOrigParamIndex = 0;
15821583

15831584
void addLoweredParameter(SILParameterInfo parameter,
@@ -1593,11 +1594,13 @@ class DestructureInputs {
15931594
std::optional<ActorIsolation> isolationInfo,
15941595
SmallVectorImpl<SILParameterInfo> &inputs,
15951596
SmallVectorImpl<int> &parameterMap,
1596-
SmallBitVector &addressableParams)
1597-
: expansion(expansion), TC(TC), Convs(conventions), Foreign(foreign),
1598-
IsolationInfo(isolationInfo), Inputs(inputs),
1599-
ParameterMap(parameterMap),
1600-
AddressableLoweredParameters(addressableParams)
1597+
SmallBitVector &addressableParams,
1598+
SmallBitVector &conditionallyAddressableParams)
1599+
: expansion(expansion), TC(TC), Convs(conventions), Foreign(foreign),
1600+
IsolationInfo(isolationInfo), Inputs(inputs),
1601+
ParameterMap(parameterMap),
1602+
AddressableLoweredParameters(addressableParams),
1603+
ConditionallyAddressableLoweredParameters(conditionallyAddressableParams)
16011604
{}
16021605

16031606
void destructure(AbstractionPattern origType,
@@ -1768,7 +1771,9 @@ class DestructureInputs {
17681771

17691772
// Any parameters not yet marked addressable shouldn't be.
17701773
assert(AddressableLoweredParameters.size() <= ParameterMap.size());
1774+
assert(ConditionallyAddressableLoweredParameters.size() <= ParameterMap.size());
17711775
AddressableLoweredParameters.resize(ParameterMap.size(), false);
1776+
ConditionallyAddressableLoweredParameters.resize(ParameterMap.size(), false);
17721777
}
17731778

17741779
void visit(AbstractionPattern origType, AnyFunctionType::Param substParam,
@@ -1809,8 +1814,8 @@ class DestructureInputs {
18091814
if (origFlags.isAddressable()) {
18101815
origType = AbstractionPattern::getOpaque();
18111816

1812-
// Remember that this lowered parameter is addressable in the
1813-
// addressable parameters vector.
1817+
// Remember that this lowered parameter is unconditionally addressable in
1818+
// the addressable parameters vector.
18141819
AddressableLoweredParameters.resize(ParameterMap.size() + 1, false);
18151820
AddressableLoweredParameters[ParameterMap.size()] = true;
18161821
} else if (hasScopedDependency) {
@@ -1821,10 +1826,14 @@ class DestructureInputs {
18211826
if (initialSubstTL.getRecursiveProperties().isAddressableForDependencies()) {
18221827
origType = AbstractionPattern::getOpaque();
18231828

1824-
// Remember that this lowered parameter is addressable in the
1825-
// addressable parameters vector.
1829+
// Remember that this lowered parameter is conditionally addressable in
1830+
// the addressable parameters vector.
18261831
AddressableLoweredParameters.resize(ParameterMap.size() + 1, false);
18271832
AddressableLoweredParameters[ParameterMap.size()] = true;
1833+
1834+
ConditionallyAddressableLoweredParameters
1835+
.resize(ParameterMap.size() + 1, false);
1836+
ConditionallyAddressableLoweredParameters[ParameterMap.size()] = true;
18281837
}
18291838
}
18301839

@@ -2565,6 +2574,7 @@ static CanSILFunctionType getSILFunctionType(
25652574
SmallVector<SILParameterInfo, 8> inputs;
25662575
SmallVector<int, 8> parameterMap;
25672576
SmallBitVector addressableParams;
2577+
SmallBitVector conditionallyAddressableParams;
25682578
{
25692579
std::optional<ActorIsolation> actorIsolation;
25702580
if (constant) {
@@ -2587,7 +2597,9 @@ static CanSILFunctionType getSILFunctionType(
25872597
}
25882598
DestructureInputs destructurer(expansionContext, TC, conventions,
25892599
foreignInfo, actorIsolation, inputs,
2590-
parameterMap, addressableParams);
2600+
parameterMap,
2601+
addressableParams,
2602+
conditionallyAddressableParams);
25912603
destructurer.destructure(origType, substFnInterfaceType.getParams(),
25922604
extInfoBuilder, unimplementable);
25932605
}
@@ -2668,11 +2680,19 @@ static CanSILFunctionType getSILFunctionType(
26682680
IndexSubset *addressableSet = addressableDeps.any()
26692681
? IndexSubset::get(TC.Context, addressableDeps)
26702682
: nullptr;
2683+
2684+
SmallBitVector condAddressableDeps = scopeIndicesSet
2685+
? scopeIndicesSet->getBitVector() & conditionallyAddressableParams
2686+
: SmallBitVector(1, false);
2687+
IndexSubset *condAddressableSet = condAddressableDeps.any()
2688+
? IndexSubset::get(TC.Context, condAddressableDeps)
2689+
: nullptr;
26712690

26722691
return LifetimeDependenceInfo(inheritIndicesSet,
26732692
scopeIndicesSet,
26742693
target, /*immortal*/ false,
2675-
addressableSet);
2694+
addressableSet,
2695+
condAddressableSet);
26762696
};
26772697
// Lower parameter dependencies.
26782698
for (unsigned i = 0; i < parameterMap.size(); ++i) {
@@ -2759,10 +2779,12 @@ static CanSILFunctionType getSILFunctionTypeForInitAccessor(
27592779
std::optional<ActorIsolation> actorIsolation; // For now always null.
27602780
SmallVector<int, 8> unusedParameterMap;
27612781
SmallBitVector unusedAddressableParams;
2782+
SmallBitVector unusedConditionalAddressableParams;
27622783
DestructureInputs destructurer(context, TC, conventions, foreignInfo,
27632784
actorIsolation, inputs,
27642785
unusedParameterMap,
2765-
unusedAddressableParams);
2786+
unusedAddressableParams,
2787+
unusedConditionalAddressableParams);
27662788
destructurer.destructure(
27672789
origType, substAccessorType.getParams(),
27682790
extInfoBuilder.withRepresentation(SILFunctionTypeRepresentation::Thin),

test/SIL/lifetime_dependence_generics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public func test(pview: borrowing PView) -> View {
3434
return pview.getDefault()
3535
}
3636

37-
// CHECK-LABEL: sil hidden @$s28lifetime_dependence_generics1PPAAE10getDefault1EQzyF : $@convention(method) <Self where Self : P> (@in_guaranteed Self) -> @lifetime(borrow address 0) @out Self.E {
37+
// CHECK-LABEL: sil hidden @$s28lifetime_dependence_generics1PPAAE10getDefault1EQzyF : $@convention(method) <Self where Self : P> (@in_guaranteed Self) -> @lifetime(borrow address_for_deps 0) @out Self.E {
3838

3939
// CHECK-LABEL: sil hidden @$s28lifetime_dependence_generics5PViewV4getEAA4ViewVyF : $@convention(method) (PView) -> @lifetime(immortal) @owned View {
4040

test/SILGen/lifetime_dependence_lowering.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,21 @@ struct Butt {
9090
@_addressableForDependencies
9191
struct AddressableForDeps {
9292
// CHECK-LABEL: sil{{.*}} @$s{{.*}}6test16{{.*}} : $
93-
// CHECK-SAME: -> @lifetime(borrow address 3) @owned Foo
93+
// CHECK-SAME: -> @lifetime(borrow address_for_deps 3) @owned Foo
9494
@lifetime(borrow self)
9595
func test16(tuple: (AddressableForDeps, AddressableForDeps),
9696
other: AddressableForDeps) -> Foo {}
9797

9898
// The dependency makes the tuple pass as a single indirect argument.
9999
// CHECK-LABEL: sil{{.*}} @$s{{.*}}6test17{{.*}} : $
100-
// CHECK-SAME: -> @lifetime(borrow address 0) @owned Foo
100+
// CHECK-SAME: -> @lifetime(borrow address_for_deps 0) @owned Foo
101101
@lifetime(borrow tuple)
102102
func test17(tuple: (AddressableForDeps, AddressableForDeps),
103103
other: AddressableForDeps) -> Foo {}
104104

105105
// The tuple destructures as usual, but `other` is passed indirectly.
106106
// CHECK-LABEL: sil{{.*}} @$s{{.*}}6test18{{.*}} : $
107-
// CHECK-SAME: -> @lifetime(borrow address 2) @owned Foo
107+
// CHECK-SAME: -> @lifetime(borrow address_for_deps 2) @owned Foo
108108
@lifetime(borrow other)
109109
func test18(tuple: (AddressableForDeps, AddressableForDeps),
110110
other: AddressableForDeps) -> Foo {}

0 commit comments

Comments
 (0)