Skip to content

Commit 1777e9b

Browse files
authored
Merge pull request #67012 from gottesmm/release-5.9-rdar111497657
[5.9][move-only] If we have a guaranteed forwarding instruction with only trivial results, treat it as a liveness use.
2 parents fc0ddf2 + e5d6451 commit 1777e9b

File tree

5 files changed

+179
-12
lines changed

5 files changed

+179
-12
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -369,16 +369,46 @@ bool Implementation::gatherUses(SILValue value) {
369369
continue;
370370
}
371371

372-
case OperandOwnership::GuaranteedForwarding:
373-
// Look through guaranteed forwarding.
372+
case OperandOwnership::GuaranteedForwarding: {
373+
// Look through guaranteed forwarding if we have at least one non-trivial
374+
// value. If we have all non-trivial values, treat this as a liveness use.
375+
SmallVector<SILValue, 8> forwardedValues;
376+
auto *fn = nextUse->getUser()->getFunction();
374377
ForwardingOperand(nextUse).visitForwardedValues([&](SILValue value) {
375-
for (auto *use : value->getUses()) {
376-
useWorklist.push_back(use);
377-
}
378+
if (value->getType().isTrivial(fn))
379+
return true;
380+
forwardedValues.push_back(value);
378381
return true;
379382
});
380-
continue;
381383

384+
if (forwardedValues.empty()) {
385+
auto leafRange =
386+
TypeTreeLeafTypeRange::get(nextUse->get(), getRootValue());
387+
if (!leafRange) {
388+
LLVM_DEBUG(llvm::dbgs() << " Failed to compute leaf range?!\n");
389+
return false;
390+
}
391+
392+
LLVM_DEBUG(llvm::dbgs() << " Found non lifetime ending use!\n");
393+
blocksToUses.insert(nextUse->getParentBlock(),
394+
{nextUse,
395+
{liveness.getNumSubElements(), *leafRange,
396+
false /*is lifetime ending*/}});
397+
liveness.updateForUse(nextUse->getUser(), *leafRange,
398+
false /*is lifetime ending*/);
399+
instToInterestingOperandIndexMap.insert(nextUse->getUser(), nextUse);
400+
continue;
401+
}
402+
403+
// If we had at least one forwarded value that is non-trivial, we need to
404+
// visit those uses.
405+
while (!forwardedValues.empty()) {
406+
for (auto *use : forwardedValues.pop_back_val()->getUses()) {
407+
useWorklist.push_back(use);
408+
}
409+
}
410+
continue;
411+
}
382412
case OperandOwnership::Borrow: {
383413
// Look through borrows.
384414
if (auto *bbi = dyn_cast<BeginBorrowInst>(nextUse->getUser())) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all)
2+
// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all)
3+
4+
enum FixedSizeQueueError : Error {
5+
case outOfSpace
6+
}
7+
8+
struct FixedSizeQueue<T> : ~Copyable {
9+
private var readOffset: Int = 0
10+
private var writeOffset: Int = 0
11+
private var ptr: UnsafeMutableBufferPointer<T>
12+
13+
init(size: Int) {
14+
ptr = UnsafeMutableBufferPointer.allocate(capacity: size)
15+
}
16+
17+
deinit {
18+
ptr.deinitialize().deallocate()
19+
}
20+
21+
mutating func read() -> T? {
22+
if readOffset == writeOffset {
23+
return nil
24+
}
25+
26+
let x = ptr[readOffset]
27+
readOffset = (readOffset + 1) % ptr.count
28+
return x
29+
}
30+
31+
mutating func write(_ element: T) throws {
32+
if ((writeOffset + 1) % ptr.count) == readOffset {
33+
throw FixedSizeQueueError.outOfSpace
34+
}
35+
ptr[writeOffset] = element
36+
writeOffset = (writeOffset + 1) % ptr.count
37+
}
38+
39+
// Drain the queue... returning the value.
40+
consuming func drain() -> UnsafeMutableBufferPointer<T> {
41+
let buffer = self.ptr
42+
discard self
43+
return buffer
44+
}
45+
}
46+
47+
func main() throws {
48+
var x = FixedSizeQueue<Int>(size: 10)
49+
precondition(x.read() == nil)
50+
try x.write(0)
51+
try x.write(9)
52+
try x.write(1)
53+
try x.write(3)
54+
precondition(x.read() == 0)
55+
precondition(x.read() == 9)
56+
precondition(x.read() == 1)
57+
precondition(x.read() == 3)
58+
59+
let d = x.drain()
60+
precondition(d[0] == 0)
61+
precondition(d[1] == 9)
62+
precondition(d[2] == 1)
63+
precondition(d[3] == 3)
64+
}
65+
66+
try main()

