Skip to content

Commit b925ee9

Browse files
authored
Merge pull request #7592 from gottesmm/lvalue_temporaries
2 parents d236577 + 03a926b commit b925ee9

File tree

10 files changed

+189
-32
lines changed

10 files changed

+189
-32
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)