[llvm] e253cdd - [MustExecute] Add backward exploration for must-be-executed-context

Hideto Ueno via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 19 21:50:03 PST 2020


Author: Hideto Ueno
Date: 2020-02-20T14:49:30+09:00
New Revision: e253cdda35eb24f29170aaaf102caed94a85201c

URL: https://github.com/llvm/llvm-project/commit/e253cdda35eb24f29170aaaf102caed94a85201c
DIFF: https://github.com/llvm/llvm-project/commit/e253cdda35eb24f29170aaaf102caed94a85201c.diff

LOG: [MustExecute] Add backward exploration for must-be-executed-context

Summary:
As mentioned in D71974, it is useful for must-be-executed-context to explore CFG backwardly.
This patch is ported from parts of D64975. We use a dominator tree to find the previous context if
a dominator tree is available.

Reviewers: jdoerfert, hfinkel, baziotis, sstefan1

Reviewed By: jdoerfert

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D74817

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/MustExecute.h
    llvm/include/llvm/Transforms/IPO/Attributor.h
    llvm/lib/Analysis/MustExecute.cpp
    llvm/test/Analysis/MustExecute/must_be_executed_context.ll
    llvm/test/Transforms/Attributor/dereferenceable-1.ll
    llvm/test/Transforms/Attributor/heap_to_stack.ll
    llvm/test/Transforms/Attributor/misc.ll
    llvm/test/Transforms/Attributor/nonnull.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/MustExecute.h b/llvm/include/llvm/Analysis/MustExecute.h
