xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- MergedLoadStoreMotion.cpp - merge and hoist/sink load/stores -------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //! \file
100b57cec5SDimitry Andric //! This pass performs merges of loads and stores on both sides of a
110b57cec5SDimitry Andric //  diamond (hammock). It hoists the loads and sinks the stores.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric // The algorithm iteratively hoists two loads to the same address out of a
140b57cec5SDimitry Andric // diamond (hammock) and merges them into a single load in the header. Similar
150b57cec5SDimitry Andric // it sinks and merges two stores to the tail block (footer). The algorithm
160b57cec5SDimitry Andric // iterates over the instructions of one side of the diamond and attempts to
178bcb0991SDimitry Andric // find a matching load/store on the other side. New tail/footer block may be
188bcb0991SDimitry Andric // insterted if the tail/footer block has more predecessors (not only the two
198bcb0991SDimitry Andric // predecessors that are forming the diamond). It hoists / sinks when it thinks
208bcb0991SDimitry Andric // it safe to do so.  This optimization helps with eg. hiding load latencies,
218bcb0991SDimitry Andric // triggering if-conversion, and reducing static code size.
220b57cec5SDimitry Andric //
230b57cec5SDimitry Andric // NOTE: This code no longer performs load hoisting, it is subsumed by GVNHoist.
240b57cec5SDimitry Andric //
250b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
260b57cec5SDimitry Andric //
270b57cec5SDimitry Andric //
280b57cec5SDimitry Andric // Example:
290b57cec5SDimitry Andric // Diamond shaped code before merge:
300b57cec5SDimitry Andric //
310b57cec5SDimitry Andric //            header:
320b57cec5SDimitry Andric //                     br %cond, label %if.then, label %if.else
330b57cec5SDimitry Andric //                        +                    +
340b57cec5SDimitry Andric //                       +                      +
350b57cec5SDimitry Andric //                      +                        +
360b57cec5SDimitry Andric //            if.then:                         if.else:
370b57cec5SDimitry Andric //               %lt = load %addr_l               %le = load %addr_l
380b57cec5SDimitry Andric //               <use %lt>                        <use %le>
390b57cec5SDimitry Andric //               <...>                            <...>
400b57cec5SDimitry Andric //               store %st, %addr_s               store %se, %addr_s
410b57cec5SDimitry Andric //               br label %if.end                 br label %if.end
420b57cec5SDimitry Andric //                     +                         +
430b57cec5SDimitry Andric //                      +                       +
440b57cec5SDimitry Andric //                       +                     +
450b57cec5SDimitry Andric //            if.end ("footer"):
460b57cec5SDimitry Andric //                     <...>
470b57cec5SDimitry Andric //
480b57cec5SDimitry Andric // Diamond shaped code after merge:
490b57cec5SDimitry Andric //
500b57cec5SDimitry Andric //            header:
510b57cec5SDimitry Andric //                     %l = load %addr_l
520b57cec5SDimitry Andric //                     br %cond, label %if.then, label %if.else
530b57cec5SDimitry Andric //                        +                    +
540b57cec5SDimitry Andric //                       +                      +
550b57cec5SDimitry Andric //                      +                        +
560b57cec5SDimitry Andric //            if.then:                         if.else:
570b57cec5SDimitry Andric //               <use %l>                         <use %l>
580b57cec5SDimitry Andric //               <...>                            <...>
590b57cec5SDimitry Andric //               br label %if.end                 br label %if.end
600b57cec5SDimitry Andric //                      +                        +
610b57cec5SDimitry Andric //                       +                      +
620b57cec5SDimitry Andric //                        +                    +
630b57cec5SDimitry Andric //            if.end ("footer"):
640b57cec5SDimitry Andric //                     %s.sink = phi [%st, if.then], [%se, if.else]
650b57cec5SDimitry Andric //                     <...>
660b57cec5SDimitry Andric //                     store %s.sink, %addr_s
670b57cec5SDimitry Andric //                     <...>
680b57cec5SDimitry Andric //
690b57cec5SDimitry Andric //
700b57cec5SDimitry Andric //===----------------------- TODO -----------------------------------------===//
710b57cec5SDimitry Andric //
720b57cec5SDimitry Andric // 1) Generalize to regions other than diamonds
730b57cec5SDimitry Andric // 2) Be more aggressive merging memory operations
740b57cec5SDimitry Andric // Note that both changes require register pressure control
750b57cec5SDimitry Andric //
760b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric #include "llvm/Transforms/Scalar/MergedLoadStoreMotion.h"
790b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
800b57cec5SDimitry Andric #include "llvm/Analysis/GlobalsModRef.h"
8106c3fb27SDimitry Andric #include "llvm/IR/IRBuilder.h"
8281ad6265SDimitry Andric #include "llvm/IR/Instructions.h"
830b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
840b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
850b57cec5SDimitry Andric #include "llvm/Transforms/Scalar.h"
860b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric using namespace llvm;
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric #define DEBUG_TYPE "mldst-motion"
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric namespace {
930b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
940b57cec5SDimitry Andric //                         MergedLoadStoreMotion Pass
950b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
960b57cec5SDimitry Andric class MergedLoadStoreMotion {
970b57cec5SDimitry Andric   AliasAnalysis *AA = nullptr;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   // The mergeLoad/Store algorithms could have Size0 * Size1 complexity,
1000b57cec5SDimitry Andric   // where Size0 and Size1 are the #instructions on the two sides of
1010b57cec5SDimitry Andric   // the diamond. The constant chosen here is arbitrary. Compiler Time
1020b57cec5SDimitry Andric   // Control is enforced by the check Size0 * Size1 < MagicCompileTimeControl.
1030b57cec5SDimitry Andric   const int MagicCompileTimeControl = 250;
1040b57cec5SDimitry Andric 
1058bcb0991SDimitry Andric   const bool SplitFooterBB;
1060b57cec5SDimitry Andric public:
MergedLoadStoreMotion(bool SplitFooterBB)1078bcb0991SDimitry Andric   MergedLoadStoreMotion(bool SplitFooterBB) : SplitFooterBB(SplitFooterBB) {}
1080b57cec5SDimitry Andric   bool run(Function &F, AliasAnalysis &AA);
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric private:
1110b57cec5SDimitry Andric   BasicBlock *getDiamondTail(BasicBlock *BB);
1120b57cec5SDimitry Andric   bool isDiamondHead(BasicBlock *BB);
1130b57cec5SDimitry Andric   // Routines for sinking stores
1140b57cec5SDimitry Andric   StoreInst *canSinkFromBlock(BasicBlock *BB, StoreInst *SI);
1150b57cec5SDimitry Andric   PHINode *getPHIOperand(BasicBlock *BB, StoreInst *S0, StoreInst *S1);
1160b57cec5SDimitry Andric   bool isStoreSinkBarrierInRange(const Instruction &Start,
1170b57cec5SDimitry Andric                                  const Instruction &End, MemoryLocation Loc);
1188bcb0991SDimitry Andric   bool canSinkStoresAndGEPs(StoreInst *S0, StoreInst *S1) const;
1198bcb0991SDimitry Andric   void sinkStoresAndGEPs(BasicBlock *BB, StoreInst *SinkCand,
1208bcb0991SDimitry Andric                          StoreInst *ElseInst);
1210b57cec5SDimitry Andric   bool mergeStores(BasicBlock *BB);
1220b57cec5SDimitry Andric };
1230b57cec5SDimitry Andric } // end anonymous namespace
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric ///
1260b57cec5SDimitry Andric /// Return tail block of a diamond.
1270b57cec5SDimitry Andric ///
getDiamondTail(BasicBlock * BB)1280b57cec5SDimitry Andric BasicBlock *MergedLoadStoreMotion::getDiamondTail(BasicBlock *BB) {
1290b57cec5SDimitry Andric   assert(isDiamondHead(BB) && "Basic block is not head of a diamond");
1300b57cec5SDimitry Andric   return BB->getTerminator()->getSuccessor(0)->getSingleSuccessor();
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric ///
1340b57cec5SDimitry Andric /// True when BB is the head of a diamond (hammock)
1350b57cec5SDimitry Andric ///
isDiamondHead(BasicBlock * BB)1360b57cec5SDimitry Andric bool MergedLoadStoreMotion::isDiamondHead(BasicBlock *BB) {
1370b57cec5SDimitry Andric   if (!BB)
1380b57cec5SDimitry Andric     return false;
1390b57cec5SDimitry Andric   auto *BI = dyn_cast<BranchInst>(BB->getTerminator());
1400b57cec5SDimitry Andric   if (!BI || !BI->isConditional())
1410b57cec5SDimitry Andric     return false;
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   BasicBlock *Succ0 = BI->getSuccessor(0);
1440b57cec5SDimitry Andric   BasicBlock *Succ1 = BI->getSuccessor(1);
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric   if (!Succ0->getSinglePredecessor())
1470b57cec5SDimitry Andric     return false;
1480b57cec5SDimitry Andric   if (!Succ1->getSinglePredecessor())
1490b57cec5SDimitry Andric     return false;
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   BasicBlock *Succ0Succ = Succ0->getSingleSuccessor();
1520b57cec5SDimitry Andric   BasicBlock *Succ1Succ = Succ1->getSingleSuccessor();
1530b57cec5SDimitry Andric   // Ignore triangles.
1540b57cec5SDimitry Andric   if (!Succ0Succ || !Succ1Succ || Succ0Succ != Succ1Succ)
1550b57cec5SDimitry Andric     return false;
1560b57cec5SDimitry Andric   return true;
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric ///
1610b57cec5SDimitry Andric /// True when instruction is a sink barrier for a store
1620b57cec5SDimitry Andric /// located in Loc
1630b57cec5SDimitry Andric ///
1640b57cec5SDimitry Andric /// Whenever an instruction could possibly read or modify the
1650b57cec5SDimitry Andric /// value being stored or protect against the store from
1660b57cec5SDimitry Andric /// happening it is considered a sink barrier.
1670b57cec5SDimitry Andric ///
isStoreSinkBarrierInRange(const Instruction & Start,const Instruction & End,MemoryLocation Loc)1680b57cec5SDimitry Andric bool MergedLoadStoreMotion::isStoreSinkBarrierInRange(const Instruction &Start,
1690b57cec5SDimitry Andric                                                       const Instruction &End,
1700b57cec5SDimitry Andric                                                       MemoryLocation Loc) {
1710b57cec5SDimitry Andric   for (const Instruction &Inst :
1720b57cec5SDimitry Andric        make_range(Start.getIterator(), End.getIterator()))
1730b57cec5SDimitry Andric     if (Inst.mayThrow())
1740b57cec5SDimitry Andric       return true;
1750b57cec5SDimitry Andric   return AA->canInstructionRangeModRef(Start, End, Loc, ModRefInfo::ModRef);
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric ///
1790b57cec5SDimitry Andric /// Check if \p BB contains a store to the same address as \p SI
1800b57cec5SDimitry Andric ///
1810b57cec5SDimitry Andric /// \return The store in \p  when it is safe to sink. Otherwise return Null.
1820b57cec5SDimitry Andric ///
canSinkFromBlock(BasicBlock * BB1,StoreInst * Store0)1830b57cec5SDimitry Andric StoreInst *MergedLoadStoreMotion::canSinkFromBlock(BasicBlock *BB1,
1840b57cec5SDimitry Andric                                                    StoreInst *Store0) {
1850b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "can Sink? : "; Store0->dump(); dbgs() << "\n");
1860b57cec5SDimitry Andric   BasicBlock *BB0 = Store0->getParent();
1870b57cec5SDimitry Andric   for (Instruction &Inst : reverse(*BB1)) {
1880b57cec5SDimitry Andric     auto *Store1 = dyn_cast<StoreInst>(&Inst);
1890b57cec5SDimitry Andric     if (!Store1)
1900b57cec5SDimitry Andric       continue;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric     MemoryLocation Loc0 = MemoryLocation::get(Store0);
1930b57cec5SDimitry Andric     MemoryLocation Loc1 = MemoryLocation::get(Store1);
19406c3fb27SDimitry Andric 
19506c3fb27SDimitry Andric     if (AA->isMustAlias(Loc0, Loc1) &&
1960b57cec5SDimitry Andric         !isStoreSinkBarrierInRange(*Store1->getNextNode(), BB1->back(), Loc1) &&
19706c3fb27SDimitry Andric         !isStoreSinkBarrierInRange(*Store0->getNextNode(), BB0->back(), Loc0) &&
19806c3fb27SDimitry Andric         Store0->hasSameSpecialState(Store1) &&
19906c3fb27SDimitry Andric         CastInst::isBitOrNoopPointerCastable(
20006c3fb27SDimitry Andric             Store0->getValueOperand()->getType(),
20106c3fb27SDimitry Andric             Store1->getValueOperand()->getType(),
202*0fca6ea1SDimitry Andric             Store0->getDataLayout()))
2030b57cec5SDimitry Andric       return Store1;
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric   return nullptr;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric ///
2090b57cec5SDimitry Andric /// Create a PHI node in BB for the operands of S0 and S1
2100b57cec5SDimitry Andric ///
getPHIOperand(BasicBlock * BB,StoreInst * S0,StoreInst * S1)2110b57cec5SDimitry Andric PHINode *MergedLoadStoreMotion::getPHIOperand(BasicBlock *BB, StoreInst *S0,
2120b57cec5SDimitry Andric                                               StoreInst *S1) {
2130b57cec5SDimitry Andric   // Create a phi if the values mismatch.
2140b57cec5SDimitry Andric   Value *Opd1 = S0->getValueOperand();
2150b57cec5SDimitry Andric   Value *Opd2 = S1->getValueOperand();
2160b57cec5SDimitry Andric   if (Opd1 == Opd2)
2170b57cec5SDimitry Andric     return nullptr;
2180b57cec5SDimitry Andric 
2195f757f3fSDimitry Andric   auto *NewPN = PHINode::Create(Opd1->getType(), 2, Opd2->getName() + ".sink");
2205f757f3fSDimitry Andric   NewPN->insertBefore(BB->begin());
2210b57cec5SDimitry Andric   NewPN->applyMergedLocation(S0->getDebugLoc(), S1->getDebugLoc());
2220b57cec5SDimitry Andric   NewPN->addIncoming(Opd1, S0->getParent());
2230b57cec5SDimitry Andric   NewPN->addIncoming(Opd2, S1->getParent());
2240b57cec5SDimitry Andric   return NewPN;
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric ///
228bdd1243dSDimitry Andric /// Check if 2 stores can be sunk, optionally together with corresponding GEPs.
2298bcb0991SDimitry Andric ///
canSinkStoresAndGEPs(StoreInst * S0,StoreInst * S1) const2308bcb0991SDimitry Andric bool MergedLoadStoreMotion::canSinkStoresAndGEPs(StoreInst *S0,
2318bcb0991SDimitry Andric                                                  StoreInst *S1) const {
232bdd1243dSDimitry Andric   if (S0->getPointerOperand() == S1->getPointerOperand())
233bdd1243dSDimitry Andric     return true;
234bdd1243dSDimitry Andric   auto *GEP0 = dyn_cast<GetElementPtrInst>(S0->getPointerOperand());
235bdd1243dSDimitry Andric   auto *GEP1 = dyn_cast<GetElementPtrInst>(S1->getPointerOperand());
236bdd1243dSDimitry Andric   return GEP0 && GEP1 && GEP0->isIdenticalTo(GEP1) && GEP0->hasOneUse() &&
237bdd1243dSDimitry Andric          (GEP0->getParent() == S0->getParent()) && GEP1->hasOneUse() &&
238bdd1243dSDimitry Andric          (GEP1->getParent() == S1->getParent());
2398bcb0991SDimitry Andric }
2408bcb0991SDimitry Andric 
2418bcb0991SDimitry Andric ///
2420b57cec5SDimitry Andric /// Merge two stores to same address and sink into \p BB
2430b57cec5SDimitry Andric ///
244bdd1243dSDimitry Andric /// Optionally also sinks GEP instruction computing the store address
2450b57cec5SDimitry Andric ///
sinkStoresAndGEPs(BasicBlock * BB,StoreInst * S0,StoreInst * S1)2468bcb0991SDimitry Andric void MergedLoadStoreMotion::sinkStoresAndGEPs(BasicBlock *BB, StoreInst *S0,
2470b57cec5SDimitry Andric                                               StoreInst *S1) {
248bdd1243dSDimitry Andric   Value *Ptr0 = S0->getPointerOperand();
249bdd1243dSDimitry Andric   Value *Ptr1 = S1->getPointerOperand();
2500b57cec5SDimitry Andric   // Only one definition?
2510b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Sink Instruction into BB \n"; BB->dump();
2520b57cec5SDimitry Andric              dbgs() << "Instruction Left\n"; S0->dump(); dbgs() << "\n";
2530b57cec5SDimitry Andric              dbgs() << "Instruction Right\n"; S1->dump(); dbgs() << "\n");
2540b57cec5SDimitry Andric   // Hoist the instruction.
2550b57cec5SDimitry Andric   BasicBlock::iterator InsertPt = BB->getFirstInsertionPt();
2560b57cec5SDimitry Andric   // Intersect optional metadata.
2570b57cec5SDimitry Andric   S0->andIRFlags(S1);
2580b57cec5SDimitry Andric   S0->dropUnknownNonDebugMetadata();
259bdd1243dSDimitry Andric   S0->applyMergedLocation(S0->getDebugLoc(), S1->getDebugLoc());
260bdd1243dSDimitry Andric   S0->mergeDIAssignID(S1);
2610b57cec5SDimitry Andric 
26206c3fb27SDimitry Andric   // Insert bitcast for conflicting typed stores (or just use original value if
26306c3fb27SDimitry Andric   // same type).
26406c3fb27SDimitry Andric   IRBuilder<> Builder(S0);
26506c3fb27SDimitry Andric   auto Cast = Builder.CreateBitOrPointerCast(S0->getValueOperand(),
26606c3fb27SDimitry Andric                                              S1->getValueOperand()->getType());
26706c3fb27SDimitry Andric   S0->setOperand(0, Cast);
26806c3fb27SDimitry Andric 
2690b57cec5SDimitry Andric   // Create the new store to be inserted at the join point.
2700b57cec5SDimitry Andric   StoreInst *SNew = cast<StoreInst>(S0->clone());
2715f757f3fSDimitry Andric   SNew->insertBefore(InsertPt);
2720b57cec5SDimitry Andric   // New PHI operand? Use it.
2730b57cec5SDimitry Andric   if (PHINode *NewPN = getPHIOperand(BB, S0, S1))
2740b57cec5SDimitry Andric     SNew->setOperand(0, NewPN);
2750b57cec5SDimitry Andric   S0->eraseFromParent();
2760b57cec5SDimitry Andric   S1->eraseFromParent();
277bdd1243dSDimitry Andric 
278bdd1243dSDimitry Andric   if (Ptr0 != Ptr1) {
279bdd1243dSDimitry Andric     auto *GEP0 = cast<GetElementPtrInst>(Ptr0);
280bdd1243dSDimitry Andric     auto *GEP1 = cast<GetElementPtrInst>(Ptr1);
281bdd1243dSDimitry Andric     Instruction *GEPNew = GEP0->clone();
282bdd1243dSDimitry Andric     GEPNew->insertBefore(SNew);
283bdd1243dSDimitry Andric     GEPNew->applyMergedLocation(GEP0->getDebugLoc(), GEP1->getDebugLoc());
284bdd1243dSDimitry Andric     SNew->setOperand(1, GEPNew);
285bdd1243dSDimitry Andric     GEP0->replaceAllUsesWith(GEPNew);
286bdd1243dSDimitry Andric     GEP0->eraseFromParent();
287bdd1243dSDimitry Andric     GEP1->replaceAllUsesWith(GEPNew);
288bdd1243dSDimitry Andric     GEP1->eraseFromParent();
289bdd1243dSDimitry Andric   }
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric ///
2930b57cec5SDimitry Andric /// True when two stores are equivalent and can sink into the footer
2940b57cec5SDimitry Andric ///
2958bcb0991SDimitry Andric /// Starting from a diamond head block, iterate over the instructions in one
2968bcb0991SDimitry Andric /// successor block and try to match a store in the second successor.
2970b57cec5SDimitry Andric ///
mergeStores(BasicBlock * HeadBB)2988bcb0991SDimitry Andric bool MergedLoadStoreMotion::mergeStores(BasicBlock *HeadBB) {
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric   bool MergedStores = false;
3018bcb0991SDimitry Andric   BasicBlock *TailBB = getDiamondTail(HeadBB);
3028bcb0991SDimitry Andric   BasicBlock *SinkBB = TailBB;
3038bcb0991SDimitry Andric   assert(SinkBB && "Footer of a diamond cannot be empty");
3040b57cec5SDimitry Andric 
3058bcb0991SDimitry Andric   succ_iterator SI = succ_begin(HeadBB);
3068bcb0991SDimitry Andric   assert(SI != succ_end(HeadBB) && "Diamond head cannot have zero successors");
3078bcb0991SDimitry Andric   BasicBlock *Pred0 = *SI;
3088bcb0991SDimitry Andric   ++SI;
3098bcb0991SDimitry Andric   assert(SI != succ_end(HeadBB) && "Diamond head cannot have single successor");
3108bcb0991SDimitry Andric   BasicBlock *Pred1 = *SI;
3110b57cec5SDimitry Andric   // tail block  of a diamond/hammock?
3120b57cec5SDimitry Andric   if (Pred0 == Pred1)
3130b57cec5SDimitry Andric     return false; // No.
3148bcb0991SDimitry Andric   // bail out early if we can not merge into the footer BB
3158bcb0991SDimitry Andric   if (!SplitFooterBB && TailBB->hasNPredecessorsOrMore(3))
3168bcb0991SDimitry Andric     return false;
3178bcb0991SDimitry Andric   // #Instructions in Pred1 for Compile Time Control
3180b57cec5SDimitry Andric   auto InstsNoDbg = Pred1->instructionsWithoutDebug();
3190b57cec5SDimitry Andric   int Size1 = std::distance(InstsNoDbg.begin(), InstsNoDbg.end());
3200b57cec5SDimitry Andric   int NStores = 0;
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric   for (BasicBlock::reverse_iterator RBI = Pred0->rbegin(), RBE = Pred0->rend();
3230b57cec5SDimitry Andric        RBI != RBE;) {
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric     Instruction *I = &*RBI;
3260b57cec5SDimitry Andric     ++RBI;
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric     // Don't sink non-simple (atomic, volatile) stores.
3290b57cec5SDimitry Andric     auto *S0 = dyn_cast<StoreInst>(I);
3300b57cec5SDimitry Andric     if (!S0 || !S0->isSimple())
3310b57cec5SDimitry Andric       continue;
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric     ++NStores;
3340b57cec5SDimitry Andric     if (NStores * Size1 >= MagicCompileTimeControl)
3350b57cec5SDimitry Andric       break;
3360b57cec5SDimitry Andric     if (StoreInst *S1 = canSinkFromBlock(Pred1, S0)) {
3378bcb0991SDimitry Andric       if (!canSinkStoresAndGEPs(S0, S1))
3380b57cec5SDimitry Andric         // Don't attempt to sink below stores that had to stick around
3390b57cec5SDimitry Andric         // But after removal of a store and some of its feeding
3400b57cec5SDimitry Andric         // instruction search again from the beginning since the iterator
3410b57cec5SDimitry Andric         // is likely stale at this point.
3420b57cec5SDimitry Andric         break;
3438bcb0991SDimitry Andric 
3448bcb0991SDimitry Andric       if (SinkBB == TailBB && TailBB->hasNPredecessorsOrMore(3)) {
3458bcb0991SDimitry Andric         // We have more than 2 predecessors. Insert a new block
3468bcb0991SDimitry Andric         // postdominating 2 predecessors we're going to sink from.
3478bcb0991SDimitry Andric         SinkBB = SplitBlockPredecessors(TailBB, {Pred0, Pred1}, ".sink.split");
3488bcb0991SDimitry Andric         if (!SinkBB)
3498bcb0991SDimitry Andric           break;
3508bcb0991SDimitry Andric       }
3518bcb0991SDimitry Andric 
3528bcb0991SDimitry Andric       MergedStores = true;
3538bcb0991SDimitry Andric       sinkStoresAndGEPs(SinkBB, S0, S1);
3540b57cec5SDimitry Andric       RBI = Pred0->rbegin();
3550b57cec5SDimitry Andric       RBE = Pred0->rend();
3560b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Search again\n"; Instruction *I = &*RBI; I->dump());
3570b57cec5SDimitry Andric     }
3580b57cec5SDimitry Andric   }
3590b57cec5SDimitry Andric   return MergedStores;
3600b57cec5SDimitry Andric }
3610b57cec5SDimitry Andric 
run(Function & F,AliasAnalysis & AA)3620b57cec5SDimitry Andric bool MergedLoadStoreMotion::run(Function &F, AliasAnalysis &AA) {
3630b57cec5SDimitry Andric   this->AA = &AA;
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric   bool Changed = false;
3660b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Instruction Merger\n");
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   // Merge unconditional branches, allowing PRE to catch more
3690b57cec5SDimitry Andric   // optimization opportunities.
3708bcb0991SDimitry Andric   // This loop doesn't care about newly inserted/split blocks
3718bcb0991SDimitry Andric   // since they never will be diamond heads.
3725ffd83dbSDimitry Andric   for (BasicBlock &BB : make_early_inc_range(F))
3730b57cec5SDimitry Andric     // Hoist equivalent loads and sink stores
3740b57cec5SDimitry Andric     // outside diamonds when possible
3755ffd83dbSDimitry Andric     if (isDiamondHead(&BB))
3765ffd83dbSDimitry Andric       Changed |= mergeStores(&BB);
3770b57cec5SDimitry Andric   return Changed;
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric PreservedAnalyses
run(Function & F,FunctionAnalysisManager & AM)3810b57cec5SDimitry Andric MergedLoadStoreMotionPass::run(Function &F, FunctionAnalysisManager &AM) {
3828bcb0991SDimitry Andric   MergedLoadStoreMotion Impl(Options.SplitFooterBB);
3830b57cec5SDimitry Andric   auto &AA = AM.getResult<AAManager>(F);
3840b57cec5SDimitry Andric   if (!Impl.run(F, AA))
3850b57cec5SDimitry Andric     return PreservedAnalyses::all();
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric   PreservedAnalyses PA;
3888bcb0991SDimitry Andric   if (!Options.SplitFooterBB)
3890b57cec5SDimitry Andric     PA.preserveSet<CFGAnalyses>();
3900b57cec5SDimitry Andric   return PA;
3910b57cec5SDimitry Andric }
392349cc55cSDimitry Andric 
printPipeline(raw_ostream & OS,function_ref<StringRef (StringRef)> MapClassName2PassName)393349cc55cSDimitry Andric void MergedLoadStoreMotionPass::printPipeline(
394349cc55cSDimitry Andric     raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
395349cc55cSDimitry Andric   static_cast<PassInfoMixin<MergedLoadStoreMotionPass> *>(this)->printPipeline(
396349cc55cSDimitry Andric       OS, MapClassName2PassName);
39706c3fb27SDimitry Andric   OS << '<';
398349cc55cSDimitry Andric   OS << (Options.SplitFooterBB ? "" : "no-") << "split-footer-bb";
39906c3fb27SDimitry Andric   OS << '>';
400349cc55cSDimitry Andric }
401