[llvm] [LICM] Drop control-flow hoisting support (PR #225630)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 01:04:37 PDT 2026


https://github.com/antoniofrighetto created https://github.com/llvm/llvm-project/pull/225630

Control-flow hoisting handling in LICM was originally introduced for hoisting PNs as part of a delayed phi-to-select conversion effort, whose enabling however was soon reverted to due compile-time regressions and the direction never pursued further. As such, unmaintained code has been removed.

>From 74c3f9414f0ecf3980e67aa4fa9ba69b413af5ec Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Wed, 23 Sep 2026 09:52:02 +0200
Subject: [PATCH] [LICM] Drop control-flow hoisting support

Control-flow hoisting handling in LICM was originally introduced
for hoisting PNs as part of a delayed phi-to-select conversion
effort, whose enabling however was soon reverted to due compile-time
regressions and the direction never pursued further. As such,
unmaintained code has been removed.
---
 llvm/lib/Transforms/Scalar/LICM.cpp           |  346 +---
 .../Transforms/LICM/hoist-phi-metadata.ll     |   72 -
 llvm/test/Transforms/LICM/hoist-phi.ll        | 1541 -----------------
 llvm/test/Transforms/LICM/pr40317.ll          |   62 -
 4 files changed, 16 insertions(+), 2005 deletions(-)
 delete mode 100644 llvm/test/Transforms/LICM/hoist-phi-metadata.ll
 delete mode 100644 llvm/test/Transforms/LICM/hoist-phi.ll
 delete mode 100644 llvm/test/Transforms/LICM/pr40317.ll

diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 17c1e927b14b00..c4335754e6c813 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -39,7 +39,6 @@
 #include "llvm/Transforms/Scalar/LICM.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PriorityWorklist.h"
-#include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/AliasSetTracker.h"
@@ -96,8 +95,6 @@ class LPMUpdater;
 
 #define DEBUG_TYPE "licm"
 
-STATISTIC(NumCreatedBlocks, "Number of blocks created");
-STATISTIC(NumClonedBranches, "Number of branches cloned");
 STATISTIC(NumSunk, "Number of instructions sunk out of loop");
 STATISTIC(NumHoisted, "Number of instructions hoisted out of loop");
 STATISTIC(NumMovedLoads, "Number of load insts hoisted or sunk");
@@ -124,10 +121,6 @@ static cl::opt<bool>
     DisablePromotion("disable-licm-promotion", cl::Hidden, cl::init(false),
                      cl::desc("Disable memory promotion in LICM pass"));
 
-static cl::opt<bool> ControlFlowHoisting(
-    "licm-control-flow-hoisting", cl::Hidden, cl::init(false),
-    cl::desc("Enable control flow (and PHI) hoisting in LICM"));
-
 static cl::opt<uint32_t> MaxNumUsesTraversed(
     "licm-max-num-uses-traversed", cl::Hidden, cl::init(8),
     cl::desc("Max num uses visited for identifying load "
@@ -199,12 +192,11 @@ static bool hoistArithmetics(Instruction &I, Loop &L,
                              ICFLoopSafetyInfo &SafetyInfo,
                              MemorySSAUpdater &MSSAU, AssumptionCache *AC,
                              DominatorTree *DT);
-static bool
-hoistInsertPastInsert(InsertElementInst *Ins, Loop *CurLoop, DominatorTree *DT,
-                      BasicBlock *HoistDest, ICFLoopSafetyInfo *SafetyInfo,
-                      MemorySSAUpdater &MSSAU, ScalarEvolution *SE,
-                      OptimizationRemarkEmitter *ORE,
-                      SmallVectorImpl<Instruction *> &HoistedInstructions);
+static bool hoistInsertPastInsert(InsertElementInst *Ins, Loop *CurLoop,
+                                  DominatorTree *DT, BasicBlock *HoistDest,
+                                  ICFLoopSafetyInfo *SafetyInfo,
+                                  MemorySSAUpdater &MSSAU, ScalarEvolution *SE,
+                                  OptimizationRemarkEmitter *ORE);
 static Instruction *cloneInstructionInExitBlock(
     Instruction &I, BasicBlock &ExitBlock, PHINode &PN, const LoopInfo *LI,
     const LoopSafetyInfo *SafetyInfo, MemorySSAUpdater &MSSAU);
@@ -645,242 +637,6 @@ bool llvm::sinkRegionForLoopNest(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
   return Changed;
 }
 
-namespace {
-// This is a helper class for hoistRegion to make it able to hoist control flow
-// in order to be able to hoist phis. The way this works is that we initially
-// start hoisting to the loop preheader, and when we see a loop invariant branch
-// we make note of this. When we then come to hoist an instruction that's
-// conditional on such a branch we duplicate the branch and the relevant control
-// flow, then hoist the instruction into the block corresponding to its original
-// block in the duplicated control flow.
-class ControlFlowHoister {
-private:
-  // Information about the loop we are hoisting from
-  LoopInfo *LI;
-  DominatorTree *DT;
-  Loop *CurLoop;
-  MemorySSAUpdater &MSSAU;
-
-  // A map of blocks in the loop to the block their instructions will be hoisted
-  // to.
-  DenseMap<BasicBlock *, BasicBlock *> HoistDestinationMap;
-
-  // The branches that we can hoist, mapped to the block that marks a
-  // convergence point of their control flow.
-  DenseMap<CondBrInst *, BasicBlock *> HoistableBranches;
-
-public:
-  ControlFlowHoister(LoopInfo *LI, DominatorTree *DT, Loop *CurLoop,
-                     MemorySSAUpdater &MSSAU)
-      : LI(LI), DT(DT), CurLoop(CurLoop), MSSAU(MSSAU) {}
-
-  void registerPossiblyHoistableBranch(CondBrInst *BI) {
-    // We can only hoist conditional branches with loop invariant operands.
-    if (!ControlFlowHoisting || !CurLoop->hasLoopInvariantOperands(BI))
-      return;
-
-    // The branch destinations need to be in the loop, and we don't gain
-    // anything by duplicating conditional branches with duplicate successors,
-    // as it's essentially the same as an unconditional branch.
-    BasicBlock *TrueDest = BI->getSuccessor(0);
-    BasicBlock *FalseDest = BI->getSuccessor(1);
-    if (!CurLoop->contains(TrueDest) || !CurLoop->contains(FalseDest) ||
-        TrueDest == FalseDest)
-      return;
-
-    // We can hoist BI if one branch destination is the successor of the other,
-    // or both have common successor which we check by seeing if the
-    // intersection of their successors is non-empty.
-    // TODO: This could be expanded to allowing branches where both ends
-    // eventually converge to a single block.
-    SmallPtrSet<BasicBlock *, 4> TrueDestSucc(llvm::from_range,
-                                              successors(TrueDest));
-    SmallPtrSet<BasicBlock *, 4> FalseDestSucc(llvm::from_range,
-                                               successors(FalseDest));
-    BasicBlock *CommonSucc = nullptr;
-    if (TrueDestSucc.count(FalseDest)) {
-      CommonSucc = FalseDest;
-    } else if (FalseDestSucc.count(TrueDest)) {
-      CommonSucc = TrueDest;
-    } else {
-      set_intersect(TrueDestSucc, FalseDestSucc);
-      // If there's one common successor use that.
-      if (TrueDestSucc.size() == 1)
-        CommonSucc = *TrueDestSucc.begin();
-      // If there's more than one pick whichever appears first in the block list
-      // (we can't use the value returned by TrueDestSucc.begin() as it's
-      // unpredicatable which element gets returned).
-      else if (!TrueDestSucc.empty()) {
-        Function *F = TrueDest->getParent();
-        auto IsSucc = [&](BasicBlock &BB) { return TrueDestSucc.count(&BB); };
-        auto It = llvm::find_if(*F, IsSucc);
-        assert(It != F->end() && "Could not find successor in function");
-        CommonSucc = &*It;
-      }
-    }
-    // The common successor has to be dominated by the branch, as otherwise
-    // there will be some other path to the successor that will not be
-    // controlled by this branch so any phi we hoist would be controlled by the
-    // wrong condition. This also takes care of avoiding hoisting of loop back
-    // edges.
-    // TODO: In some cases this could be relaxed if the successor is dominated
-    // by another block that's been hoisted and we can guarantee that the
-    // control flow has been replicated exactly.
-    if (CommonSucc && DT->dominates(BI, CommonSucc))
-      HoistableBranches[BI] = CommonSucc;
-  }
-
-  bool canHoistPHI(PHINode *PN) {
-    // The phi must have loop invariant operands.
-    if (!ControlFlowHoisting || !CurLoop->hasLoopInvariantOperands(PN))
-      return false;
-    // We can hoist phis if the block they are in is the target of hoistable
-    // branches which cover all of the predecessors of the block.
-    BasicBlock *BB = PN->getParent();
-    SmallPtrSet<BasicBlock *, 8> PredecessorBlocks(llvm::from_range,
-                                                   predecessors(BB));
-    // If we have less predecessor blocks than predecessors then the phi will
-    // have more than one incoming value for the same block which we can't
-    // handle.
-    // TODO: This could be handled be erasing some of the duplicate incoming
-    // values.
-    if (PredecessorBlocks.size() != pred_size(BB))
-      return false;
-    for (auto &Pair : HoistableBranches) {
-      if (Pair.second == BB) {
-        // Which blocks are predecessors via this branch depends on if the
-        // branch is triangle-like or diamond-like.
-        if (Pair.first->getSuccessor(0) == BB) {
-          PredecessorBlocks.erase(Pair.first->getParent());
-          PredecessorBlocks.erase(Pair.first->getSuccessor(1));
-        } else if (Pair.first->getSuccessor(1) == BB) {
-          PredecessorBlocks.erase(Pair.first->getParent());
-          PredecessorBlocks.erase(Pair.first->getSuccessor(0));
-        } else {
-          PredecessorBlocks.erase(Pair.first->getSuccessor(0));
-          PredecessorBlocks.erase(Pair.first->getSuccessor(1));
-        }
-      }
-    }
-    // PredecessorBlocks will now be empty if for every predecessor of BB we
-    // found a hoistable branch source.
-    return PredecessorBlocks.empty();
-  }
-
-  BasicBlock *getOrCreateHoistedBlock(BasicBlock *BB) {
-    if (!ControlFlowHoisting)
-      return CurLoop->getLoopPreheader();
-    // If BB has already been hoisted, return that
-    if (auto It = HoistDestinationMap.find(BB); It != HoistDestinationMap.end())
-      return It->second;
-
-    // Check if this block is conditional based on a pending branch
-    auto HasBBAsSuccessor =
-        [&](DenseMap<CondBrInst *, BasicBlock *>::value_type &Pair) {
-          return BB != Pair.second && (Pair.first->getSuccessor(0) == BB ||
-                                       Pair.first->getSuccessor(1) == BB);
-        };
-    auto It = llvm::find_if(HoistableBranches, HasBBAsSuccessor);
-
-    // If not involved in a pending branch, hoist to preheader
-    BasicBlock *InitialPreheader = CurLoop->getLoopPreheader();
-    if (It == HoistableBranches.end()) {
-      LLVM_DEBUG(dbgs() << "LICM using "
-                        << InitialPreheader->getNameOrAsOperand()
-                        << " as hoist destination for "
-                        << BB->getNameOrAsOperand() << "\n");
-      HoistDestinationMap[BB] = InitialPreheader;
-      return InitialPreheader;
-    }
-    CondBrInst *BI = It->first;
-    assert(std::none_of(std::next(It), HoistableBranches.end(),
-                        HasBBAsSuccessor) &&
-           "BB is expected to be the target of at most one branch");
-
-    LLVMContext &C = BB->getContext();
-    BasicBlock *TrueDest = BI->getSuccessor(0);
-    BasicBlock *FalseDest = BI->getSuccessor(1);
-    BasicBlock *CommonSucc = HoistableBranches[BI];
-    BasicBlock *HoistTarget = getOrCreateHoistedBlock(BI->getParent());
-
-    // Create hoisted versions of blocks that currently don't have them
-    auto CreateHoistedBlock = [&](BasicBlock *Orig) {
-      auto [It, Inserted] = HoistDestinationMap.try_emplace(Orig);
-      if (!Inserted)
-        return It->second;
-      BasicBlock *New =
-          BasicBlock::Create(C, Orig->getName() + ".licm", Orig->getParent());
-      It->second = New;
-      DT->addNewBlock(New, HoistTarget);
-      if (CurLoop->getParentLoop())
-        CurLoop->getParentLoop()->addBasicBlockToLoop(New, *LI);
-      ++NumCreatedBlocks;
-      LLVM_DEBUG(dbgs() << "LICM created " << New->getName()
-                        << " as hoist destination for " << Orig->getName()
-                        << "\n");
-      return New;
-    };
-    BasicBlock *HoistTrueDest = CreateHoistedBlock(TrueDest);
-    BasicBlock *HoistFalseDest = CreateHoistedBlock(FalseDest);
-    BasicBlock *HoistCommonSucc = CreateHoistedBlock(CommonSucc);
-
-    // Link up these blocks with branches.
-    if (!HoistCommonSucc->hasTerminator()) {
-      // The new common successor we've generated will branch to whatever that
-      // hoist target branched to.
-      BasicBlock *TargetSucc = HoistTarget->getSingleSuccessor();
-      assert(TargetSucc && "Expected hoist target to have a single successor");
-      HoistCommonSucc->moveBefore(TargetSucc);
-      UncondBrInst::Create(TargetSucc, HoistCommonSucc);
-    }
-    if (!HoistTrueDest->hasTerminator()) {
-      HoistTrueDest->moveBefore(HoistCommonSucc);
-      UncondBrInst::Create(HoistCommonSucc, HoistTrueDest);
-    }
-    if (!HoistFalseDest->hasTerminator()) {
-      HoistFalseDest->moveBefore(HoistCommonSucc);
-      UncondBrInst::Create(HoistCommonSucc, HoistFalseDest);
-    }
-
-    // If BI is being cloned to what was originally the preheader then
-    // HoistCommonSucc will now be the new preheader.
-    if (HoistTarget == InitialPreheader) {
-      // Phis in the loop header now need to use the new preheader.
-      InitialPreheader->replaceSuccessorsPhiUsesWith(HoistCommonSucc);
-      MSSAU.wireOldPredecessorsToNewImmediatePredecessor(
-          HoistTarget->getSingleSuccessor(), HoistCommonSucc, {HoistTarget});
-      // The new preheader dominates the loop header.
-      DomTreeNode *PreheaderNode = DT->getNode(HoistCommonSucc);
-      DomTreeNode *HeaderNode = DT->getNode(CurLoop->getHeader());
-      DT->changeImmediateDominator(HeaderNode, PreheaderNode);
-      // The preheader hoist destination is now the new preheader, with the
-      // exception of the hoist destination of this branch.
-      for (auto &Pair : HoistDestinationMap)
-        if (Pair.second == InitialPreheader && Pair.first != BI->getParent())
-          Pair.second = HoistCommonSucc;
-    }
-
-    // Now finally clone BI.
-    auto *NewBI =
-        CondBrInst::Create(BI->getCondition(), HoistTrueDest, HoistFalseDest,
-                           HoistTarget->getTerminator()->getIterator());
-    HoistTarget->getTerminator()->eraseFromParent();
-    // md_prof should also come from the original branch - since the
-    // condition was hoisted, the branch probabilities shouldn't change.
-    NewBI->copyMetadata(*BI, {LLVMContext::MD_prof});
-    // FIXME: Issue #152767: debug info should also be the same as the
-    // original branch, **if** the user explicitly indicated that.
-    NewBI->setDebugLoc(HoistTarget->getTerminator()->getDebugLoc());
-
-    ++NumClonedBranches;
-
-    assert(CurLoop->getLoopPreheader() &&
-           "Hoisting blocks should not have destroyed preheader");
-    return HoistDestinationMap[BB];
-  }
-};
-} // namespace
-
 /// Walk the specified region of the CFG (defined by all blocks dominated by
 /// the specified block, and that are in the current loop) in depth first
 /// order w.r.t the DominatorTree.  This allows us to visit definitions before
@@ -899,15 +655,6 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
          CurLoop != nullptr && SafetyInfo != nullptr &&
          "Unexpected input to hoistRegion.");
 
-  ControlFlowHoister CFH(LI, DT, CurLoop, MSSAU);
-
-  // Keep track of instructions that have been hoisted, as they may need to be
-  // re-hoisted if they end up not dominating all of their uses.
-  SmallVector<Instruction *, 16> HoistedInstructions;
-
-  // For PHI hoisting to work we need to hoist blocks before their successors.
-  // We can do this by iterating through the blocks in the loop in reverse
-  // post-order.
   LoopBlocksRPO Worklist(CurLoop);
   Worklist.perform(LI);
   bool Changed = false;
@@ -922,25 +669,19 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
       // Try hoisting the instruction out to the preheader.  We can only do
       // this if all of the operands of the instruction are loop invariant and
       // if it is safe to hoist the instruction.
-      // TODO: It may be safe to hoist if we are hoisting to a conditional block
-      // and we have accurately duplicated the control flow from the loop header
-      // to that block.
       if (CurLoop->hasLoopInvariantOperands(&I) &&
           canSinkOrHoistInst(I, AA, DT, CurLoop, MSSAU, true, Flags, ORE) &&
           isSafeToExecuteUnconditionally(I, DT, TLI, CurLoop, SafetyInfo, ORE,
                                          Preheader->getTerminator(), AC,
                                          AllowSpeculation)) {
-        hoist(I, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
-              MSSAU, SE, ORE);
-        HoistedInstructions.push_back(&I);
+        hoist(I, DT, CurLoop, Preheader, SafetyInfo, MSSAU, SE, ORE);
         Changed = true;
         continue;
       }
 
       if (auto *Ins = dyn_cast<InsertElementInst>(&I))
-        if (hoistInsertPastInsert(Ins, CurLoop, DT,
-                                  CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
-                                  MSSAU, SE, ORE, HoistedInstructions)) {
+        if (hoistInsertPastInsert(Ins, CurLoop, DT, Preheader, SafetyInfo,
+                                  MSSAU, SE, ORE)) {
           Changed = true;
           continue;
         }
@@ -966,9 +707,8 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
         I.replaceAllUsesWith(Product);
         eraseInstruction(I, *SafetyInfo, MSSAU);
 
-        hoist(*ReciprocalDivisor, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB),
-              SafetyInfo, MSSAU, SE, ORE);
-        HoistedInstructions.push_back(ReciprocalDivisor);
+        hoist(*ReciprocalDivisor, DT, CurLoop, Preheader, SafetyInfo, MSSAU, SE,
+              ORE);
         Changed = true;
         continue;
       }
@@ -985,72 +725,20 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
       if ((IsInvariantStart(I) || isGuard(&I)) &&
           CurLoop->hasLoopInvariantOperands(&I) &&
           MustExecuteWithoutWritesBefore(I)) {
-        hoist(I, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
-              MSSAU, SE, ORE);
-        HoistedInstructions.push_back(&I);
+        hoist(I, DT, CurLoop, Preheader, SafetyInfo, MSSAU, SE, ORE);
         Changed = true;
         continue;
       }
 
-      if (PHINode *PN = dyn_cast<PHINode>(&I)) {
-        if (CFH.canHoistPHI(PN)) {
-          // Redirect incoming blocks first to ensure that we create hoisted
-          // versions of those blocks before we hoist the phi.
-          for (unsigned int i = 0; i < PN->getNumIncomingValues(); ++i)
-            PN->setIncomingBlock(
-                i, CFH.getOrCreateHoistedBlock(PN->getIncomingBlock(i)));
-          hoist(*PN, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
-                MSSAU, SE, ORE);
-          assert(DT->dominates(PN, BB) && "Conditional PHIs not expected");
-          Changed = true;
-          continue;
-        }
-      }
-
       // Try to reassociate instructions so that part of computations can be
       // done out of loop.
       if (hoistArithmetics(I, *CurLoop, *SafetyInfo, MSSAU, AC, DT)) {
         Changed = true;
         continue;
       }
-
-      // Remember possibly hoistable branches so we can actually hoist them
-      // later if needed.
-      if (CondBrInst *BI = dyn_cast<CondBrInst>(&I))
-        CFH.registerPossiblyHoistableBranch(BI);
     }
   }
 
