Skip to content

Commit 30a364d

Browse files
authored
Merge pull request #80031 from meg-gupta/closurelifetimefixup
Fix ClosureLifetimeFixup to insert destroys at leaking blocks
2 parents 25b10eb + c528afc commit 30a364d

File tree

4 files changed

+52
-3
lines changed

4 files changed

+52
-3
lines changed

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,8 @@ SILValue makeValueAvailable(SILValue value, SILBasicBlock *inBlock);
580580
/// use blocks inside a loop relative to \p value. The client must create
581581
/// separate copies for any uses within the loop.
582582
void endLifetimeAtLeakingBlocks(SILValue value,
583-
ArrayRef<SILBasicBlock *> userBBs);
583+
ArrayRef<SILBasicBlock *> userBBs,
584+
DeadEndBlocks *deadEndBlocks = nullptr);
584585

585586
/// Given a forwarding instruction, eliminate it if all of its users are debug
586587
/// instructions and ownership uses.

lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,11 @@ static bool tryExtendLifetimeToLastUse(
10631063
deadEndBlocks->isDeadEnd(builder.getInsertionPoint()->getParent()));
10641064
builder.createDestroyValue(loc, closureCopy, DontPoisonRefs, isDeadEnd);
10651065
});
1066+
1067+
// Closure User may not be post-dominating the previously created copy_value.
1068+
// Create destroy_value at leaking blocks.
1069+
1070+
endLifetimeAtLeakingBlocks(closureCopy, {singleUser->getParent()}, deadEndBlocks);
10661071
/*
10671072
llvm::errs() << "after lifetime extension of\n";
10681073
escapingClosure->dump();

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,7 +1913,8 @@ bool swift::tryEliminateOnlyOwnershipUsedForwardingInst(
19131913
// The consuming use blocks are assumed either not to inside a loop relative to
19141914
// \p value or they must have their own copies.
19151915
void swift::endLifetimeAtLeakingBlocks(SILValue value,
1916-
ArrayRef<SILBasicBlock *> uses) {
1916+
ArrayRef<SILBasicBlock *> uses,
1917+
DeadEndBlocks *deadEndBlocks) {
19171918
if (!value->getFunction()->hasOwnership())
19181919
return;
19191920

@@ -1926,8 +1927,14 @@ void swift::endLifetimeAtLeakingBlocks(SILValue value,
19261927
// Insert a destroy_value in the leaking block
19271928
auto front = postDomBlock->begin();
19281929
SILBuilderWithScope newBuilder(front);
1930+
swift::IsDeadEnd_t isDeadEnd = swift::IsntDeadEnd;
1931+
if (deadEndBlocks) {
1932+
isDeadEnd = IsDeadEnd_t(deadEndBlocks->isDeadEnd(
1933+
newBuilder.getInsertionPoint()->getParent()));
1934+
}
19291935
newBuilder.createDestroyValue(
1930-
RegularLocation::getAutoGeneratedLocation(), value);
1936+
RegularLocation::getAutoGeneratedLocation(), value, DontPoisonRefs,
1937+
isDeadEnd);
19311938
});
19321939
}
19331940

test/SILOptimizer/closure-lifetime-fixup.sil

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,3 +410,39 @@ bb2(%error : @owned $any Error):
410410
destroy_value [dead_end] %nonescaping_nothrower : $@noescape @callee_guaranteed () -> (Int, @error any Error)
411411
unreachable
412412
}
413+
414+
415+
sil @nonthrowing : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> (Int, @error any Error)) -> ()
416+
sil @throwsfn : $@convention(thin) () -> ((), @error any Error)
417+
418+
// Ensure no ownership verification error
419+
// CHECK-LABEL: sil [ossa] @testRethrowing : {{.*}} {
420+
// CHECK: [[NOTHROWER:%[^,]+]] = function_ref @nothrower
421+
// CHECK: [[THICK_NOTHROWER:%[^,]+]] = thin_to_thick_function [[NOTHROWER]]
422+
// CHECK: [[THROWING_NOTHROWER:%[^,]+]] = convert_function [[THICK_NOTHROWER]]
423+
// CHECK: [[NOTHROWER_COPY:%[^,]+]] = copy_value [[THROWING_NOTHROWER]]
424+
// CHECK: {{bb[0-9]+}}
425+
// CHECK: destroy_value [[NOTHROWER_COPY]]
426+
// CHECK: {{bb[0-9]+}}
427+
// CHECK: destroy_value [[NOTHROWER_COPY]]
428+
// CHECK-LABEL: } // end sil function 'testRethrowing'
429+
sil [ossa] @testRethrowing : $@convention(thin) () -> ((), @error any Error) {
430+
bb0:
431+
%nothrower = function_ref @nothrower : $@convention(thin) () -> Int
432+
%thick_nothrower = thin_to_thick_function %nothrower : $@convention(thin) () -> Int to $@callee_guaranteed () -> Int
433+
%throwing_nothrower = convert_function %thick_nothrower : $@callee_guaranteed () -> Int to $@callee_guaranteed () -> (Int, @error any Error)
434+
%nonescaping_nothrower = convert_escape_to_noescape [not_guaranteed] %throwing_nothrower : $@callee_guaranteed () -> (Int, @error any Error) to $@noescape @callee_guaranteed () -> (Int, @error any Error)
435+
%throwsfnref = function_ref @throwsfn : $@convention(thin) () -> ((), @error any Error)
436+
try_apply %throwsfnref() : $@convention(thin) () -> ((), @error any Error), normal bb1, error bb2
437+
438+
bb1(%arg : $()):
439+
%nonthrower = function_ref @nonthrowing : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> (Int, @error any Error)) -> ()
440+
apply %nonthrower(%nonescaping_nothrower) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> (Int, @error any Error)) -> ()
441+
destroy_value %nonescaping_nothrower : $@noescape @callee_guaranteed () -> (Int, @error any Error)
442+
%8 = tuple ()
443+
return %8 : $()
444+
445+
bb2(%error : @owned $any Error):
446+
destroy_value %nonescaping_nothrower : $@noescape @callee_guaranteed () -> (Int, @error any Error)
447+
throw %error
448+
}

0 commit comments

Comments
 (0)