Skip to content

Commit 03a926b

Browse files
committed
[silgen] When emitting lvalue gets into temporaries, cleanup the temporaries as early as possible.
Previously, we were emitting these cleanups at the end of the lexical scope instead of at the end of the formal evaluation scope. This change ensures that we always emit the cleanup immediately at the end of the formal evaluation scope. Previously in most cases we got away with this due to the +0 self hack. Basically we would emit a get for a self parameter and then immediately use that self parameter as a guaranteed parameter. Then the hack would insert the destroy value forwarding the lexical scope level cleanup at the same time. rdar://29791263
1 parent 503a2c5 commit 03a926b

File tree

9 files changed

+177
-24
lines changed

9 files changed

+177
-24
lines changed

lib/SILGen/Cleanup.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ void CleanupManager::setCleanupState(Cleanup &cleanup, CleanupState state) {
179179
// Do the transition now to avoid doing it in N places below.
180180
CleanupState oldState = cleanup.getState();
181181
(void)oldState;
182-
cleanup.setState(state);
182+
cleanup.setState(Gen, state);
183183

184184
assert(state != oldState && "trivial cleanup state change");
185185
assert(oldState != CleanupState::Dead && "changing state of dead cleanup");
@@ -201,7 +201,7 @@ void CleanupStateRestorationScope::pushCleanupState(CleanupHandle handle,
201201
"changing state of dead cleanup");
202202

203203
CleanupState oldState = cleanup.getState();
204-
cleanup.setState(newState);
204+
cleanup.setState(Cleanups.Gen, newState);
205205

206206
SavedStates.push_back({handle, oldState});
207207
}
@@ -229,7 +229,7 @@ void CleanupStateRestorationScope::pop() {
229229
Cleanup &cleanup = *iter;
230230
assert(cleanup.getState() != CleanupState::Dead &&
231231
"changing state of dead cleanup");
232-
cleanup.setState(stateToRestore);
232+
cleanup.setState(Cleanups.Gen, stateToRestore);
233233
}
234234
}
235235

lib/SILGen/Cleanup.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class JumpDest;
3333
class SILGenFunction;
3434
class ManagedValue;
3535
class SharedBorrowFormalAccess;
36+
class FormalEvaluationScope;
3637

