Skip to content

Commit 711fc48

Browse files
authored
Merge pull request swiftlang#30243 from gottesmm/pr-79ceec70022725264b06f2d626c8793a8d917737
2 parents ebe8aac + 621573e commit 711fc48

File tree

2 files changed

+167
-119
lines changed

2 files changed

+167
-119
lines changed

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,32 @@ struct InstModCallbacks {
292292
[](SILValue oldValue, SILValue newValue) {
293293
oldValue->replaceAllUsesWith(newValue);
294294
};
295+
std::function<void(SingleValueInstruction *, SILValue)>
296+
eraseAndRAUWSingleValueInst =
297+
[](SingleValueInstruction *i, SILValue newValue) {
298+
i->replaceAllUsesWith(newValue);
299+
i->eraseFromParent();
300+
};
295301

296302
InstModCallbacks(decltype(deleteInst) deleteInst,
297303
decltype(createdNewInst) createdNewInst,
298304
decltype(replaceValueUsesWith) replaceValueUsesWith)
299305
: deleteInst(deleteInst), createdNewInst(createdNewInst),
300-
replaceValueUsesWith(replaceValueUsesWith) {}
306+
replaceValueUsesWith(replaceValueUsesWith),
307+
eraseAndRAUWSingleValueInst(
308+
[](SingleValueInstruction *i, SILValue newValue) {
309+
i->replaceAllUsesWith(newValue);
310+
i->eraseFromParent();
311+
}) {}
312+
313+
InstModCallbacks(
314+
decltype(deleteInst) deleteInst, decltype(createdNewInst) createdNewInst,
315+
decltype(replaceValueUsesWith) replaceValueUsesWith,
316+
decltype(eraseAndRAUWSingleValueInst) eraseAndRAUWSingleValueInst)
317+
: deleteInst(deleteInst), createdNewInst(createdNewInst),
318+
replaceValueUsesWith(replaceValueUsesWith),
319+
eraseAndRAUWSingleValueInst(eraseAndRAUWSingleValueInst) {}
320+
301321
InstModCallbacks() = default;
302322
~InstModCallbacks() = default;
303323
InstModCallbacks(const InstModCallbacks &) = default;

lib/SILOptimizer/Transforms/SemanticARCOpts.cpp

Lines changed: 146 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ STATISTIC(NumLoadCopyConvertedToLoadBorrow,
4646
namespace {
4747

4848
class LiveRange {
49+
/// The parent value that introduces the live range.
50+
SILValue value;
51+
4952
/// A list of destroy_values of the live range.
5053
SmallVector<Operand *, 2> destroyingUses;
5154

@@ -83,6 +86,32 @@ class LiveRange {
8386
ArrayRef<Operand *> getNonConsumingForwardingUses() const {
8487
return generalForwardingUses;
8588
}
89+
90+
/// A consuming operation that:
91+
///
92+
/// 1. If \p insertEndBorrows is true inserts end borrows at all
93+
/// destroying insts locations.
94+
///
95+
/// 2. Deletes all destroy_values.
96+
///
97+
/// 3. RAUW value with newGuaranteedValue.
98+
///
99+
/// 4. Convert all of the general forwarding instructions from
100+
/// @owned -> @guaranteed. "Like Dominoes".
101+
///
102+
/// 5. Leaves all of the unknown consuming users alone. It is up to
103+
/// the caller to handle converting their ownership.
104+
void convertToGuaranteedAndRAUW(SILValue newGuaranteedValue,
105+
InstModCallbacks callbacks) &&;
106+
107+
/// Given a new guaranteed value, insert end_borrow for the newGuaranteedValue
108+
/// at all of our destroy_values in prepration for converting from owned to
109+
/// guaranteed.
110+
///
111+
/// This is used when converting load [copy] -> load_borrow.
112+
void insertEndBorrowsAtDestroys(SILValue newGuaranteedValue,
113+
DeadEndBlocks &deadEndBlocks,
114+
ValueLifetimeAnalysis::Frontier &scratch);
86115
};
87116

88117
} // end anonymous namespace
@@ -101,7 +130,8 @@ LiveRange::DestroyingInstsRange LiveRange::getDestroyingInsts() const {
101130
}
102131

103132
LiveRange::LiveRange(SILValue value)
104-
: destroyingUses(), generalForwardingUses(), unknownConsumingUses() {
133+
: value(value), destroyingUses(), generalForwardingUses(),
134+
unknownConsumingUses() {
105135
assert(value.getOwnershipKind() == ValueOwnershipKind::Owned);
106136

107137
// We know that our silvalue produces an @owned value. Look through all of our
@@ -198,6 +228,108 @@ LiveRange::LiveRange(SILValue value)
198228
}
199229
}
200230

231+
void LiveRange::insertEndBorrowsAtDestroys(
232+
SILValue newGuaranteedValue, DeadEndBlocks &deadEndBlocks,
233+
ValueLifetimeAnalysis::Frontier &scratch) {
234+
assert(scratch.empty() && "Expected scratch to be initially empty?!");
235+
236+
// Since we are looking through forwarding uses that can accept guaranteed
237+
// parameters, we can have multiple destroy_value along the same path. We need
238+
// to find the post-dominating block set of these destroy value to ensure that
239+
// we do not insert multiple end_borrow.
240+
//
241+
// TODO: Hoist this out?
242+
auto *inst = value->getDefiningInstruction();
243+
assert(inst && "Should only call this with value's that are actually part of "
244+
"an instruction");
245+
246+
ValueLifetimeAnalysis analysis(inst, getDestroyingInsts());
247+
bool foundCriticalEdges = !analysis.computeFrontier(
248+
scratch, ValueLifetimeAnalysis::DontModifyCFG, &deadEndBlocks);
249+
(void)foundCriticalEdges;
250+
assert(!foundCriticalEdges);
251+
auto loc = RegularLocation::getAutoGeneratedLocation();
252+
while (!scratch.empty()) {
253+
auto *insertPoint = scratch.pop_back_val();
254+
SILBuilderWithScope builder(insertPoint);
255+
builder.createEndBorrow(loc, newGuaranteedValue);
256+
}
257+
}
258+
259+
void LiveRange::convertToGuaranteedAndRAUW(SILValue newGuaranteedValue,
260+
InstModCallbacks callbacks) && {
261+
assert(isa<SingleValueInstruction>(value) &&
262+
"Can only convert single value instruction live ranges to guaranteed");
263+
while (!destroyingUses.empty()) {
264+
auto *d = destroyingUses.pop_back_val();
265+
callbacks.deleteInst(d->getUser());
266+
++NumEliminatedInsts;
267+
}
268+
269+
callbacks.eraseAndRAUWSingleValueInst(cast<SingleValueInstruction>(value),
270+
newGuaranteedValue);
271+
272+
// Then change all of our guaranteed forwarding insts to have guaranteed
273+
// ownership kind instead of what ever they previously had (ignoring trivial
274+
// results);
275+
while (!generalForwardingUses.empty()) {
276+
auto *i = generalForwardingUses.pop_back_val()->getUser();
277+
278+
// If this is a term inst, just convert all of its incoming values that are
279+
// owned to be guaranteed.
280+
if (auto *ti = dyn_cast<TermInst>(i)) {
281+
for (auto &succ : ti->getSuccessors()) {
282+
auto *succBlock = succ.getBB();
283+
284+
// If we do not have any arguments, then continue.
285+
if (succBlock->args_empty())
286+
continue;
287+
288+
for (auto *succArg : succBlock->getSILPhiArguments()) {
289+
// If we have an any value, just continue.
290+
if (succArg->getOwnershipKind() == ValueOwnershipKind::Owned) {
291+
succArg->setOwnershipKind(ValueOwnershipKind::Guaranteed);
292+
}
293+
}
294+
}
295+
continue;
296+
}
297+
298+
assert(i->hasResults());
299+
for (SILValue result : i->getResults()) {
300+
if (auto *svi = dyn_cast<OwnershipForwardingSingleValueInst>(result)) {
301+
if (svi->getOwnershipKind() == ValueOwnershipKind::Owned) {
302+
svi->setOwnershipKind(ValueOwnershipKind::Guaranteed);
303+
}
304+
continue;
305+
}
306+
307+
if (auto *ofci = dyn_cast<OwnershipForwardingConversionInst>(result)) {
308+
if (ofci->getOwnershipKind() == ValueOwnershipKind::Owned) {
309+
ofci->setOwnershipKind(ValueOwnershipKind::Guaranteed);
310+
}
311+
continue;
312+
}
313+
314+
if (auto *sei = dyn_cast<OwnershipForwardingSelectEnumInstBase>(result)) {
315+
if (sei->getOwnershipKind() == ValueOwnershipKind::Owned) {
316+
sei->setOwnershipKind(ValueOwnershipKind::Guaranteed);
317+
}
318+
continue;
319+
}
320+
321+
if (auto *mvir = dyn_cast<MultipleValueInstructionResult>(result)) {
322+
if (mvir->getOwnershipKind() == ValueOwnershipKind::Owned) {
323+
mvir->setOwnershipKind(ValueOwnershipKind::Guaranteed);
324+
}
325+
continue;
326+
}
327+
328+
llvm_unreachable("unhandled forwarding instruction?!");
329+
}
330+
}
331+
}
332+
201333
//===----------------------------------------------------------------------===//
202334
// Address Written To Analysis
203335
//===----------------------------------------------------------------------===//
@@ -321,76 +453,6 @@ bool IsAddressWrittenToDefUseAnalysis::isWrittenToHelper(SILValue initialValue)
321453
return false;
322454
}
323455

324-
//===----------------------------------------------------------------------===//
325-
// Convert Forwarding Insts from Owned -> Guaranteed
326-
//===----------------------------------------------------------------------===//
327-
328-
static void convertForwardingUsesFromOwnedToGuaranteed(
329-
ArrayRef<Operand *> guaranteedForwardingUses) {
330-
// Then change all of our guaranteed forwarding insts to have guaranteed
331-
// ownership kind instead of what ever they previously had (ignoring trivial
332-
// results);
333-
while (!guaranteedForwardingUses.empty()) {
334-
auto *use = guaranteedForwardingUses.back();
335-
guaranteedForwardingUses = guaranteedForwardingUses.drop_back();
336-
337-
auto *i = use->getUser();
338-
339-
// If this is a term inst, just convert all of its incoming values that are
340-
// owned to be guaranteed.
341-
if (auto *ti = dyn_cast<TermInst>(i)) {
342-
for (auto &succ : ti->getSuccessors()) {
343-
auto *succBlock = succ.getBB();
344-
345-
// If we do not have any arguments, then continue.
346-
if (succBlock->args_empty())
347-
continue;
348-
349-
for (auto *succArg : succBlock->getSILPhiArguments()) {
350-
// If we have an any value, just continue.
351-
if (succArg->getOwnershipKind() == ValueOwnershipKind::Owned) {
352-
succArg->setOwnershipKind(ValueOwnershipKind::Guaranteed);
353-
}
354-
}
355-
}
356-
continue;
357-
}
358-
359-
assert(i->hasResults());
360-
for (SILValue result : i->getResults()) {
361-
if (auto *svi = dyn_cast<OwnershipForwardingSingleValueInst>(result)) {
362-
if (svi->getOwnershipKind() == ValueOwnershipKind::Owned) {
363-
svi->setOwnershipKind(ValueOwnershipKind::Guaranteed);
364-
}
365-
continue;
366-
}
367-
368-
if (auto *ofci = dyn_cast<OwnershipForwardingConversionInst>(result)) {
369-
if (ofci->getOwnershipKind() == ValueOwnershipKind::Owned) {
370-
ofci->setOwnershipKind(ValueOwnershipKind::Guaranteed);
371-
}
372-
continue;
373-
}
374-
375-
if (auto *sei = dyn_cast<OwnershipForwardingSelectEnumInstBase>(result)) {
376-
if (sei->getOwnershipKind() == ValueOwnershipKind::Owned) {
377-
sei->setOwnershipKind(ValueOwnershipKind::Guaranteed);
378-
}
379-
continue;
380-
}
381-
382-
if (auto *mvir = dyn_cast<MultipleValueInstructionResult>(result)) {
383-
if (mvir->getOwnershipKind() == ValueOwnershipKind::Owned) {
384-
mvir->setOwnershipKind(ValueOwnershipKind::Guaranteed);
385-
}
386-
continue;
387-
}
388-
389-
llvm_unreachable("unhandled forwarding instruction?!");
390-
}
391-
}
392-
}
393-
394456
//===----------------------------------------------------------------------===//
395457
// Implementation
396458
//===----------------------------------------------------------------------===//
@@ -473,6 +535,15 @@ struct SemanticARCOptVisitor
473535
visitedSinceLastMutation.clear();
474536
}
475537

538+
InstModCallbacks getCallbacks() {
539+
return InstModCallbacks(
540+
[this](SILInstruction *inst) { eraseInstruction(inst); },
541+
[](SILInstruction *) {}, [](SILValue, SILValue) {},
542+
[this](SingleValueInstruction *i, SILValue value) {
543+
eraseAndRAUWSingleValueInstruction(i, value);
544+
});
545+
}
546+
476547
/// The default visitor.
477548
bool visitSILInstruction(SILInstruction *i) {
478549
assert(!isGuaranteedForwardingInst(i) &&
@@ -808,18 +879,8 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
808879
}
809880

810881
// Otherwise, we know that our copy_value/destroy_values are all completely
811-
// within the guaranteed value scope. First delete the destroys/copies.
812-
while (!destroys.empty()) {
813-
auto *d = destroys.back();
814-
destroys = destroys.drop_back();
815-
eraseInstruction(d->getUser());
816-
++NumEliminatedInsts;
817-
}
818-
819-
eraseAndRAUWSingleValueInstruction(cvi, cvi->getOperand());
820-
convertForwardingUsesFromOwnedToGuaranteed(
821-
lr.getNonConsumingForwardingUses());
822-
882+
// within the guaranteed value scope. So RAUW and convert to guaranteed!
883+
std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), getCallbacks());
823884
++NumEliminatedInsts;
824885
return true;
825886
}
@@ -1291,41 +1352,8 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
12911352
auto *lbi =
12921353
SILBuilderWithScope(li).createLoadBorrow(li->getLoc(), li->getOperand());
12931354

