Skip to content

Commit b7d00b0

Browse files
committed
[sil-ownershipoptutils] Move some helper methods to their own file section from replaceAllUsesAndErase's section before adding replaceSingleUse.
Both APIs may use these APIs so it makes sense to move them to their own section.
1 parent 29806a3 commit b7d00b0

File tree

1 file changed

+165
-164
lines changed

1 file changed

+165
-164
lines changed

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 165 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,132 @@
3232

3333
using namespace swift;
3434

35+
//===----------------------------------------------------------------------===//
36+
// Utility Helper Functions
37+
//===----------------------------------------------------------------------===//
38+
39+
static void cleanupOperandsBeforeDeletion(SILInstruction *oldValue,
40+
InstModCallbacks &callbacks) {
41+
SILBuilderWithScope builder(oldValue);
42+
for (auto &op : oldValue->getAllOperands()) {
43+
if (!op.isLifetimeEnding()) {
44+
continue;
45+
}
46+
47+
switch (op.get().getOwnershipKind()) {
48+
case OwnershipKind::Any:
49+
llvm_unreachable("Invalid ownership for value");
50+
case OwnershipKind::Owned: {
51+
auto *dvi = builder.createDestroyValue(oldValue->getLoc(), op.get());
52+
callbacks.createdNewInst(dvi);
53+
continue;
54+
}
55+
case OwnershipKind::Guaranteed: {
56+
// Should only happen once we model destructures as true reborrows.
57+
auto *ebi = builder.createEndBorrow(oldValue->getLoc(), op.get());
58+
callbacks.createdNewInst(ebi);
59+
continue;
60+
}
61+
case OwnershipKind::None:
62+
continue;
63+
case OwnershipKind::Unowned:
64+
llvm_unreachable("Unowned object can never be consumed?!");
65+
}
66+
llvm_unreachable("Covered switch isn't covered");
67+
}
68+
}
69+
70+
static SILPhiArgument *
71+
insertOwnedBaseValueAlongBranchEdge(BranchInst *bi, SILValue innerCopy,
72+
InstModCallbacks &callbacks) {
73+
auto *destBB = bi->getDestBB();
74+
// We need to create the phi argument before calling addNewEdgeValueToBranch
75+
// since it checks that the destination block has enough arguments for the
76+
// argument.
77+
auto *phiArg =
78+
destBB->createPhiArgument(innerCopy->getType(), OwnershipKind::Owned);
79+
addNewEdgeValueToBranch(bi, destBB, innerCopy, callbacks);
80+
81+
// Grab our predecessor blocks, ignoring us, add to the branch edge an
82+
// undef corresponding to our value.
83+
//
84+
// We gather all predecessor blocks in a separate array to avoid
85+
// iterator invalidation issues as we mess with terminators.
86+
SmallVector<SILBasicBlock *, 8> predecessorBlocks(
87+
destBB->getPredecessorBlocks());
88+
89+
for (auto *predBlock : predecessorBlocks) {
90+
if (predBlock == innerCopy->getParentBlock())
91+
continue;
92+
addNewEdgeValueToBranch(
93+
predBlock->getTerminator(), destBB,
94+
SILUndef::get(innerCopy->getType(), *destBB->getParent()), callbacks);
95+
}
96+
97+
return phiArg;
98+
}
99+
100+
static void getAllNonTrivialUsePointsOfBorrowedValue(
101+
SILValue value, SmallVectorImpl<Operand *> &usePoints,
102+
SmallVectorImpl<BorrowingOperand> &reborrowPoints) {
103+
assert(value.getOwnershipKind() == OwnershipKind::Guaranteed);
104+
105+
unsigned firstOffset = usePoints.size();
106+
llvm::copy(value->getUses(), std::back_inserter(usePoints));
107+
108+
if (usePoints.size() == firstOffset)
109+
return;
110+
111+
// NOTE: Use points resizes in this loop so usePoints.size() may be
112+
// different every time.
113+
for (unsigned i = firstOffset; i < usePoints.size(); ++i) {
114+
if (auto fOperand = ForwardingOperand::get(usePoints[i])) {
115+
fOperand->visitForwardedValues([&](SILValue transitiveValue) {
116+
// Do not include transitive uses with 'none' ownership
117+
if (transitiveValue.getOwnershipKind() == OwnershipKind::None)
118+
return true;
119+
for (auto *transitiveUse : transitiveValue->getUses())
120+
usePoints.push_back(transitiveUse);
121+
return true;
122+
});
123+
continue;
124+
}
125+
126+
if (auto borrowingOp = BorrowingOperand::get(usePoints[i])) {
127+
// If we have a reborrow, we have no further work to do, our reborrow is
128+
// already a use and we will handle the reborrow separately.
129+
if (borrowingOp->isReborrow())
130+
continue;
131+
132+
// Otherwise, try to grab additional end scope instructions to find more
133+
// liveness info. Stash any reborrow uses so that we can eliminate the
134+
// reborrow before we are done processing.
135+
borrowingOp->visitLocalEndScopeUses([&](Operand *scopeEndingUse) {
136+
if (auto scopeEndingBorrowingOp =
137+
BorrowingOperand::get(scopeEndingUse)) {
138+
if (scopeEndingBorrowingOp->isReborrow()) {
139+
reborrowPoints.push_back(scopeEndingUse);
140+
return true;
141+
}
142+
}
143+
usePoints.push_back(scopeEndingUse);
144+
return true;
145+
});
146+
147+
// Now break up all of the reborrows
148+
continue;
149+
}
150+
151+
// If our base guaranteed value does not have any consuming uses (consider
152+
// function arguments), we need to be sure to include interior pointer
153+
// operands since we may not get a use from a end_scope instruction.
154+
if (auto intPtrOperand = InteriorPointerOperand::get(usePoints[i])) {
155+
intPtrOperand->getImplicitUses(usePoints);
156+
continue;
157+
}
158+
}
159+
}
160+
35161
//===----------------------------------------------------------------------===//
36162
// Ownership Lifetime Extender
37163
//===----------------------------------------------------------------------===//
@@ -247,170 +373,14 @@ OwnershipLifetimeExtender::copyBorrowAndExtendForLifetimeEndingRAUW(
247373
}
248374

