Skip to content

Commit 5d53c3f

Browse files
authored
Merge pull request #26898 from gottesmm/pr-ec34aef279bb7b977ac23243588bb03b3f435c62
2 parents cc9672e + e5f1aea commit 5d53c3f

File tree

2 files changed

+114
-6
lines changed

2 files changed

+114
-6
lines changed

lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,11 @@ static bool canHandleOperand(SILValue operand, SmallVectorImpl<SILValue> &out) {
280280
return false;
281281

282282
/// TODO: Add support for begin_borrow, load_borrow.
283-
return all_of(out, [](SILValue v) { return isa<SILFunctionArgument>(v); });
283+
auto canHandleValue = [](SILValue v) -> bool {
284+
return isa<SILFunctionArgument>(v) || isa<LoadBorrowInst>(v) ||
285+
isa<BeginBorrowInst>(v);
286+
};
287+
return all_of(out, canHandleValue);
284288
}
285289

286290
// Eliminate a copy of a borrowed value, if:
@@ -328,6 +332,9 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
328332
// make sure all of them are destroy_value. For our non-destroying
329333
// instructions, make sure that they accept a guaranteed value. After that,
330334
// make sure that our destroys are within the lifetime of our borrowed values.
335+
//
336+
// TODO: Change isConsumed to return branch propagated users for destroys, so
337+
// we do not need to construct another array.
331338
SmallVector<DestroyValueInst *, 16> destroys;
332339
SmallVector<SILInstruction *, 16> guaranteedForwardingInsts;
333340
if (isConsumed(cvi, destroys, &guaranteedForwardingInsts))
@@ -339,11 +346,38 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
339346
// post-dominated by the end_borrow set. If they do not, then the
340347
// copy_value is lifetime extending the guaranteed value, we can not
341348
// eliminate it.
342-
//
343-
// TODO: When we support begin_borrow/load_borrow a linear linfetime
344-
// check will be needed here.
345-
assert(all_of(borrowIntroducers,
346-
[](SILValue v) { return isa<SILFunctionArgument>(v); }));
349+
{
350+
SmallVector<BranchPropagatedUser, 8> destroysForLinearLifetimeCheck(
351+
destroys.begin(), destroys.end());
352+
SmallVector<BranchPropagatedUser, 8> endBorrowInsts;
353+
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
354+
for (SILValue v : borrowIntroducers) {
355+
if (isa<SILFunctionArgument>(v)) {
356+
continue;
357+
}
358+
359+
SWIFT_DEFER {
360+
endBorrowInsts.clear();
361+
visitedBlocks.clear();
362+
};
363+
364+
if (auto *lbi = dyn_cast<LoadBorrowInst>(v)) {
365+
llvm::copy(lbi->getEndBorrows(), std::back_inserter(endBorrowInsts));
366+
} else if (auto *bbi = dyn_cast<BeginBorrowInst>(v)) {
367+
llvm::copy(bbi->getEndBorrows(), std::back_inserter(endBorrowInsts));
368+
} else {
369+
llvm_unreachable("Unhandled borrow introducer?!");
370+
}
371+
372+
// Make sure that our destroys are properly nested within our end
373+
// borrows. Otherwise, we can not optimize.
374+
auto result = valueHasLinearLifetime(
375+
v, endBorrowInsts, destroysForLinearLifetimeCheck, visitedBlocks,
376+
getDeadEndBlocks(), ownership::ErrorBehaviorKind::ReturnFalse);
377+
if (result.getFoundError())
378+
return false;
379+
}
380+
}
347381

348382
// Otherwise, we know that our copy_value/destroy_values are all completely
349383
// within the guaranteed value scope. First delete the destroys/copies.

test/SILOptimizer/semantic-arc-opts.sil

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ import Builtin
1010

1111
sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
1212
sil @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
13+
sil @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject
1314

1415
struct NativeObjectPair {
1516
var obj1 : Builtin.NativeObject
1617
var obj2 : Builtin.NativeObject
1718
}
1819

20+
sil @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
21+
1922
class Klass {}
2023

2124
struct MyInt {
@@ -702,3 +705,74 @@ bb1:
702705
return %9999 : $()
703706
}
704707

708+
// CHECK-LABEL: sil [ossa] @begin_borrow_simple : $@convention(thin) () -> () {
709+
// CHECK-NOT: copy_value
710+
// CHECK: } // end sil function 'begin_borrow_simple'
711+
sil [ossa] @begin_borrow_simple : $@convention(thin) () -> () {
712+
bb0:
713+
%0 = function_ref @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
714+
%1 = apply %0() : $@convention(thin) () -> @owned NativeObjectPair
715+
%2 = begin_borrow %1 : $NativeObjectPair
716+
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
717+
%4 = copy_value %3 : $Builtin.NativeObject
718+
%5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
719+
apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
720+
destroy_value %4 : $Builtin.NativeObject
721+
end_borrow %2 : $NativeObjectPair
722+
destroy_value %1 : $NativeObjectPair
723+
%9999 = tuple()
724+
return %9999 : $()
725+
}
726+
727+
// CHECK-LABEL: sil [ossa] @begin_borrow_fail : $@convention(thin) () -> () {
728+
// CHECK: copy_value
729+
// CHECK: } // end sil function 'begin_borrow_fail'
730+
sil [ossa] @begin_borrow_fail : $@convention(thin) () -> () {
731+
bb0:
732+
%0 = function_ref @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
733+
%1 = apply %0() : $@convention(thin) () -> @owned NativeObjectPair
734+
%2 = begin_borrow %1 : $NativeObjectPair
735+
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
736+
%4 = copy_value %3 : $Builtin.NativeObject
737+
%5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
738+
apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
739+
end_borrow %2 : $NativeObjectPair
740+
destroy_value %4 : $Builtin.NativeObject
741+
destroy_value %1 : $NativeObjectPair
742+
%9999 = tuple()
743+
return %9999 : $()
744+
}
745+
746+
// CHECK-LABEL: sil [ossa] @load_borrow_simple : $@convention(thin) (@in NativeObjectPair) -> () {
747+
// CHECK-NOT: copy_value
748+
// CHECK: } // end sil function 'load_borrow_simple'
749+
sil [ossa] @load_borrow_simple : $@convention(thin) (@in NativeObjectPair) -> () {
750+
bb0(%0 : $*NativeObjectPair):
751+
%2 = load_borrow %0 : $*NativeObjectPair
752+
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
753+
%4 = copy_value %3 : $Builtin.NativeObject
754+
%5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
755+
apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
756+
destroy_value %4 : $Builtin.NativeObject
757+
end_borrow %2 : $NativeObjectPair
758+
destroy_addr %0 : $*NativeObjectPair
759+
%9999 = tuple()
760+
return %9999 : $()
761+
}
762+
763+
// CHECK-LABEL: sil [ossa] @load_borrow_fail : $@convention(thin) (@in NativeObjectPair) -> () {
764+
// CHECK: copy_value
765+
// CHECK: } // end sil function 'load_borrow_fail'
766+
sil [ossa] @load_borrow_fail : $@convention(thin) (@in NativeObjectPair) -> () {
767+
bb0(%0 : $*NativeObjectPair):
768+
%2 = load_borrow %0 : $*NativeObjectPair
769+
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
770+
%4 = copy_value %3 : $Builtin.NativeObject
771+
%5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
772+
apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
773+
end_borrow %2 : $NativeObjectPair
774+
destroy_value %4 : $Builtin.NativeObject
775+
destroy_addr %0 : $*NativeObjectPair
776+
%9999 = tuple()
777+
return %9999 : $()
778+
}

0 commit comments

Comments
 (0)