3738
/// The valid states that a cleanup can be in.
3839
enum class CleanupState {
@@ -56,10 +57,11 @@ llvm::raw_ostream &operator<<(raw_ostream &os, CleanupState state);
5657

5758
class LLVM_LIBRARY_VISIBILITY Cleanup {
5859
unsigned allocatedSize;
59-
CleanupState state;
6060

6161
friend class CleanupManager;
6262
protected:
63+
CleanupState state;
64+
6365
Cleanup() {}
6466
virtual ~Cleanup() {}
6567

@@ -69,7 +71,9 @@ class LLVM_LIBRARY_VISIBILITY Cleanup {
6971
size_t allocated_size() const { return allocatedSize; }
7072

7173
CleanupState getState() const { return state; }
72-
void setState(CleanupState newState) { state = newState; }
74+
virtual void setState(SILGenFunction &gen, CleanupState newState) {
75+
state = newState;
76+
}
7377
bool isActive() const { return state >= CleanupState::Active; }
7478
bool isDead() const { return state == CleanupState::Dead; }
7579

@@ -121,6 +125,7 @@ class LLVM_LIBRARY_VISIBILITY CleanupManager {
121125

122126
friend class CleanupStateRestorationScope;
123127
friend class SharedBorrowFormalEvaluation;
128+
friend class FormalEvaluationScope;
124129

125130
public:
126131
CleanupManager(SILGenFunction &Gen)

lib/SILGen/FormalEvaluation.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,23 @@ void FormalAccess::_anchor() {}
2727
// Shared Borrow Formal Evaluation
2828
//===----------------------------------------------------------------------===//
2929

30-
void SharedBorrowFormalAccess::finish(SILGenFunction &gen) {
30+
void SharedBorrowFormalAccess::finishImpl(SILGenFunction &gen) {
3131
gen.B.createEndBorrow(CleanupLocation::get(loc), borrowedValue,
3232
originalValue);
3333
}
3434

35+
//===----------------------------------------------------------------------===//
36+
// OwnedFormalAccess
37+
//===----------------------------------------------------------------------===//
38+
39+
void OwnedFormalAccess::finishImpl(SILGenFunction &gen) {
40+
auto cleanupLoc = CleanupLocation::get(loc);
41+
if (value->getType().isAddress())
42+
gen.B.createDestroyAddr(cleanupLoc, value);
43+
else
44+
gen.B.emitDestroyValueOperation(cleanupLoc, value);
45+
}
46+
3547
//===----------------------------------------------------------------------===//
3648
// Formal Evaluation Scope
3749
//===----------------------------------------------------------------------===//
@@ -76,7 +88,21 @@ void FormalEvaluationScope::popImpl() {
7688
// Grab the next evaluation...
7789
FormalAccess &access = *iter;
7890

79-
// and deactivate the cleanup.
91+
// If this access was already finished, continue. This can happen if an
92+
// owned formal access was forwarded.
93+
if (access.isFinished()) {
94+
assert(access.getKind() == FormalAccess::Owned &&
95+
"Only owned formal accesses should be forwarded.");
96+
// We can not check that our cleanup is actually dead since the cleanup
97+
// may have been popped at this point and the stack may have new values.
98+
continue;
99+
}
100+
101+
assert(!access.isFinished() && "Can not finish a formal access cleanup "
102+
"twice");
103+
104+
// and deactivate the cleanup. This will set the isFinished bit for owned
105+
// FormalAccess.
80106
gen.Cleanups.setCleanupState(access.getCleanup(), CleanupState::Dead);
81107

82108
// Attempt to diagnose problems where obvious aliasing introduces illegal
@@ -112,3 +138,14 @@ void FormalEvaluationScope::popImpl() {
112138
// And then pop off all stack elements until we reach the savedDepth.
113139
context.pop(savedDepth.getValue());
114140
}
141+
142+
//===----------------------------------------------------------------------===//
143+
// Formal Evaluation Context
144+
//===----------------------------------------------------------------------===//
145+
146+
void FormalEvaluationContext::dump(SILGenFunction &gen) {
147+
for (auto II = begin(), IE = end(); II != IE; ++II) {
148+
FormalAccess &access = *II;
149+
gen.Cleanups.dump(access.getCleanup());
150+
}
151+
}

lib/SILGen/FormalEvaluation.h

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class LogicalPathComponent;
2626

2727
class FormalAccess {
2828
public:
29-
enum Kind { Shared, Exclusive };
29+
enum Kind { Shared, Exclusive, Owned };
3030

3131
private:
3232
unsigned allocatedSize;
@@ -35,10 +35,12 @@ class FormalAccess {
3535
protected:
3636
SILLocation loc;
3737
CleanupHandle cleanup;
38+
bool finished;
3839

3940
FormalAccess(unsigned allocatedSize, Kind kind, SILLocation loc,
4041
CleanupHandle cleanup)
41-
: allocatedSize(allocatedSize), kind(kind), loc(loc), cleanup(cleanup) {}
42+
: allocatedSize(allocatedSize), kind(kind), loc(loc), cleanup(cleanup),
43+
finished(false) {}
4244

4345
public:
4446
virtual ~FormalAccess() {}
@@ -57,7 +59,14 @@ class FormalAccess {
5759

5860
Kind getKind() const { return kind; }
5961

60-
virtual void finish(SILGenFunction &gen) = 0;
62+
void finish(SILGenFunction &gen) { finishImpl(gen); }
63+
64+
void setFinished() { finished = true; }
65+
66+
bool isFinished() const { return finished; }
67+
68+
protected:
69+
virtual void finishImpl(SILGenFunction &gen) = 0;
6170
};
6271

6372
class SharedBorrowFormalAccess : public FormalAccess {
@@ -69,10 +78,26 @@ class SharedBorrowFormalAccess : public FormalAccess {
6978
SILValue originalValue, SILValue borrowedValue)
7079
: FormalAccess(sizeof(*this), FormalAccess::Shared, loc, cleanup),
7180
originalValue(originalValue), borrowedValue(borrowedValue) {}
72-
void finish(SILGenFunction &gen) override;
7381

7482
SILValue getBorrowedValue() const { return borrowedValue; }
7583
SILValue getOriginalValue() const { return originalValue; }
84+
85+
private:
86+
void finishImpl(SILGenFunction &gen) override;
87+
};
88+
89+
class OwnedFormalAccess : public FormalAccess {
90+
SILValue value;
91+
92+
public:
93+
OwnedFormalAccess(SILLocation loc, CleanupHandle cleanup, SILValue value)
94+
: FormalAccess(sizeof(*this), FormalAccess::Owned, loc, cleanup),
95+
value(value) {}
96+
97+
SILValue getValue() const { return value; }
98+
99+
private:
100+
void finishImpl(SILGenFunction &gen) override;
76101
};
77102

78103
class FormalEvaluationContext {
@@ -113,6 +138,8 @@ class FormalEvaluationContext {
113138
/// Pop objects off of the stack until \p the object pointed to by stable_iter
114139
/// is the top element of the stack.
115140
void pop(stable_iterator stable_iter) { stack.pop(stable_iter); }
141+
142+
void dump(SILGenFunction &gen);
116143
};
117144

118145
class FormalEvaluationScope {

lib/SILGen/LValue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ struct LLVM_LIBRARY_VISIBILITY ExclusiveBorrowFormalAccess : FormalAccess {
508508
component->writeback(gen, loc, base, materialized, isFinal);
509509
}
510510

511-
void finish(SILGenFunction &gen) override {
511+
void finishImpl(SILGenFunction &gen) override {
512512
performWriteback(gen, /*isFinal*/ true);
513513
}
514514
};

lib/SILGen/SILGenDecl.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,16 @@ SILGenFunction::emitTemporary(SILLocation loc, const TypeLowering &tempTL) {
13531353
return useBufferAsTemporary(addr, tempTL);
13541354
}
13551355

1356+
std::unique_ptr<TemporaryInitialization>
1357+
SILGenFunction::emitFormalAccessTemporary(SILLocation loc,
1358+
const TypeLowering &tempTL) {
1359+
SILValue addr = emitTemporaryAllocation(loc, tempTL.getLoweredType());
1360+
CleanupHandle cleanup =
1361+
enterDormantFormalAccessTemporaryCleanup(addr, loc, tempTL);
1362+
return std::unique_ptr<TemporaryInitialization>(
1363+
new TemporaryInitialization(addr, cleanup));
1364+
}
1365+
13561366
/// Create an Initialization for an uninitialized buffer.
13571367
std::unique_ptr<TemporaryInitialization>
13581368
SILGenFunction::useBufferAsTemporary(SILValue addr,
@@ -1372,6 +1382,59 @@ SILGenFunction::enterDormantTemporaryCleanup(SILValue addr,
13721382
return Cleanups.getCleanupsDepth();
13731383
}
13741384

1385+
namespace {
1386+
1387+
struct FormalAccessReleaseValueCleanup : Cleanup {
1388+
FormalEvaluationContext::stable_iterator Depth;
1389+
1390+
FormalAccessReleaseValueCleanup() : Depth() {}
1391+
1392+
void setState(SILGenFunction &gen, CleanupState newState) override {
1393+
if (newState == CleanupState::Dead) {
1394+
getEvaluation(gen).setFinished();
1395+
}
1396+
1397+
state = newState;
1398+
}
1399+
1400+
void emit(SILGenFunction &gen, CleanupLocation l) override {
1401+
getEvaluation(gen).finish(gen);
1402+
}
1403+
1404+
void dump(SILGenFunction &gen) const override {
1405+
#ifndef NDEBUG
1406+
llvm::errs() << "FormalAccessReleaseValueCleanup "
1407+
<< "State:" << getState() << "\n"
1408+
<< "Value:" << getValue(gen) << "\n";
1409+
#endif
1410+
}
1411+
1412+
OwnedFormalAccess &getEvaluation(SILGenFunction &gen) const {
1413+
auto &evaluation = *gen.FormalEvalContext.find(Depth);
1414+
assert(evaluation.getKind() == FormalAccess::Owned);
1415+
return static_cast<OwnedFormalAccess &>(evaluation);
1416+
}
1417+
1418+
SILValue getValue(SILGenFunction &gen) const {
1419+
return getEvaluation(gen).getValue();
1420+
}
1421+
};
1422+
1423+
} // end anonymous namespace
1424+
1425+
CleanupHandle SILGenFunction::enterDormantFormalAccessTemporaryCleanup(
1426+
SILValue addr, SILLocation loc, const TypeLowering &tempTL) {
1427+
if (tempTL.isTrivial())
1428+
return CleanupHandle::invalid();
1429+
1430+
auto &cleanup = Cleanups.pushCleanup<FormalAccessReleaseValueCleanup>();
1431+
CleanupHandle handle = Cleanups.getTopCleanup();
1432+
Cleanups.setCleanupState(handle, CleanupState::Dormant);
1433+
FormalEvalContext.push<OwnedFormalAccess>(loc, handle, addr);
1434+
cleanup.Depth = FormalEvalContext.stable_begin();
1435+
return handle;
1436+
}
1437+
13751438
void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
13761439
assert(vd->getDeclContext()->isLocalContext() &&
13771440
"can't emit a local var for a non-local var decl");

lib/SILGen/SILGenFunction.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,6 +1533,14 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
15331533
std::unique_ptr<TemporaryInitialization>
15341534
emitTemporary(SILLocation loc, const TypeLowering &tempTL);
15351535

1536+
/// Emit the allocation for a local temporary, provides an
1537+
/// Initialization that can be used to initialize it, and registers
1538+
/// cleanups in the current active formal evaluation scope.
1539+
///
1540+
/// The initialization is guaranteed to be a single buffer.
1541+
std::unique_ptr<TemporaryInitialization>
1542+
emitFormalAccessTemporary(SILLocation loc, const TypeLowering &tempTL);
1543+
15361544
/// Provides an Initialization that can be used to initialize an already-
15371545
/// allocated temporary, and registers cleanups in the active scope.
15381546
///
@@ -1545,6 +1553,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
15451553
CleanupHandle enterDormantTemporaryCleanup(SILValue temp,
15461554
const TypeLowering &tempTL);
15471555

1556+
/// Enter a currently-dormant cleanup to destroy the value in the
1557+
/// given address.
1558+
CleanupHandle
1559+
enterDormantFormalAccessTemporaryCleanup(SILValue temp, SILLocation loc,
1560+
const TypeLowering &tempTL);
1561+
15481562
/// Destroy and deallocate an initialized local variable.
15491563
void destroyLocalVariable(SILLocation L, VarDecl *D);
15501564

lib/SILGen/SILGenLValue.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenLValue
150150
AccessKind accessKind);
151151
};
152152

153-
static ManagedValue emitGetIntoTemporary(SILGenFunction &gen,
154-
SILLocation loc,
155-
ManagedValue base,
156-
LogicalPathComponent &&component) {
157-
// Create a temporary.
158-
auto temporaryInit =
159-
gen.emitTemporary(loc, gen.getTypeLowering(component.getTypeOfRValue()));
160-
153+
static ManagedValue
154+
emitGetIntoTemporary(SILGenFunction &gen, SILLocation loc, ManagedValue base,
155+
std::unique_ptr<TemporaryInitialization> &&temporaryInit,
156+
LogicalPathComponent &&component) {
161157
// Emit a 'get' into the temporary.
162158
RValue value =
163159
std::move(component).get(gen, loc, base, SGFContext(temporaryInit.get()));
@@ -177,7 +173,12 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &gen,
177173
// If this is just for a read, emit a load into a temporary memory
178174
// location.
179175
if (kind == AccessKind::Read) {
180-
return emitGetIntoTemporary(gen, loc, base, std::move(*this));
176+
// Create a temporary.
177+
std::unique_ptr<TemporaryInitialization> temporaryInit =
178+
gen.emitFormalAccessTemporary(loc,
179+
gen.getTypeLowering(getTypeOfRValue()));
180+
return emitGetIntoTemporary(gen, loc, base, std::move(temporaryInit),
181+
std::move(*this));
181182
}
182183

183184
assert(gen.InWritebackScope &&
@@ -189,6 +190,11 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &gen,
189190

190191
ManagedValue temporary;
191192
{
193+
// Create a temporary.
194+
std::unique_ptr<TemporaryInitialization> temporaryInit =
195+
gen.emitFormalAccessTemporary(loc,
196+
gen.getTypeLowering(getTypeOfRValue()));
197+
192198
FormalEvaluationScope Scope(gen);
193199

194200
// Otherwise, we need to emit a get and set. Borrow the base for
@@ -197,7 +203,8 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &gen,
197203
base ? base.formalEvaluationBorrow(gen, loc) : ManagedValue();
198204

199205
// Emit a 'get' into a temporary and then pop the borrow of base.
200-
temporary = emitGetIntoTemporary(gen, loc, getterBase, std::move(*this));
206+
temporary = emitGetIntoTemporary(
207+
gen, loc, getterBase, std::move(temporaryInit), std::move(*this));
201208
}
202209

203210
// Push a writeback for the temporary.

0 commit comments

Comments
 (0)