Skip to content

Commit 16fffd1

Browse files
committed
Fix MoveOnlyWrappedTypeEliminator handling of store_borrow.
Defer visiting an instruction until its operands have been visited. Otherwise, this pass will crash during ownership verification with invalid operand ownership. Fixes rdar://152879038 ([moveonly] MoveOnlyWrappedTypeEliminator ownership verifier crashes on @_addressableSelf)
1 parent 694aebb commit 16fffd1

File tree

3 files changed

+99
-7
lines changed

3 files changed

+99
-7
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,28 @@ namespace {
6060

6161
struct SILMoveOnlyWrappedTypeEliminatorVisitor
6262
: SILInstructionVisitor<SILMoveOnlyWrappedTypeEliminatorVisitor, bool> {
63+
64+
// Instructions waiting to be visited.
65+
llvm::SmallSetVector<SILInstruction *, 8> &pendingInsts;
66+
llvm::SmallVector<SILInstruction *, 8> deferredInsts;
67+
68+
SILMoveOnlyWrappedTypeEliminatorVisitor(llvm::SmallSetVector<SILInstruction *, 8> &pendingInsts):
69+
pendingInsts(pendingInsts)
70+
{}
71+
72+
// If 'user's operand is not yet visited, push it onto the end of
73+
// 'pendingInsts' and pretend we didn't see it yet. This is only relevant for
74+
// non-address operands in which ownership should be consistent.
75+
bool waitFor(SILInstruction *user, SILValue operand) {
76+
if (auto *def = operand.getDefiningInstruction()) {
77+
if (pendingInsts.contains(def)) {
78+
deferredInsts.push_back(user);
79+
return false;
80+
}
81+
}
82+
return true;
83+
}
84+
6385
bool visitSILInstruction(SILInstruction *inst) {
6486
llvm::errs() << "Unhandled SIL Instruction: " << *inst;
6587
llvm_unreachable("error");
@@ -79,13 +101,19 @@ struct SILMoveOnlyWrappedTypeEliminatorVisitor
79101
}
80102

81103
bool visitStoreInst(StoreInst *si) {
104+
if (!waitFor(si, si->getSrc())) {
105+
return false;
106+
}
82107
if (!si->getSrc()->getType().isTrivial(*si->getFunction()))
83108
return false;
84109
si->setOwnershipQualifier(StoreOwnershipQualifier::Trivial);
85110
return true;
86111
}
87112

88113
bool visitStoreBorrowInst(StoreBorrowInst *si) {
114+
if (!waitFor(si, si->getSrc())) {
115+
return false;
116+
}
89117
if (!si->getSrc()->getType().isTrivial(*si->getFunction()))
90118
return false;
91119
SILBuilderWithScope b(si);
@@ -332,6 +360,9 @@ bool SILMoveOnlyWrappedTypeEliminator::process() {
332360
return true;
333361
};
334362

363+
// (1) Check each value's type for the MoveOnly wrapper, (2) strip the wrapper
364+
// type, and (3) add all uses to 'touchedInsts' in forward order for
365+
// efficiency.
335366
for (auto &bb : *fn) {
336367
for (auto *arg : bb.getArguments()) {
337368
bool relevant = visitValue(arg);
@@ -377,9 +408,18 @@ bool SILMoveOnlyWrappedTypeEliminator::process() {
377408
madeChange = true;
378409
}
379410

380-
SILMoveOnlyWrappedTypeEliminatorVisitor visitor;
381-
while (!touchedInsts.empty()) {
382-
visitor.visit(touchedInsts.pop_back_val());
411+
SILMoveOnlyWrappedTypeEliminatorVisitor visitor{touchedInsts};
412+
while(true) {
413+
while (!touchedInsts.empty()) {
414+
visitor.visit(touchedInsts.pop_back_val());
415+
}
416+
if (visitor.deferredInsts.empty())
417+
break;
418+
419+
for (auto *inst : visitor.deferredInsts) {
420+
touchedInsts.insert(inst);
421+
}
422+
visitor.deferredInsts.clear();
383423
}
384424

385425
return madeChange;

test/SILOptimizer/moveonly_addressors.swift

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -parse-stdlib -module-name Swift -DADDRESS_ONLY -emit-sil -verify %s
2-
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -parse-stdlib -module-name Swift -DLOADABLE -emit-sil -verify %s
3-
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -parse-stdlib -module-name Swift -DTRIVIAL -emit-sil -verify %s
4-
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -parse-stdlib -module-name Swift -DEMPTY -emit-sil -verify %s
1+
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -enable-experimental-feature AddressableParameters -parse-stdlib -module-name Swift -DADDRESS_ONLY -emit-sil -verify %s
2+
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -enable-experimental-feature AddressableParameters -parse-stdlib -module-name Swift -DLOADABLE -emit-sil -verify %s
3+
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -enable-experimental-feature AddressableParameters -parse-stdlib -module-name Swift -DTRIVIAL -emit-sil -verify %s
4+
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -enable-experimental-feature AddressableParameters -parse-stdlib -module-name Swift -DEMPTY -emit-sil -verify %s
55

66
// REQUIRES: swift_feature_BuiltinModule
7+
// REQUIRES: swift_feature_AddressableParameters
78

89
// TODO: Use the real stdlib types once `UnsafePointer` supports noncopyable
910
// types.
@@ -54,6 +55,13 @@ struct S {
5455
unsafeAddress { return makeUpAPointer() }
5556
unsafeMutableAddress { return makeUpAPointer() }
5657
}
58+
59+
var pointer: Builtin.RawPointer {
60+
@_addressableSelf
61+
get {
62+
Builtin.addressOfBorrow(self)
63+
}
64+
}
5765
}
5866

5967
struct SNC: ~Copyable {
@@ -122,3 +130,10 @@ func test(mut_snc snc: inout SNC) {
122130
mod(&snc.mutableData)
123131
take(snc.mutableData) // expected-error{{missing reinitialization of inout parameter 'snc.mutableData' after consume}} expected-note{{consumed here}}
124132
}
133+
134+
// Test calling passing a no-implicit-copy value as an indirect funtion argument. This requires the
135+
// MoveOnlyWrappedTypeEliminator to handle a store_borrow with multiple move-only operands without crashing in the
136+
// verifier with invalid operand ownership.
137+
func testAddressableNoImplicitCopy(s: consuming S) -> Builtin.RawPointer {
138+
s.pointer
139+
}

test/SILOptimizer/moveonly_type_eliminator.sil

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ struct TrivialPair {
2626

2727
sil @use_trivial : $@convention(thin) (Trivial) -> ()
2828

29+
sil @readIndirectTrivial : $@convention(method) (@in_guaranteed Trivial) -> ()
30+
2931
class Klass {
3032
func foo()
3133
}
@@ -674,3 +676,38 @@ bb0(%0 : $@thin Trivial.Type):
674676
%13 = tuple ()
675677
return %13 : $()
676678
}
679+
680+
// Test deferred visitation of a store_borrow until both operands have been visited.
681+
//
682+
// CHECK-LABEL: sil hidden [ossa] @testLoadStoreBorrow : $@convention(thin) (Trivial) -> () {
683+
// CHECK: bb0(%0 : @noImplicitCopy @_eagerMove $Trivial):
684+
// CHECK: [[VAR:%[0-9]+]] = alloc_stack [var_decl] [moveable_value_debuginfo] $Trivial, var, name "c"
685+
// CHECK: store %0 to [trivial] [[VAR]] : $*Trivial
686+
// CHECK: [[ACCESS:%[0-9]+]] = begin_access [read] [static] [[VAR]] : $*Trivial
687+
// CHECK: [[LD:%[0-9]+]] = load [trivial] [[ACCESS]] : $*Trivial
688+
// CHECK: [[ARG:%[0-9]+]] = alloc_stack [moveable_value_debuginfo] $Trivial
689+
// CHECK: store [[LD]] to [trivial] [[ARG]] : $*Trivial
690+
// CHECK-NOT: borrow
691+
// CHECK-LABEL: } // end sil function 'testLoadStoreBorrow'
692+
sil hidden [ossa] @testLoadStoreBorrow : $@convention(thin) (Trivial) -> () {
693+
bb0(%0 : @noImplicitCopy @_eagerMove $Trivial):
694+
%1 = alloc_stack [var_decl] $@moveOnly Trivial, var, name "c", type $@moveOnly Trivial
695+
%2 = moveonlywrapper_to_copyable_addr %1
696+
store %0 to [trivial] %2
697+
%4 = begin_access [read] [static] %1
698+
%5 = load_borrow %4
699+
%6 = alloc_stack $@moveOnly Trivial
700+
// This store_borrow has two move-only operands.
701+
%7 = store_borrow %5 to %6
702+
%8 = function_ref @readIndirectTrivial : $@convention(method) (@in_guaranteed Trivial) -> ()
703+
%9 = moveonlywrapper_to_copyable_addr %7
704+
%10 = apply %8(%9) : $@convention(method) (@in_guaranteed Trivial) -> ()
705+
end_borrow %7
706+
end_borrow %5
707+
end_access %4
708+
dealloc_stack %6
709+
destroy_addr %1
710+
dealloc_stack %1
711+
%99 = tuple ()
712+
return %99 : $()
713+
}

0 commit comments

Comments
 (0)