Skip to content

Commit 6e5f036

Browse files
committed
[ownership] Create a single introducer version of getUnderlyingBorrowIntroducingValues and rename it to getAllBorrowIntroducingValues(...).
I also added a comment to getAllBorrowIntroducingValues(...) that explained the situations where one could have multiple borrow introducing values: 1. True phi arguments. 2. Aggregate forming instructions.
1 parent 21a2cdb commit 6e5f036

File tree

5 files changed

+129
-69
lines changed

5 files changed

+129
-69
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -541,13 +541,24 @@ struct BorrowScopeIntroducingValue {
541541
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
542542
const BorrowScopeIntroducingValue &value);
543543

544-
/// Look up through the def-use chain of \p inputValue, recording any "borrow"
545-
/// introducing values that we find into \p out. If at any point, we find a
546-
/// point in the chain we do not understand, we bail and return false. If we are
547-
/// able to understand all of the def-use graph, we know that we have found all
548-
/// of the borrow introducing values, we return true.
549-
bool getUnderlyingBorrowIntroducingValues(
550-
SILValue inputValue, SmallVectorImpl<BorrowScopeIntroducingValue> &out);
544+
/// Look up the def-use graph starting at use \p inputOperand, recording any
545+
/// "borrow" introducing values that we find into \p out. If at any point, we
546+
/// find a point in the chain we do not understand, we bail and return false. If
547+
/// we are able to understand all of the def-use graph, we know that we have
548+
/// found all of the borrow introducing values, we return true.
549+
///
550+
/// NOTE: This may return multiple borrow introducing values in cases where
551+
/// there are phi-like nodes in the IR like any true phi block arguments or
552+
/// aggregate literal instructions (struct, tuple, enum, etc.).
553+
bool getAllBorrowIntroducingValues(
554+
SILValue value, SmallVectorImpl<BorrowScopeIntroducingValue> &out);
555+
556+
/// Look up the def-use graph starting at \p inputOperand and see if
557+
/// we can find a single BorrowScopeIntroducingValue for \p
558+
/// inputOperand. Returns None if there are multiple such introducers
559+
/// or if while processing we find a user we do not understand.
560+
Optional<BorrowScopeIntroducingValue>
561+
getSingleBorrowIntroducingValue(SILValue value);
551562

552563
} // namespace swift
553564

lib/SIL/OwnershipUtils.cpp

Lines changed: 104 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -305,57 +305,6 @@ void BorrowScopeIntroducingValue::visitLocalScopeEndingUses(
305305
llvm_unreachable("Covered switch isn't covered?!");
306306
}
307307

