void EpilogueARCContext::initializeDataflow() { for (auto &B : *F) { // Find the exit blocks. if (isInterestedFunctionExitingBlock(&B)) { ExitBlocks.insert(&B); } // Allocate the storage. EpilogueARCBlockStates[&B] = new (BPA.Allocate()) EpilogueARCBlockState(); } // Split the SILargument into local arguments to each specific basic block. llvm::SmallVector<SILValue, 4> ToProcess; llvm::DenseSet<SILValue> Processed; ToProcess.push_back(Arg); while (!ToProcess.empty()) { SILValue CArg = ToProcess.pop_back_val(); if (!CArg) continue; if (Processed.find(CArg) != Processed.end()) continue; Processed.insert(CArg); SILArgument *A = dyn_cast<SILArgument>(CArg); if (A && !A->isFunctionArg()) { // Find predecessor and break the SILArgument to predecessors. for (auto X : A->getParent()->getPreds()) { // Try to find the predecessor edge-value. SILValue IA = A->getIncomingValue(X); EpilogueARCBlockStates[X]->LocalArg = IA; // Maybe the edge value is another SILArgument. ToProcess.push_back(IA); } } } }
/// Determine the number of iterations the loop is at most executed. The loop /// might contain early exits so this is the maximum if no early exits are /// taken. static Optional<uint64_t> getMaxLoopTripCount(SILLoop *Loop, SILBasicBlock *Preheader, SILBasicBlock *Header, SILBasicBlock *Latch) { // Skip a split backedge. SILBasicBlock *OrigLatch = Latch; if (!Loop->isLoopExiting(Latch) && !(Latch = Latch->getSinglePredecessor())) return None; if (!Loop->isLoopExiting(Latch)) return None; // Get the loop exit condition. auto *CondBr = dyn_cast<CondBranchInst>(Latch->getTerminator()); if (!CondBr) return None; // Match an add 1 recurrence. SILArgument *RecArg; IntegerLiteralInst *End; SILValue RecNext; if (!match(CondBr->getCondition(), m_BuiltinInst(BuiltinValueKind::ICMP_EQ, m_SILValue(RecNext), m_IntegerLiteralInst(End)))) return None; if (!match(RecNext, m_TupleExtractInst(m_ApplyInst(BuiltinValueKind::SAddOver, m_SILArgument(RecArg), m_One()), 0))) return None; if (RecArg->getParent() != Header) return None; auto *Start = dyn_cast_or_null<IntegerLiteralInst>( RecArg->getIncomingValue(Preheader).getDef()); if (!Start) return None; if (RecNext != RecArg->getIncomingValue(OrigLatch)) return None; auto StartVal = Start->getValue(); auto EndVal = End->getValue(); if (StartVal.sgt(EndVal)) return None; auto Dist = EndVal - StartVal; if (Dist.getBitWidth() > 64) return None; if (Dist == 0) return None; return Dist.getZExtValue(); }
void ReleaseCodeMotionContext::computeCodeMotionGenKillSet() { for (SILBasicBlock *BB : PO->getPostOrder()) { auto *State = BlockStates[BB]; bool InterestBlock = false; for (auto I = BB->rbegin(), E = BB->rend(); I != E; ++I) { // Check whether this instruction blocks any RC root code motion. for (unsigned i = 0; i < RCRootVault.size(); ++i) { if (!State->BBMaxSet.test(i) || !mayBlockCodeMotion(&*I, RCRootVault[i])) continue; // This instruction blocks this RC root. InterestBlock = true; State->BBKillSet.set(i); State->BBGenSet.reset(i); } // If this is an epilogue release and we are freezing epilogue release // simply continue. if (FreezeEpilogueReleases && ERM.isEpilogueRelease(&*I)) continue; // If this is a release instruction, it also generates. if (isReleaseInstruction(&*I)) { unsigned idx = RCRootIndex[getRCRoot(&*I)]; State->BBGenSet.set(idx); assert(State->BBKillSet.test(idx) && "Killset computed incorrectly"); State->BBKillSet.reset(idx); InterestBlock = true; } } // Handle SILArgument, SILArgument can invalidate. for (unsigned i = 0; i < RCRootVault.size(); ++i) { SILArgument *A = dyn_cast<SILArgument>(RCRootVault[i]); if (!A || A->getParent() != BB) continue; InterestBlock = true; State->BBKillSet.set(i); State->BBGenSet.reset(i); } // Is this interesting to the last iteration of the data flow. if (!InterestBlock) continue; InterestBlocks.insert(BB); } }
/// Like ValueIsPHI but also check if the PHI has no source /// operands, i.e., it was just added. static SILArgument *ValueIsNewPHI(SILValue Val, SILSSAUpdater *Updater) { SILArgument *PHI = ValueIsPHI(Val, Updater); if (PHI) { auto *PhiBB = PHI->getParent(); size_t PhiIdx = PHI->getIndex(); // If all predecessor edges are 'not set' this is a new phi. for (auto *PredBB : PhiBB->getPreds()) { OperandValueArrayRef Edges = getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); assert(PhiIdx < Edges.size() && "Not enough edges!"); SILValue V = Edges[PhiIdx]; // Check for the 'not set' sentinel. if (V.getDef() != Updater->PHISentinel.get()) return nullptr; } return PHI; } return nullptr; }
void ConsumedResultToEpilogueRetainMatcher:: findMatchingRetains(SILBasicBlock *BB) { // Iterate over the instructions post-order and find retains associated with // return value. SILValue RV = SILValue(); for (auto II = BB->rbegin(), IE = BB->rend(); II != IE; ++II) { if (ReturnInst *RI = dyn_cast<ReturnInst>(&*II)) { RV = RI->getOperand(); break; } } // Somehow, we managed not to find a return value. if (!RV) return; // OK. we've found the return value, now iterate on the CFG to find all the // post-dominating retains. // // The ConsumedArgToEpilogueReleaseMatcher finds the final releases // in the following way. // // 1. If an instruction, which is not releaseinst nor releasevalue, that // could decrement reference count is found. bail out. // // 2. If a release is found and the release that can not be mapped to any // @owned argument. bail as this release may well be the final release of // an @owned argument, but somehow rc-identity fails to prove that. // // 3. A release that is mapped to an argument which already has a release // that overlaps with this release. This release for sure is not the final // release. constexpr unsigned WorkListMaxSize = 4; llvm::DenseSet<SILBasicBlock *> RetainFrees; llvm::SmallVector<BasicBlockRetainValue, 4> WorkList; llvm::DenseSet<SILBasicBlock *> HandledBBs; WorkList.push_back(std::make_pair(BB, RV)); HandledBBs.insert(BB); while (!WorkList.empty()) { // Too many blocks ?. if (WorkList.size() > WorkListMaxSize) { EpilogueRetainInsts.clear(); return; } // Try to find a retain %value in this basic block. auto R = WorkList.pop_back_val(); RetainKindValue Kind = findMatchingRetainsInBasicBlock(R.first, R.second); // We've found a retain on this path. if (Kind.first == FindRetainKind::Found) { EpilogueRetainInsts.push_back(Kind.second); continue; } // There is a MayDecrement instruction. if (Kind.first == FindRetainKind::Blocked) { EpilogueRetainInsts.clear(); return; } // There is a self-recursion. Use the apply instruction as the retain. if (Kind.first == FindRetainKind::Recursion) { EpilogueRetainInsts.push_back(Kind.second); continue; } // Did not find a retain in this block, try to go to its predecessors. if (Kind.first == FindRetainKind::None) { // We can not find a retain in a block with no predecessors. if (R.first->getPreds().begin() == R.first->getPreds().end()) { EpilogueRetainInsts.clear(); return; } // This block does not have a retain. RetainFrees.insert(R.first); // If this is a SILArgument of current basic block, we can split it up to // values in the predecessors. SILArgument *SA = dyn_cast<SILArgument>(R.second); if (SA && SA->getParent() != R.first) SA = nullptr; for (auto X : R.first->getPreds()) { if (HandledBBs.find(X) != HandledBBs.end()) continue; // Try to use the predecessor edge-value. if (SA && SA->getIncomingValue(X)) { WorkList.push_back(std::make_pair(X, SA->getIncomingValue(X))); } else WorkList.push_back(std::make_pair(X, R.second)); HandledBBs.insert(X); } } } // Lastly, check whether all the successor blocks are retain-free. if (!isTransitiveSuccessorsRetainFree(RetainFrees)) EpilogueRetainInsts.clear(); // At this point, we've either failed to find any epilogue retains or // all the post-dominating epilogue retains. }
void ReleaseCodeMotionContext::computeCodeMotionInsertPoints() { // The BBSetIns have converged, run last iteration and figure out insertion // point for each RC root. for (SILBasicBlock *BB : PO->getPostOrder()) { // Intersect in the successor BBSetIns. mergeBBDataFlowStates(BB); ReleaseBlockState *S = BlockStates[BB]; // Compute insertion point generated by the edge value transition. // If there is a transition from 1 to 0, that means we have a partial // merge, which means the release can NOT be hoisted to the current block. // place it at the successors. for (unsigned i = 0; i < RCRootVault.size(); ++i) { if (S->BBSetOut[i]) continue; for (auto &Succ : BB->getSuccessors()) { BlockState *SBB = BlockStates[Succ]; if (!SBB->BBSetIn[i]) continue; InsertPoints[RCRootVault[i]].push_back(&*(*Succ).begin()); } } // Is this block interesting ? if (MultiIteration && !InterestBlocks.count(BB)) continue; // Compute insertion point generated by MayUse terminator inst. // If terminator instruction can block the RC root. We will have no // choice but to anchor the release instructions in the successor blocks. for (unsigned i = 0; i < RCRootVault.size(); ++i) { SILInstruction *Term = BB->getTerminator(); if (!S->BBSetOut[i] || !mayBlockCodeMotion(Term, RCRootVault[i])) continue; for (auto &Succ : BB->getSuccessors()) { BlockState *SBB = BlockStates[Succ]; if (!SBB->BBSetIn[i]) continue; InsertPoints[RCRootVault[i]].push_back(&*(*Succ).begin()); } S->BBSetOut.reset(i); } // Compute insertion point generated within the basic block. Process // instructions in post-order fashion. for (auto I = std::next(BB->rbegin()), E = BB->rend(); I != E; ++I) { for (unsigned i = 0; i < RCRootVault.size(); ++i) { if (!S->BBSetOut[i] || !mayBlockCodeMotion(&*I, RCRootVault[i])) continue; auto *InsertPt = &*std::next(SILBasicBlock::iterator(&*I)); InsertPoints[RCRootVault[i]].push_back(InsertPt); S->BBSetOut.reset(i); } // If we are freezing this epilogue release. Simply continue. if (FreezeEpilogueReleases && ERM.isEpilogueRelease(&*I)) continue; // This release generates. if (isReleaseInstruction(&*I)) { S->BBSetOut.set(RCRootIndex[getRCRoot(&*I)]); } } // Compute insertion point generated by SILArgument. SILArgument blocks if // it defines the released value. for (unsigned i = 0; i < RCRootVault.size(); ++i) { if (!S->BBSetOut[i]) continue; SILArgument *A = dyn_cast<SILArgument>(RCRootVault[i]); if (!A || A->getParent() != BB) continue; InsertPoints[RCRootVault[i]].push_back(&*BB->begin()); S->BBSetOut.reset(i); } // Lastly update the BBSetIn, only necessary when we are running a single // iteration dataflow. if (!MultiIteration) { S->updateBBSetIn(S->BBSetOut); } } }