-  // If we hoisted instructions to a conditional block they may not dominate
-  // their uses that weren't hoisted (such as phis where some operands are not
-  // loop invariant). If so make them unconditional by moving them to their
-  // immediate dominator. We iterate through the instructions in reverse order
-  // which ensures that when we rehoist an instruction we rehoist its operands,
-  // and also keep track of where in the block we are rehoisting to make sure
-  // that we rehoist instructions before the instructions that use them.
-  Instruction *HoistPoint = nullptr;
-  if (ControlFlowHoisting) {
-    for (Instruction *I : reverse(HoistedInstructions)) {
-      if (!llvm::all_of(I->uses(),
-                        [&](Use &U) { return DT->dominates(I, U); })) {
-        BasicBlock *Dominator =
-            DT->getNode(I->getParent())->getIDom()->getBlock();
-        if (!HoistPoint || !DT->dominates(HoistPoint->getParent(), Dominator)) {
-          if (HoistPoint)
-            assert(DT->dominates(Dominator, HoistPoint->getParent()) &&
-                   "New hoist point expected to dominate old hoist point");
-          HoistPoint = Dominator->getTerminator();
-        }
-        LLVM_DEBUG(dbgs() << "LICM rehoisting to "
-                          << HoistPoint->getParent()->getNameOrAsOperand()
-                          << ": " << *I << "\n");
-        moveInstructionBefore(*I, HoistPoint->getIterator(), *SafetyInfo, MSSAU,
-                              SE);
-        HoistPoint = I;
-        Changed = true;
-      }
-    }
-  }
   if (VerifyMemorySSA)
     MSSAU.getMemorySSA()->verifyMemorySSA();
 