249375
//===----------------------------------------------------------------------===//
250-
// Ownership Fixup RAUW
376+
// Reborrow Elimination
251377
//===----------------------------------------------------------------------===//
252378

253-
/// Given an old value and a new value, lifetime extend new value as appropriate
254-
/// so we can RAUW new value with old value and preserve ownership
255-
/// invariants. We leave fixing up the lifetime of old value to our caller.
256-
namespace {
257-
258-
struct OwnershipRAUWUtility {
259-
SingleValueInstruction *oldValue;
260-
SILValue newValue;
261-
OwnershipFixupContext &ctx;
262-
263-
void rewriteReborrows(SILValue borrow, ArrayRef<BorrowingOperand> reborrows);
264-
void eliminateReborrowsOfRecursiveBorrows(
265-
ArrayRef<BorrowingOperand> transitiveReborrows,
266-
SmallVectorImpl<Operand *> &usePoints);
267-
268-
SILBasicBlock::iterator handleUnowned();
269-
270-
SILBasicBlock::iterator handleGuaranteed();
271-
272-
SILBasicBlock::iterator perform();
273-
274-
/// Insert copies/borrows as appropriate to eliminate any reborrows of
275-
/// borrowed value, given we are going to replace it with newValue.
276-
void eliminateReborrows(BorrowedValue oldBorrowedValue, SILValue newValue);
277-
278-
OwnershipLifetimeExtender getLifetimeExtender() { return {ctx}; }
279-
280-
const InstModCallbacks &getCallbacks() const { return ctx.callbacks; }
281-
};
282-
283-
} // anonymous namespace
284-
285-
static void cleanupOperandsBeforeDeletion(SILInstruction *oldValue,
286-
InstModCallbacks &callbacks) {
287-
SILBuilderWithScope builder(oldValue);
288-
for (auto &op : oldValue->getAllOperands()) {
289-
if (!op.isLifetimeEnding()) {
290-
continue;
291-
}
292-
293-
switch (op.get().getOwnershipKind()) {
294-
case OwnershipKind::Any:
295-
llvm_unreachable("Invalid ownership for value");
296-
case OwnershipKind::Owned: {
297-
auto *dvi = builder.createDestroyValue(oldValue->getLoc(), op.get());
298-
callbacks.createdNewInst(dvi);
299-
continue;
300-
}
301-
case OwnershipKind::Guaranteed: {
302-
// Should only happen once we model destructures as true reborrows.
303-
auto *ebi = builder.createEndBorrow(oldValue->getLoc(), op.get());
304-
callbacks.createdNewInst(ebi);
305-
continue;
306-
}
307-
case OwnershipKind::None:
308-
continue;
309-
case OwnershipKind::Unowned:
310-
llvm_unreachable("Unowned object can never be consumed?!");
311-
}
312-
llvm_unreachable("Covered switch isn't covered");
313-
}
314-
}
315-
316-
static SILPhiArgument *
317-
insertOwnedBaseValueAlongBranchEdge(BranchInst *bi, SILValue innerCopy,
318-
InstModCallbacks &callbacks) {
319-
auto *destBB = bi->getDestBB();
320-
// We need to create the phi argument before calling addNewEdgeValueToBranch
321-
// since it checks that the destination block has enough arguments for the
322-
// argument.
323-
auto *phiArg =
324-
destBB->createPhiArgument(innerCopy->getType(), OwnershipKind::Owned);
325-
addNewEdgeValueToBranch(bi, destBB, innerCopy, callbacks);
326-
327-
// Grab our predecessor blocks, ignoring us, add to the branch edge an
328-
// undef corresponding to our value.
329-
//
330-
// We gather all predecessor blocks in a separate array to avoid
331-
// iterator invalidation issues as we mess with terminators.
332-
SmallVector<SILBasicBlock *, 8> predecessorBlocks(
333-
destBB->getPredecessorBlocks());
334-
335-
for (auto *predBlock : predecessorBlocks) {
336-
if (predBlock == innerCopy->getParentBlock())
337-
continue;
338-
addNewEdgeValueToBranch(
339-
predBlock->getTerminator(), destBB,
340-
SILUndef::get(innerCopy->getType(), *destBB->getParent()), callbacks);
341-
}
342-
343-
return phiArg;
344-
}
345-
346-
static void getAllNonTrivialUsePointsOfBorrowedValue(
347-
SILValue value, SmallVectorImpl<Operand *> &usePoints,
348-
SmallVectorImpl<BorrowingOperand> &reborrowPoints) {
349-
assert(value.getOwnershipKind() == OwnershipKind::Guaranteed);
350-
351-
unsigned firstOffset = usePoints.size();
352-
llvm::copy(value->getUses(), std::back_inserter(usePoints));
353-
354-
if (usePoints.size() == firstOffset)
355-
return;
356-
357-
// NOTE: Use points resizes in this loop so usePoints.size() may be
358-
// different every time.
359-
for (unsigned i = firstOffset; i < usePoints.size(); ++i) {
360-
if (auto fOperand = ForwardingOperand::get(usePoints[i])) {
361-
fOperand->visitForwardedValues([&](SILValue transitiveValue) {
362-
// Do not include transitive uses with 'none' ownership
363-
if (transitiveValue.getOwnershipKind() == OwnershipKind::None)
364-
return true;
365-
for (auto *transitiveUse : transitiveValue->getUses())
366-
usePoints.push_back(transitiveUse);
367-
return true;
368-
});
369-
continue;
370-
}
371-
372-
if (auto borrowingOp = BorrowingOperand::get(usePoints[i])) {
373-
// If we have a reborrow, we have no further work to do, our reborrow is
374-
// already a use and we will handle the reborrow separately.
375-
if (borrowingOp->isReborrow())
376-
continue;
377-
378-
// Otherwise, try to grab additional end scope instructions to find more
379-
// liveness info. Stash any reborrow uses so that we can eliminate the
380-
// reborrow before we are done processing.
381-
borrowingOp->visitLocalEndScopeUses([&](Operand *scopeEndingUse) {
382-
if (auto scopeEndingBorrowingOp =
383-
BorrowingOperand::get(scopeEndingUse)) {
384-
if (scopeEndingBorrowingOp->isReborrow()) {
385-
reborrowPoints.push_back(scopeEndingUse);
386-
return true;
387-
}
388-
}
389-
usePoints.push_back(scopeEndingUse);
390-
return true;
391-
});
392-
393-
// Now break up all of the reborrows
394-
continue;
395-
}
396-
397-
// If our base guaranteed value does not have any consuming uses (consider
398-
// function arguments), we need to be sure to include interior pointer
399-
// operands since we may not get a use from a end_scope instruction.
400-
if (auto intPtrOperand = InteriorPointerOperand::get(usePoints[i])) {
401-
intPtrOperand->getImplicitUses(usePoints);
402-
continue;
403-
}
404-
}
405-
}
406-
407-
void OwnershipRAUWUtility::eliminateReborrowsOfRecursiveBorrows(
379+
static void eliminateReborrowsOfRecursiveBorrows(
408380
ArrayRef<BorrowingOperand> transitiveReborrows,
409-
SmallVectorImpl<Operand *> &usePoints) {
381+
SmallVectorImpl<Operand *> &usePoints, InstModCallbacks &callbacks) {
410382
SmallVector<std::pair<SILPhiArgument *, SILPhiArgument *>, 8>
411383
baseBorrowedValuePair;
412-
auto &callbacks = ctx.callbacks;
413-
414384
// Ok, we have transitive reborrows.
415385
for (auto borrowingOperand : transitiveReborrows) {
416386
// We eliminate the reborrow by creating a new copy+borrow at the reborrow
@@ -478,13 +448,13 @@ void OwnershipRAUWUtility::eliminateReborrowsOfRecursiveBorrows(
478448
}
479449
}
480450

481-
void OwnershipRAUWUtility::rewriteReborrows(
482-
SILValue newBorrowedValue, ArrayRef<BorrowingOperand> foundReborrows) {
451+
static void rewriteReborrows(SILValue newBorrowedValue,
452+
ArrayRef<BorrowingOperand> foundReborrows,
453+
InstModCallbacks &callbacks) {
483454
// Each initial reborrow that we have is a use of oldValue, so we know
484455
// that copy should be valid at the reborrow.
485456
SmallVector<std::pair<SILPhiArgument *, SILPhiArgument *>, 8>
486457
baseBorrowedValuePair;
487-
auto &callbacks = ctx.callbacks;
488458
for (auto reborrow : foundReborrows) {
489459
auto *bi = cast<BranchInst>(reborrow.op->getUser());
490460
SILBuilderWithScope reborrowBuilder(bi);
@@ -539,6 +509,37 @@ void OwnershipRAUWUtility::rewriteReborrows(
539509
}
540510
}
541511

512+
//===----------------------------------------------------------------------===//
513+
// Ownership Fixup RAUW
514+
//===----------------------------------------------------------------------===//
515+
516+
/// Given an old value and a new value, lifetime extend new value as appropriate
517+
/// so we can RAUW new value with old value and preserve ownership
518+
/// invariants. We leave fixing up the lifetime of old value to our caller.
519+
namespace {
520+
521+
struct OwnershipRAUWUtility {
522+
SingleValueInstruction *oldValue;
523+
SILValue newValue;
524+
OwnershipFixupContext &ctx;
525+
526+
SILBasicBlock::iterator handleUnowned();
527+
528+
SILBasicBlock::iterator handleGuaranteed();
529+
530+
SILBasicBlock::iterator perform();
531+
532+
/// Insert copies/borrows as appropriate to eliminate any reborrows of
533+
/// borrowed value, given we are going to replace it with newValue.
534+
void eliminateReborrows(BorrowedValue oldBorrowedValue, SILValue newValue);
535+
536+
OwnershipLifetimeExtender getLifetimeExtender() { return {ctx}; }
537+
538+
const InstModCallbacks &getCallbacks() const { return ctx.callbacks; }
539+
};
540+
541+
} // anonymous namespace
542+
542543
SILBasicBlock::iterator OwnershipRAUWUtility::handleUnowned() {
543544
auto &callbacks = ctx.callbacks;
544545
switch (newValue.getOwnershipKind()) {
@@ -639,7 +640,7 @@ SILBasicBlock::iterator OwnershipRAUWUtility::handleGuaranteed() {
639640
// If we have any transitive reborrows on sub-borrows.
640641
if (recursiveBorrowScopeReborrows.size())
641642
eliminateReborrowsOfRecursiveBorrows(recursiveBorrowScopeReborrows,
642-
usePoints);
643+
usePoints, ctx.callbacks);
643644

644645
auto extender = getLifetimeExtender();
645646
SILValue newBorrowedValue =
@@ -663,7 +664,7 @@ SILBasicBlock::iterator OwnershipRAUWUtility::handleGuaranteed() {
663664
if (auto oldValueBorrowedVal = BorrowedValue::get(oldValue)) {
664665
SmallVector<BorrowingOperand, 8> foundReborrows;
665666
if (oldValueBorrowedVal->gatherReborrows(foundReborrows)) {
666-
rewriteReborrows(newBorrowedValue, foundReborrows);
667+
rewriteReborrows(newBorrowedValue, foundReborrows, ctx.callbacks);
667668
}
668669
}
669670

0 commit comments

Comments
 (0)