diff --git a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp --- a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp +++ b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp @@ -1759,48 +1759,72 @@ bool AssignmentTrackingLowering::join( const BasicBlock &BB, const SmallPtrSet &Visited) { - BlockInfo BBLiveIn; - bool FirstJoin = true; - // LiveIn locs for BB is the join of the already-processed preds' LiveOut - // locs. + + SmallVector VisitedPreds; + // Ignore backedges if we have not visited the predecessor yet. As the + // predecessor hasn't yet had locations propagated into it, most locations + // will not yet be valid, so treat them as all being uninitialized and + // potentially valid. If a location guessed to be correct here is + // invalidated later, we will remove it when we revisit this block. This + // is essentially the same as initialising all LocKinds and Assignments to + // an implicit ⊥ value which is the identity value for the join operation. for (auto I = pred_begin(&BB), E = pred_end(&BB); I != E; I++) { - // Ignore backedges if we have not visited the predecessor yet. As the - // predecessor hasn't yet had locations propagated into it, most locations - // will not yet be valid, so treat them as all being uninitialized and - // potentially valid. If a location guessed to be correct here is - // invalidated later, we will remove it when we revisit this block. This - // is essentially the same as initialising all LocKinds and Assignments to - // an implicit ⊥ value which is the identity value for the join operation. const BasicBlock *Pred = *I; - if (!Visited.count(Pred)) - continue; + if (Visited.count(Pred)) + VisitedPreds.push_back(Pred); + } - auto PredLiveOut = LiveOut.find(Pred); - // Pred must have been processed already. See comment at start of this loop. - assert(PredLiveOut != LiveOut.end()); + // No preds visited yet. + if (VisitedPreds.empty()) { + auto It = LiveIn.try_emplace(&BB, BlockInfo()); + bool DidInsert = It.second; + if (DidInsert) + It.first->second.init(TrackedVariablesVectorSize); + return /*Changed*/ DidInsert; + } + + // Exactly one visited pred. Copy the LiveOut from that pred into BB LiveIn. + if (VisitedPreds.size() == 1) { + const BlockInfo &PredLiveOut = LiveOut.find(VisitedPreds[0])->second; + auto CurrentLiveInEntry = LiveIn.find(&BB); - // Perform the join of BBLiveIn (current live-in info) and PrevLiveOut. - if (FirstJoin) - BBLiveIn = PredLiveOut->second; + // Check if there isn't an entry, or there is but the LiveIn set has + // changed (expensive check). + if (CurrentLiveInEntry == LiveIn.end()) + LiveIn.insert(std::make_pair(&BB, PredLiveOut)); + else if (PredLiveOut != CurrentLiveInEntry->second) + CurrentLiveInEntry->second = PredLiveOut; else - BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second); - FirstJoin = false; + return /*Changed*/ false; + return /*Changed*/ true; } - if (FirstJoin) - BBLiveIn.init(TrackedVariablesVectorSize); + // More than one pred. Join LiveOuts of blocks 1 and 2. + assert(VisitedPreds.size() > 1); + const BlockInfo &PredLiveOut0 = LiveOut.find(VisitedPreds[0])->second; + const BlockInfo &PredLiveOut1 = LiveOut.find(VisitedPreds[1])->second; + BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1); + + // Join the LiveOuts of subsequent blocks. + ArrayRef Tail = ArrayRef(VisitedPreds).drop_front(2); + for (const BasicBlock *Pred : Tail) { + const auto &PredLiveOut = LiveOut.find(Pred); + assert(PredLiveOut != LiveOut.end() && + "block should have been processed already"); + BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second); + } + // Save the joined result for BB. auto CurrentLiveInEntry = LiveIn.find(&BB); // Check if there isn't an entry, or there is but the LiveIn set has changed // (expensive check). - if (CurrentLiveInEntry == LiveIn.end() || - BBLiveIn != CurrentLiveInEntry->second) { - LiveIn[&BB] = std::move(BBLiveIn); - // A change has occured. - return true; - } - // No change. - return false; + if (CurrentLiveInEntry == LiveIn.end()) + LiveIn.try_emplace(&BB, std::move(BBLiveIn)); + else if (BBLiveIn != CurrentLiveInEntry->second) + CurrentLiveInEntry->second = std::move(BBLiveIn); + else + return /*Changed*/ false; + return /*Changed*/ true; } /// Return true if A fully contains B.