@@ -1083,12 +771,11 @@ getConstantInsertionIndex(InsertElementInst *Ins) {
   return InsertedIdxCI->getValue().getLimitedValue();
 }
 
-static bool
-hoistInsertPastInsert(InsertElementInst *Ins, Loop *CurLoop, DominatorTree *DT,
-                      BasicBlock *HoistDest, ICFLoopSafetyInfo *SafetyInfo,
-                      MemorySSAUpdater &MSSAU, ScalarEvolution *SE,
-                      OptimizationRemarkEmitter *ORE,
-                      SmallVectorImpl<Instruction *> &HoistedInstructions) {
+static bool hoistInsertPastInsert(InsertElementInst *Ins, Loop *CurLoop,
+                                  DominatorTree *DT, BasicBlock *HoistDest,
+                                  ICFLoopSafetyInfo *SafetyInfo,
+                                  MemorySSAUpdater &MSSAU, ScalarEvolution *SE,
+                                  OptimizationRemarkEmitter *ORE) {
   // Canonicalize:
   //   %inner = insertelement %base, %variant, C1
   //   %outer = insertelement %inner, %invariant, C2
@@ -1136,7 +823,6 @@ hoistInsertPastInsert(InsertElementInst *Ins, Loop *CurLoop, DominatorTree *DT,
   Ins->setOperand(0, Inner->getOperand(0));
   Inner->setOperand(0, Ins);
   hoist(*Ins, DT, CurLoop, HoistDest, SafetyInfo, MSSAU, SE, ORE);
-  HoistedInstructions.push_back(Ins);
   return true;
 }
 
diff --git a/llvm/test/Transforms/LICM/hoist-phi-metadata.ll b/llvm/test/Transforms/LICM/hoist-phi-metadata.ll
deleted file mode 100644
index 9b7387495df294..00000000000000
--- a/llvm/test/Transforms/LICM/hoist-phi-metadata.ll
+++ /dev/null
@@ -1,72 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --version 2
-; Test that hoisting conditional branches copies the debug and profiling info
-; metadata from the branch being hoisted.
-; RUN: opt -S -passes=licm -licm-control-flow-hoisting=1 %s -o - | FileCheck %s
-
-define void @triangle_phi(i32 %x, ptr %p) {
-; CHECK-LABEL: define void @triangle_phi
-; CHECK-SAME: (i32 [[X:%.*]], ptr [[P:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i32 [[X]], 0
-; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_LICM:%.*]], label [[THEN_LICM:%.*]], !prof [[PROF2:![0-9]+]]
-; CHECK:       if.licm:
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X]], 1
-; CHECK-NEXT:    br label [[THEN_LICM]]
-; CHECK:       then.licm:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[ADD]], [[IF_LICM]] ], [ [[X]], [[ENTRY:%.*]] ]
-; CHECK-NEXT:    store i32 [[PHI]], ptr [[P]], align 4
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i32 [[PHI]], 0
-; CHECK-NEXT:    br label [[LOOP:%.*]]
-; CHECK:       loop:
-; CHECK-NEXT:    br i1 [[CMP1]], label [[IF:%.*]], label [[THEN:%.*]], !dbg [[DBG3:![0-9]+]], !prof [[PROF2]]
-; CHECK:       if:
-; CHECK-NEXT:    br label [[THEN]]
-; CHECK:       then:
-; CHECK-NEXT:    br i1 [[CMP2]], label [[LOOP]], label [[END:%.*]], !dbg [[DBG7:![0-9]+]], !prof [[PROF8:![0-9]+]]
-; CHECK:       end:
-; CHECK-NEXT:    ret void
-;
-entry:
-  br label %loop, !dbg !5
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %then, !dbg !6, !prof !8
-if:
-  %add = add i32 %x, 1
-  br label %then
-
-then:
-  %phi = phi i32 [ %add, %if ], [ %x, %loop ]
-  store i32 %phi, ptr %p
-  %cmp2 = icmp ne i32 %phi, 0
-  br i1 %cmp2, label %loop, label %end, !dbg !7, !prof !9
-
-end:
-  ret void
-}
-
-!llvm.module.flags = !{!2, !3}
-
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1)
-!1 = !DIFile(filename: "t", directory: "/")
-!2 = !{i32 7, !"Dwarf Version", i32 5}
-!3 = !{i32 2, !"Debug Info Version", i32 3}
-!4 = distinct !DISubprogram(name: "triangle_phi", linkageName: "triangle_phi", scope: !1, file: !1, line: 1, unit: !0, type: !10)
-!5 = !DILocation(line: 1, column: 22, scope: !4)
-!6 = !DILocation(line: 2, column: 22, scope: !4)
-!7 = !DILocation(line: 3, column: 22, scope: !4)
-!8 = !{!"branch_weights", i32 5, i32 7}
-!9 = !{!"branch_weights", i32 13, i32 11}
-;.
-; CHECK: [[META0:![0-9]+]] = !{i32 7, !"Dwarf Version", i32 5}
-; CHECK: [[META1:![0-9]+]] = !{i32 2, !"Debug Info Version", i32 3}
-; CHECK: [[PROF2]] = !{!"branch_weights", i32 5, i32 7}
-; CHECK: [[DBG3]] = !DILocation(line: 2, column: 22, scope: [[META4:![0-9]+]])
-; CHECK: [[META4]] = distinct !DISubprogram(name: "triangle_phi", linkageName: "triangle_phi", scope: [[META5:![0-9]+]], file: [[META5]], line: 1, type: [[TYPE:![0-9]+]], spFlags: DISPFlagDefinition, unit: [[META6:![0-9]+]])
-; CHECK: [[META5]] = !DIFile(filename: "{{.*}}t", directory: {{.*}})
-; CHECK: [[META6]] = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: [[META5]], isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug)
-; CHECK: [[DBG7]] = !DILocation(line: 3, column: 22, scope: [[META4]])
-; CHECK: [[PROF8]] = !{!"branch_weights", i32 13, i32 11}
-;.
-!10 = !DISubroutineType(types: !11)
-!11 = !{null}
diff --git a/llvm/test/Transforms/LICM/hoist-phi.ll b/llvm/test/Transforms/LICM/hoist-phi.ll
deleted file mode 100644
index bf999b98a1dac3..00000000000000
--- a/llvm/test/Transforms/LICM/hoist-phi.ll
+++ /dev/null
@@ -1,1541 +0,0 @@
-; RUN: opt -S -passes=licm < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
-; RUN: opt -S -passes=licm -licm-control-flow-hoisting=1 < %s | FileCheck %s -check-prefixes=CHECK,CHECK-ENABLED
-; RUN: opt -S -passes=licm -licm-control-flow-hoisting=0 < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
-; RUN: opt -passes='require<opt-remark-emit>,loop-mssa(licm)' -S < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
-
-; RUN: opt -passes='require<opt-remark-emit>,loop-mssa(licm)' -licm-control-flow-hoisting=1 -verify-memoryssa -S < %s | FileCheck %s -check-prefixes=CHECK,CHECK-ENABLED
-; Enable run below when adding promotion. e.g. "store i32 %phi, ptr %p" is promoted to phi.lcssa.
-; opt -passes='require<opt-remark-emit>,loop-mssa(licm)' -licm-control-flow-hoisting=0 -verify-memoryssa -S < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
-
-
-; CHECK-LABEL: @triangle_phi
-define void @triangle_phi(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK: %cmp1 = icmp sgt i32 %x, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK: %add = add i32 %x, 1
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: phi i32 [ %add, %[[IF_LICM]] ], [ %x, %entry ]
-; CHECK-ENABLED: store i32 %phi, ptr %p
-; CHECK-ENABLED: %cmp2 = icmp ne i32 %phi, 0
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %then
-
-if:
-  %add = add i32 %x, 1
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %x, %loop ]
-; CHECK-DISABLED: %cmp2 = icmp ne i32 %phi, 0
-then:
-  %phi = phi i32 [ %add, %if ], [ %x, %loop ]
-  store i32 %phi, ptr %p
-  %cmp2 = icmp ne i32 %phi, 0
-  br i1 %cmp2, label %loop, label %end
-
-; CHECK-LABEL: end:
-; CHECK-DISABLED: %[[PHI_LCSSA:.*]] = phi i32 [ %phi, %then ]
-; CHECK-DISABLED: store i32 %[[PHI_LCSSA]], ptr %p
-end:
-  ret void
-}
-
-; CHECK-LABEL: @diamond_phi
-define void @diamond_phi(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK: %cmp1 = icmp sgt i32 %x, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-DAG: %add = add i32 %x, 1
-; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE_LICM]]:
-; CHECK-DAG: %sub = sub i32 %x, 1
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]
-; CHECK-ENABLED: %phi = phi i32 [ %add, %[[IF_LICM]] ], [ %sub, %[[ELSE_LICM]] ]
-; CHECK-ENABLED: store i32 %phi, ptr %p
-; CHECK-ENABLED: %cmp2 = icmp ne i32 %phi, 0
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %else
-
-if:
-  %add = add i32 %x, 1
-  br label %then
-
-else:
-  %sub = sub i32 %x, 1
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %sub, %else ]
-; CHECK-DISABLED: %cmp2 = icmp ne i32 %phi, 0
-then:
-  %phi = phi i32 [ %add, %if ], [ %sub, %else ]
-  store i32 %phi, ptr %p
-  %cmp2 = icmp ne i32 %phi, 0
-  br i1 %cmp2, label %loop, label %end
-
-; CHECK-LABEL: end:
-; CHECK-DISABLED: %[[PHI_LCSSA:.*]] = phi i32 [ %phi, %then ]
-; CHECK-DISABLED: store i32 %[[PHI_LCSSA]], ptr %p
-end:
-  ret void
-}
-
-; TODO: This is currently too complicated for us to be able to hoist the phi.
-; CHECK-LABEL: @three_way_phi
-define void @three_way_phi(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
-; CHECK-DAG: %add = add i32 %x, 1
-; CHECK-DAG: %cmp2 = icmp sgt i32 %add, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK: %sub = sub i32 %x, 1
-; CHECK: br label %loop
-
-entry:
-  br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %then
-
-if:
-  %add = add i32 %x, 1
-  %cmp2 = icmp sgt i32 %add, 0
-  br i1 %cmp2, label %if.if, label %then
-
-if.if:
-  %sub = sub i32 %x, 1
-  br label %then
-
-then:
-  %phi = phi i32 [ 0, %loop ], [ %add, %if ], [ %sub, %if.if ]
-  store i32 %phi, ptr %p
-  %cmp3 = icmp ne i32 %phi, 0
-  br i1 %cmp3, label %loop, label %end
-
-end:
-  ret void
-}
-
-; TODO: This is currently too complicated for us to be able to hoist the phi.
-; CHECK-LABEL: @tree_phi
-define void @tree_phi(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
-; CHECK-DAG: %add = add i32 %x, 1
-; CHECK-DAG: %cmp2 = icmp sgt i32 %add, 0
-; CHECK-DAG: %sub = sub i32 %x, 1
-; CHECK: br label %loop
-
-entry:
-  br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %else
-
-if:
-  %add = add i32 %x, 1
-  %cmp2 = icmp sgt i32 %add, 0
-  br i1 %cmp2, label %if.if, label %if.else
-
-if.if:
-  br label %then
-
-if.else:
-  br label %then
-
-else:
-  %sub = sub i32 %x, 1
-  br label %then
-
-then:
-  %phi = phi i32 [ %add, %if.if ], [ 0, %if.else ], [ %sub, %else ]
-  store i32 %phi, ptr %p
-  %cmp3 = icmp ne i32 %phi, 0
-  br i1 %cmp3, label %loop, label %end
-
-end:
-  ret void
-}
-
-; TODO: We can hoist the first phi, but not the second.
-; CHECK-LABEL: @phi_phi
-define void @phi_phi(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
-; CHECK-DAG: %add = add i32 %x, 1
-; CHECK-DAG: %cmp2 = icmp sgt i32 %add, 0
-; CHECK-DAG: %sub = sub i32 %x, 1
-; CHECK-ENABLED: br i1 %cmp2, label %[[IF_IF_LICM:.*]], label %[[IF_ELSE_LICM:.*]]
-
-; CHECK-ENABLED: [[IF_IF_LICM]]:
-; CHECK-ENABLED: br label %[[IF_THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[IF_ELSE_LICM]]:
-; CHECK-ENABLED: br label %[[IF_THEN_LICM]]
-
-; CHECK-ENABLED: [[IF_THEN_LICM]]:
-; CHECK-ENABLED: %phi1 = phi i32 [ %add, %[[IF_IF_LICM]] ], [ 0, %[[IF_ELSE_LICM]] ]
-; CHECK: br label %loop
-
-entry:
-  br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %else
-
-if:
-  %add = add i32 %x, 1
-  %cmp2 = icmp sgt i32 %add, 0
-  br i1 %cmp2, label %if.if, label %if.else
-
-if.if:
-  br label %if.then
-
-if.else:
-  br label %if.then
-
-; CHECK-LABEL: if.then:
-; CHECK-DISABLED: %phi1 = phi i32 [ %add, %if.if ], [ 0, %if.else ]
-if.then:
-  %phi1 = phi i32 [ %add, %if.if ], [ 0, %if.else ]
-  br label %then
-
-else:
-  %sub = sub i32 %x, 1
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK: %phi2 = phi i32 [ %phi1, %if.then ], [ %sub, %else ]
-then:
-  %phi2 = phi i32 [ %phi1, %if.then ], [ %sub, %else ]
-  store i32 %phi2, ptr %p
-  %cmp3 = icmp ne i32 %phi2, 0
-  br i1 %cmp3, label %loop, label %end
-
-end:
-  ret void
-}
-
-; Check that we correctly duplicate empty control flow.
-; CHECK-LABEL: @empty_triangle_phi
-define i8 @empty_triangle_phi(i32 %x, i32 %y) {
-; CHECK-LABEL: entry:
-; CHECK: %cmp1 = icmp eq i32 %x, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %entry ]
-; CHECK: %cmp2 = icmp eq i32 %y, 0
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp eq i32 %x, 0
-  br i1 %cmp1, label %if, label %then
-
-if:
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %loop ]
-then:
-  %phi = phi i8 [ 0, %if ], [ 1, %loop ]
-  %cmp2 = icmp eq i32 %y, 0
-  br i1 %cmp2, label %end, label %loop
-
-end:
-  ret i8 %phi
-}
-
-; CHECK-LABEL: @empty_diamond_phi
-define i8 @empty_diamond_phi(i32 %x, i32 %y) {
-; CHECK-LABEL: entry:
-; CHECK: %cmp1 = icmp eq i32 %x, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %[[ELSE_LICM]] ]
-; CHECK: %cmp2 = icmp eq i32 %y, 0
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp eq i32 %x, 0
-  br i1 %cmp1, label %if, label %else
-
-if:
-  br label %then
-
-else:
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %else ]
-then:
-  %phi = phi i8 [ 0, %if ], [ 1, %else ]
-  %cmp2 = icmp eq i32 %y, 0
-  br i1 %cmp2, label %end, label %loop
-
-end:
-  ret i8 %phi
-}
-
-; Check that we correctly handle the case that the first thing we try to hoist is a phi.
-; CHECK-LABEL: @empty_triangle_phi_first
-define i8 @empty_triangle_phi_first(i32 %x, i1 %cond) {
-; CHECK-LABEL: entry:
-; CHECK-ENABLED: br i1 %cond, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %entry ]
-; CHECK: %cmp = icmp eq i32 %x, 0
-; CHECK: br label %loop
-
-loop:
-  br i1 %cond, label %if, label %then
-
-if:
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %loop ]
-then:
-  %phi = phi i8 [ 0, %if ], [ 1, %loop ]
-  %cmp = icmp eq i32 %x, 0
-  br i1 %cmp, label %end, label %loop
-
-end:
-  ret i8 %phi
-}
-
-; CHECK-LABEL: @empty_diamond_phi
-define i8 @empty_diamond_phi_first(i32 %x, i1 %cond) {
-; CHECK-LABEL: entry:
-; CHECK-ENABLED: br i1 %cond, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %[[ELSE_LICM]] ]
-; CHECK: %cmp = icmp eq i32 %x, 0
-; CHECK: br label %loop
-
-loop:
-  br i1 %cond, label %if, label %else
-
-if:
-  br label %then
-
-else:
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %else ]
-then:
-  %phi = phi i8 [ 0, %if ], [ 1, %else ]
-  %cmp = icmp eq i32 %x, 0
-  br i1 %cmp, label %end, label %loop
-
-end:
-  ret i8 %phi
-}
-
-; CHECK-LABEL: @empty_triangle_phi_first
-define i8 @empty_triangle_phi_first_empty_loop_head(i32 %x, i1 %cond) {
-; CHECK-LABEL: entry:
-; CHECK-ENABLED: br i1 %cond, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %entry ]
-; CHECK: %cmp = icmp eq i32 %x, 0
-; CHECK: br label %loop
-
-loop:
-  br label %test
-
-test:
-  br i1 %cond, label %if, label %then
-
-if:
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %test ]
-then:
-  %phi = phi i8 [ 0, %if ], [ 1, %test ]
-  %cmp = icmp eq i32 %x, 0
-  br i1 %cmp, label %end, label %loop
-
-end:
-  ret i8 %phi
-}
-
-; CHECK-LABEL: @empty_diamond_phi_first_empty_loop_head
-define i8 @empty_diamond_phi_first_empty_loop_head(i32 %x, i1 %cond) {
-; CHECK-LABEL: entry:
-; CHECK-ENABLED: br i1 %cond, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %[[ELSE_LICM]] ]
-; CHECK: %cmp = icmp eq i32 %x, 0
-; CHECK: br label %loop
-
-loop:
-  br label %test
-
-test:
-  br i1 %cond, label %if, label %else
-
-if:
-  br label %then
-
-else:
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %else ]
-then:
-  %phi = phi i8 [ 0, %if ], [ 1, %else ]
-  %cmp = icmp eq i32 %x, 0
-  br i1 %cmp, label %end, label %loop
-
-end:
-  ret i8 %phi
-}
-
-; The phi is on one branch of a diamond while simultaneously at the end of a
-; triangle. Check that we duplicate the triangle and not the diamond.
-; CHECK-LABEL: @triangle_diamond
-define void @triangle_diamond(ptr %ptr, i32 %x, i32 %y) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp ne i32 %x, 0
-; CHECK-DAG: %cmp2 = icmp ne i32 %y, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi = phi i32 [ 0, %[[IF_LICM]] ], [ 127, %entry ]
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp ne i32 %x, 0
-  br i1 %cmp1, label %if, label %then
-
-if:
-  %cmp2 = icmp ne i32 %y, 0
-  br i1 %cmp2, label %if.then, label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i32 [ 0, %if ], [ 127, %loop ]
-then:
-  %phi = phi i32 [ 0, %if ], [ 127, %loop ]
-  store i32 %phi, ptr %ptr
-  br label %end
-
-if.then:
-  br label %end
-
-end:
-  br label %loop
-}
-
-; As the previous, but the end of the diamond is the head of the loop.
-; CHECK-LABEL: @triangle_diamond_backedge
-define void @triangle_diamond_backedge(ptr %ptr, i32 %x, i32 %y) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp ne i32 %x, 0
-; CHECK-DAG: %cmp2 = icmp ne i32 %y, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi = phi i32 [ 0, %[[IF_LICM]] ], [ 127, %entry ]
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp ne i32 %x, 0
-  br i1 %cmp1, label %if, label %then
-
-if:
-  %cmp2 = icmp ne i32 %y, 0
-  br i1 %cmp2, label %backedge, label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i32 [ 0, %if ], [ 127, %loop ]
-then:
-  %phi = phi i32 [ 0, %if ], [ 127, %loop ]
-  store i32 %phi, ptr %ptr
-  br label %loop
-
-backedge:
-  br label %loop
-}
-
-; TODO: The inner diamonds can be hoisted, but not currently the outer diamond
-; CHECK-LABEL: @diamonds_inside_diamond
-define void @diamonds_inside_diamond(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
-; CHECK-DAG: %cmp3 = icmp slt i32 %x, -10
-; CHECK-ENABLED: br i1 %cmp3, label %[[ELSE_IF_LICM:.*]], label %[[ELSE_ELSE_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[ELSE_IF_LICM]]:
-; CHECK-ENABLED: br label %[[ELSE_THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE_ELSE_LICM]]:
-; CHECK-ENABLED: br label %[[ELSE_THEN_LICM]]
-
-; CHECK-ENABLED: [[ELSE_THEN_LICM]]:
-; CHECK-ENABLED: %phi2 = phi i32 [ 2, %[[ELSE_IF_LICM]] ], [ 3, %[[ELSE_ELSE_LICM]] ]
-; CHECK: %cmp2 = icmp sgt i32 %x, 10
-; CHECK-ENABLED: br i1 %cmp2, label %[[IF_IF_LICM:.*]], label %[[IF_ELSE_LICM:.*]]
-
-; CHECK-ENABLED: [[IF_IF_LICM]]:
-; CHECK-ENABLED: br label %[[IF_THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[IF_ELSE_LICM]]:
-; CHECK-ENABLED: br label %[[IF_THEN_LICM]]
-
-; CHECK-ENABLED: [[IF_THEN_LICM]]:
-; CHECK-ENABLED: %phi1 = phi i32 [ 0, %[[IF_IF_LICM]] ], [ 1, %[[IF_ELSE_LICM]] ]
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %else
-
-if:
-  %cmp2 = icmp sgt i32 %x, 10
-  br i1 %cmp2, label %if.if, label %if.else
-
-if.if:
-  br label %if.then
-
-if.else:
-  br label %if.then
-
-; CHECK-LABEL: if.then:
-; CHECK-DISABLED: %phi1 = phi i32 [ 0, %if.if ], [ 1, %if.else ]
-if.then:
-  %phi1 = phi i32 [ 0, %if.if ], [ 1, %if.else ]
-  br label %then
-
-else:
-  %cmp3 = icmp slt i32 %x, -10
-  br i1 %cmp3, label %else.if, label %else.else
-
-else.if:
-  br label %else.then
-
-else.else:
-  br label %else.then
-
-; CHECK-LABEL: else.then:
-; CHECK-DISABLED: %phi2 = phi i32 [ 2, %else.if ], [ 3, %else.else ]
-else.then:
-  %phi2 = phi i32 [ 2, %else.if ], [ 3, %else.else ]
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK: %phi3 = phi i32 [ %phi1, %if.then ], [ %phi2, %else.then ]
-; CHECK: %cmp4 = icmp ne i32 %phi3, 0
-then:
-  %phi3 = phi i32 [ %phi1, %if.then ], [ %phi2, %else.then ]
-  store i32 %phi3, ptr %p
-  %cmp4 = icmp ne i32 %phi3, 0
-  br i1 %cmp4, label %loop, label %end
-
-end:
-  ret void
-}
-
-; We can hoist blocks that contain an edge that exits the loop by ignoring that
-; edge in the hoisted block.
-define void @triangle_phi_loopexit(i32 %x, ptr %p) {
-; CHECK-DISABLED-LABEL: @triangle_phi_loopexit(
-; CHECK-DISABLED-NEXT:  entry:
-; CHECK-DISABLED-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], 1
-; CHECK-DISABLED-NEXT:    [[CMP1:%.*]] = icmp sgt i32 [[X]], 0
-; CHECK-DISABLED-NEXT:    [[CMP2:%.*]] = icmp sgt i32 10, [[ADD]]
-; CHECK-DISABLED-NEXT:    br label [[LOOP:%.*]]
-; CHECK-DISABLED:       loop:
-; CHECK-DISABLED-NEXT:    br i1 [[CMP1]], label [[IF:%.*]], label [[THEN:%.*]]
-; CHECK-DISABLED:       if:
-; CHECK-DISABLED-NEXT:    br i1 [[CMP2]], label [[THEN]], label [[END:%.*]]
-; CHECK-DISABLED:       then:
-; CHECK-DISABLED-NEXT:    [[PHI:%.*]] = phi i32 [ [[ADD]], [[IF]] ], [ [[X]], [[LOOP]] ]
-; CHECK-DISABLED-NEXT:    store i32 [[PHI]], ptr [[P:%.*]], align 4
-; CHECK-DISABLED-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[PHI]], 0
-; CHECK-DISABLED-NEXT:    br i1 [[CMP3]], label [[LOOP]], label [[END]]
-; CHECK-DISABLED:       end:
-; CHECK-DISABLED-NEXT:    ret void
-;
-; CHECK-ENABLED-LABEL: @triangle_phi_loopexit(
-; CHECK-ENABLED-NEXT:  entry:
-; CHECK-ENABLED-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], 1
-; CHECK-ENABLED-NEXT:    [[CMP1:%.*]] = icmp sgt i32 [[X]], 0
-; CHECK-ENABLED-NEXT:    [[CMP2:%.*]] = icmp sgt i32 10, [[ADD]]
-; CHECK-ENABLED-NEXT:    br i1 [[CMP1]], label [[IF_LICM:%.*]], label [[THEN_LICM:%.*]]
-; CHECK-ENABLED:       if.licm:
-; CHECK-ENABLED-NEXT:    br label [[THEN_LICM]]
-; CHECK-ENABLED:       then.licm:
-; CHECK-ENABLED-NEXT:    [[PHI:%.*]] = phi i32 [ [[ADD]], [[IF_LICM]] ], [ [[X]], [[ENTRY:%.*]] ]
-; CHECK-ENABLED-NEXT:    [[CMP3:%.*]] = icmp ne i32 [[PHI]], 0
-; CHECK-ENABLED-NEXT:    br label [[LOOP:%.*]]
-; CHECK-ENABLED:       loop:
-; CHECK-ENABLED-NEXT:    br i1 [[CMP1]], label [[IF:%.*]], label [[THEN:%.*]]
-; CHECK-ENABLED:       if:
-; CHECK-ENABLED-NEXT:    br i1 [[CMP2]], label [[THEN]], label [[END:%.*]]
-; CHECK-ENABLED:       then:
-; CHECK-ENABLED-NEXT:    store i32 [[PHI]], ptr [[P:%.*]], align 4
-; CHECK-ENABLED-NEXT:    br i1 [[CMP3]], label [[LOOP]], label [[END]]
-; CHECK-ENABLED:       end:
-; CHECK-ENABLED-NEXT:    ret void
-;
-entry:
-  br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %then
-
-if:
-  %add = add i32 %x, 1
-  %cmp2 = icmp sgt i32 10, %add
-  br i1 %cmp2, label %then, label %end
-
-then:
-  %phi = phi i32 [ %add, %if ], [ %x, %loop ]
-  store i32 %phi, ptr %p
-  %cmp3 = icmp ne i32 %phi, 0
-  br i1 %cmp3, label %loop, label %end
-
-end:
-  ret void
-}
-
-; CHECK-LABEL: @diamond_phi_oneloopexit
-define void @diamond_phi_oneloopexit(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %add = add i32 %x, 1
-; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
-; CHECK-DAG: %cmp2 = icmp sgt i32 10, %add
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE_LICM]]:
-; CHECK-DAG: %sub = sub i32 %x, 1
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]
-; CHECK-ENABLED: %phi = phi i32 [ %add, %[[IF_LICM]] ], [ %sub, %[[ELSE_LICM]] ]
-; CHECK-ENABLED: %cmp3 = icmp ne i32 %phi, 0
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %else
-
-if:
-  %add = add i32 %x, 1
-  %cmp2 = icmp sgt i32 10, %add
-  br i1 %cmp2, label %then, label %end
-
-else:
-  %sub = sub i32 %x, 1
-  br label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %sub, %else ]
-then:
-  %phi = phi i32 [ %add, %if ], [ %sub, %else ]
-  store i32 %phi, ptr %p
-  %cmp3 = icmp ne i32 %phi, 0
-  br i1 %cmp3, label %loop, label %end
-
-end:
-  ret void
-}
-
-; CHECK-LABEL: @diamond_phi_twoloopexit
-define void @diamond_phi_twoloopexit(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %sub = sub i32 %x, 1
-; CHECK-DAG: %add = add i32 %x, 1
-; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
-; CHECK-DAG: %cmp2 = icmp sgt i32 10, %add
-; CHECK-DAG: %cmp3 = icmp sgt i32 10, %sub
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]
-; CHECK-ENABLED: %phi = phi i32 [ %add, %[[IF_LICM]] ], [ %sub, %[[ELSE_LICM]] ]
-; CHECK-ENABLED: %cmp4 = icmp ne i32 %phi, 0
-; CHECK: br label %loop
-
-loop:
-  %cmp1 = icmp sgt i32 %x, 0
-  br i1 %cmp1, label %if, label %else
-
-if:
-  %add = add i32 %x, 1
-  %cmp2 = icmp sgt i32 10, %add
-  br i1 %cmp2, label %then, label %end
-
-else:
-  %sub = sub i32 %x, 1
-  %cmp3 = icmp sgt i32 10, %sub
-  br i1 %cmp3, label %then, label %end
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %sub, %else ]
-; CHECK-DISABLED: %cmp4 = icmp ne i32 %phi, 0
-then:
-  %phi = phi i32 [ %add, %if ], [ %sub, %else ]
-  store i32 %phi, ptr %p
-  %cmp4 = icmp ne i32 %phi, 0
-  br i1 %cmp4, label %loop, label %end
-
-end:
-  ret void
-}
-
-; The store cannot be hoisted, so add and shr cannot be hoisted into a
-; conditional block.
-; CHECK-LABEL: @conditional_use
-define void @conditional_use(i32 %x, ptr %p) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cond = icmp ugt i32 %x, 0
-; CHECK-DAG: %add = add i32 %x, 5
-; CHECK-DAG: %shr = ashr i32 %add, 1
-; CHECK: br label %loop
-entry:
-  br label %loop
-
-loop:
-  %cond = icmp ugt i32 %x, 0
-  br i1 %cond, label %if, label %else
-
-; CHECK-LABEL: if:
-; CHECK: store i32 %shr, ptr %p, align 4
-if:
-  %add = add i32 %x, 5
-  %shr = ashr i32 %add, 1
-  store i32 %shr, ptr %p, align 4
-  br label %then
-
-else:
-  br label %then
-
-then:
-  br label %loop
-}
-
-; A diamond with two triangles on the left and one on the right. This test is
-; to check that we have a unique loop preheader when we hoist the store (and so
-; don't fail an assertion).
-; CHECK-LABEL: @triangles_in_diamond
-define void @triangles_in_diamond(ptr %ptr, i1 %arg) {
-; CHECK-LABEL: entry:
-; CHECK: store i32 0, ptr %ptr, align 4
-; CHECK: br label %loop
-entry:
-  br label %loop
-
-loop:
-  br i1 %arg, label %left_triangle_1, label %right_triangle
-
-left_triangle_1:
-  br i1 %arg, label %left_triangle_1_if, label %left_triangle_2
-
-left_triangle_1_if:
-  br label %left_triangle_2
-
-left_triangle_2:
-  br i1 %arg, label %left_triangle_2_if, label %left_triangle_2_then
-
-left_triangle_2_if:
-  br label %left_triangle_2_then
-
-left_triangle_2_then:
-  br label %loop.end
-
-right_triangle:
-  br i1 %arg, label %right_triangle.if, label %right_triangle.then
-
-right_triangle.if:
-  br label %right_triangle.then
-
-right_triangle.then:
-  br label %loop.end
-
-loop.end:
-  store i32 0, ptr %ptr, align 4
-  br label %loop
-}
-
-; %cmp dominates its used after being hoisted, but not after %brmerge is rehoisted
-; CHECK-LABEL: @rehoist
-define void @rehoist(ptr %this, i32 %x, i1 %arg) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %sub = add nsw i32 %x, -1
-; CHECK-DAG: %cmp = icmp eq i32 0, %sub
-; CHECK-DAG: %brmerge = or i1 %cmp, true
-entry:
-  %sub = add nsw i32 %x, -1
-  br label %loop
-
-loop:
-  br i1 %arg, label %if1, label %else1
-
-if1:
-  call void %this(ptr %this)
-  br label %then1
-
-else1:
-  br label %then1
-
-then1:
-  %cmp = icmp eq i32 0, %sub
-  br i1 %cmp, label %end, label %else2
-
-else2:
-  %brmerge = or i1 %cmp, true
-  br i1 %brmerge, label %if3, label %end
-
-if3:
-  br label %end
-
-end:
-  br label %loop
-}
-
-; A test case that uses empty blocks in a way that can cause control flow
-; hoisting to get confused.
-; CHECK-LABEL: @empty_blocks_multiple_conditional_branches
-define void @empty_blocks_multiple_conditional_branches(float %arg, ptr %ptr, i1 %arg2) {
-; CHECK-LABEL: entry
-; CHECK-DAG: %div1 = fmul float %arg, 4.000000e+00
-; CHECK-DAG: %div2 = fmul float %arg, 2.000000e+00
-entry:
-  br label %loop
-
-; The exact path to the phi isn't checked here, because it depends on whether
-; cond2 or cond3 is hoisted first
-; CHECK-ENABLED: %phi = phi float [ 0.000000e+00, %{{.*}} ], [ %div1, %{{.*}} ]
-; CHECK: br label %loop
-
-loop:
-  br i1 %arg2, label %backedge2, label %cond1
-
-cond1:
-  br i1 %arg2, label %cond1.if, label %cond1.else
-
-cond1.else:
-  br label %cond3
-
-cond1.if:
-  br label %cond1.if.next
-
-cond1.if.next:
-  br label %cond2
-
-cond2:
-  %div1 = fmul float %arg, 4.000000e+00
-  br i1 %arg2, label %cond2.if, label %cond2.then
-
-cond2.if:
-  br label %cond2.then
-
-; CHECK-LABEL: cond2.then:
-; CHECK-DISABLED: %phi = phi float [ 0.000000e+00, %cond2 ], [ %div1, %cond2.if ]
-cond2.then:
-  %phi = phi float [ 0.000000e+00, %cond2 ], [ %div1, %cond2.if ]
-  store float %phi, ptr %ptr
-  br label %backedge2
-
-cond3:
-  br i1 %arg2, label %cond3.then, label %cond3.if
-
-cond3.if:
-  %div2 = fmul float %arg, 2.000000e+00
-  store float %div2, ptr %ptr
-  br label %cond3.then
-
-cond3.then:
-  br label %loop
-
-backedge2:
-  br label %loop
-}
-
-; We can't do much here, so mainly just check that we don't crash.
-; CHECK-LABEL: @many_path_phi
-define void @many_path_phi(ptr %ptr1, ptr %ptr2, i1 %arg) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %gep3 = getelementptr inbounds i32, ptr %ptr2, i32 2
-; CHECK-DAG: %gep2 = getelementptr inbounds i32, ptr %ptr2, i32 2
-; CHECK: br label %loop
-entry:
-  br label %loop
-
-loop:
-  %phi1 = phi i32 [ 0, %entry ], [ %phi2, %end ]
-  %cmp1 = icmp ugt i32 %phi1, 3
-  br i1 %cmp1, label %cond2, label %cond1
-
-cond1:
-  br i1 %arg, label %end, label %cond1.else
-
-cond1.else:
-  %gep2 = getelementptr inbounds i32, ptr %ptr2, i32 2
-  %val2 = load i32, ptr %gep2, align 4
-  %cmp2 = icmp eq i32 %val2, 13
-  br i1 %cmp2, label %cond1.end, label %end
-
-cond1.end:
-  br label %end
-
-cond2:
-  br i1 %arg, label %end, label %cond2.else
-
-cond2.else:
-  %gep3 = getelementptr inbounds i32, ptr %ptr2, i32 2
-  %val3 = load i32, ptr %gep3, align 4
-  %cmp3 = icmp eq i32 %val3, 13
-  br i1 %cmp3, label %cond2.end, label %end
-
-cond2.end:
-  br label %end
-
-end:
-  %phi2 = phi i32 [ 1, %cond1 ], [ 2, %cond1.else ], [ 3, %cond1.end ], [ 4, %cond2 ], [ 5, %cond2.else ], [ 6, %cond2.end ]
-  br label %loop
-}
-
-; Check that we correctly handle the hoisting of %gep when theres a critical
-; edge that branches to the preheader.
-; CHECK-LABEL: @crit_edge
-define void @crit_edge(ptr %ptr, i32 %idx, i1 %cond1, i1 %cond2, i1 %arg) {
-; CHECK-LABEL: entry:
-; CHECK: %gep = getelementptr inbounds i32, ptr %ptr, i32 %idx
-; CHECK: br label %preheader
-entry:
-  br label %preheader
-
-preheader:
-  br label %loop
-
-loop:
-  br i1 %cond1, label %then, label %if
-
-if:
-  %gep = getelementptr inbounds i32, ptr %ptr, i32 %idx
-  %val = load i32, ptr %gep
-  br label %then
-
-then:
-  %phi = phi i32 [ %val, %if ], [ 0, %loop ]
-  store i32 %phi, ptr %ptr
-  br i1 %cond2, label %loop, label %crit_edge
-
-crit_edge:
-  br label %preheader
-}
-
-; Check that the conditional sub is correctly hoisted from the inner loop to the
-; preheader of the outer loop.
-; CHECK-LABEL: @hoist_from_innermost_loop
-define void @hoist_from_innermost_loop(i32 %nx, ptr %ptr, i1 %arg) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %sub = sub nsw i32 0, %nx
-; CHECK: br label %outer_loop
-entry:
-  br label %outer_loop
-
-outer_loop:
-  br label %middle_loop
-
-middle_loop:
-  br label %inner_loop
-
-inner_loop:
-  br i1 %arg, label %inner_loop_end, label %if
-
-if:
-  %sub = sub nsw i32 0, %nx
-  store i32 %sub, ptr %ptr, align 4
-  br label %inner_loop_end
-
-inner_loop_end:
-  br i1 %arg, label %inner_loop, label %middle_loop_end
-
-middle_loop_end:
-  br i1 %arg, label %middle_loop, label %outer_loop_end
-
-outer_loop_end:
-  br label %outer_loop
-}
-
-; We have a diamond starting from %if, but %if.if is also reachable from %loop,
-; so %gep should not be conditionally hoisted.
-; CHECK-LABEL: @diamond_with_extra_in_edge
-define void @diamond_with_extra_in_edge(ptr %ptr1, ptr %ptr2, i32 %arg) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp2 = icmp ne i32 0, %arg
-; CHECK-DAG: %gep = getelementptr i32, ptr %ptr1, i32 4
-; CHECK: br label %loop
-entry:
-  br label %loop
-
-loop:
-  %phi1 = phi i32 [ 0, %entry ], [ %phi2, %then ]
-  %cmp1 = icmp ugt i32 16, %phi1
-  br i1 %cmp1, label %if, label %if.if
-
-if:
-  %cmp2 = icmp ne i32 0, %arg
-  br i1 %cmp2, label %if.if, label %if.else
-
-if.if:
-  %gep = getelementptr i32, ptr %ptr1, i32 4
-  %val = load i32, ptr %gep, align 4
-  br label %then
-
-if.else:
-  br label %then
-
-then:
-  %phi2 = phi i32 [ %val, %if.if ], [ %phi1, %if.else ]
-  store i32 %phi2, ptr %ptr2, align 4
-  br label %loop
-}
-
-; %loop/%if/%then form a triangle, but %loop/%if/%then/%end also form a diamond.
-; The triangle should be picked for conditional hoisting.
-; CHECK-LABEL: @both_triangle_and_diamond
-define void @both_triangle_and_diamond(ptr %ptr1, ptr %ptr2, i32 %arg) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp ne i32 0, %arg
-; CHECK-DAG: %gep = getelementptr i32, ptr %ptr1, i32 4
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF_LICM]]:
-; CHECK-ENABLED: br label %[[THEN_LICM]]
-
-; CHECK-ENABLED: [[THEN_LICM]]:
-; CHECK-ENABLED: %phi2 = phi i32 [ 0, %[[IF_LICM]] ], [ 1, %entry ]
-; CHECK: br label %loop
-
-loop:
-  %phi1 = phi i32 [ 0, %entry ], [ %phi3, %end ]
-  %cmp1 = icmp ne i32 0, %arg
-  br i1 %cmp1, label %if, label %then
-
-if:
-  %gep = getelementptr i32, ptr %ptr1, i32 4
-  %val = load i32, ptr %gep, align 4
-  %cmp2 = icmp ugt i32 16, %phi1
-  br i1 %cmp2, label %end, label %then
-
-; CHECK-LABEL: then:
-; CHECK-DISABLED: %phi2 = phi i32 [ 0, %if ], [ 1, %loop ]
-then:
-  %phi2 = phi i32 [ 0, %if ], [ 1, %loop ]
-  br label %end
-
-end:
-  %phi3 = phi i32 [ %phi2, %then ], [ %val, %if ]
-  store i32 %phi3, ptr %ptr2, align 4
-  br label %loop
-}
-
-; We shouldn't duplicate the branch at the end of %loop and should instead hoist
-; %val to %entry.
-; CHECK-LABEL: @same_destination_branch
-define i32 @same_destination_branch(i32 %arg1, i32 %arg2) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp ne i32 %arg2, 0
-; CHECK-DAG: %val = add i32 %arg1, 1
-; CHECK: br label %loop
-entry:
-  br label %loop
-
-; CHECK-LABEL: loop:
-; CHECK: %phi = phi i32 [ 0, %entry ], [ %add, %then ]
-loop:
-  %phi = phi i32 [ 0, %entry ], [ %add, %then ]
-  %add = add i32 %phi, 1
-  %cmp1 = icmp ne i32 %arg2, 0
-  br i1 %cmp1, label %if, label %if
-
-if:
-  %val = add i32 %arg1, 1
-  br label %then
-
-then:
-  %cmp2 = icmp ne i32 %val, %phi
-  br i1 %cmp2, label %loop, label %end
-
-end:
-  ret i32 %val
-}
-
-; Diamond-like control flow but the left/right blocks actually have the same
-; destinations.
-; TODO: We could potentially hoist all of phi2-4, but currently only hoist phi2.
-; CHECK-LABEL: @diamond_like_same_destinations
-define i32 @diamond_like_same_destinations(i32 %arg1, i32 %arg2) {
-; CHECK-LABEL: entry:
-; CHECK-DAG: %cmp1 = icmp ne i32 %arg1, 0
-; CHECK-DAG: %cmp2 = icmp ugt i32 %arg2, 1
-; CHECK-DAG: %cmp3 = icmp ugt i32 %arg2, 2
-; CHECK-ENABLED: br i1 %cmp1, label %[[LEFT1_LICM:.*]], label %[[RIGHT1_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[LEFT1_LICM]]:
-; CHECK-ENABLED: br label %[[LEFT2_LICM:.*]]
-
-; CHECK-ENABLED: [[RIGHT1_LICM]]:
-; CHECK-ENABLED: br label %[[LEFT2_LICM]]
-
-; CHECK-ENABLED: [[LEFT2_LICM]]:
-; CHECK-ENABLED: %phi2 = phi i32 [ 0, %[[LEFT1_LICM]] ], [ 1, %[[RIGHT1_LICM]] ]
-; CHECK: br label %loop
-
-loop:
-  %phi1 = phi i32 [ 0, %entry ], [ %add, %loopend ]
-  %add = add i32 %phi1, 1
-  %cmp1 = icmp ne i32 %arg1, 0
-  br i1 %cmp1, label %left1, label %right1
-
-left1:
-  %cmp2 = icmp ugt i32 %arg2, 1
-  br i1 %cmp2, label %left2, label %right2
-
-right1:
-  %cmp3 = icmp ugt i32 %arg2, 2
-  br i1 %cmp3, label %left2, label %right2
-
-; CHECK-LABEL: left2:
-; CHECK-DISABLED: %phi2 = phi i32 [ 0, %left1 ], [ 1, %right1 ]
-left2:
-  %phi2 = phi i32 [ 0, %left1 ], [ 1, %right1 ]
-  br label %loopend
-
-; CHECK-LABEL: right2:
-; CHECK: %phi3 = phi i32 [ 2, %left1 ], [ 3, %right1 ]
-right2:
-  %phi3 = phi i32 [ 2, %left1 ], [ 3, %right1 ]
-  br label %loopend
-
-; CHECK-LABEL: loopend:
-; CHECK: %phi4 = phi i32 [ %phi2, %left2 ], [ %phi3, %right2 ]
-loopend:
-  %phi4 = phi i32 [ %phi2, %left2 ], [ %phi3, %right2 ]
-  %cmp4 = icmp ne i32 %phi1, 32
-  br i1 %cmp4, label %loop, label %end
-
-end:
-  ret i32 %phi4
-}
-
-; A phi with multiple incoming values for the same block due to a branch with
-; two destinations that are actually the same. We can't hoist this.
-; TODO: This could be hoisted by erasing one of the incoming values.
-; CHECK-LABEL: @phi_multiple_values_same_block
-define i32 @phi_multiple_values_same_block(i32 %arg, i1 %arg2) {
-; CHECK-LABEL: entry:
-; CHECK: %cmp = icmp sgt i32 %arg, 4
-; CHECK-NOT: phi
-; CHECK: br label %loop
-entry:
-  br label %loop
-
-loop:
-  %cmp = icmp sgt i32 %arg, 4
-  br i1 %cmp, label %if, label %then
-
-if:
-  br i1 %arg2, label %then, label %then
-
-then:
-  %phi = phi i32 [ %arg, %loop ], [ 1, %if ], [ 1, %if ]
-  br i1 %arg2, label %exit, label %loop
-
-exit:
-  ret i32 %phi
-}
-
-; %phi is conditionally used in %d, and the store that %d is used in cannot be
-; hoisted. This means that we have to rehoist %d, but have to make sure to
-; rehoist it after %phi.
-; CHECK-LABEL: @phi_conditional_use
-define i64 @phi_conditional_use(i32 %f, ptr %g) {
-; CHECK-LABEL: entry:
-; CHECK: %cmp1 = icmp eq i32 %f, 1
-; CHECK: %cmp2 = icmp eq i32 %f, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_END_LICM:.*]], label %[[IF_THEN_LICM:.*]]
-entry:
-  %cmp1 = icmp eq i32 %f, 1
-  %cmp2 = icmp eq i32 %f, 0
-  br label %loop
-
-; CHECK-ENABLED: [[IF_THEN_LICM]]:
-; CHECK-ENABLED: br label %[[IF_END_LICM]]
-
-; CHECK-ENABLED: [[IF_END_LICM]]:
-; CHECK-ENABLED: %phi = phi i64 [ 0, %entry ], [ 1, %[[IF_THEN_LICM]] ]
-; CHECK-ENABLED: %d = getelementptr inbounds i32, ptr %g, i64 %phi
-; CHECK-ENABLED: i1 %cmp2, label %[[LOOP_BACKEDGE_LICM:.*]], label %[[IF_THEN2_LICM:.*]]
-
-; CHECK-ENABLED: [[IF_THEN2_LICM]]:
-; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM]]
-
-; CHECK-ENABLED: [[LOOP_BACKEDGE_LICM]]:
-; CHECK: br label %loop
-
-loop:
-  br i1 %cmp1, label %if.end, label %if.then
-
-if.then:
-  br label %if.end
-
-; CHECK-LABEL: if.end:
-; CHECK-DISABLED: %phi = phi i64 [ 0, %loop ], [ 1, %if.then ]
-if.end:
-  %phi = phi i64 [ 0, %loop ], [ 1, %if.then ]
-  br i1 %cmp2, label %loop.backedge, label %if.then2
-
-; CHECK-LABEL: if.then2:
-; CHECK-DISABLED: %d = getelementptr inbounds i32, ptr %g, i64 %phi
-if.then2:
-  %d = getelementptr inbounds i32, ptr %g, i64 %phi
-  store i32 1, ptr %d, align 4
-  br label %loop.backedge
-
-loop.backedge:
-  br label %loop
-}
-
-; As above, but we have two such phis
-; CHECK-LABEL: @phi_conditional_use_twice
-define i64 @phi_conditional_use_twice(i32 %f, ptr %g) {
-; CHECK-LABEL: entry:
-; CHECK: %cmp1 = icmp eq i32 %f, 1
-; CHECK: %cmp2 = icmp eq i32 %f, 0
-; CHECK-ENABLED: br i1 %cmp1, label %[[IF_END_LICM:.*]], label %[[IF_THEN_LICM:.*]]
-entry:
-  %cmp1 = icmp eq i32 %f, 1
-  %cmp2 = icmp eq i32 %f, 0
-  %cmp3 = icmp sgt i32 %f, 0
-  br label %loop
-
-; CHECK-ENABLED: [[IF_THEN_LICM]]:
-; CHECK-ENABLED: br label %[[IF_END_LICM]]
-
-; CHECK-ENABLED: [[IF_END_LICM]]:
-; CHECK-ENABLED: %phi1 = phi i64 [ 0, %entry ], [ 1, %[[IF_THEN_LICM]] ]
-; CHECK-ENABLED: %d = getelementptr inbounds i32, ptr %g, i64 %phi1
-; CHECK-ENABLED: i1 %cmp2, label %[[IF_END2_LICM:.*]], label %[[IF_THEN2_LICM:.*]]
-
-; CHECK-ENABLED: [[IF_THEN2_LICM]]:
-; CHECK-ENABLED: br label %[[IF_END2_LICM]]
-
-; CHECK-ENABLED: [[IF_END2_LICM]]:
-; CHECK-ENABLED: %phi2 = phi i64 [ 2, %[[IF_END_LICM]] ], [ 3, %[[IF_THEN2_LICM]] ]
-; CHECK-ENABLED: %e = getelementptr inbounds i32, ptr %g, i64 %phi2
-; CHECK-ENABLED: i1 %cmp3, label %[[LOOP_BACKEDGE_LICM:.*]], label %[[IF_THEN3_LICM:.*]]
-
-; CHECK-ENABLED: [[IF_THEN3_LICM]]:
-; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM]]
-
-; CHECK-ENABLED: [[LOOP_BACKEDGE_LICM]]:
-; CHECK: br label %loop
-
-loop:
-  br i1 %cmp1, label %if.end, label %if.then
-
-if.then:
-  br label %if.end
-
-; CHECK-LABEL: if.end:
-; CHECK-DISABLED: %phi1 = phi i64 [ 0, %loop ], [ 1, %if.then ]
-if.end:
-  %phi1 = phi i64 [ 0, %loop ], [ 1, %if.then ]
-  br i1 %cmp2, label %if.end2, label %if.then2
-
-; CHECK-LABEL: if.then2:
-; CHECK-DISABLED: %d = getelementptr inbounds i32, ptr %g, i64 %phi1
-if.then2:
-  %d = getelementptr inbounds i32, ptr %g, i64 %phi1
-  store i32 1, ptr %d, align 4
-  br label %if.end2
-
-; CHECK-LABEL: if.end2:
-; CHECK-DISABLED: %phi2 = phi i64 [ 2, %if.end ], [ 3, %if.then2 ]
-if.end2:
-  %phi2 = phi i64 [ 2, %if.end ], [ 3, %if.then2 ]
-  br i1 %cmp3, label %loop.backedge, label %if.then3
-
-; CHECK-LABEL: if.then3:
-; CHECK-DISABLED: %e = getelementptr inbounds i32, ptr %g, i64 %phi2
-if.then3:
-  %e = getelementptr inbounds i32, ptr %g, i64 %phi2
-  store i32 1, ptr %e, align 4
-  br label %loop.backedge
-
-loop.backedge:
-  br label %loop
-}
-
-; The order that we hoist instructions from the loop is different to the textual
-; order in the function. Check that we can rehoist this correctly.
-; CHECK-LABEL: @rehoist_wrong_order_1
-define void @rehoist_wrong_order_1(ptr %ptr, i1 %arg) {
-; CHECK-LABEL: entry
-; CHECK-DAG: %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
-; CHECK-DAG: %gep3 = getelementptr inbounds i32, ptr %ptr, i64 3
-; CHECK-DAG: %gep1 = getelementptr inbounds i32, ptr %ptr, i64 1
-; CHECK-ENABLED: br i1 %arg, label %[[IF1_LICM:.*]], label %[[ELSE1_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF1_LICM]]:
-; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE1_LICM]]:
-; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM]]
-
-; CHECK-ENABLED: [[LOOP_BACKEDGE_LICM]]:
-; CHECK-ENABLED: br i1 %arg, label %[[IF3_LICM:.*]], label %[[END_LICM:.*]]
-
-; CHECK-ENABLED: [[IF3_LICM]]:
-; CHECK-ENABLED: br label %[[END_LICM]]
-
-; CHECK-ENABLED: [[END_LICM]]:
-; CHECK: br label %loop
-
-loop:
-  br i1 %arg, label %if1, label %else1
-
-if1:
-  %gep1 = getelementptr inbounds i32, ptr %ptr, i64 1
-  store i32 0, ptr %gep1, align 4
-  br label %loop.backedge
-
-else1:
-  %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
-  store i32 0, ptr %gep2, align 4
-  br i1 %arg, label %if2, label %loop.backedge
-
-if2:
-  br i1 %arg, label %if3, label %end
-
-if3:
-  %gep3 = getelementptr inbounds i32, ptr %ptr, i64 3
-  store i32 0, ptr %gep3, align 4
-  br label %end
-
-end:
-  br label %loop.backedge
-
-loop.backedge:
-  br label %loop
-
-}
-
-; CHECK-LABEL: @rehoist_wrong_order_2
-define void @rehoist_wrong_order_2(ptr %ptr, i1 %arg) {
-; CHECK-LABEL: entry
-; CHECK-DAG: %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
-; CHECK-DAG: %gep3 = getelementptr inbounds i32, ptr %gep2, i64 3
-; CHECK-DAG: %gep1 = getelementptr inbounds i32, ptr %ptr, i64 1
-; CHECK-ENABLED: br i1 %arg, label %[[IF1_LICM:.*]], label %[[ELSE1_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF1_LICM]]:
-; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE1_LICM]]:
-; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM]]
-
-; CHECK-ENABLED: [[LOOP_BACKEDGE_LICM]]:
-; CHECK-ENABLED: br i1 %arg, label %[[IF3_LICM:.*]], label %[[END_LICM:.*]]
-
-; CHECK-ENABLED: [[IF3_LICM]]:
-; CHECK-ENABLED: br label %[[END_LICM]]
-
-; CHECK-ENABLED: [[END_LICM]]:
-; CHECK: br label %loop
-
-loop:
-  br i1 %arg, label %if1, label %else1
-
-if1:
-  %gep1 = getelementptr inbounds i32, ptr %ptr, i64 1
-  store i32 0, ptr %gep1, align 4
-  br label %loop.backedge
-
-else1:
-  %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
-  store i32 0, ptr %gep2, align 4
-  br i1 %arg, label %if2, label %loop.backedge
-
-if2:
-  br i1 %arg, label %if3, label %end
-
-if3:
-  %gep3 = getelementptr inbounds i32, ptr %gep2, i64 3
-  store i32 0, ptr %gep3, align 4
-  br label %end
-
-end:
-  br label %loop.backedge
-
-loop.backedge:
-  br label %loop
-}
-
-; CHECK-LABEL: @rehoist_wrong_order_3
-define void @rehoist_wrong_order_3(ptr %ptr, i1 %arg) {
-; CHECK-LABEL: entry
-; CHECK-DAG: %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
-; CHECK-DAG: %gep1 = getelementptr inbounds i32, ptr %ptr, i64 1
-; CHECK-ENABLED: br i1 %arg, label %[[IF1_LICM:.*]], label %[[ELSE1_LICM:.*]]
-entry:
-  br label %loop
-
-; CHECK-ENABLED: [[IF1_LICM]]:
-; CHECK-ENABLED: br label %[[IF2_LICM:.*]]
-
-; CHECK-ENABLED: [[ELSE1_LICM]]:
-; CHECK-ENABLED: br label %[[IF2_LICM]]
-
-; CHECK-ENABLED: [[IF2_LICM]]:
-; CHECK-ENABLED: %phi = phi ptr [ %gep1, %[[IF1_LICM]] ], [ %gep2, %[[ELSE1_LICM]] ]
-; CHECK-ENABLED: %gep3 = getelementptr inbounds i32, ptr %phi, i64 3
-; CHECK-ENABLED: br i1 %arg, label %[[IF3_LICM:.*]], label %[[END_LICM:.*]]
-
-; CHECK-ENABLED: [[IF3_LICM]]:
-; CHECK-ENABLED: br label %[[END_LICM]]
-
-; CHECK-ENABLED: [[END_LICM]]:
-; CHECK: br label %loop
-
-loop:
-  br i1 %arg, label %if1, label %else1
-
-if1:
-  %gep1 = getelementptr inbounds i32, ptr %ptr, i64 1
-  store i32 0, ptr %gep1, align 4
-  br label %if2
-
-else1:
-  %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
-  store i32 0, ptr %gep2, align 4
-  br i1 %arg, label %if2, label %loop.backedge
-
-if2:
-  %phi = phi ptr [ %gep1, %if1 ], [ %gep2, %else1 ]
-  br i1 %arg, label %if3, label %end
-
-if3:
-  %gep3 = getelementptr inbounds i32, ptr %phi, i64 3
-  store i32 0, ptr %gep3, align 4
-  br label %end
-
-end:
-  br label %loop.backedge
-
-loop.backedge:
-  br label %loop
-}
diff --git a/llvm/test/Transforms/LICM/pr40317.ll b/llvm/test/Transforms/LICM/pr40317.ll
deleted file mode 100644
index 32e0dfabd27ca4..00000000000000
--- a/llvm/test/Transforms/LICM/pr40317.ll
+++ /dev/null
@@ -1,62 +0,0 @@
-; RUN: opt -S -mcpu=z13 -passes=licm -licm-control-flow-hoisting -verify-memoryssa < %s | FileCheck %s
-
-target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
-target triple = "s390x-ibm-linux"
-
-%0 = type { %1, %1, i16, %2 }
-%1 = type <{ i16, i8, i32, i32, i32, i64, i64 }>
-%2 = type { i8, i16, i16, [2 x i8] }
-
- at 0 = internal global %0 { %1 <{ i16 22437, i8 117, i32 2017322857, i32 900074563, i32 -1390364, i64 0, i64 0 }>, %1 <{ i16 0, i8 7, i32 -387299562, i32 925371866, i32 -1, i64 4826244575317081679, i64 1 }>, i16 8, %2 { i8 0, i16 0, i16 3, [2 x i8] undef } }, align 2
- at g_18 = external dso_local global i64, align 8
-
-; Function Attrs: argmemonly nounwind
-declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1) #1
-
-; CHECK-LABEL: @func_94
-; CHECK: bb:
-; CHECK: tail call void @llvm.memset.p0.i64
-; CHECK: load i32
-; CHECK: bb6.licm:
-; Function Attrs: noreturn nounwind
-define dso_local void @func_94(i16 %arg, ptr nocapture %arg1) local_unnamed_addr #3 {
-bb:
-  tail call void @llvm.memset.p0.i64(ptr align 8 undef, i8 0, i64 80, i1 false)
-  br label %bb3
-
-bb3:                                              ; preds = %bb13, %bb
-  %tmp5 = icmp eq i16 %arg, 0
-  br i1 %tmp5, label %bb6, label %bb13
-
-bb6:                                              ; preds = %bb3
-  %tmp7 = load i32, ptr getelementptr inbounds (%0, ptr @0, i64 0, i32 1, i32 2), align 1, !tbaa !11
-  %tmp8 = zext i32 %tmp7 to i64
-  %sext = shl i64 %tmp8, 56
-  %tmp10 = ashr exact i64 %sext, 56
-  store i64 %tmp10, ptr %arg1, align 8, !tbaa !12
-  br label %bb13
-
-bb13:                                             ; preds = %bb3, %bb6
-  br label %bb3
-}
-
-attributes #0 = { "use-soft-float"="false" }
-attributes #1 = { argmemonly nounwind }
-attributes #2 = { norecurse nounwind readnone "use-soft-float"="false" }
-attributes #3 = { noreturn nounwind "use-soft-float"="false" }
-
-!llvm.ident = !{!0}
-
-!0 = !{!"clang version 8.0.0 (http://llvm.org/git/clang.git e593a791f2cf19db84237b0b9d632e9966a00a39) (http://llvm.org/git/llvm.git fe0523d1bd7def3ef62cfb3dd37a8b1941aafa81)"}
-!1 = !{!2, !8, i64 46}
-!2 = !{!"S5", !3, i64 0, !3, i64 31, !4, i64 62, !9, i64 64}
-!3 = !{!"S2", !4, i64 0, !5, i64 2, !7, i64 3, !7, i64 7, !7, i64 11, !8, i64 15, !8, i64 23}
-!4 = !{!"short", !5, i64 0}
-!5 = !{!"omnipotent char", !6, i64 0}
-!6 = !{!"Simple C/C++ TBAA"}
-!7 = !{!"int", !5, i64 0}
-!8 = !{!"long", !5, i64 0}
-!9 = !{!"S3", !7, i64 0, !4, i64 2, !4, i64 4}
-!10 = !{!2, !7, i64 42}
-!11 = !{!2, !7, i64 34}
-!12 = !{!8, !8, i64 0}



More information about the llvm-commits mailing list