Index: llvm/include/llvm/Analysis/MustExecute.h =================================================================== --- llvm/include/llvm/Analysis/MustExecute.h +++ llvm/include/llvm/Analysis/MustExecute.h @@ -178,6 +178,12 @@ 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 @@ 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 @@ /// 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 @@ 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; + using VisitedSetTy = + DenseSet>; /// Private constructors. MustBeExecutedIterator(ExplorerTy &Explorer, const Instruction *I); @@ -339,6 +351,9 @@ /// 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 @@ /// 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,25 @@ /// \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 = true, + bool ExploreCFGBackward = true, GetterTy LIGetter = [](const Function &) { return nullptr; }, + GetterTy DTGetter = + [](const Function &) { return nullptr; }, GetterTy 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 +495,28 @@ 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 +524,7 @@ /// PostDominatorTree. ///{ GetterTy LIGetter; + GetterTy DTGetter; GetterTy PDTGetter; ///} Index: llvm/lib/Analysis/MustExecute.cpp =================================================================== --- llvm/lib/Analysis/MustExecute.cpp +++ llvm/lib/Analysis/MustExecute.cpp @@ -368,12 +368,21 @@ LIs.push_back(LI); return LI; }; + GetterTy DTGetter = [&](const Function &F) { + DominatorTree *DT = new DominatorTree(const_cast(F)); + DTs.push_back(DT); + return DT; + }; GetterTy PDTGetter = [&](const Function &F) { PostDominatorTree *PDT = new PostDominatorTree(const_cast(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 @@ 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 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 @@ 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 @@ } 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; } Index: llvm/test/Analysis/MustExecute/must_be_executed_context.ll =================================================================== --- llvm/test/Analysis/MustExecute/must_be_executed_context.ll +++ llvm/test/Analysis/MustExecute/must_be_executed_context.ll @@ -48,6 +48,7 @@ ; 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 +63,10 @@ ; 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 +75,11 @@ ; 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 +90,32 @@ ; 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 +183,12 @@ ; 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 @@ -176,6 +207,13 @@ ; 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 +235,21 @@ ; 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 +276,31 @@ ; ME: call void @E() ; ME-NOT: mustexec ; ME-NEXT: br -; FIXME: Missing A, B, and D (backward), as well as 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 +316,31 @@ ; 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 +350,24 @@ ; 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 +392,62 @@ 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 +465,7 @@ } 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 +474,17 @@ ; 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 +493,8 @@ ; 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 +502,39 @@ ; 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 Index: llvm/test/Transforms/Attributor/dereferenceable-1.ll =================================================================== --- llvm/test/Transforms/Attributor/dereferenceable-1.ll +++ llvm/test/Transforms/Attributor/dereferenceable-1.ll @@ -143,9 +143,7 @@ ; 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 @@ %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 Index: llvm/test/Transforms/Attributor/heap_to_stack.ll =================================================================== --- llvm/test/Transforms/Attributor/heap_to_stack.ll +++ llvm/test/Transforms/Attributor/heap_to_stack.ll @@ -170,7 +170,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ %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 } Index: llvm/test/Transforms/Attributor/misc.ll =================================================================== --- llvm/test/Transforms/Attributor/misc.ll +++ 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 @@ ; 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 @@ ; 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 @@ ; 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: Index: llvm/test/Transforms/Attributor/nonnull.ll =================================================================== --- llvm/test/Transforms/Attributor/nonnull.ll +++ llvm/test/Transforms/Attributor/nonnull.ll @@ -209,8 +209,7 @@ 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 @@ } 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 }