Skip to content

Commit b58ea4b

Browse files
authored
Merge pull request #30151 from gottesmm/pr-5d7a1ea2d4ae11d647fceb405a4c2307150f7b06
[ownership] Create a single introducer version of getUnderlyingBorrowIntroducingValues and rename it to getAllBorrowIntroducingValues(...).
2 parents 926f105 + 6e5f036 commit b58ea4b

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
@@ -545,13 +545,24 @@ struct BorrowScopeIntroducingValue {
545545
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
546546
const BorrowScopeIntroducingValue &value);
547547

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

556567
} // namespace swift
557568

lib/SIL/OwnershipUtils.cpp

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

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

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

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)