Skip to content

Commit 68cf0b9

Browse files
authored
Merge pull request #83712 from jckarter/stmt-condition-addressable
Fixes for `@addressable` references to variables in `if` and `guard` conditions
2 parents 4edddf2 + dc043cf commit 68cf0b9

File tree

6 files changed

+136
-149
lines changed

6 files changed

+136
-149
lines changed

lib/SILGen/Cleanup.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ enum class CleanupState {
7474
PersistentlyActive
7575
};
7676

77+
inline bool isActiveCleanupState(CleanupState state) {
78+
return state >= CleanupState::Active;
79+
}
80+
7781
llvm::raw_ostream &operator<<(raw_ostream &os, CleanupState state);
7882

7983
class LLVM_LIBRARY_VISIBILITY Cleanup {
@@ -109,7 +113,7 @@ class LLVM_LIBRARY_VISIBILITY Cleanup {
109113
virtual void setState(SILGenFunction &SGF, CleanupState newState) {
110114
state = newState;
111115
}
112-
bool isActive() const { return state >= CleanupState::Active; }
116+
bool isActive() const { return isActiveCleanupState(state); }
113117
bool isDead() const { return state == CleanupState::Dead; }
114118

115119
virtual void emit(SILGenFunction &SGF, CleanupLocation loc,

lib/SILGen/SILGenDecl.cpp

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "Cleanup.h"
1314
#include "Initialization.h"
1415
#include "LValue.h"
1516
#include "RValue.h"
@@ -682,10 +683,18 @@ namespace {
682683

683684
static void deallocateAddressable(SILGenFunction &SGF,
684685
SILLocation l,
685-
const SILGenFunction::VarLoc::AddressableBuffer::State &state) {
686-
SGF.B.createEndBorrow(l, state.storeBorrow);
686+
const SILGenFunction::AddressableBuffer::State &state,
687+
CleanupState cleanupState) {
688+
// Only delete the value if the variable was active on this path.
689+
// The stack slot exists within the variable scope regardless, so always
690+
// needs to be cleaned up.
691+
bool active = isActiveCleanupState(cleanupState);
692+
if (active) {
693+
SGF.B.createEndBorrow(l, state.storeBorrow);
694+
}
687695
SGF.B.createDeallocStack(l, state.allocStack);
688-
if (state.reabstraction
696+
if (active
697+
&& state.reabstraction
689698
&& !state.reabstraction->getType().isTrivial(SGF.F)) {
690699
SGF.B.createDestroyValue(l, state.reabstraction);
691700
}
@@ -695,28 +704,33 @@ static void deallocateAddressable(SILGenFunction &SGF,
695704
/// binding.
696705
class DeallocateLocalVariableAddressableBuffer : public Cleanup {
697706
ValueDecl *vd;
707+
CleanupHandle destroyVarHandle;
698708
public:
699-
DeallocateLocalVariableAddressableBuffer(ValueDecl *vd) : vd(vd) {}
709+
DeallocateLocalVariableAddressableBuffer(ValueDecl *vd,
710+
CleanupHandle destroyVarHandle)
711+
: vd(vd), destroyVarHandle(destroyVarHandle) {}
700712

701713
void emit(SILGenFunction &SGF, CleanupLocation l,
702714
ForUnwind_t forUnwind) override {
703715
auto addressableBuffer = SGF.getAddressableBufferInfo(vd);
704716
if (!addressableBuffer) {
705717
return;
706718
}
707-
auto found = SGF.VarLocs.find(vd);
708-
if (found == SGF.VarLocs.end()) {
709-
return;
710-
}
711719

720+
// Reflect the state of the variable's original cleanup.
721+
CleanupState cleanupState = CleanupState::Active;
722+
if (destroyVarHandle.isValid()) {
723+
cleanupState = SGF.Cleanups.getCleanup(destroyVarHandle).getState();
724+
}
725+
712726
if (auto *state = addressableBuffer->getState()) {
713-
// The addressable buffer was forced, so clean it up now.
714-
deallocateAddressable(SGF, l, *state);
727+
// The addressable buffer was already forced, so clean up now.
728+
deallocateAddressable(SGF, l, *state, cleanupState);
715729
} else {
716730
// Remember this insert location in case we need to force the addressable
717731
// buffer later.
718732
SILInstruction *marker = SGF.B.createTuple(l, {});
719-
addressableBuffer->cleanupPoints.emplace_back(marker);
733+
addressableBuffer->cleanupPoints.push_back({marker, cleanupState});
720734
}
721735
}
722736

@@ -824,7 +838,7 @@ class LetValueInitialization : public Initialization {
824838

825839
// If the binding has an addressable buffer forced, it should be cleaned
826840
// up at this scope.
827-
SGF.enterLocalVariableAddressableBufferScope(vd);
841+
SGF.enterLocalVariableAddressableBufferScope(vd, DestroyCleanup);
828842
}
829843

830844
~LetValueInitialization() override {
@@ -2241,10 +2255,11 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
22412255
}
22422256

22432257
void
2244-
SILGenFunction::enterLocalVariableAddressableBufferScope(VarDecl *decl) {
2258+
SILGenFunction::enterLocalVariableAddressableBufferScope(VarDecl *decl,
2259+
CleanupHandle destroyCleanup) {
22452260
auto marker = B.createTuple(decl, {});
2246-
AddressableBuffers[decl] = marker;
2247-
Cleanups.pushCleanup<DeallocateLocalVariableAddressableBuffer>(decl);
2261+
AddressableBuffers[decl].insertPoint = marker;
2262+
Cleanups.pushCleanup<DeallocateLocalVariableAddressableBuffer>(decl, destroyCleanup);
22482263
}
22492264

22502265
SILValue
@@ -2296,27 +2311,12 @@ SILGenFunction::getLocalVariableAddressableBuffer(VarDecl *decl,
22962311
SILValue reabstraction, allocStack, storeBorrow;
22972312
{
22982313
SavedInsertionPointRAII save(B);
2299-
SILInstruction *insertPoint = nullptr;
2300-
// Look through bindings that might alias the original addressable buffer
2301-
// (such as case block variables, which use an alias variable to represent the
2302-
// incoming value from all of the case label patterns).
2303-
VarDecl *origDecl = decl;
2304-
do {
2305-
auto bufferIter = AddressableBuffers.find(origDecl);
2306-
ASSERT(bufferIter != AddressableBuffers.end()
2307-
&& "local variable didn't have an addressability scope set");
2308-
2309-
insertPoint = bufferIter->second.getInsertPoint();
2310-
if (insertPoint) {
2311-
break;
2312-
}
2314+
auto *addressableBuffer = getAddressableBufferInfo(decl);
23132315

2314-
origDecl = bufferIter->second.getOriginalForAlias();
2315-
ASSERT(origDecl && "no insert point or alias for addressable declaration!");
2316-
} while (true);
2317-
2318-
assert(insertPoint && "didn't find an insertion point for the addressable buffer");
2319-
B.setInsertionPoint(insertPoint);
2316+
assert(addressableBuffer
2317+
&& addressableBuffer->insertPoint
2318+
&& "didn't find an insertion point for the addressable buffer");
2319+
B.setInsertionPoint(addressableBuffer->insertPoint);
23202320
auto allocStackTy = fullyAbstractedTy;
23212321
if (value->getType().isMoveOnlyWrapped()) {
23222322
allocStackTy = allocStackTy.addingMoveOnlyWrapper();
@@ -2366,18 +2366,19 @@ SILGenFunction::getLocalVariableAddressableBuffer(VarDecl *decl,
23662366
// Record the addressable representation.
23672367
auto *addressableBuffer = getAddressableBufferInfo(decl);
23682368
auto *newState
2369-
= new VarLoc::AddressableBuffer::State(reabstraction, allocStack, storeBorrow);
2369+
= new AddressableBuffer::State(reabstraction, allocStack, storeBorrow);
23702370
addressableBuffer->stateOrAlias = newState;
23712371

23722372
// Emit cleanups on any paths where we previously would have cleaned up
23732373
// the addressable representation if it had been forced earlier.
23742374
decltype(addressableBuffer->cleanupPoints) cleanupPoints;
23752375
cleanupPoints.swap(addressableBuffer->cleanupPoints);
23762376

2377-
for (SILInstruction *cleanupPoint : cleanupPoints) {
2378-
SavedInsertionPointRAII insertCleanup(B, cleanupPoint);
2379-
deallocateAddressable(*this, cleanupPoint->getLoc(), *newState);
2380-
cleanupPoint->eraseFromParent();
2377+
for (auto &cleanupPoint : cleanupPoints) {
2378+
SavedInsertionPointRAII insertCleanup(B, cleanupPoint.inst);
2379+
deallocateAddressable(*this, cleanupPoint.inst->getLoc(), *newState,
2380+
cleanupPoint.state);
2381+
cleanupPoint.inst->eraseFromParent();
23812382
}
23822383

23832384
return storeBorrow;
@@ -2415,9 +2416,12 @@ void BlackHoleInitialization::copyOrInitValueInto(SILGenFunction &SGF, SILLocati
24152416
SGF.B.createIgnoredUse(loc, value.getValue());
24162417
}
24172418

2418-
SILGenFunction::VarLoc::AddressableBuffer::~AddressableBuffer() {
2419-
for (auto cleanupPoint : cleanupPoints) {
2420-
cleanupPoint->eraseFromParent();
2419+
SILGenFunction::AddressableBuffer::~AddressableBuffer() {
2420+
if (insertPoint) {
2421+
insertPoint->eraseFromParent();
2422+
}
2423+
for (auto &cleanupPoint : cleanupPoints) {
2424+
cleanupPoint.inst->eraseFromParent();
24212425
}
24222426
if (auto state = stateOrAlias.dyn_cast<State*>()) {
24232427
delete state;

lib/SILGen/SILGenFunction.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,19 +2005,16 @@ void SILGenFunction::emitAssignOrInit(SILLocation loc, ManagedValue selfValue,
20052005
AssignOrInitInst::Unknown);
20062006
}
20072007

2008-
SILGenFunction::VarLoc::AddressableBuffer *
2008+
SILGenFunction::AddressableBuffer *
20092009
SILGenFunction::getAddressableBufferInfo(ValueDecl *vd) {
20102010
do {
2011-
auto found = VarLocs.find(vd);
2012-
if (found == VarLocs.end()) {
2013-
return nullptr;
2014-
}
2011+
auto &found = AddressableBuffers[vd];
20152012

2016-
if (auto orig = found->second.addressableBuffer.stateOrAlias
2013+
if (auto orig = found.stateOrAlias
20172014
.dyn_cast<VarDecl*>()) {
20182015
vd = orig;
20192016
continue;
20202017
}
2021-
return &found->second.addressableBuffer;
2018+
return &found;
20222019
} while (true);
20232020
}

0 commit comments

Comments
 (0)