Skip to content

Commit e4566c8

Browse files
authored
Merge pull request #74768 from meg-gupta/clffix
Fixes to ClosureLifetimeFixup's copy elimination for noncopyable values
2 parents 29a8981 + e71cd4b commit e4566c8

File tree

2 files changed

+39
-18
lines changed

2 files changed

+39
-18
lines changed

lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,18 @@ collectStackClosureLifetimeEnds(SmallVectorImpl<SILInstruction *> &lifetimeEnds,
554554
}
555555
}
556556

557+
static bool lookThroughMarkDependenceChainForValue(MarkDependenceInst *mark,
558+
PartialApplyInst *pai) {
559+
if (mark->getValue() == pai) {
560+
return true;
561+
}
562+
auto *markChain = dyn_cast<MarkDependenceInst>(mark->getValue());
563+
if (!markChain) {
564+
return false;
565+
}
566+
return lookThroughMarkDependenceChainForValue(markChain, pai);
567+
}
568+
557569
/// Rewrite a partial_apply convert_escape_to_noescape sequence with a single
558570
/// apply/try_apply user to a partial_apply [stack] terminated with a
559571
/// dealloc_stack placed after the apply.
@@ -735,7 +747,6 @@ static SILValue tryRewriteToPartialApplyStack(
735747
unsigned appliedArgStartIdx =
736748
newPA->getOrigCalleeType()->getNumParameters() - newPA->getNumArguments();
737749

738-
MarkDependenceInst *markDepChain = nullptr;
739750
for (unsigned i : indices(newPA->getArgumentOperands())) {
740751
auto &arg = newPA->getArgumentOperands()[i];
741752
SILValue copy = arg.get();
@@ -775,6 +786,7 @@ static SILValue tryRewriteToPartialApplyStack(
775786
CopyAddrInst *initialization = nullptr;
776787
MarkDependenceInst *markDep = nullptr;
777788
for (auto *use : stack->getUses()) {
789+
auto *user = use->getUser();
778790
// Since we removed the `dealloc_stack`s from the capture arguments,
779791
// the only uses of this stack slot should be the initialization, the
780792
// partial application, and possibly a mark_dependence from the
@@ -788,31 +800,19 @@ static SILValue tryRewriteToPartialApplyStack(
788800
// %md = mark_dependence %pai on %0
789801
// %md2 = mark_dependence %md on %1
790802
// to tie all of those operands together on the same partial_apply.
791-
//
792-
// FIXME: Should we not be chaining like this and just emit independent
793-
// mark_dependence?
794-
if (markDepChain && mark->getValue() == markDepChain) {
795-
markDep = mark;
796-
markDepChain = mark;
797-
continue;
798-
}
799803

800-
// If we're marking dependence of the current partial_apply on this
801-
// stack slot, that's fine.
802-
if (mark->getValue() != newPA
803-
|| mark->getBase() != stack) {
804+
// Check if we're marking dependence on this stack slot for the current
805+
// partial_apply or it's chain of mark_dependences.
806+
if (!lookThroughMarkDependenceChainForValue(mark, newPA) ||
807+
mark->getBase() != stack) {
804808
LLVM_DEBUG(llvm::dbgs() << "-- had unexpected mark_dependence use\n";
805809
use->getUser()->print(llvm::dbgs());
806810
llvm::dbgs() << "\n");
807-
811+
initialization = nullptr;
808812
break;
809813
}
810814
markDep = mark;
811815

812-
if (!markDepChain) {
813-
markDepChain = mark;
814-
}
815-
816816
continue;
817817
}
818818

@@ -840,7 +840,13 @@ static SILValue tryRewriteToPartialApplyStack(
840840
initialization = possibleInit;
841841
continue;
842842
}
843+
if (isa<DebugValueInst>(user) || isa<DestroyAddrInst>(user) ||
844+
isa<DeallocStackInst>(user)) {
845+
continue;
846+
}
843847
LLVM_DEBUG(llvm::dbgs() << "-- unrecognized use\n");
848+
// Reset initialization on an unrecognized use
849+
initialization = nullptr;
844850
break;
845851
}
846852
if (!initialization) {

test/SILOptimizer/moveonly_closure_lifetime_fixup_address_only_borrowed_captures.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,27 @@ struct E<T>: ~Copyable {
88
var t: T
99
}
1010

11+
struct C<T> {
12+
var t: T
13+
}
14+
1115
var escaper: () -> () = {}
1216

1317
func nonescaping(_ x: () -> ()) { }
1418
func escaping(_ x: @escaping () -> ()) { escaper = x }
1519

1620
func borrow<T>(_: borrowing E<T>) {}
21+
func borrow<T>(_: borrowing C<T>) {}
22+
23+
func testMultiCapture<T>(_ e: borrowing E<T>, _ c: C<T>) {
24+
// CHECK: [[C_STK:%.*]] = alloc_stack $C<T>
25+
// CHECK: copy_addr %1 to [init] [[C_STK]] : $*C<T>
26+
// CHECK: partial_apply {{.*}}[on_stack] {{.*}}([[C_STK]], %0) :
27+
nonescaping {
28+
borrow(c)
29+
borrow(e)
30+
}
31+
}
1732

1833
// CHECK-LABEL: sil {{.*}}16testNeverEscaped
1934
func testNeverEscaped<T>(_ e: borrowing E<T>) {

0 commit comments

Comments
 (0)