/// Returns true if FirstIV is a SILArgument or SILInstruction in a BB that /// dominates the BB of A. static bool dominatesArgument(DominanceInfo *DI, SILArgument *A, SILValue FirstIV) { SILBasicBlock *OtherBB = FirstIV->getParentBB(); if (!OtherBB || OtherBB == A->getParent()) return false; return DI->dominates(OtherBB, A->getParent()); }
/// TODO: Refactor this code so the decision on whether or not to accept an /// instruction. bool swift::getFinalReleasesForValue(SILValue V, ReleaseTracker &Tracker) { llvm::SmallPtrSet<SILBasicBlock *, 16> LiveIn; llvm::SmallPtrSet<SILBasicBlock *, 16> UseBlocks; // First attempt to get the BB where this value resides. auto *DefBB = V->getParentBB(); if (!DefBB) return false; bool seenRelease = false; SILInstruction *OneRelease = nullptr; // We'll treat this like a liveness problem where the value is the def. Each // block that has a use of the value has the value live-in unless it is the // block with the value. for (auto *UI : V->getUses()) { auto *User = UI->getUser(); auto *BB = User->getParent(); if (!Tracker.isUserAcceptable(User)) return false; Tracker.trackUser(User); if (BB != DefBB) LiveIn.insert(BB); // Also keep track of the blocks with uses. UseBlocks.insert(BB); // Try to speed up the trivial case of single release/dealloc. if (isa<StrongReleaseInst>(User) || isa<DeallocBoxInst>(User)) { if (!seenRelease) OneRelease = User; else OneRelease = nullptr; seenRelease = true; } } // Only a single release/dealloc? We're done! if (OneRelease) { Tracker.trackLastRelease(OneRelease); return true; } propagateLiveness(LiveIn, DefBB); // Now examine each block we saw a use in. If it has no successors // that are in LiveIn, then the last use in the block is the final // release/dealloc. for (auto *BB : UseBlocks) if (!successorHasLiveIn(BB, LiveIn)) if (!addLastUse(V, BB, Tracker)) return false; return true; }
void Operand::hoistAddressProjections(SILInstruction *InsertBefore, DominanceInfo *DomTree) { SILValue V = get(); SILInstruction *Prev = nullptr; auto *InsertPt = InsertBefore; while (true) { SILValue Incoming = stripSinglePredecessorArgs(V); // Forward the incoming arg from a single predeccessor. if (V != Incoming) { if (V == get()) { // If we are the operand itself set the operand to the incoming // argument. set(Incoming); V = Incoming; } else { // Otherwise, set the previous projections operand to the incoming // argument. assert(Prev && "Must have seen a projection"); Prev->setOperand(0, Incoming); V = Incoming; } } switch (V->getKind()) { case ValueKind::StructElementAddrInst: case ValueKind::TupleElementAddrInst: case ValueKind::RefElementAddrInst: case ValueKind::UncheckedTakeEnumDataAddrInst: { auto *Inst = cast<SILInstruction>(V); // We are done once the current projection dominates the insert point. if (DomTree->dominates(Inst->getParent(), InsertBefore->getParent())) return; // Move the current projection and memorize it for the next iteration. Prev = Inst; Inst->moveBefore(InsertPt); InsertPt = Inst; V = Inst->getOperand(0); continue; } default: assert(DomTree->dominates(V->getParentBB(), InsertBefore->getParent()) && "The projected value must dominate the insertion point"); return; } } }
static bool dominates(DominanceInfo *DT, SILValue V, SILBasicBlock *B) { if (auto ValueBB = V->getParentBB()) return DT->dominates(ValueBB, B); return false; }
bool RCIdentityFunctionInfo:: findDominatingNonPayloadedEdge(SILBasicBlock *IncomingEdgeBB, SILValue RCIdentity) { // First grab the NonPayloadedEnumBB and RCIdentityBB. If we cannot find // either of them, return false. SILBasicBlock *RCIdentityBB = RCIdentity->getParentBB(); if (!RCIdentityBB) return false; // Make sure that the incoming edge bb is not the RCIdentityBB. We are not // trying to handle this case here, so simplify by just bailing if we detect // it. // // I think the only way this can happen is if we have a switch_enum of some // sort with multiple incoming values going into the destination BB. We are // not interested in handling that case anyways. // // FIXME: If we ever split all critical edges, this should be relooked at. if (IncomingEdgeBB == RCIdentityBB) return false; // Now we know that RCIdentityBB and IncomingEdgeBB are different. Prove that // RCIdentityBB dominates IncomingEdgeBB. SILFunction *F = RCIdentityBB->getParent(); // First make sure that IncomingEdgeBB dominates NonPayloadedEnumBB. If not, // return false. DominanceInfo *DI = DA->get(F); if (!DI->dominates(RCIdentityBB, IncomingEdgeBB)) return false; // Now walk up the dominator tree from IncomingEdgeBB to RCIdentityBB and see // if we can find a use of RCIdentity that dominates IncomingEdgeBB and // enables us to know that RCIdentity must be a no-payload enum along // IncomingEdge. We don't care if the case or enum of RCIdentity match the // case or enum along RCIdentityBB since a pairing of retain, release of two // non-payloaded enums can always be eliminated (since we can always eliminate // ref count operations on non-payloaded enums). // RCIdentityBB must have a valid dominator tree node. auto *EndDomNode = DI->getNode(RCIdentityBB); if (!EndDomNode) return false; for (auto *Node = DI->getNode(IncomingEdgeBB); Node; Node = Node->getIDom()) { // Search for uses of RCIdentity in Node->getBlock() that will enable us to // know that it has a non-payloaded enum case. SILBasicBlock *DominatingBB = Node->getBlock(); llvm::Optional<bool> Result = proveNonPayloadedEnumCase(DominatingBB, RCIdentity); // If we found either a signal of a payloaded or a non-payloaded enum, // return that value. if (Result.hasValue()) return Result.getValue(); // If we didn't reach RCIdentityBB, keep processing up the DomTree. if (DominatingBB != RCIdentityBB) continue; // Otherwise, we failed to find any interesting information, return false. return false; } return false; }