mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
AllocStackToBox: fix a bug which results in a too early released captured variable
In case of a borrowed `alloc_box`, the optimization didn't look through the `begin_borrow` when calculating the final release of the box. This resulted in inserting the destroy of the inserted `alloc_stack` too early. rdar://97087762
This commit is contained in:
@@ -53,9 +53,9 @@ static llvm::cl::opt<bool> AllocBoxToStackAnalyzeApply(
|
||||
// SIL Utilities for alloc_box Promotion
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static SILValue stripOffCopyValue(SILValue V) {
|
||||
while (auto *CVI = dyn_cast<CopyValueInst>(V)) {
|
||||
V = CVI->getOperand();
|
||||
static SILValue stripOffCopyAndBorrow(SILValue V) {
|
||||
while (isa<CopyValueInst>(V) || isa<BeginBorrowInst>(V)) {
|
||||
V = cast<SingleValueInstruction>(V)->getOperand(0);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ static bool addLastRelease(SILValue V, SILBasicBlock *BB,
|
||||
for (auto I = BB->rbegin(); I != BB->rend(); ++I) {
|
||||
if (isa<StrongReleaseInst>(*I) || isa<DeallocBoxInst>(*I) ||
|
||||
isa<DestroyValueInst>(*I)) {
|
||||
if (stripOffCopyValue(I->getOperand(0)) != V)
|
||||
if (stripOffCopyAndBorrow(I->getOperand(0)) != V)
|
||||
continue;
|
||||
|
||||
Releases.push_back(&*I);
|
||||
|
||||
@@ -469,6 +469,43 @@ bb0(%0 : $Int):
|
||||
unreachable
|
||||
}
|
||||
|
||||
sil [ossa] @closureWithBoxArg : $@convention(thin) (@guaranteed { var SomeClass }) -> () {
|
||||
bb0(%0 : @guaranteed ${ var SomeClass }):
|
||||
%r = tuple ()
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
sil [ossa] @useClosure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
|
||||
bb0(%0 : @guaranteed $@callee_guaranteed () -> ()):
|
||||
%r = tuple ()
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @finalReleaseWithBorrow
|
||||
// CHECK: [[S:%[0-9]+]] = alloc_stack {{.*}}$SomeClass
|
||||
// CHECK-NOT: destroy_addr
|
||||
// CHECK: [[F:%[0-9]+]] = function_ref @useClosure
|
||||
// CHECK: apply [[F]]
|
||||
// CHECK: destroy_addr [[S]]
|
||||
// CHECK: } // end sil function 'finalReleaseWithBorrow'
|
||||
sil [ossa] @finalReleaseWithBorrow : $@convention(thin) (@owned SomeClass) -> () {
|
||||
bb0(%0 : @owned $SomeClass):
|
||||
%1 = alloc_box $ { var SomeClass }
|
||||
%2 = begin_borrow %1 : ${ var SomeClass }
|
||||
%1a = project_box %2 : ${ var SomeClass }, 0
|
||||
store %0 to [init] %1a : $*SomeClass
|
||||
%3 = function_ref @closureWithBoxArg : $@convention(thin) (@guaranteed { var SomeClass }) -> ()
|
||||
%4 = copy_value %2 : ${ var SomeClass }
|
||||
%5 = partial_apply [callee_guaranteed] %3(%4) : $@convention(thin) (@guaranteed { var SomeClass }) -> ()
|
||||
end_borrow %2 : ${ var SomeClass }
|
||||
destroy_value %1 : ${ var SomeClass }
|
||||
%6 = function_ref @useClosure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
|
||||
apply %6(%5) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
|
||||
destroy_value %5 : $@callee_guaranteed () -> ()
|
||||
%10 = tuple ()
|
||||
return %10 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [transparent] [serialized] [ossa] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> ()
|
||||
sil [transparent] [serialized] [ossa] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> () {
|
||||
// CHECK: bb0
|
||||
|
||||
Reference in New Issue
Block a user