index d88cdf40ed87..56db454470b7 100644
--- a/llvm/include/llvm/Analysis/MustExecute.h
+++ b/llvm/include/llvm/Analysis/MustExecute.h
@@ -178,6 +178,12 @@ class ICFLoopSafetyInfo: public LoopSafetyInfo {
 
 struct MustBeExecutedContextExplorer;
 
+/// Enum that allows us to spell out the direction.
+enum class ExplorationDirection {
+  BACKWARD = 0,
+  FORWARD = 1,
+};
+
 /// Must be executed iterators visit stretches of instructions that are
 /// guaranteed to be executed together, potentially with other instruction
 /// executed in-between.
@@ -282,16 +288,18 @@ struct MustBeExecutedIterator {
 
   MustBeExecutedIterator(const MustBeExecutedIterator &Other)
       : Visited(Other.Visited), Explorer(Other.Explorer),
-        CurInst(Other.CurInst) {}
+        CurInst(Other.CurInst), Head(Other.Head), Tail(Other.Tail) {}
 
   MustBeExecutedIterator(MustBeExecutedIterator &&Other)
       : Visited(std::move(Other.Visited)), Explorer(Other.Explorer),
-        CurInst(Other.CurInst) {}
+        CurInst(Other.CurInst), Head(Other.Head), Tail(Other.Tail) {}
 
   MustBeExecutedIterator &operator=(MustBeExecutedIterator &&Other) {
     if (this != &Other) {
       std::swap(Visited, Other.Visited);
       std::swap(CurInst, Other.CurInst);
+      std::swap(Head, Other.Head);
+      std::swap(Tail, Other.Tail);
     }
     return *this;
   }
@@ -315,7 +323,7 @@ struct MustBeExecutedIterator {
   /// Equality and inequality operators. Note that we ignore the history here.
   ///{
   bool operator==(const MustBeExecutedIterator &Other) const {
-    return CurInst == Other.CurInst;
+    return CurInst == Other.CurInst && Head == Other.Head && Tail == Other.Tail;
   }
 
   bool operator!=(const MustBeExecutedIterator &Other) const {
@@ -328,10 +336,14 @@ struct MustBeExecutedIterator {
   const Instruction *getCurrentInst() const { return CurInst; }
 
   /// Return true if \p I was encountered by this iterator already.
-  bool count(const Instruction *I) const { return Visited.count(I); }
+  bool count(const Instruction *I) const {
+    return Visited.count({I, ExplorationDirection::FORWARD}) ||
+           Visited.count({I, ExplorationDirection::BACKWARD});
+  }
 
 private:
-  using VisitedSetTy = DenseSet<const Instruction *>;
+  using VisitedSetTy =
+      DenseSet<PointerIntPair<const Instruction *, 1, ExplorationDirection>>;
 
   /// Private constructors.
   MustBeExecutedIterator(ExplorerTy &Explorer, const Instruction *I);
@@ -339,6 +351,9 @@ struct MustBeExecutedIterator {
   /// Reset the iterator to its initial state pointing at \p I.
   void reset(const Instruction *I);
 
+  /// Reset the iterator to point at \p I, keep cached state.
+  void resetInstruction(const Instruction *I);
+
   /// Try to advance one of the underlying positions (Head or Tail).
   ///
   /// \return The next instruction in the must be executed context, or nullptr
@@ -357,6 +372,11 @@ struct MustBeExecutedIterator {
   /// initially the program point itself.
   const Instruction *CurInst;
 
+  /// Two positions that mark the program points where this iterator will look
+  /// for the next instruction. Note that the current instruction is either the
+  /// one pointed to by Head, Tail, or both.
+  const Instruction *Head, *Tail;
+
   friend struct MustBeExecutedContextExplorer;
 };
 
@@ -379,14 +399,24 @@ struct MustBeExecutedContextExplorer {
   /// \param ExploreInterBlock    Flag to indicate if instructions in blocks
   ///                             other than the parent of PP should be
   ///                             explored.
+  /// \param ExploreCFGForward    Flag to indicate if instructions located after
+  ///                             PP in the CFG, e.g., post-dominating PP,
+  ///                             should be explored.
+  /// \param ExploreCFGBackward   Flag to indicate if instructions located
+  ///                             before PP in the CFG, e.g., dominating PP,
+  ///                             should be explored.
   MustBeExecutedContextExplorer(
-      bool ExploreInterBlock,
+      bool ExploreInterBlock, bool ExploreCFGForward, bool ExploreCFGBackward,
       GetterTy<const LoopInfo> LIGetter =
           [](const Function &) { return nullptr; },
+      GetterTy<const DominatorTree> DTGetter =
+          [](const Function &) { return nullptr; },
       GetterTy<const PostDominatorTree> PDTGetter =
           [](const Function &) { return nullptr; })
-      : ExploreInterBlock(ExploreInterBlock), LIGetter(LIGetter),
-        PDTGetter(PDTGetter), EndIterator(*this, nullptr) {}
+      : ExploreInterBlock(ExploreInterBlock),
+        ExploreCFGForward(ExploreCFGForward),
+        ExploreCFGBackward(ExploreCFGBackward), LIGetter(LIGetter),
+        DTGetter(DTGetter), PDTGetter(PDTGetter), EndIterator(*this, nullptr) {}
 
   /// Clean up the dynamically allocated iterators.
   ~MustBeExecutedContextExplorer() {
@@ -464,14 +494,28 @@ struct MustBeExecutedContextExplorer {
   const Instruction *
   getMustBeExecutedNextInstruction(MustBeExecutedIterator &It,
                                    const Instruction *PP);
+  /// Return the previous instr. that is guaranteed to be executed before \p PP.
+  ///
+  /// \param It              The iterator that is used to traverse the must be
+  ///                        executed context.
+  /// \param PP              The program point for which the previous instr.
+  ///                        that is guaranteed to execute is determined.
+  const Instruction *
+  getMustBeExecutedPrevInstruction(MustBeExecutedIterator &It,
+                                   const Instruction *PP);
 
   /// Find the next join point from \p InitBB in forward direction.
   const BasicBlock *findForwardJoinPoint(const BasicBlock *InitBB);
 
+  /// Find the next join point from \p InitBB in backward direction.
+  const BasicBlock *findBackwardJoinPoint(const BasicBlock *InitBB);
+
   /// Parameter that limit the performed exploration. See the constructor for
   /// their meaning.
   ///{
   const bool ExploreInterBlock;
+  const bool ExploreCFGForward;
+  const bool ExploreCFGBackward;
   ///}
 
 private:
@@ -479,6 +523,7 @@ struct MustBeExecutedContextExplorer {
   /// PostDominatorTree.
   ///{
   GetterTy<const LoopInfo> LIGetter;
+  GetterTy<const DominatorTree> DTGetter;
   GetterTy<const PostDominatorTree> PDTGetter;
   ///}
 

diff  --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 2fd5f59efa66..1cc29cdb6d31 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -569,8 +569,10 @@ struct AnalysisGetter {
 struct InformationCache {
   InformationCache(const Module &M, AnalysisGetter &AG,
                    SetVector<Function *> *CGSCC)
-      : DL(M.getDataLayout()), Explorer(/* ExploreInterBlock */ true), AG(AG),
-        CGSCC(CGSCC) {}
+      : DL(M.getDataLayout()),
+        Explorer(/* ExploreInterBlock */ true, /* ExploreCFGForward */ true,
+                 /* ExploreCFGBackward */ true),
+        AG(AG), CGSCC(CGSCC) {}
 
   /// A map type from opcodes to instructions with this opcode.
   using OpcodeInstMapTy = DenseMap<unsigned, SmallVector<Instruction *, 32>>;

diff  --git a/llvm/lib/Analysis/MustExecute.cpp b/llvm/lib/Analysis/MustExecute.cpp
index 952c2cbfec4e..ec285c51f160 100644
--- a/llvm/lib/Analysis/MustExecute.cpp
+++ b/llvm/lib/Analysis/MustExecute.cpp
@@ -368,12 +368,21 @@ bool MustBeExecutedContextPrinter::runOnModule(Module &M) {
     LIs.push_back(LI);
     return LI;
   };
+  GetterTy<DominatorTree> DTGetter = [&](const Function &F) {
+    DominatorTree *DT = new DominatorTree(const_cast<Function &>(F));
+    DTs.push_back(DT);
+    return DT;
+  };
   GetterTy<PostDominatorTree> PDTGetter = [&](const Function &F) {
     PostDominatorTree *PDT = new PostDominatorTree(const_cast<Function &>(F));
     PDTs.push_back(PDT);
     return PDT;
   };
-  MustBeExecutedContextExplorer Explorer(true, LIGetter, PDTGetter);
+  MustBeExecutedContextExplorer Explorer(
+      /* ExploreInterBlock */ true,
+      /* ExploreCFGForward */ true,
+      /* ExploreCFGBackward */ true, LIGetter, DTGetter, PDTGetter);
+
   for (Function &F : M) {
     for (Instruction &I : instructions(F)) {
       dbgs() << "-- Explore context of: " << I << "\n";
@@ -632,6 +641,72 @@ MustBeExecutedContextExplorer::findForwardJoinPoint(const BasicBlock *InitBB) {
   LLVM_DEBUG(dbgs() << "\tJoin block: " << JoinBB->getName() << "\n");
   return JoinBB;
 }
+const BasicBlock *
+MustBeExecutedContextExplorer::findBackwardJoinPoint(const BasicBlock *InitBB) {
+  const LoopInfo *LI = LIGetter(*InitBB->getParent());
+  const DominatorTree *DT = DTGetter(*InitBB->getParent());
+  LLVM_DEBUG(dbgs() << "\tFind backward join point for " << InitBB->getName()
+                    << (LI ? " [LI]" : "") << (DT ? " [DT]" : ""));
+
+  // Try to determine a join block through the help of the dominance tree. If no
+  // tree was provided, we perform simple pattern matching for one block
+  // conditionals only.
+  if (DT)
+    if (const auto *InitNode = DT->getNode(InitBB))
+      if (const auto *IDomNode = InitNode->getIDom())
+        return IDomNode->getBlock();
+
+  const Loop *L = LI ? LI->getLoopFor(InitBB) : nullptr;
+  const BasicBlock *HeaderBB = L ? L->getHeader() : nullptr;
+
+  // Determine the predecessor blocks but ignore backedges.
+  SmallVector<const BasicBlock *, 8> Worklist;
+  for (const BasicBlock *PredBB : predecessors(InitBB)) {
+    bool IsBackedge =
+        (PredBB == InitBB) || (HeaderBB == InitBB && L->contains(PredBB));
+    // Loop backedges are ignored in backwards propagation: control has to come
+    // from somewhere.
+    if (!IsBackedge)
+      Worklist.push_back(PredBB);
+  }
+
+  // If there are no other predecessor blocks, there is no join point.
+  if (Worklist.empty())
+    return nullptr;
+
+  // If there is one predecessor block, it is the join point.
+  if (Worklist.size() == 1)
+    return Worklist[0];
+
+  const BasicBlock *JoinBB = nullptr;
+  if (Worklist.size() == 2) {
+    const BasicBlock *Pred0 = Worklist[0];
+    const BasicBlock *Pred1 = Worklist[1];
+    const BasicBlock *Pred0UniquePred = Pred0->getUniquePredecessor();
+    const BasicBlock *Pred1UniquePred = Pred1->getUniquePredecessor();
+    if (Pred0 == Pred1UniquePred) {
+      // InitBB <-          Pred0 = JoinBB
+      // InitBB <- Pred1 <- Pred0 = JoinBB
+      JoinBB = Pred0;
+    } else if (Pred1 == Pred0UniquePred) {
+      // InitBB <- Pred0 <- Pred1 = JoinBB
+      // InitBB <-          Pred1 = JoinBB
+      JoinBB = Pred1;
+    } else if (Pred0UniquePred == Pred1UniquePred) {
+      // InitBB <- Pred0 <- JoinBB
+      // InitBB <- Pred1 <- JoinBB
+      JoinBB = Pred0UniquePred;
+    }
+  }
+
+  if (!JoinBB && L)
+    JoinBB = L->getHeader();
+
+  // In backwards direction there is no need to show termination of previous
+  // instructions. If they do not terminate, the code afterward is dead, making
+  // any information/transformation correct anyway.
+  return JoinBB;
+}
 
 const Instruction *
 MustBeExecutedContextExplorer::getMustBeExecutedNextInstruction(
@@ -690,6 +765,47 @@ MustBeExecutedContextExplorer::getMustBeExecutedNextInstruction(
   return nullptr;
 }
 
+const Instruction *
+MustBeExecutedContextExplorer::getMustBeExecutedPrevInstruction(
+    MustBeExecutedIterator &It, const Instruction *PP) {
+  if (!PP)
+    return PP;
+
+  bool IsFirst = !(PP->getPrevNode());
+  LLVM_DEBUG(dbgs() << "Find next instruction for " << *PP
+                    << (IsFirst ? " [IsFirst]" : "") << "\n");
+
+  // If we explore only inside a given basic block we stop at the first
+  // instruction.
+  if (!ExploreInterBlock && IsFirst) {
+    LLVM_DEBUG(dbgs() << "\tReached block front in intra-block mode, done\n");
+    return nullptr;
+  }
+
+  // The block and function that contains the current position.
+  const BasicBlock *PPBlock = PP->getParent();
+
+  // If we are inside a block we know what instruction was executed before, the
+  // previous one.
+  if (!IsFirst) {
+    const Instruction *PrevPP = PP->getPrevNode();
+    LLVM_DEBUG(
+        dbgs() << "\tIntermediate instruction, continue with previous\n");
+    // We did not enter a callee so we simply return the previous instruction.
+    return PrevPP;
+  }
+
+  // Finally, we have to handle the case where the program point is the first in
+  // a block but not in the function. We use the findBackwardJoinPoint helper
+  // function with information about the function and helper analyses, if
+  // available.
+  if (const BasicBlock *JoinBB = findBackwardJoinPoint(PPBlock))
+    return &JoinBB->back();
+
+  LLVM_DEBUG(dbgs() << "\tNo join point found\n");
+  return nullptr;
+}
+
 MustBeExecutedIterator::MustBeExecutedIterator(
     MustBeExecutedContextExplorer &Explorer, const Instruction *I)
     : Explorer(Explorer), CurInst(I) {
@@ -697,16 +813,31 @@ MustBeExecutedIterator::MustBeExecutedIterator(
 }
 
 void MustBeExecutedIterator::reset(const Instruction *I) {
-  CurInst = I;
   Visited.clear();
-  Visited.insert(I);
+  resetInstruction(I);
+}
+
+void MustBeExecutedIterator::resetInstruction(const Instruction *I) {
+  CurInst = I;
+  Head = Tail = nullptr;
+  Visited.insert({I, ExplorationDirection::FORWARD});
+  Visited.insert({I, ExplorationDirection::BACKWARD});
+  if (Explorer.ExploreCFGForward)
+    Head = I;
+  if (Explorer.ExploreCFGBackward)
+    Tail = I;
 }
 
 const Instruction *MustBeExecutedIterator::advance() {
   assert(CurInst && "Cannot advance an end iterator!");
-  const Instruction *Next =
-      Explorer.getMustBeExecutedNextInstruction(*this, CurInst);
-  if (Next && !Visited.insert(Next).second)
-    Next = nullptr;
-  return Next;
+  Head = Explorer.getMustBeExecutedNextInstruction(*this, Head);
+  if (Head && Visited.insert({Head, ExplorationDirection ::FORWARD}).second)
+    return Head;
+  Head = nullptr;
+
+  Tail = Explorer.getMustBeExecutedPrevInstruction(*this, Tail);
+  if (Tail && Visited.insert({Tail, ExplorationDirection ::BACKWARD}).second)
+    return Tail;
+  Tail = nullptr;
+  return nullptr;
 }

diff  --git a/llvm/test/Analysis/MustExecute/must_be_executed_context.ll b/llvm/test/Analysis/MustExecute/must_be_executed_context.ll
index fd650872dd91..d65e08e6ff3f 100644
--- a/llvm/test/Analysis/MustExecute/must_be_executed_context.ll
+++ b/llvm/test/Analysis/MustExecute/must_be_executed_context.ll
@@ -24,7 +24,6 @@
 ;                F    | A, B,       E, F
 ;                   G | A, B,       E, F, G
 ;
-; FIXME: We miss the B -> E and backward exploration.
 ;
 ; There are no loops so print-mustexec will not do anything.
 ; ME-NOT: mustexec
@@ -48,6 +47,7 @@ bb:
 ; MBEC-NEXT:   [F: simple_conditional]   br i1 %tmp, label %bb2, label %bb1
 ; MBEC-NEXT:   [F: simple_conditional]   call void @E()
 ; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NEXT:   [F: simple_conditional]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: %tmp
 
@@ -62,6 +62,10 @@ bb1:                                              ; preds = %bb
 ; MBEC-NEXT:   [F: simple_conditional]   br label %bb2
 ; MBEC-NEXT:   [F: simple_conditional]   call void @E()
 ; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NEXT:   [F: simple_conditional]   br i1 %tmp, label %bb2, label %bb1
+; MBEC-NEXT:   [F: simple_conditional]   %tmp = icmp eq i32 %arg, 0
+; MBEC-NEXT:   [F: simple_conditional]   call void @B()
+; MBEC-NEXT:   [F: simple_conditional]   call void @A()
 ; MBEC-NOT:    call
 
   call void @D()
@@ -70,6 +74,11 @@ bb1:                                              ; preds = %bb
 ; MBEC-NEXT:   [F: simple_conditional]   br label %bb2
 ; MBEC-NEXT:   [F: simple_conditional]   call void @E()
 ; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NEXT:   [F: simple_conditional]   call void @C()
+; MBEC-NEXT:   [F: simple_conditional]   br i1 %tmp, label %bb2, label %bb1
+; MBEC-NEXT:   [F: simple_conditional]   %tmp = icmp eq i32 %arg, 0
+; MBEC-NEXT:   [F: simple_conditional]   call void @B()
+; MBEC-NEXT:   [F: simple_conditional]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: br
 
@@ -80,17 +89,32 @@ bb2:                                              ; preds = %bb, %bb1
 ; MBEC:      -- Explore context of:   call void @E()
 ; MBEC-NEXT:   [F: simple_conditional]   call void @E()
 ; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NEXT:   [F: simple_conditional]   br i1 %tmp, label %bb2, label %bb1
+; MBEC-NEXT:   [F: simple_conditional]   %tmp = icmp eq i32 %arg, 0
+; MBEC-NEXT:   [F: simple_conditional]   call void @B()
+; MBEC-NEXT:   [F: simple_conditional]   call void @A()
 ; MBEC-NOT:    call
 
   call void @F() ; might not return!
 ; MBEC:      -- Explore context of:   call void @F()
 ; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NEXT:   [F: simple_conditional]   call void @E()
+; MBEC-NEXT:   [F: simple_conditional]   br i1 %tmp, label %bb2, label %bb1
+; MBEC-NEXT:   [F: simple_conditional]   %tmp = icmp eq i32 %arg, 0
+; MBEC-NEXT:   [F: simple_conditional]   call void @B()
+; MBEC-NEXT:   [F: simple_conditional]   call void @A()
 ; MBEC-NOT:    call
 
   call void @G()
 ; MBEC:      -- Explore context of:   call void @G()
 ; MBEC-NEXT:   [F: simple_conditional]   call void @G()
 ; MBEC-NEXT:   [F: simple_conditional]   ret void
+; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NEXT:   [F: simple_conditional]   call void @E()
+; MBEC-NEXT:   [F: simple_conditional]   br i1 %tmp, label %bb2, label %bb1
+; MBEC-NEXT:   [F: simple_conditional]   %tmp = icmp eq i32 %arg, 0
+; MBEC-NEXT:   [F: simple_conditional]   call void @B()
+; MBEC-NEXT:   [F: simple_conditional]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: ret
 
@@ -158,6 +182,12 @@ bb2:                                              ; preds = %.backedge, %bb
 ; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp = add nsw i32 %.0, 1
 ; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp3 = icmp eq i32 %tmp, %arg1
 ; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp3, label %bb4, label %bb5
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp6 = add nsw i32 %.0, 2
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp7 = icmp eq i32 %tmp6, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp7, label %bb8, label %bb9
+; MBEC-NEXT:   [F: complex_loops_and_control]   %.0 = phi i32 [ %arg, %bb ], [ %.0.be, %.backedge ]
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb2
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: %tmp
   %tmp = add nsw i32 %.0, 1
@@ -169,13 +199,19 @@ bb4:                                              ; preds = %bb2
 ; ME: call void @C()
 ; ME-NOT: mustexec
 ; ME-NEXT: br
-; FIXME: Missing A and B (backward)
 ; MBEC:      -- Explore context of:   call void @C()
 ; MBEC-NEXT:   [F: complex_loops_and_control]   call void @C()
 ; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb5
 ; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp6 = add nsw i32 %.0, 2
 ; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp7 = icmp eq i32 %tmp6, %arg1
 ; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp7, label %bb8, label %bb9
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp3, label %bb4, label %bb5
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp3 = icmp eq i32 %tmp, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp = add nsw i32 %.0, 1
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @B()
+; MBEC-NEXT:   [F: complex_loops_and_control]   %.0 = phi i32 [ %arg, %bb ], [ %.0.be, %.backedge ]
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb2
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: br
   br label %bb5
@@ -197,12 +233,21 @@ bb9:                                              ; preds = %bb5
 ; ME: call void @D()
 ; ME-NOT: mustexec
 ; ME-NEXT: %tmp10
-; FIXME: Missing A and B (backward)
 ; MBEC:      -- Explore context of:   call void @D()
 ; MBEC-NEXT:   [F: complex_loops_and_control]   call void @D()
 ; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp10 = add nsw i32 %.0, 3
 ; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp11 = icmp eq i32 %tmp10, %arg1
 ; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp11, label %bb12, label %bb13
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp7, label %bb8, label %bb9
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp7 = icmp eq i32 %tmp6, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp6 = add nsw i32 %.0, 2
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp3, label %bb4, label %bb5
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp3 = icmp eq i32 %tmp, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp = add nsw i32 %.0, 1
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @B()
+; MBEC-NEXT:   [F: complex_loops_and_control]   %.0 = phi i32 [ %arg, %bb ], [ %.0.be, %.backedge ]
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb2
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: %tmp10
   %tmp10 = add nsw i32 %.0, 3
@@ -229,13 +274,32 @@ bb18:                                             ; preds = %bb14
 ; ME: call void @E()
 ; ME-NOT: mustexec
 ; ME-NEXT: br
-; FIXME: Missing A, B, and D (backward), as well as F
+; FIXME: Missing F
 ; MBEC:      -- Explore context of:   call void @E()
-; MBEC-NEXT:   [F: complex_loops_and_control]   call void @E()
-; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb19
-; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp20 = add nsw i32 %.1, 2
-; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp21 = icmp eq i32 %tmp20, %arg1
-; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp21, label %bb14, label %bb22
+; MBEC-NEXT:  [F: complex_loops_and_control]   call void @E()
+; MBEC-NEXT:  [F: complex_loops_and_control]   br label %bb19
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp20 = add nsw i32 %.1, 2
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp21 = icmp eq i32 %tmp20, %arg1
+; MBEC-NEXT:  [F: complex_loops_and_control]   br i1 %tmp21, label %bb14, label %bb22
+; MBEC-NEXT:  [F: complex_loops_and_control]   br i1 %tmp16, label %bb17, label %bb18
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp16 = icmp eq i32 %tmp15, %arg1
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp15 = add nsw i32 %.1, 1
+; MBEC-NEXT:  [F: complex_loops_and_control]   %.1 = phi i32 [ %tmp10, %bb13 ], [ %tmp20, %bb19 ]
+; MBEC-NEXT:  [F: complex_loops_and_control]   br label %bb14
+; MBEC-NEXT:  [F: complex_loops_and_control]   br i1 %tmp11, label %bb12, label %bb13
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp11 = icmp eq i32 %tmp10, %arg1
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp10 = add nsw i32 %.0, 3
+; MBEC-NEXT:  [F: complex_loops_and_control]   call void @D()
+; MBEC-NEXT:  [F: complex_loops_and_control]   br i1 %tmp7, label %bb8, label %bb9
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp7 = icmp eq i32 %tmp6, %arg1
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp6 = add nsw i32 %.0, 2
+; MBEC-NEXT:  [F: complex_loops_and_control]   br i1 %tmp3, label %bb4, label %bb5
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp3 = icmp eq i32 %tmp, %arg1
+; MBEC-NEXT:  [F: complex_loops_and_control]   %tmp = add nsw i32 %.0, 1
+; MBEC-NEXT:  [F: complex_loops_and_control]   call void @B()
+; MBEC-NEXT:  [F: complex_loops_and_control]   %.0 = phi i32 [ %arg, %bb ], [ %.0.be, %.backedge ]
+; MBEC-NEXT:  [F: complex_loops_and_control]   br label %bb2
+; MBEC-NEXT:  [F: complex_loops_and_control]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: br
   br label %bb19
@@ -251,9 +315,31 @@ bb22:                                             ; preds = %bb19
 ; ME: call void @F()
 ; ME-NOT: mustexec
 ; ME-NEXT: br
-; FIXME: Missing A, B, and D (backward)
 ; MBEC:      -- Explore context of:   call void @F()
 ; MBEC-NEXT:   [F: complex_loops_and_control]   call void @F()
+; MBEC-NEXT:   [F: complex_loops_and_control]   %.lcssa = phi i32 [ %tmp20, %bb19 ]
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp21, label %bb14, label %bb22
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp21 = icmp eq i32 %tmp20, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp20 = add nsw i32 %.1, 2
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp16, label %bb17, label %bb18
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp16 = icmp eq i32 %tmp15, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp15 = add nsw i32 %.1, 1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %.1 = phi i32 [ %tmp10, %bb13 ], [ %tmp20, %bb19 ]
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb14
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp11, label %bb12, label %bb13
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp11 = icmp eq i32 %tmp10, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp10 = add nsw i32 %.0, 3
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @D()
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp7, label %bb8, label %bb9
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp7 = icmp eq i32 %tmp6, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp6 = add nsw i32 %.0, 2
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp3, label %bb4, label %bb5
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp3 = icmp eq i32 %tmp, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp = add nsw i32 %.0, 1
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @B()
+; MBEC-NEXT:   [F: complex_loops_and_control]   %.0 = phi i32 [ %arg, %bb ], [ %.0.be, %.backedge ]
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb2
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: br
   br label %.backedge
@@ -263,10 +349,24 @@ bb23:                                             ; preds = %bb12
 ; ME: call void @G()
 ; ME-NOT: mustexec
 ; ME-NEXT: ret
-; FIXME: Missing A, B, and D (backward)
 ; MBEC:      -- Explore context of:   call void @G()
 ; MBEC-NEXT:   [F: complex_loops_and_control]   call void @G()
 ; MBEC-NEXT:   [F: complex_loops_and_control]   ret void
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb23
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp11, label %bb12, label %bb13
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp11 = icmp eq i32 %tmp10, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp10 = add nsw i32 %.0, 3
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @D()
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp7, label %bb8, label %bb9
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp7 = icmp eq i32 %tmp6, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp6 = add nsw i32 %.0, 2
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp3, label %bb4, label %bb5
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp3 = icmp eq i32 %tmp, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp = add nsw i32 %.0, 1
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @B()
+; MBEC-NEXT:   [F: complex_loops_and_control]   %.0 = phi i32 [ %arg, %bb ], [ %.0.be, %.backedge ]
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb2
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @A()
 ; MBEC-NOT:    call
 ; MBEC:      -- Explore context of: ret
   ret void
@@ -291,36 +391,62 @@ declare i32 @g(i32*) nounwind willreturn
 declare void @h(i32*) nounwind willreturn
 
 define i32 @nonnull_exec_ctx_1(i32* %a, i32 %b) {
-; MBEC:      -- Explore context of:   %tmp3 = icmp eq i32 %b, 0
+; MBEC: -- Explore context of:   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
 ; MBEC-NEXT: -- Explore context of:   br i1 %tmp3, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   ret i32 %tmp5
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp5 = tail call i32 @g(i32* nonnull %a)
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   tail call void @h(i32* %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp8 = add nuw i32 %tmp7, 1
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp9 = icmp eq i32 %tmp8, %b
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp9, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   tail call void @h(i32* %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   tail call void @h(i32* %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp8 = add nuw i32 %tmp7, 1
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp9 = icmp eq i32 %tmp8, %b
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp9, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   %tmp8 = add nuw i32 %tmp7, 1
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp8 = add nuw i32 %tmp7, 1
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp9 = icmp eq i32 %tmp8, %b
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp9, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   tail call void @h(i32* %a)
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   %tmp9 = icmp eq i32 %tmp8, %b
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp9 = icmp eq i32 %tmp8, %b
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp9, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp8 = add nuw i32 %tmp7, 1
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   tail call void @h(i32* %a)
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   br i1 %tmp9, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp9, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp9 = icmp eq i32 %tmp8, %b
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp8 = add nuw i32 %tmp7, 1
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   tail call void @h(i32* %a)
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_1]   %tmp3 = icmp eq i32 %b, 0
 en:
   %tmp3 = icmp eq i32 %b, 0
   br i1 %tmp3, label %ex, label %hd
@@ -338,7 +464,7 @@ hd:
 }
 
 define i32 @nonnull_exec_ctx_2(i32* %a, i32 %b) nounwind willreturn {
-; MBEC:      -- Explore context of:   %tmp3 = icmp eq i32 %b, 0
+; MBEC: -- Explore context of:   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
@@ -347,11 +473,17 @@ define i32 @nonnull_exec_ctx_2(i32* %a, i32 %b) nounwind willreturn {
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   ret i32 %tmp5
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   tail call void @h(i32* %a)
@@ -360,6 +492,8 @@ define i32 @nonnull_exec_ctx_2(i32* %a, i32 %b) nounwind willreturn {
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp9, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   tail call void @h(i32* %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   tail call void @h(i32* %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp8 = add nuw i32 %tmp7, 1
@@ -367,21 +501,39 @@ define i32 @nonnull_exec_ctx_2(i32* %a, i32 %b) nounwind willreturn {
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp9, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   %tmp8 = add nuw i32 %tmp7, 1
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp8 = add nuw i32 %tmp7, 1
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp9 = icmp eq i32 %tmp8, %b
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp9, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   tail call void @h(i32* %a)
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   %tmp9 = icmp eq i32 %tmp8, %b
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp9 = icmp eq i32 %tmp8, %b
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp9, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp8 = add nuw i32 %tmp7, 1
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   tail call void @h(i32* %a)
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 ; MBEC-NEXT: -- Explore context of:   br i1 %tmp9, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp9, label %ex, label %hd
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp5 = tail call i32 @g(i32* nonnull %a)
 ; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   ret i32 %tmp5
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp9 = icmp eq i32 %tmp8, %b
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp8 = add nuw i32 %tmp7, 1
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   tail call void @h(i32* %a)
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   br i1 %tmp3, label %ex, label %hd
+; MBEC-NEXT:   [F: nonnull_exec_ctx_2]   %tmp3 = icmp eq i32 %b, 0
 en:
   %tmp3 = icmp eq i32 %b, 0
   br i1 %tmp3, label %ex, label %hd

diff  --git a/llvm/test/Transforms/Attributor/dereferenceable-1.ll b/llvm/test/Transforms/Attributor/dereferenceable-1.ll
index b42d85a34ea5..a47785ec8480 100644
--- a/llvm/test/Transforms/Attributor/dereferenceable-1.ll
+++ b/llvm/test/Transforms/Attributor/dereferenceable-1.ll
@@ -143,9 +143,7 @@ if.true:
 ; ATTRIBUTOR:   %D = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
   %D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
 
-; FIXME: This should be tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
-;        Making must-be-executed-context backward exploration will fix this.
-; ATTRIBUTOR:   %E = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) 
+; ATTRIBUTOR:   %E = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr)
   %E = tail call i32 @unkown_f(i32* %ptr)
 
   ret void
@@ -178,9 +176,7 @@ if.true:
   %D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
 
   %E = tail call i32 @unkown_f(i32* %ptr)
-; FIXME: This should be @unkown_f(i32* nonnull dereferenceable(8) %ptr) 
-;        Making must-be-executed-context backward exploration will fix this.
-; ATTRIBUTOR:   %E = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr)
+; ATTRIBUTOR:   %E = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr)
 
   ret void
 

diff  --git a/llvm/test/Transforms/Attributor/heap_to_stack.ll b/llvm/test/Transforms/Attributor/heap_to_stack.ll
index 3d8b1b3aacea..8dc9b945d589 100644
--- a/llvm/test/Transforms/Attributor/heap_to_stack.ll
+++ b/llvm/test/Transforms/Attributor/heap_to_stack.ll
@@ -170,7 +170,7 @@ define void @test8() {
   store i32 10, i32* %2
   %3 = load i32, i32* %2
   tail call void @foo(i32* %2)
-  ; CHECK: @free(i8* %1)
+  ; CHECK: @free(i8* nonnull dereferenceable(4) %1)
   tail call void @free(i8* %1)
   ret void
 }
@@ -185,7 +185,7 @@ define void @test9() {
   store i32 10, i32* %2
   %3 = load i32, i32* %2
   tail call void @foo_nounw(i32* %2)
-  ; CHECK: @free(i8* %1)
+  ; CHECK: @free(i8* nonnull dereferenceable(4) %1)
   tail call void @free(i8* %1)
   ret void
 }
@@ -307,7 +307,7 @@ define i32 @test13() {
   store i32 10, i32* %2
   %3 = load i32, i32* %2
   tail call void @free(i8* %1)
-  ; CHECK: tail call void @free(i8* noalias %1)
+  ; CHECK: tail call void @free(i8* noalias nonnull dereferenceable(4) %1)
   ret i32 %3
 }
 
@@ -320,7 +320,7 @@ define i32 @test_sle() {
   store i32 10, i32* %2
   %3 = load i32, i32* %2
   tail call void @free(i8* %1)
-  ; CHECK: tail call void @free(i8* noalias %1)
+  ; CHECK: tail call void @free(i8* noalias nonnull dereferenceable(4) %1)
   ret i32 %3
 }
 
@@ -333,7 +333,7 @@ define i32 @test_overflow() {
   store i32 10, i32* %2
   %3 = load i32, i32* %2
   tail call void @free(i8* %1)
-  ; CHECK: tail call void @free(i8* noalias %1)
+  ; CHECK: tail call void @free(i8* noalias nonnull dereferenceable(4) %1)
   ret i32 %3
 }
 
@@ -362,10 +362,10 @@ define void @test16a(i8 %v, i8** %P) {
   %1 = tail call noalias i8* @malloc(i64 4)
   ; CHECK-NEXT: store i8 %v, i8* %1
   store i8 %v, i8* %1
-  ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
+  ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree nonnull dereferenceable(1) %1)
   tail call void @no_sync_func(i8* %1)
   ; CHECK-NOT: @free(i8* %1)
-  tail call void @free(i8* %1)
+  tail call void @free(i8* nonnull dereferenceable(1) %1)
   ret void
 }
 

diff  --git a/llvm/test/Transforms/Attributor/misc.ll b/llvm/test/Transforms/Attributor/misc.ll
index f8b7504b2f5a..5f0a91128fcc 100644
--- a/llvm/test/Transforms/Attributor/misc.ll
+++ b/llvm/test/Transforms/Attributor/misc.ll
@@ -6,7 +6,7 @@
 
 define internal void @internal(void (i8*)* %fp) {
 ; CHECK-LABEL: define {{[^@]+}}@internal
-; CHECK-SAME: (void (i8*)* [[FP:%.*]])
+; CHECK-SAME: (void (i8*)* nonnull [[FP:%.*]])
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
 ; CHECK-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
@@ -19,14 +19,14 @@ define internal void @internal(void (i8*)* %fp) {
 ; CHECK-NEXT:    ret void
 ;
 ; DECL_CS-LABEL: define {{[^@]+}}@internal
-; DECL_CS-SAME: (void (i8*)* [[FP:%.*]])
+; DECL_CS-SAME: (void (i8*)* nonnull [[FP:%.*]])
 ; DECL_CS-NEXT:  entry:
 ; DECL_CS-NEXT:    [[A:%.*]] = alloca i32, align 4
 ; DECL_CS-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; DECL_CS-NEXT:    call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
 ; DECL_CS-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; DECL_CS-NEXT:    call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
-; DECL_CS-NEXT:    call void @callback2(void (i8*)* [[FP]])
+; DECL_CS-NEXT:    call void @callback2(void (i8*)* nonnull [[FP]])
 ; DECL_CS-NEXT:    [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
 ; DECL_CS-NEXT:    call void [[FP]](i8* [[TMP1]])
 ; DECL_CS-NEXT:    ret void
@@ -56,7 +56,7 @@ define void @external(void (i8*)* %fp) {
 ; CHECK-NEXT:    call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
 ; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
 ; CHECK-NEXT:    call void [[FP]](i8* [[TMP1]])
-; CHECK-NEXT:    call void @internal(void (i8*)* [[FP]])
+; CHECK-NEXT:    call void @internal(void (i8*)* nonnull [[FP]])
 ; CHECK-NEXT:    ret void
 ;
 ; DECL_CS-LABEL: define {{[^@]+}}@external
@@ -70,7 +70,7 @@ define void @external(void (i8*)* %fp) {
 ; DECL_CS-NEXT:    call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
 ; DECL_CS-NEXT:    [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
 ; DECL_CS-NEXT:    call void [[FP]](i8* [[TMP1]])
-; DECL_CS-NEXT:    call void @internal(void (i8*)* [[FP]])
+; DECL_CS-NEXT:    call void @internal(void (i8*)* nonnull [[FP]])
 ; DECL_CS-NEXT:    ret void
 ;
 entry:

diff  --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll
index 39bc63a6358e..fb5ec5514d55 100644
--- a/llvm/test/Transforms/Attributor/nonnull.ll
+++ b/llvm/test/Transforms/Attributor/nonnull.ll
@@ -209,8 +209,7 @@ bb4:                                              ; preds = %bb1
   br label %bb9
 
 bb6:                                              ; preds = %bb1
-; FIXME: missing nonnull. It should be @f2(i32* nonnull %arg)
-; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* nofree readonly %arg)
+; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* nofree nonnull readonly align 4 dereferenceable(4) %arg)
   %tmp7 = tail call i32* @f2(i32* %arg)
   ret i32* %tmp7
 
@@ -220,12 +219,9 @@ bb9:                                              ; preds = %bb4, %bb
 }
 
 define internal i32* @f2(i32* %arg) {
-; FIXME: missing nonnull. It should be nonnull @f2(i32* nonnull %arg)
-; ATTRIBUTOR: define internal nonnull i32* @f2(i32* nofree readonly %arg)
+; ATTRIBUTOR: define internal nonnull i32* @f2(i32* nofree nonnull readonly align 4 dereferenceable(4) %arg)
 bb:
-
-; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg)
-; ATTRIBUTOR:   %tmp = tail call nonnull i32* @f1(i32* nofree readonly %arg)
+; ATTRIBUTOR:   %tmp = tail call nonnull i32* @f1(i32* nofree nonnull readonly align 4 dereferenceable(4) %arg)
   %tmp = tail call i32* @f1(i32* %arg)
   ret i32* %tmp
 }


        


More information about the llvm-commits mailing list