diff --git a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp index fdf9509c9e176..449dc127be27a 100644 --- a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp @@ -54,9 +54,13 @@ class LiveRange { /// A list of destroy_values of the live range. SmallVector<Operand *, 2> destroyingUses; - /// A list of forwarding instructions that forward our destroys ownership, but - /// that are also able to forward guaranteed ownership. - SmallVector<Operand *, 2> generalForwardingUses; + /// A list of forwarding instructions that forward owned ownership, but that + /// are also able to be converted to guaranteed ownership. If we are able to + /// eliminate this LiveRange due to it being from a guaranteed value, we must + /// flip the ownership of all of these instructions to guaranteed from owned. + /// + /// Corresponds to isOwnershipForwardingInst(...). + SmallVector<Operand *, 2> ownershipForwardingUses; /// Consuming uses that we were not able to understand as a forwarding /// instruction or a destroy_value. These must be passed a strongly control @@ -80,8 +84,7 @@ class LiveRange { /// Semantically this implies that a value is never passed off as +1 to memory /// or another function implying it can be used everywhere at +0. HasConsumingUse_t - hasConsumingUse(FrozenMultiMap<SILPhiArgument *, OwnedValueIntroducer> - *phiToIncomingValueMultiMap = nullptr) const; + hasUnknownConsumingUse(bool assumingFixedPoint = false) const; ArrayRef<Operand *> getDestroyingUses() const { return destroyingUses; } @@ -113,8 +116,8 @@ class LiveRange { OwnedValueIntroducer getIntroducer() const { return introducer; } - ArrayRef<Operand *> getNonConsumingForwardingUses() const { - return generalForwardingUses; + ArrayRef<Operand *> getOwnershipForwardingUses() const { + return ownershipForwardingUses; } void convertOwnedGeneralForwardingUsesToGuaranteed(); @@ -185,7 +188,7 @@ LiveRange::DestroyingInstsRange LiveRange::getDestroyingInsts() const { LiveRange::LiveRange(SILValue value) : introducer(*OwnedValueIntroducer::get(value)), destroyingUses(), - generalForwardingUses(), unknownConsumingUses() { + ownershipForwardingUses(), unknownConsumingUses() { assert(introducer.value.getOwnershipKind() == ValueOwnershipKind::Owned); // We know that our silvalue produces an @owned value. Look through all of our @@ -246,7 +249,7 @@ LiveRange::LiveRange(SILValue value) // Ok, this is a forwarding instruction whose ownership we can flip from // owned -> guaranteed. - generalForwardingUses.push_back(op); + ownershipForwardingUses.push_back(op); // If we have a non-terminator, just visit its users recursively to see if // the the users force the live range to be alive. @@ -336,8 +339,8 @@ void LiveRange::insertEndBorrowsAtDestroys( } void LiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() { - while (!generalForwardingUses.empty()) { - auto *i = generalForwardingUses.pop_back_val()->getUser(); + while (!ownershipForwardingUses.empty()) { + auto *i = ownershipForwardingUses.pop_back_val()->getUser(); // If this is a term inst, just convert all of its incoming values that are // owned to be guaranteed. @@ -436,9 +439,8 @@ void LiveRange::convertArgToGuaranteed(DeadEndBlocks &deadEndBlocks, convertOwnedGeneralForwardingUsesToGuaranteed(); } -LiveRange::HasConsumingUse_t LiveRange::hasConsumingUse( - FrozenMultiMap<SILPhiArgument *, OwnedValueIntroducer> - *phiToIncomingValueMultiMap) const { +LiveRange::HasConsumingUse_t +LiveRange::hasUnknownConsumingUse(bool assumingAtFixPoint) const { // First do a quick check if we have /any/ unknown consuming // uses. If we do not have any, return false early. if (unknownConsumingUses.empty()) { @@ -447,7 +449,7 @@ LiveRange::HasConsumingUse_t LiveRange::hasConsumingUse( // Ok, we do have some unknown consuming uses. If we aren't asked to // update phiToIncomingValueMultiMap, then just return true quickly. - if (!phiToIncomingValueMultiMap) { + if (!assumingAtFixPoint) { return HasConsumingUse_t::Yes; } @@ -828,7 +830,6 @@ static bool canEliminatePhi( if (!introducer.isConvertableToGuaranteed()) { return false; } - // If this linear search is too slow, we can change the // multimap to sort the mapped to list by pointer // instead of insertion order. In such a case, we could @@ -870,9 +871,9 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { // First compute the LiveRange for our phi argument. For simplicity, we only // handle cases now where our phi argument does not have any phi unknown // consumers. - SILPhiArgument *phiArg = pair.first; - LiveRange phiArgLiveRange(phiArg); - if (bool(phiArgLiveRange.hasConsumingUse())) { + SILPhiArgument *phi = pair.first; + LiveRange phiLiveRange(phi); + if (bool(phiLiveRange.hasUnknownConsumingUse())) { continue; } @@ -880,7 +881,7 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { // our incoming values are able to be converted to guaranteed. Now for each // incoming value, compute the incoming values ownership roots and see if // all of the ownership roots are in our owned incoming value array. - if (!phiArg->getIncomingPhiOperands(incomingValueOperandList)) { + if (!phi->getIncomingPhiOperands(incomingValueOperandList)) { continue; } @@ -903,7 +904,7 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { for (Operand *incomingValueOperand : incomingValueOperandList) { originalIncomingValues.push_back(incomingValueOperand->get()); SILType type = incomingValueOperand->get()->getType(); - auto *undef = SILUndef::get(type, *phiArg->getFunction()); + auto *undef = SILUndef::get(type, *phi->getFunction()); incomingValueOperand->set(undef); } @@ -956,7 +957,7 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { } // Then convert the phi's live range to be guaranteed. - std::move(phiArgLiveRange) + std::move(phiLiveRange) .convertArgToGuaranteed(getDeadEndBlocks(), lifetimeFrontier, getCallbacks()); @@ -980,7 +981,7 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { madeChange = true; if (VerifyAfterTransform) { - phiArg->getFunction()->verify(); + phi->getFunction()->verify(); } } @@ -1175,9 +1176,9 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst // forwarding or a user that truly represents a necessary consume of the value // (e.x. storing into memory). LiveRange lr(cvi); - auto hasConsumingUseState = - lr.hasConsumingUse(getPhiToIncomingValueMultiMap()); - if (hasConsumingUseState == LiveRange::HasConsumingUse_t::Yes) { + auto hasUnknownConsumingUseState = + lr.hasUnknownConsumingUse(getPhiToIncomingValueMultiMap()); + if (hasUnknownConsumingUseState == LiveRange::HasConsumingUse_t::Yes) { return false; } @@ -1286,7 +1287,8 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst // was consumed, the hasConsumedUse code updated phiToIncomingValueMultiMap // for us before returning its prognosis. After we reach a fixed point, we // will try to eliminate this value then. - if (hasConsumingUseState == LiveRange::HasConsumingUse_t::YesButAllPhiArgs) { + if (hasUnknownConsumingUseState == + LiveRange::HasConsumingUse_t::YesButAllPhiArgs) { auto *op = lr.getSingleUnknownConsumingUse(); assert(op); unsigned opNum = op->getOperandNumber(); @@ -1302,7 +1304,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst auto *arg = succBlock->getSILPhiArguments()[opNum]; LiveRange phiArgLR(arg); - if (bool(phiArgLR.hasConsumingUse())) { + if (bool(phiArgLR.hasUnknownConsumingUse())) { return false; } @@ -1784,7 +1786,7 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) { // -> load_borrow if we can put a copy_value on a cold path and thus // eliminate RR traffic on a hot path. LiveRange lr(li); - if (bool(lr.hasConsumingUse())) + if (bool(lr.hasUnknownConsumingUse())) return false; // Then check if our address is ever written to. If it is, then we cannot use