308-
bool swift::getUnderlyingBorrowIntroducingValues(
309-
SILValue inputValue, SmallVectorImpl<BorrowScopeIntroducingValue> &out) {
310-
if (inputValue.getOwnershipKind() != ValueOwnershipKind::Guaranteed)
311-
return false;
312-
313-
SmallVector<SILValue, 32> worklist;
314-
worklist.emplace_back(inputValue);
315-
316-
while (!worklist.empty()) {
317-
SILValue v = worklist.pop_back_val();
318-
319-
// First check if v is an introducer. If so, stash it and continue.
320-
if (auto scopeIntroducer = BorrowScopeIntroducingValue::get(v)) {
321-
out.push_back(*scopeIntroducer);
322-
continue;
323-
}
324-
325-
// If v produces .none ownership, then we can ignore it. It is important
326-
// that we put this before checking for guaranteed forwarding instructions,
327-
// since we want to ignore guaranteed forwarding instructions that in this
328-
// specific case produce a .none value.
329-
if (v.getOwnershipKind() == ValueOwnershipKind::None)
330-
continue;
331-
332-
// Otherwise if v is an ownership forwarding value, add its defining
333-
// instruction
334-
if (isGuaranteedForwardingValue(v)) {
335-
if (auto *i = v->getDefiningInstruction()) {
336-
llvm::transform(i->getAllOperands(), std::back_inserter(worklist),
337-
[](const Operand &op) -> SILValue { return op.get(); });
338-
continue;
339-
}
340-
341-
// Otherwise, we should have a block argument that is defined by a single
342-
// predecessor terminator.
343-
auto *arg = cast<SILPhiArgument>(v);
344-
auto *termInst = arg->getSingleTerminator();
345-
assert(termInst && termInst->isTransformationTerminator());
346-
llvm::transform(termInst->getAllOperands(), std::back_inserter(worklist),
347-
[](const Operand &op) -> SILValue { return op.get(); });
348-
continue;
349-
}
350-
351-
// Otherwise, this is an introducer we do not understand. Bail and return
352-
// false.
353-
return false;
354-
}
355-
356-
return true;
357-
}
358-
359308
llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &os,
360309
BorrowScopeIntroducingValueKind kind) {
361310
kind.print(os);
@@ -438,3 +387,107 @@ bool BorrowScopeIntroducingValue::visitLocalScopeTransitiveEndingUses(
438387

439388
return foundError;
440389
}
390+
391+
//===----------------------------------------------------------------------===//
392+
// Introducer Searching Routines
393+
//===----------------------------------------------------------------------===//
394+
395+
bool swift::getAllBorrowIntroducingValues(
396+
SILValue inputValue, SmallVectorImpl<BorrowScopeIntroducingValue> &out) {
397+
if (inputValue.getOwnershipKind() != ValueOwnershipKind::Guaranteed)
398+
return false;
399+
400+
SmallVector<SILValue, 32> worklist;
401+
worklist.emplace_back(inputValue);
402+
403+
while (!worklist.empty()) {
404+
SILValue value = worklist.pop_back_val();
405+
406+
// First check if v is an introducer. If so, stash it and continue.
407+
if (auto scopeIntroducer = BorrowScopeIntroducingValue::get(value)) {
408+
out.push_back(*scopeIntroducer);
409+
continue;
410+
}
411+
412+
// If v produces .none ownership, then we can ignore it. It is important
413+
// that we put this before checking for guaranteed forwarding instructions,
414+
// since we want to ignore guaranteed forwarding instructions that in this
415+
// specific case produce a .none value.
416+
if (value.getOwnershipKind() == ValueOwnershipKind::None)
417+
continue;
418+
419+
// Otherwise if v is an ownership forwarding value, add its defining
420+
// instruction
421+
if (isGuaranteedForwardingValue(value)) {
422+
if (auto *i = value->getDefiningInstruction()) {
423+
llvm::copy(i->getOperandValues(true /*skip type dependent ops*/),
424+
std::back_inserter(worklist));
425+
continue;
426+
}
427+
428+
// Otherwise, we should have a block argument that is defined by a single
429+
// predecessor terminator.
430+
auto *arg = cast<SILPhiArgument>(value);
431+
auto *termInst = arg->getSingleTerminator();
432+
assert(termInst && termInst->isTransformationTerminator());
433+
assert(termInst->getNumOperands() == 1 &&
434+
"Transforming terminators should always have a single operand");
435+
worklist.push_back(termInst->getAllOperands()[0].get());
436+
continue;
437+
}
438+
439+
// Otherwise, this is an introducer we do not understand. Bail and return
440+
// false.
441+
return false;
442+
}
443+
444+
return true;
445+
}
446+
447+
Optional<BorrowScopeIntroducingValue>
448+
swift::getSingleBorrowIntroducingValue(SILValue inputValue) {
449+
if (inputValue.getOwnershipKind() != ValueOwnershipKind::Guaranteed)
450+
return None;
451+
452+
SILValue currentValue = inputValue;
453+
while (true) {
454+
// First check if our initial value is an introducer. If we have one, just
455+
// return it.
456+
if (auto scopeIntroducer = BorrowScopeIntroducingValue::get(currentValue)) {
457+
return scopeIntroducer;
458+
}
459+
460+
// Otherwise if v is an ownership forwarding value, add its defining
461+
// instruction
462+
if (isGuaranteedForwardingValue(currentValue)) {
463+
if (auto *i = currentValue->getDefiningInstruction()) {
464+
auto instOps = i->getOperandValues(true /*ignore type dependent ops*/);
465+
// If we have multiple incoming values, return .None. We can't handle
466+
// this.
467+
auto begin = instOps.begin();
468+
if (std::next(begin) != instOps.end()) {
469+
return None;
470+
}
471+
// Otherwise, set currentOp to the single operand and continue.
472+
currentValue = *begin;
473+
continue;
474+
}
475+
476+
// Otherwise, we should have a block argument that is defined by a single
477+
// predecessor terminator.
478+
auto *arg = cast<SILPhiArgument>(currentValue);
479+
auto *termInst = arg->getSingleTerminator();
480+
assert(termInst && termInst->isTransformationTerminator());
481+
assert(termInst->getNumOperands() == 1 &&
482+
"Transformation terminators should only have single operands");
483+
currentValue = termInst->getAllOperands()[0].get();
484+
continue;
485+
}
486+
487+
// Otherwise, this is an introducer we do not understand. Bail and return
488+
// None.
489+
return None;
490+
}
491+
492+
llvm_unreachable("Should never hit this");
493+
}

lib/SILOptimizer/Mandatory/OSLogOptimization.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -871,13 +871,7 @@ static Optional<BorrowScopeIntroducingValue>
871871
getUniqueBorrowScopeIntroducingValue(SILValue value) {
872872
assert(value.getOwnershipKind() == ValueOwnershipKind::Guaranteed &&
873873
"parameter must be a guarenteed value");
874-
SmallVector<BorrowScopeIntroducingValue, 4> borrowIntroducers;
875-
getUnderlyingBorrowIntroducingValues(value, borrowIntroducers);
876-
assert(borrowIntroducers.size() > 0 &&
877-
"folding guaranteed value with no borrow introducer");
878-
if (borrowIntroducers.size() > 1)
879-
return None;
880-
return borrowIntroducers[0];
874+
return getSingleBorrowIntroducingValue(value);
881875
}
882876

883877
/// Replace all uses of \c originalVal by \c foldedVal and adjust lifetimes of

lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ SILValue AvailableValueAggregator::aggregateValues(SILType LoadTy,
609609
result = builder.emitCopyValueOperation(Loc, borrowedResult);
610610
SmallVector<BorrowScopeIntroducingValue, 4> introducers;
611611
bool foundIntroducers =
612-
getUnderlyingBorrowIntroducingValues(borrowedResult, introducers);
612+
getAllBorrowIntroducingValues(borrowedResult, introducers);
613613
(void)foundIntroducers;
614614
assert(foundIntroducers);
615615
for (auto value : introducers) {
@@ -631,7 +631,7 @@ SILValue AvailableValueAggregator::aggregateValues(SILType LoadTy,
631631
result = builder.emitCopyValueOperation(Loc, borrowedResult);
632632
SmallVector<BorrowScopeIntroducingValue, 4> introducers;
633633
bool foundIntroducers =
634-
getUnderlyingBorrowIntroducingValues(borrowedResult, introducers);
634+
getAllBorrowIntroducingValues(borrowedResult, introducers);
635635
(void)foundIntroducers;
636636
assert(foundIntroducers);
637637
for (auto value : introducers) {

lib/SILOptimizer/Transforms/SemanticARCOpts.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,10 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
657657
// Find all borrow introducers for our copy operand. If we are unable to find
658658
// all of the reproducers (due to pattern matching failure), conservatively
659659
// return false. We can not optimize.
660-
if (!getUnderlyingBorrowIntroducingValues(cvi->getOperand(),
661-
borrowScopeIntroducers))
660+
//
661+
// NOTE: We can get multiple introducers if our copy_value's operand
662+
// value runs through a phi or an aggregate forming instruction.
663+
if (!getAllBorrowIntroducingValues(cvi->getOperand(), borrowScopeIntroducers))
662664
return false;
663665

664666
// Then go over all of our uses and see if the value returned by our copy

0 commit comments

Comments
 (0)