1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[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:
Hideto Ueno 2020-02-20 13:00:43 +09:00
parent 735b538753
commit 26e1302f3c
8 changed files with 378 additions and 56 deletions

View File

@ -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;
///}

View File

@ -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>>;

View File

@ -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;
}

View File

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

View File

@ -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

View File

@ -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
}

View File

@ -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:

View File

@ -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
}