Skip to content

Commit 8187aae

Browse files
committed
[Exclusivity] Handle copy_addr+destroy_addr folding with end_access markers.
1 parent f469fb7 commit 8187aae

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

lib/SIL/SILBuilder.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,38 @@ SILBasicBlock *SILBuilder::splitBlockForFallthrough() {
157157
return NewBB;
158158
}
159159

160+
static bool setAccessToDeinit(BeginAccessInst *beginAccess) {
161+
// It's possible that AllocBoxToStack could catch some cases that
162+
// AccessEnforcementSelection does not promote to [static]. Ultimately, this
163+
// should be an assert, but only after we the two passes can be fixes to share
164+
// a common analysis.
165+
if (beginAccess->getEnforcement() == SILAccessEnforcement::Dynamic)
166+
return false;
167+
168+
beginAccess->setAccessKind(SILAccessKind::Deinit);
169+
return true;
170+
}
171+
160172
PointerUnion<CopyAddrInst *, DestroyAddrInst *>
161173
SILBuilder::emitDestroyAddr(SILLocation Loc, SILValue Operand) {
162174
// Check to see if the instruction immediately before the insertion point is a
163175
// copy_addr from the specified operand. If so, we can fold this into the
164176
// copy_addr as a take.
177+
BeginAccessInst *beginAccess = nullptr;
165178
auto I = getInsertionPoint(), BBStart = getInsertionBB()->begin();
166179
while (I != BBStart) {
167180
auto *Inst = &*--I;
168181

169182
if (auto CA = dyn_cast<CopyAddrInst>(Inst)) {
170-
if (CA->getSrc() == Operand && !CA->isTakeOfSrc()) {
171-
CA->setIsTakeOfSrc(IsTake);
172-
return CA;
183+
if (!CA->isTakeOfSrc()) {
184+
if (CA->getSrc() == Operand && !CA->isTakeOfSrc()) {
185+
CA->setIsTakeOfSrc(IsTake);
186+
return CA;
187+
}
188+
if (CA->getSrc() == beginAccess && setAccessToDeinit(beginAccess)) {
189+
CA->setIsTakeOfSrc(IsTake);
190+
return CA;
191+
}
173192
}
174193
}
175194

@@ -178,6 +197,15 @@ SILBuilder::emitDestroyAddr(SILLocation Loc, SILValue Operand) {
178197
if (isa<DeallocStackInst>(Inst))
179198
continue;
180199

200+
// An end_access of the same address may be able to be rewritten as a
201+
// [deinit] access.
202+
if (auto endAccess = dyn_cast<EndAccessInst>(Inst)) {
203+
if (endAccess->getSource() == Operand) {
204+
beginAccess = endAccess->getBeginAccess();
205+
continue;
206+
}
207+
}
208+
181209
// This code doesn't try to prove tricky validity constraints about whether
182210
// it is safe to push the destroy_addr past interesting instructions.
183211
if (Inst->mayHaveSideEffects())

test/SILOptimizer/allocbox_to_stack_ownership.sil

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,3 +1024,38 @@ bb3:
10241024
unreachable
10251025
}
10261026

1027+
// Test that
1028+
// begin_access [read], copy_addr, end_access, destroy_addr
1029+
// is folded into
1030+
// begin_access [deinit], copy_addr [take], end_access
1031+
//
1032+
// CHECK-LABEL: sil @deinit_access : $@convention(thin) <T> (@in T) -> (@out T, @out T) {
1033+
// CHECK: bb0(%0 : @trivial $*T, %1 : @trivial $*T, %2 : @trivial $*T):
1034+
// CHECK: [[STK:%.*]] = alloc_stack $T, var, name "x"
1035+
// CHECK: copy_addr %2 to [initialization] [[STK]] : $*T
1036+
// CHECK: [[READ:%.*]] = begin_access [read] [static] [[STK]] : $*T
1037+
// CHECK: copy_addr [[READ]] to [initialization] %0 : $*T
1038+
// CHECK: end_access [[READ]] : $*T
1039+
// CHECK: [[READ:%.*]] = begin_access [deinit] [static] [[STK]] : $*T
1040+
// CHECK: copy_addr [take] [[READ]] to [initialization] %1 : $*T
1041+
// CHECK: end_access [[READ]] : $*T
1042+
// CHECK: dealloc_stack [[STK]] : $*T
1043+
// CHECK: destroy_addr %2 : $*T
1044+
// CHECK: return %{{.*}} : $()
1045+
// CHECK-LABEL: } // end sil function 'deinit_access'
1046+
sil @deinit_access : $@convention(thin) <T> (@in T) -> (@out T, @out T) {
1047+
bb0(%0 : @owned $*T, %1 : @owned $*T, %2 : @owned $*T):
1048+
%4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>, var, name "x"
1049+
%5 = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
1050+
copy_addr %2 to [initialization] %5 : $*T
1051+
%7 = begin_access [read] [static] %5 : $*T
1052+
copy_addr %7 to [initialization] %0 : $*T
1053+
end_access %7 : $*T
1054+
%10 = begin_access [read] [static] %5 : $*T
1055+
copy_addr %10 to [initialization] %1 : $*T
1056+
end_access %10 : $*T
1057+
destroy_value %4 : $<τ_0_0> { var τ_0_0 } <T>
1058+
destroy_addr %2 : $*T
1059+
%15 = tuple ()
1060+
return %15 : $()
1061+
}

0 commit comments

Comments
 (0)