1294-
// Since we are looking through forwarding uses that can accept guaranteed
1295-
// parameters, we can have multiple destroy_value along the same path. We need
1296-
// to find the post-dominating block set of these destroy value to ensure that
1297-
// we do not insert multiple end_borrow.
1298-
assert(lifetimeFrontier.empty());
1299-
ValueLifetimeAnalysis analysis(li, lr.getDestroyingInsts());
1300-
bool foundCriticalEdges = !analysis.computeFrontier(
1301-
lifetimeFrontier, ValueLifetimeAnalysis::DontModifyCFG,
1302-
&getDeadEndBlocks());
1303-
(void)foundCriticalEdges;
1304-
assert(!foundCriticalEdges);
1305-
auto loc = RegularLocation::getAutoGeneratedLocation();
1306-
while (!lifetimeFrontier.empty()) {
1307-
auto *insertPoint = lifetimeFrontier.pop_back_val();
1308-
SILBuilderWithScope builder(insertPoint);
1309-
builder.createEndBorrow(loc, lbi);
1310-
}
1311-
1312-
// Then delete all of our destroy_value.
1313-
auto destroyValues = lr.getDestroyingUses();
1314-
while (!destroyValues.empty()) {
1315-
auto *dvi = destroyValues.back();
1316-
destroyValues = destroyValues.drop_back();
1317-
eraseInstruction(dvi->getUser());
1318-
++NumEliminatedInsts;
1319-
}
1320-
1321-
// RAUW our other uses from the load to the load_borrow.
1322-
eraseAndRAUWSingleValueInstruction(li, lbi);
1323-
1324-
// And then change the ownership all of our owned forwarding users to be
1325-
// guaranteed.
1326-
convertForwardingUsesFromOwnedToGuaranteed(
1327-
lr.getNonConsumingForwardingUses());
1328-
1355+
lr.insertEndBorrowsAtDestroys(lbi, getDeadEndBlocks(), lifetimeFrontier);
1356+
std::move(lr).convertToGuaranteedAndRAUW(lbi, getCallbacks());
13291357
++NumEliminatedInsts;
13301358
++NumLoadCopyConvertedToLoadBorrow;
13311359
return true;

0 commit comments

Comments
 (0)