test/SILOptimizer/moveonly_addresschecker.sil

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,3 +677,58 @@ bb0:
677677
%21 = tuple ()
678678
return %21 : $()
679679
}
680+
681+
struct FixedSizeQueue : ~Copyable {
682+
var ptr: Builtin.Int32
683+
}
684+
685+
sil @get_fixedsize_queue : $@convention(thin) () -> @owned FixedSizeQueue
686+
687+
// CHECK-LABEL: sil [ossa] @test_return_trivial_type : $@convention(thin) (@owned FixedSizeQueue) -> Builtin.Int32 {
688+
// CHECK: bb0([[ARG:%.*]] : @owned $
689+
// CHECK: [[ALLOC:%.*]] = alloc_stack [lexical] $FixedSizeQueue
690+
// CHECK: store [[ARG]] to [init] [[ALLOC]]
691+
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[ALLOC]]
692+
// CHECK: [[ALLOC2:%.*]] = alloc_stack $FixedSizeQueue
693+
// CHECK: copy_addr [take] [[ACCESS]] to [init] [[ALLOC2]]
694+
// CHECK: [[LOADED:%.*]] = load_borrow [[ALLOC2]]
695+
// CHECK: end_access [[ACCESS]]
696+
// CHECK: [[BORROW:%.*]] = begin_borrow [[LOADED]]
697+
// CHECK: [[TRIVIAL_VALUE:%.*]] = struct_extract [[BORROW]]
698+
// CHECK: end_borrow [[BORROW]]
699+
// CHECK: end_borrow [[LOADED]]
700+
// CHECK: destroy_addr [[ALLOC2]]
701+
// CHECK: dealloc_stack [[ALLOC2]]
702+
// CHECK: [[NEW_VALUE:%.*]] = apply {{%.*}}()
703+
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[ALLOC]]
704+
// CHECK: store [[NEW_VALUE]] to [init] [[ACCESS]]
705+
// CHECK: end_access [[ACCESS]]
706+
// CHECK: destroy_addr [[ALLOC]]
707+
// CHECK: dealloc_stack [[ALLOC]]
708+
// CHECK: return [[TRIVIAL_VALUE]]
709+
// CHECK: } // end sil function 'test_return_trivial_type'
710+
sil [ossa] @test_return_trivial_type : $@convention(thin) (@owned FixedSizeQueue) -> Builtin.Int32 {
711+
bb0(%0 : @owned $FixedSizeQueue):
712+
%1 = alloc_stack [lexical] $FixedSizeQueue, var, name "self", implicit
713+
%2 = mark_must_check [consumable_and_assignable] %1 : $*FixedSizeQueue
714+
store %0 to [init] %2 : $*FixedSizeQueue
715+
%4 = begin_access [modify] [static] %2 : $*FixedSizeQueue
716+
%5 = alloc_stack $FixedSizeQueue
717+
%6 = mark_must_check [consumable_and_assignable] %5 : $*FixedSizeQueue
718+
copy_addr %4 to [init] %6 : $*FixedSizeQueue
719+
%8 = load [take] %6 : $*FixedSizeQueue
720+
end_access %4 : $*FixedSizeQueue
721+
%10 = begin_borrow %8 : $FixedSizeQueue
722+
%11 = struct_extract %10 : $FixedSizeQueue, #FixedSizeQueue.ptr
723+
end_borrow %10 : $FixedSizeQueue
724+
destroy_value %8 : $FixedSizeQueue
725+
dealloc_stack %5 : $*FixedSizeQueue
726+
%21 = function_ref @get_fixedsize_queue : $@convention(thin) () -> @owned FixedSizeQueue
727+
%22 = apply %21() : $@convention(thin) () -> @owned FixedSizeQueue
728+
%23 = begin_access [modify] [static] %2 : $*FixedSizeQueue
729+
store %22 to [assign] %23 : $*FixedSizeQueue
730+
end_access %23 : $*FixedSizeQueue
731+
destroy_addr %2 : $*FixedSizeQueue
732+
dealloc_stack %1 : $*FixedSizeQueue
733+
return %11 : $Builtin.Int32
734+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-emit-sil -O -sil-verify-all -verify -enable-experimental-feature MoveOnlyPartialConsumption -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s
2+
3+
// This file contains tests that used to crash due to verifier errors. It must
4+
// be separate from moveonly_addresschecker_diagnostics since when we fail on
5+
// the diagnostics in that file, we do not actually run the verifier.
6+
7+
struct TestTrivialReturnValue : ~Copyable {
8+
var i: Int = 5
9+
10+
// We used to error on return buffer.
11+
consuming func drain() -> Int {
12+
let buffer = (consume self).i
13+
self = .init(i: 5)
14+
return buffer
15+
}
16+
}

test/SILOptimizer/moveonly_borrow_to_destructure_transform.sil

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,12 @@ bb0(%0 : @owned $MoveOnlyKlass):
147147
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
148148
// CHECK: [[MARKED_ARG:%.*]] = mark_must_check [no_consume_or_assign] [[ARG_COPY]]
149149
// CHECK: [[MARKED_ARG_COPY:%.*]] = copy_value [[MARKED_ARG]]
150-
// CHECK: [[MISC_USE:%.*]] = function_ref @misc_use : $@convention(thin) () -> ()
151-
// CHECK: apply [[MISC_USE]]()
152150
// CHECK: [[BORROW:%.*]] = begin_borrow [[MARKED_ARG_COPY]]
153151
// CHECK: [[EXT:%.*]] = struct_extract [[BORROW]]
154152
// CHECK: end_borrow [[BORROW]]
155-
// CHECK: destroy_value [[MARKED_ARG_COPY]]
153+
// CHECK: [[MISC_USE:%.*]] = function_ref @misc_use : $@convention(thin) () -> ()
154+
// CHECK: apply [[MISC_USE]]()
155+
// CHECK: destroy_value [[MARKED_ARG]]
156156
// CHECK: return [[EXT]]
157157
// CHECK: } // end sil function 'test_return_of_extracted_trivial_type'
158158
sil [ossa] @test_return_of_extracted_trivial_type : $@convention(thin) (@guaranteed SingleIntContainingStruct) -> Builtin.Int32 {
@@ -862,9 +862,9 @@ bbCont:
862862
// CHECK: [[BB_E_SECOND]]([[BBARG:%.*]] : @owned
863863
// CHECK: [[BBARG_BORROW:%.*]] = begin_borrow [[BBARG]]
864864
// CHECK: [[BBARG_BORROW_EXT:%.*]] = struct_extract [[BBARG_BORROW]]
865-
// CHECK: apply {{%.*}}([[BBARG_BORROW_EXT]])
866865
// CHECK: end_borrow [[BBARG_BORROW]]
867866
// CHECK: destroy_value [[BBARG]]
867+
// CHECK: apply {{%.*}}([[BBARG_BORROW_EXT]])
868868
// CHECK: br [[BB_CONT]]
869869
//
870870
// CHECK: [[BB_E_THIRD]]([[BBARG:%.*]] : @owned
@@ -955,9 +955,9 @@ bbCont:
955955
// CHECK: [[BB_E_SECOND]]([[BBARG:%.*]] : @owned
956956
// CHECK: [[BBARG_BORROW:%.*]] = begin_borrow [[BBARG]]
957957
// CHECK: [[BBARG_BORROW_EXT:%.*]] = struct_extract [[BBARG_BORROW]]
958-
// CHECK: apply {{%.*}}([[BBARG_BORROW_EXT]])
959958
// CHECK: end_borrow [[BBARG_BORROW]]
960959
// CHECK: destroy_value [[BBARG]]
960+
// CHECK: apply {{%.*}}([[BBARG_BORROW_EXT]])
961961
// CHECK: br [[BB_CONT]]
962962
//
963963
// CHECK: [[BB_E_THIRD]]([[BBARG:%.*]] : @owned
@@ -1076,4 +1076,4 @@ bb2:
10761076
end_borrow %3 : $KlassPair
10771077
destroy_value %2 : $KlassPair
10781078
unwind
1079-
}
1079+
}

0 commit comments

Comments
 (0)