SILBasicBlock *swift::splitEdge(TermInst *T, unsigned EdgeIdx, DominanceInfo *DT, SILLoopInfo *LI) { auto *SrcBB = T->getParent(); auto *Fn = SrcBB->getParent(); SILBasicBlock *DestBB = T->getSuccessors()[EdgeIdx]; // Create a new basic block in the edge, and insert it after the SrcBB. auto *EdgeBB = new (Fn->getModule()) SILBasicBlock(Fn, SrcBB); SmallVector<SILValue, 16> Args; getEdgeArgs(T, EdgeIdx, EdgeBB, Args); SILBuilder(EdgeBB).createBranch(T->getLoc(), DestBB, Args); // Strip the arguments and rewire the branch in the source block. changeBranchTarget(T, EdgeIdx, EdgeBB, /*PreserveArgs=*/false); if (!DT && !LI) return EdgeBB; // Update the dominator tree. if (DT) { auto *SrcBBNode = DT->getNode(SrcBB); // Unreachable code could result in a null return here. if (SrcBBNode) { // The new block is dominated by the SrcBB. auto *EdgeBBNode = DT->addNewBlock(EdgeBB, SrcBB); // Are all predecessors of DestBB dominated by DestBB? auto *DestBBNode = DT->getNode(DestBB); bool OldSrcBBDominatesAllPreds = std::all_of( DestBB->pred_begin(), DestBB->pred_end(), [=](SILBasicBlock *B) { if (B == EdgeBB) return true; auto *PredNode = DT->getNode(B); if (!PredNode) return true; if (DT->dominates(DestBBNode, PredNode)) return true; return false; }); // If so, the new bb dominates DestBB now. if (OldSrcBBDominatesAllPreds) DT->changeImmediateDominator(DestBBNode, EdgeBBNode); } } if (!LI) return EdgeBB; // Update loop info. Both blocks must be in a loop otherwise the split block // is outside the loop. SILLoop *SrcBBLoop = LI->getLoopFor(SrcBB); if (!SrcBBLoop) return EdgeBB; SILLoop *DstBBLoop = LI->getLoopFor(DestBB); if (!DstBBLoop) return EdgeBB; // Same loop. if (DstBBLoop == SrcBBLoop) { DstBBLoop->addBasicBlockToLoop(EdgeBB, LI->getBase()); return EdgeBB; } // Edge from inner to outer loop. if (DstBBLoop->contains(SrcBBLoop)) { DstBBLoop->addBasicBlockToLoop(EdgeBB, LI->getBase()); return EdgeBB; } // Edge from outer to inner loop. if (SrcBBLoop->contains(DstBBLoop)) { SrcBBLoop->addBasicBlockToLoop(EdgeBB, LI->getBase()); return EdgeBB; } // Neither loop contains the other. The destination must be the header of its // loop. Otherwise, we would be creating irreducible control flow. assert(DstBBLoop->getHeader() == DestBB && "Creating irreducible control flow?"); // Add to outer loop if there is one. if (auto *Parent = DstBBLoop->getParentLoop()) Parent->addBasicBlockToLoop(EdgeBB, LI->getBase()); return EdgeBB; }
ShortestPathAnalysis::Weight ShortestPathAnalysis:: getWeight(SILBasicBlock *BB, Weight CallerWeight) { assert(BB->getParent() == F); SILLoop *Loop = LI->getLoopFor(BB); if (!Loop) { // We are not in a loop. So just account the length of our function scope // in to the length of the CallerWeight. return Weight(CallerWeight.ScopeLength + getScopeLength(BB, 0), CallerWeight.LoopWeight); } int LoopDepth = Loop->getLoopDepth(); // Deal with the corner case of having more than 4 nested loops. while (LoopDepth >= MaxNumLoopLevels) { --LoopDepth; Loop = Loop->getParentLoop(); } Weight W(getScopeLength(BB, LoopDepth), SingleLoopWeight); // Add weights for all the loops BB is in. while (Loop) { assert(LoopDepth > 0); BlockInfo *HeaderInfo = getBlockInfo(Loop->getHeader()); int InnerLoopLength = HeaderInfo->getScopeLength(LoopDepth) * ShortestPathAnalysis::LoopCount; int OuterLoopWeight = SingleLoopWeight; int OuterScopeLength = HeaderInfo->getScopeLength(LoopDepth - 1); // Reaching the outermost loop, we use the CallerWeight to get the outer // length+loopweight. if (LoopDepth == 1) { // If the apply in the caller is not in a significant loop, just stop with // what we have now. if (CallerWeight.LoopWeight < 4) return W; // If this function is part of the caller's scope length take the caller's // scope length. Note: this is not the case e.g. if the apply is in a // then-branch of an if-then-else in the caller and the else-branch is // the short path. if (CallerWeight.ScopeLength > OuterScopeLength) OuterScopeLength = CallerWeight.ScopeLength; OuterLoopWeight = CallerWeight.LoopWeight; } assert(OuterScopeLength >= InnerLoopLength); // If the current loop is only a small part of its outer loop, we don't // take the outer loop that much into account. Only if the current loop is // actually the "main part" in the outer loop we add the full loop weight // for the outer loop. if (OuterScopeLength < InnerLoopLength * 2) { W.LoopWeight += OuterLoopWeight - 1; } else if (OuterScopeLength < InnerLoopLength * 3) { W.LoopWeight += OuterLoopWeight - 2; } else if (OuterScopeLength < InnerLoopLength * 4) { W.LoopWeight += OuterLoopWeight - 3; } else { return W; } --LoopDepth; Loop = Loop->getParentLoop(); } assert(LoopDepth == 0); return W; }