forked from OSchip/llvm-project
				
			[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
This commit is contained in:
		
							parent
							
								
									8e76fec0ae
								
							
						
					
					
						commit
						e253cdda35
					
				| 
						 | 
				
			
			@ -178,6 +178,12 @@ public:
 | 
			
		|||
 | 
			
		||||
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 @@ private:
 | 
			
		|||
  /// 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 @@ private:
 | 
			
		|||
  /// 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 @@ private:
 | 
			
		|||
  /// PostDominatorTree.
 | 
			
		||||
  ///{
 | 
			
		||||
  GetterTy<const LoopInfo> LIGetter;
 | 
			
		||||
  GetterTy<const DominatorTree> DTGetter;
 | 
			
		||||
  GetterTy<const PostDominatorTree> PDTGetter;
 | 
			
		||||
  ///}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -569,8 +569,10 @@ private:
 | 
			
		|||
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>>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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]   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
 | 
			
		||||
| 
						 | 
				
			
			@ -296,31 +396,57 @@ define i32 @nonnull_exec_ctx_1(i32* %a, i32 %b) {
 | 
			
		|||
; 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue