Skip to content

Commit 182bd34

Browse files
committed
[SILInliner] Borrow guaranteed yields.
When inlining a begin_apply, if one of the values is yielded by guaranteed convention, if the yielded value is itself owned, borrow it during inlining. Doing so is necessary because users of the yielded value are expecting a value with guaranteed ownership. For example, it's valid to store_borrow such a value but not an owned value.
1 parent 1f3e159 commit 182bd34

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,20 @@ class BeginApplySite {
162162
auto calleeYields = yield->getYieldedValues();
163163
auto callerYields = BeginApply->getYieldedValues();
164164
assert(calleeYields.size() == callerYields.size());
165+
SmallVector<BeginBorrowInst *, 2> guaranteedYields;
165166
for (auto i : indices(calleeYields)) {
166167
auto remappedYield = getMappedValue(calleeYields[i]);
168+
// When owned values are yielded @guaranteed, the mapped value must be
169+
// borrowed and the result be substituted in place of the originally
170+
// yielded value. Otherwise, there could be uses of the original value
171+
// which require an @guaranteed operand into which we'd be attempting to
172+
// substitute an @owned operand.
173+
if (calleeYields[i]->getOwnershipKind() == OwnershipKind::Owned &&
174+
!yield->getOperandRef(i).isConsuming()) {
175+
auto *bbi = Builder->createBeginBorrow(Loc, remappedYield);
176+
guaranteedYields.push_back(bbi);
177+
remappedYield = bbi;
178+
}
167179
callerYields[i]->replaceAllUsesWith(remappedYield);
168180
}
169181
Builder->createBranch(Loc, returnToBB);
@@ -172,11 +184,17 @@ class BeginApplySite {
172184
if (EndApply) {
173185
SavedInsertionPointRAII savedIP(*Builder, EndApplyBB);
174186
auto resumeBB = remapBlock(yield->getResumeBB());
187+
for (auto *bbi : guaranteedYields) {
188+
Builder->createEndBorrow(EndApply->getLoc(), bbi);
189+
}
175190
Builder->createBranch(EndApply->getLoc(), resumeBB);
176191
}
177192
if (AbortApply) {
178193
SavedInsertionPointRAII savedIP(*Builder, AbortApplyBB);
179194
auto unwindBB = remapBlock(yield->getUnwindBB());
195+
for (auto *bbi : guaranteedYields) {
196+
Builder->createEndBorrow(EndApply->getLoc(), bbi);
197+
}
180198
Builder->createBranch(AbortApply->getLoc(), unwindBB);
181199
}
182200
return true;

test/SILOptimizer/inline_begin_apply.sil

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,23 @@ unwind:
4444
unwind
4545
}
4646

47+
sil [ossa] @getSomeClass : $@convention(thin) () -> @owned SomeClass
48+
49+
sil [transparent] [ossa] @yield_owned_as_guaranteed : $@yield_once @convention(thin) () -> @yields @guaranteed SomeClass {
50+
%getSomeClass = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass
51+
%SomeClass = apply %getSomeClass() : $@convention(thin) () -> @owned SomeClass
52+
yield %SomeClass : $SomeClass, resume bb1, unwind bb2
53+
54+
bb1:
55+
destroy_value %SomeClass : $SomeClass
56+
%retval = tuple ()
57+
return %retval : $()
58+
59+
bb2:
60+
destroy_value %SomeClass : $SomeClass
61+
unwind
62+
}
63+
4764
sil [transparent] [ossa] @test_unreachable : $@yield_once <C: SomeClass> () -> (@yields @in Indirect<C>) {
4865
entry:
4966
unreachable
@@ -555,3 +572,48 @@ bb2:
555572
return %ret : $()
556573
}
557574

575+
576+
// CHECK-LABEL: sil [ossa] @test_store_borrow_owned_as_guaranteed_yield : {{.*}} {
577+
// CHECK: {{bb[0-9]+}}:
578+
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $SomeClass
579+
// CHECK: [[INSTANCE:%[^,]+]] = apply
580+
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
581+
// CHECK: [[BORROW:%[^,]+]] = store_borrow [[LIFETIME]] to [[ADDR]]
582+
// CHECK: yield [[BORROW]] {{.*}}, resume [[BB_RESUME:bb[0-9]+]], unwind [[BB_UNWIND:bb[0-9]+]]
583+
// CHECK: [[BB_RESUME]]:
584+
// CHECK: end_borrow [[BORROW]]
585+
// CHECK: dealloc_stack [[ADDR]]
586+
// CHECK: end_borrow [[LIFETIME]]
587+
// CHECK: destroy_value [[INSTANCE]]
588+
// CHECK: tuple ()
589+
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
590+
// CHECK: return [[RETVAL]]
591+
// CHECK: [[BB_UNWIND]]:
592+
// CHECK: end_borrow [[BORROW]]
593+
// CHECK: dealloc_stack [[ADDR]]
594+
// CHECK: end_borrow [[LIFETIME]]
595+
// CHECK: destroy_value [[INSTANCE]]
596+
// CHECK: unwind
597+
// CHECK-LABEL: } // end sil function 'test_store_borrow_owned_as_guaranteed_yield'
598+
sil [ossa] @test_store_borrow_owned_as_guaranteed_yield : $@yield_once @convention(thin) @substituted <T> () -> @yields @in_guaranteed T for <SomeClass> {
599+
entry:
600+
%addr = alloc_stack $SomeClass
601+
%callee = function_ref @yield_owned_as_guaranteed : $@yield_once @convention(thin) () -> @yields @guaranteed SomeClass
602+
(%instance, %token) = begin_apply %callee() : $@yield_once @convention(thin) () -> @yields @guaranteed SomeClass
603+
%borrow = store_borrow %instance to %addr : $*SomeClass
604+
yield %borrow : $*SomeClass, resume bb_resume, unwind bb_unwind
605+
606+
bb_resume:
607+
end_borrow %borrow : $*SomeClass
608+
dealloc_stack %addr : $*SomeClass
609+
end_apply %token
610+
%retval = tuple ()
611+
return %retval : $()
612+
613+
bb_unwind:
614+
end_borrow %borrow : $*SomeClass
615+
dealloc_stack %addr : $*SomeClass
616+
abort_apply %token
617+
unwind
618+
619+
}

0 commit comments

Comments
 (0)