forked from OSchip/llvm-project
PredicateInfo: Handle critical edges
Summary: This adds support for placing predicateinfo such that it affects critical edges. This fixes the issues mentioned by Nuno on the mailing list. Depends on D29519 Reviewers: davide, nlopes Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D29606 llvm-svn: 294921
This commit is contained in:
parent
eccb8740d1
commit
dbe8264c93
llvm
include/llvm/Transforms/Utils
lib/Transforms/Utils
test/Transforms/Util/PredicateInfo
|
@ -53,6 +53,7 @@
|
|||
#define LLVM_TRANSFORMS_UTILS_PREDICATEINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
|
@ -193,8 +194,8 @@ private:
|
|||
typedef SmallVectorImpl<ValueDFS> ValueDFSStack;
|
||||
void convertUsesToDFSOrdered(Value *, SmallVectorImpl<ValueDFS> &);
|
||||
Value *materializeStack(unsigned int &, ValueDFSStack &, Value *);
|
||||
bool stackIsInScope(const ValueDFSStack &, int DFSIn, int DFSOut) const;
|
||||
void popStackUntilDFSScope(ValueDFSStack &, int DFSIn, int DFSOut);
|
||||
bool stackIsInScope(const ValueDFSStack &, const ValueDFS &) const;
|
||||
void popStackUntilDFSScope(ValueDFSStack &, const ValueDFS &);
|
||||
ValueInfo &getOrCreateValueInfo(Value *);
|
||||
const ValueInfo &getValueInfo(Value *) const;
|
||||
Function &F;
|
||||
|
@ -214,6 +215,9 @@ private:
|
|||
DenseMap<Value *, unsigned int> ValueInfoNums;
|
||||
// OrderedBasicBlocks used during sorting uses
|
||||
DenseMap<const BasicBlock *, std::unique_ptr<OrderedBasicBlock>> OBBMap;
|
||||
// The set of edges along which we can only handle phi uses, due to critical
|
||||
// edges.
|
||||
DenseSet<BasicBlockEdge> PhiUsesOnly;
|
||||
};
|
||||
|
||||
// This pass does eager building and then printing of PredicateInfo. It is used
|
||||
|
|
|
@ -66,10 +66,12 @@ struct ValueDFS {
|
|||
int DFSIn = 0;
|
||||
int DFSOut = 0;
|
||||
unsigned int LocalNum = LN_Middle;
|
||||
PredicateBase *PInfo = nullptr;
|
||||
// Only one of Def or Use will be set.
|
||||
Value *Def = nullptr;
|
||||
Use *U = nullptr;
|
||||
// Neither PInfo nor PhiOnly participate in the ordering
|
||||
PredicateBase *PInfo = nullptr;
|
||||
bool PhiOnly = false;
|
||||
};
|
||||
|
||||
// This compares ValueDFS structures, creating OrderedBasicBlocks where
|
||||
|
@ -90,12 +92,39 @@ struct ValueDFS_Compare {
|
|||
|
||||
bool SameBlock = std::tie(A.DFSIn, A.DFSOut) == std::tie(B.DFSIn, B.DFSOut);
|
||||
|
||||
// We want to put the def that will get used for a given set of phi uses,
|
||||
// before those phi uses.
|
||||
// So we sort by edge, then by def.
|
||||
// Note that only phi nodes uses and defs can come last.
|
||||
if (SameBlock && A.LocalNum == LN_Last && B.LocalNum == LN_Last)
|
||||
return comparePHIRelated(A, B);
|
||||
|
||||
if (!SameBlock || A.LocalNum != LN_Middle || B.LocalNum != LN_Middle)
|
||||
return std::tie(A.DFSIn, A.DFSOut, A.LocalNum, A.Def, A.U) <
|
||||
std::tie(B.DFSIn, B.DFSOut, B.LocalNum, B.Def, B.U);
|
||||
return localComesBefore(A, B);
|
||||
}
|
||||
|
||||
// For a phi use, or a non-materialized def, return the edge it represents.
|
||||
const std::pair<const BasicBlock *, const BasicBlock *>
|
||||
getBlockEdge(const ValueDFS &VD) const {
|
||||
if (!VD.Def && VD.U) {
|
||||
auto *PHI = cast<PHINode>(VD.U->getUser());
|
||||
return std::make_pair(PHI->getIncomingBlock(*VD.U), PHI->getParent());
|
||||
}
|
||||
// This is really a non-materialized def.
|
||||
auto *PBranch = cast<PredicateBranch>(VD.PInfo);
|
||||
return std::make_pair(PBranch->BranchBB, PBranch->SplitBB);
|
||||
}
|
||||
|
||||
// For two phi related values, return the ordering.
|
||||
bool comparePHIRelated(const ValueDFS &A, const ValueDFS &B) const {
|
||||
auto &ABlockEdge = getBlockEdge(A);
|
||||
auto &BBlockEdge = getBlockEdge(B);
|
||||
// Now sort by block edge and then defs before uses.
|
||||
return std::tie(ABlockEdge, A.Def, A.U) < std::tie(BBlockEdge, B.Def, B.U);
|
||||
}
|
||||
|
||||
// Get the definition of an instruction that occurs in the middle of a block.
|
||||
Value *getMiddleDef(const ValueDFS &VD) const {
|
||||
if (VD.Def)
|
||||
|
@ -160,16 +189,37 @@ struct ValueDFS_Compare {
|
|||
|
||||
} // namespace PredicateInfoClasses
|
||||
|
||||
bool PredicateInfo::stackIsInScope(const ValueDFSStack &Stack, int DFSIn,
|
||||
int DFSOut) const {
|
||||
bool PredicateInfo::stackIsInScope(const ValueDFSStack &Stack,
|
||||
const ValueDFS &VDUse) const {
|
||||
if (Stack.empty())
|
||||
return false;
|
||||
return DFSIn >= Stack.back().DFSIn && DFSOut <= Stack.back().DFSOut;
|
||||
// If it's a phi only use, make sure it's for this phi node edge, and that the
|
||||
// use is in a phi node. If it's anything else, and the top of the stack is
|
||||
// phionly, we need to pop the stack. We deliberately sort phi uses next to
|
||||
// the defs they must go with so that we can know it's time to pop the stack
|
||||
// when we hit the end of the phi uses for a given def.
|
||||
if (Stack.back().PhiOnly) {
|
||||
if (!VDUse.U)
|
||||
return false;
|
||||
auto *PHI = dyn_cast<PHINode>(VDUse.U->getUser());
|
||||
if (!PHI)
|
||||
return false;
|
||||
// The only phionly defs should be branch info.
|
||||
auto *PBranch = dyn_cast<PredicateBranch>(Stack.back().PInfo);
|
||||
assert(PBranch && "Only branches should have PHIOnly defs");
|
||||
// Check edge
|
||||
BasicBlock *EdgePred = PHI->getIncomingBlock(*VDUse.U);
|
||||
if (EdgePred != PBranch->BranchBB)
|
||||
return false;
|
||||
}
|
||||
|
||||
return (VDUse.DFSIn >= Stack.back().DFSIn &&
|
||||
VDUse.DFSOut <= Stack.back().DFSOut);
|
||||
}
|
||||
|
||||
void PredicateInfo::popStackUntilDFSScope(ValueDFSStack &Stack, int DFSIn,
|
||||
int DFSOut) {
|
||||
while (!Stack.empty() && !stackIsInScope(Stack, DFSIn, DFSOut))
|
||||
void PredicateInfo::popStackUntilDFSScope(ValueDFSStack &Stack,
|
||||
const ValueDFS &VD) {
|
||||
while (!Stack.empty() && !stackIsInScope(Stack, VD))
|
||||
Stack.pop_back();
|
||||
}
|
||||
|
||||
|
@ -271,20 +321,11 @@ void PredicateInfo::processBranch(BranchInst *BI, BasicBlock *BranchBB,
|
|||
SmallVector<Value *, 8> CmpOperands;
|
||||
BasicBlock *FirstBB = BI->getSuccessor(0);
|
||||
BasicBlock *SecondBB = BI->getSuccessor(1);
|
||||
bool FirstSinglePred = FirstBB->getSinglePredecessor();
|
||||
bool SecondSinglePred = SecondBB->getSinglePredecessor();
|
||||
SmallVector<BasicBlock *, 2> SuccsToProcess;
|
||||
bool isAnd = false;
|
||||
bool isOr = false;
|
||||
// First make sure we have single preds for these successors, as we can't
|
||||
// usefully propagate true/false info to them if there are multiple paths to
|
||||
// them.
|
||||
if (FirstSinglePred)
|
||||
SuccsToProcess.push_back(FirstBB);
|
||||
if (SecondSinglePred)
|
||||
SuccsToProcess.push_back(SecondBB);
|
||||
if (SuccsToProcess.empty())
|
||||
return;
|
||||
SuccsToProcess.push_back(FirstBB);
|
||||
SuccsToProcess.push_back(SecondBB);
|
||||
// Second, see if we have a comparison we support
|
||||
SmallVector<Value *, 2> ComparisonsToProcess;
|
||||
CmpInst::Predicate Pred;
|
||||
|
@ -321,6 +362,8 @@ void PredicateInfo::processBranch(BranchInst *BI, BasicBlock *BranchBB,
|
|||
new PredicateBranch(Op, BranchBB, Succ, Cmp, TakenEdge);
|
||||
AllInfos.push_back(PB);
|
||||
OperandInfo.Infos.push_back(PB);
|
||||
if (!Succ->getSinglePredecessor())
|
||||
PhiUsesOnly.insert({BranchBB, Succ});
|
||||
}
|
||||
}
|
||||
CmpOperands.clear();
|
||||
|
@ -368,29 +411,14 @@ Value *PredicateInfo::materializeStack(unsigned int &Counter,
|
|||
RenameIter == RenameStack.begin() ? OrigOp : (RenameIter - 1)->Def;
|
||||
ValueDFS &Result = *RenameIter;
|
||||
auto *ValInfo = Result.PInfo;
|
||||
// For branches, we can just place the operand in the split block. For
|
||||
// assume, we have to place it right before the assume to ensure we dominate
|
||||
// all of our uses.
|
||||
// For branches, we can just place the operand in the branch block before
|
||||
// the terminator. For assume, we have to place it right before the assume
|
||||
// to ensure we dominate all of our uses. Always insert right before the
|
||||
// relevant instruction (terminator, assume), so that we insert in proper
|
||||
// order in the case of multiple predicateinfo in the same block.
|
||||
if (isa<PredicateBranch>(ValInfo)) {
|
||||
auto *PBranch = cast<PredicateBranch>(ValInfo);
|
||||
// It's possible we are trying to insert multiple predicateinfos in the
|
||||
// same block at the beginning of the block. When we do this, we need to
|
||||
// insert them one after the other, not one before the other. To see if we
|
||||
// have already inserted predicateinfo into this block, we see if Op !=
|
||||
// OrigOp && Op->getParent() == PBranch->SplitBB. Op must be an
|
||||
// instruction we inserted if it's not the original op.
|
||||
BasicBlock::iterator InsertPt;
|
||||
if (Op == OrigOp ||
|
||||
cast<Instruction>(Op)->getParent() != PBranch->SplitBB) {
|
||||
InsertPt = PBranch->SplitBB->begin();
|
||||
// Insert after last phi node.
|
||||
while (isa<PHINode>(InsertPt))
|
||||
++InsertPt;
|
||||
} else {
|
||||
// Insert after op.
|
||||
InsertPt = ++(cast<Instruction>(Op)->getIterator());
|
||||
}
|
||||
IRBuilder<> B(PBranch->SplitBB, InsertPt);
|
||||
IRBuilder<> B(PBranch->BranchBB->getTerminator());
|
||||
Function *IF = Intrinsic::getDeclaration(
|
||||
F.getParent(), Intrinsic::ssa_copy, Op->getType());
|
||||
Value *PIC = B.CreateCall(IF, Op, Op->getName() + "." + Twine(Counter++));
|
||||
|
@ -400,12 +428,7 @@ Value *PredicateInfo::materializeStack(unsigned int &Counter,
|
|||
auto *PAssume = dyn_cast<PredicateAssume>(ValInfo);
|
||||
assert(PAssume &&
|
||||
"Should not have gotten here without it being an assume");
|
||||
// Unlike above, this should already insert in the right order when we
|
||||
// insert multiple predicateinfos in the same block. Because we are
|
||||
// always inserting right before the assume (instead of the beginning of a
|
||||
// block), newer insertions will end up after older ones.
|
||||
IRBuilder<> B(PAssume->AssumeInst->getParent(),
|
||||
PAssume->AssumeInst->getIterator());
|
||||
IRBuilder<> B(PAssume->AssumeInst);
|
||||
Function *IF = Intrinsic::getDeclaration(
|
||||
F.getParent(), Intrinsic::ssa_copy, Op->getType());
|
||||
Value *PIC = B.CreateCall(IF, Op);
|
||||
|
@ -447,28 +470,49 @@ void PredicateInfo::renameUses(SmallPtrSetImpl<Value *> &OpsToRename) {
|
|||
// created otherwise.
|
||||
for (auto &PossibleCopy : ValueInfo.Infos) {
|
||||
ValueDFS VD;
|
||||
BasicBlock *CopyBB = nullptr;
|
||||
// Determine where we are going to place the copy by the copy type.
|
||||
// The predicate info for branches always come first, they will get
|
||||
// materialized in the split block at the top of the block.
|
||||
// The predicate info for assumes will be somewhere in the middle,
|
||||
// it will get materialized in front of the assume.
|
||||
if (const auto *PBranch = dyn_cast<PredicateBranch>(PossibleCopy)) {
|
||||
CopyBB = PBranch->SplitBB;
|
||||
VD.LocalNum = LN_First;
|
||||
} else if (const auto *PAssume =
|
||||
dyn_cast<PredicateAssume>(PossibleCopy)) {
|
||||
CopyBB = PAssume->AssumeInst->getParent();
|
||||
if (const auto *PAssume = dyn_cast<PredicateAssume>(PossibleCopy)) {
|
||||
VD.LocalNum = LN_Middle;
|
||||
} else
|
||||
llvm_unreachable("Unhandled predicate info type");
|
||||
DomTreeNode *DomNode = DT.getNode(CopyBB);
|
||||
if (!DomNode)
|
||||
continue;
|
||||
VD.DFSIn = DomNode->getDFSNumIn();
|
||||
VD.DFSOut = DomNode->getDFSNumOut();
|
||||
VD.PInfo = PossibleCopy;
|
||||
OrderedUses.push_back(VD);
|
||||
DomTreeNode *DomNode = DT.getNode(PAssume->AssumeInst->getParent());
|
||||
if (!DomNode)
|
||||
continue;
|
||||
VD.DFSIn = DomNode->getDFSNumIn();
|
||||
VD.DFSOut = DomNode->getDFSNumOut();
|
||||
VD.PInfo = PossibleCopy;
|
||||
OrderedUses.push_back(VD);
|
||||
} else if (const auto *PBranch =
|
||||
dyn_cast<PredicateBranch>(PossibleCopy)) {
|
||||
// If we can only do phi uses, we treat it like it's in the branch
|
||||
// block, and handle it specially. We know that it goes last, and only
|
||||
// dominate phi uses.
|
||||
if (PhiUsesOnly.count({PBranch->BranchBB, PBranch->SplitBB})) {
|
||||
VD.LocalNum = LN_Last;
|
||||
auto *DomNode = DT.getNode(PBranch->BranchBB);
|
||||
if (DomNode) {
|
||||
VD.DFSIn = DomNode->getDFSNumIn();
|
||||
VD.DFSOut = DomNode->getDFSNumOut();
|
||||
VD.PInfo = PossibleCopy;
|
||||
VD.PhiOnly = true;
|
||||
OrderedUses.push_back(VD);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, we are in the split block (even though we perform
|
||||
// insertion in the branch block).
|
||||
// Insert a possible copy at the split block and before the branch.
|
||||
VD.LocalNum = LN_First;
|
||||
auto *DomNode = DT.getNode(PBranch->SplitBB);
|
||||
if (DomNode) {
|
||||
VD.DFSIn = DomNode->getDFSNumIn();
|
||||
VD.DFSOut = DomNode->getDFSNumOut();
|
||||
VD.PInfo = PossibleCopy;
|
||||
OrderedUses.push_back(VD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
convertUsesToDFSOrdered(Op, OrderedUses);
|
||||
|
@ -492,10 +536,10 @@ void PredicateInfo::renameUses(SmallPtrSetImpl<Value *> &OpsToRename) {
|
|||
<< VD.DFSOut << ")\n");
|
||||
|
||||
bool ShouldPush = (VD.Def || PossibleCopy);
|
||||
bool OutOfScope = !stackIsInScope(RenameStack, VD.DFSIn, VD.DFSOut);
|
||||
bool OutOfScope = !stackIsInScope(RenameStack, VD);
|
||||
if (OutOfScope || ShouldPush) {
|
||||
// Sync to our current scope.
|
||||
popStackUntilDFSScope(RenameStack, VD.DFSIn, VD.DFSOut);
|
||||
popStackUntilDFSScope(RenameStack, VD);
|
||||
ShouldPush |= (VD.Def || PossibleCopy);
|
||||
if (ShouldPush) {
|
||||
RenameStack.push_back(VD);
|
||||
|
|
|
@ -98,12 +98,12 @@ define void @test3(i32 %x, i32 %y) {
|
|||
; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
|
||||
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
|
||||
; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
|
||||
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK-NEXT: br i1 [[Z]], label [[BOTH_ZERO:%.*]], label [[NOPE:%.*]]
|
||||
; CHECK: both_zero:
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[YZ_0]])
|
||||
; CHECK-NEXT: call void @bar(i32 [[X_0]])
|
||||
|
@ -178,15 +178,15 @@ case3:
|
|||
define i1 @test5(i32 %x, i32 %y) {
|
||||
; CHECK-LABEL: @test5(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
|
||||
; CHECK: same:
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[X_0]], [[Y_0]]
|
||||
; CHECK-NEXT: ret i1 [[CMP2]]
|
||||
; CHECK: different:
|
||||
; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[X_1]], [[Y_1]]
|
||||
; CHECK-NEXT: ret i1 [[CMP3]]
|
||||
;
|
||||
|
@ -251,15 +251,15 @@ different:
|
|||
define i1 @test7(i32 %x, i32 %y) {
|
||||
; CHECK-LABEL: @test7(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
|
||||
; CHECK: same:
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[X_0]], [[Y_0]]
|
||||
; CHECK-NEXT: ret i1 [[CMP2]]
|
||||
; CHECK: different:
|
||||
; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: [[CMP3:%.*]] = icmp sgt i32 [[X_1]], [[Y_1]]
|
||||
; CHECK-NEXT: ret i1 [[CMP3]]
|
||||
;
|
||||
|
@ -278,15 +278,15 @@ different:
|
|||
define i1 @test7_fp(float %x, float %y) {
|
||||
; CHECK-LABEL: @test7_fp(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK: [[X_0:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])
|
||||
; CHECK: [[X_1:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])
|
||||
; CHECK: [[Y_0:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])
|
||||
; CHECK: [[Y_1:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
|
||||
; CHECK: same:
|
||||
; CHECK: [[Y_0:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])
|
||||
; CHECK: [[X_0:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = fcmp ule float [[X_0]], [[Y_0]]
|
||||
; CHECK-NEXT: ret i1 [[CMP2]]
|
||||
; CHECK: different:
|
||||
; CHECK: [[Y_1:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])
|
||||
; CHECK: [[X_1:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])
|
||||
; CHECK-NEXT: [[CMP3:%.*]] = fcmp ogt float [[X_1]], [[Y_1]]
|
||||
; CHECK-NEXT: ret i1 [[CMP3]]
|
||||
;
|
||||
|
@ -351,10 +351,10 @@ different:
|
|||
define i32 @test9(i32 %i, i32 %j) {
|
||||
; CHECK-LABEL: @test9(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], [[J:%.*]]
|
||||
; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])
|
||||
; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[RET:%.*]]
|
||||
; CHECK: cond_true:
|
||||
; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])
|
||||
; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])
|
||||
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[I_0]], [[J_0]]
|
||||
; CHECK-NEXT: ret i32 [[DIFF]]
|
||||
; CHECK: ret:
|
||||
|
@ -374,10 +374,10 @@ ret:
|
|||
define i32 @test10(i32 %j, i32 %i) {
|
||||
; CHECK-LABEL: @test10(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], [[J:%.*]]
|
||||
; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])
|
||||
; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[RET:%.*]]
|
||||
; CHECK: cond_true:
|
||||
; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])
|
||||
; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])
|
||||
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[I_0]], [[J_0]]
|
||||
; CHECK-NEXT: ret i32 [[DIFF]]
|
||||
; CHECK: ret:
|
||||
|
@ -401,16 +401,16 @@ define i32 @test11(i32 %x) {
|
|||
; CHECK-NEXT: [[V0:%.*]] = call i32 @yogibar()
|
||||
; CHECK-NEXT: [[V1:%.*]] = call i32 @yogibar()
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V0]], [[V1]]
|
||||
; CHECK: [[V0_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0]])
|
||||
; CHECK: [[V1_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V1]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[NEXT:%.*]]
|
||||
; CHECK: cond_true:
|
||||
; CHECK: [[V1_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V1]])
|
||||
; CHECK-NEXT: ret i32 [[V1_0]]
|
||||
; CHECK: next:
|
||||
; CHECK: [[V0_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0]])
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[X:%.*]], [[V0_0]]
|
||||
; CHECK: [[V0_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0_0]])
|
||||
; CHECK-NEXT: br i1 [[CMP2]], label [[COND_TRUE2:%.*]], label [[NEXT2:%.*]]
|
||||
; CHECK: cond_true2:
|
||||
; CHECK: [[V0_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0_0]])
|
||||
; CHECK-NEXT: ret i32 [[V0_0_1]]
|
||||
; CHECK: next2:
|
||||
; CHECK-NEXT: ret i32 0
|
||||
|
@ -437,12 +437,12 @@ next2:
|
|||
define i32 @test12(i32 %x) {
|
||||
; CHECK-LABEL: @test12(
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
|
||||
; CHECK: cond_true:
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: br label [[RET:%.*]]
|
||||
; CHECK: cond_false:
|
||||
; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: br label [[RET]]
|
||||
; CHECK: ret:
|
||||
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[X_0]], [[COND_TRUE]] ], [ [[X_1]], [[COND_FALSE]] ]
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -print-predicateinfo < %s 2>&1 | FileCheck %s
|
||||
define i1 @f(i32 %x, i1 %y) {
|
||||
; CHECK-LABEL: @f(
|
||||
; CHECK-NEXT: br i1 [[Y:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
|
||||
; CHECK: bb0:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X:%.*]], 0
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[BB2:%.*]], label [[BB3:%.*]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: [[X2:%.*]] = add nuw nsw i32 [[X]], 1
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X2]], 2
|
||||
; CHECK: [[X2_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X2]])
|
||||
; CHECK-NEXT: br i1 [[CMP2]], label [[BB2]], label [[BB3]]
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: [[X3:%.*]] = phi i32 [ [[X_0]], [[BB0]] ], [ [[X2_0]], [[BB1]] ]
|
||||
; CHECK-NEXT: br label [[BB3]]
|
||||
; CHECK: bb3:
|
||||
; CHECK-NEXT: ret i1 false
|
||||
;
|
||||
br i1 %y, label %bb0, label %bb1
|
||||
bb0:
|
||||
%cmp = icmp sge i32 %x, 0 ; x > 0
|
||||
br i1 %cmp, label %bb2, label %bb3
|
||||
bb1:
|
||||
%x2 = add nsw nuw i32 %x, 1
|
||||
%cmp2 = icmp sge i32 %x2, 2 ; x+1 > 2 / x > 1
|
||||
br i1 %cmp2, label %bb2, label %bb3
|
||||
bb2:
|
||||
%x3 = phi i32 [ %x, %bb0 ], [ %x2, %bb1 ]
|
||||
br label %bb3
|
||||
bb3:
|
||||
ret i1 0
|
||||
}
|
||||
|
||||
define i1 @g(i32 %x, i1 %y) {
|
||||
; CHECK-LABEL: @g(
|
||||
; CHECK-NEXT: br i1 [[Y:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
|
||||
; CHECK: bb0:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X:%.*]], 0
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[BB3:%.*]], label [[BB2:%.*]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: [[X2:%.*]] = add nuw nsw i32 [[X]], 1
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X2]], 2
|
||||
; CHECK: [[X2_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X2]])
|
||||
; CHECK-NEXT: br i1 [[CMP2]], label [[BB3]], label [[BB2]]
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: [[X3:%.*]] = phi i32 [ [[X_0]], [[BB0]] ], [ [[X2_0]], [[BB1]] ]
|
||||
; CHECK-NEXT: br label [[BB3]]
|
||||
; CHECK: bb3:
|
||||
; CHECK-NEXT: ret i1 false
|
||||
;
|
||||
br i1 %y, label %bb0, label %bb1
|
||||
bb0:
|
||||
%cmp = icmp sge i32 %x, 0 ; x > 0
|
||||
br i1 %cmp, label %bb3, label %bb2
|
||||
bb1:
|
||||
%x2 = add nsw nuw i32 %x, 1
|
||||
%cmp2 = icmp sge i32 %x2, 2 ; x+1 > 2 / x > 1
|
||||
br i1 %cmp2, label %bb3, label %bb2
|
||||
bb2:
|
||||
%x3 = phi i32 [ %x, %bb0 ], [ %x2, %bb1 ]
|
||||
br label %bb3
|
||||
bb3:
|
||||
ret i1 0
|
||||
}
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -print-predicateinfo -analyze < %s 2>&1 | FileCheck %s
|
||||
|
||||
define i32 @f1(i32 %x) {
|
||||
; CHECK-LABEL: @f1(
|
||||
; CHECK-NEXT: bb0:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[BB2:%.*]], label [[BB1:%.*]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: br label [[BB2]]
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[X_0]], [[BB0:%.*]] ], [ 0, [[BB1]] ]
|
||||
; CHECK-NEXT: [[FOO:%.*]] = add i32 [[COND]], [[X]]
|
||||
; CHECK-NEXT: ret i32 [[FOO]]
|
||||
;
|
||||
bb0:
|
||||
%cmp = icmp eq i32 %x, 0
|
||||
br i1 %cmp, label %bb2, label %bb1
|
||||
bb1:
|
||||
br label %bb2
|
||||
bb2:
|
||||
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
%foo = add i32 %cond, %x
|
||||
ret i32 %foo
|
||||
}
|
||||
|
||||
define i32 @f2(i32 %x) {
|
||||
; CHECK-LABEL: @f2(
|
||||
; CHECK-NEXT: bb0:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 0
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[BB1:%.*]], label [[BB2:%.*]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: br label [[BB2]]
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[X_0]], [[BB0:%.*]] ], [ 0, [[BB1]] ]
|
||||
; CHECK-NEXT: [[FOO:%.*]] = add i32 [[COND]], [[X]]
|
||||
; CHECK-NEXT: ret i32 [[FOO]]
|
||||
;
|
||||
bb0:
|
||||
%cmp = icmp ne i32 %x, 0
|
||||
br i1 %cmp, label %bb1, label %bb2
|
||||
bb1:
|
||||
br label %bb2
|
||||
bb2:
|
||||
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
%foo = add i32 %cond, %x
|
||||
ret i32 %foo
|
||||
}
|
||||
|
||||
define i32 @f3(i32 %x) {
|
||||
; CHECK-LABEL: @f3(
|
||||
; CHECK-NEXT: bb0:
|
||||
; CHECK-NEXT: switch i32 [[X:%.*]], label [[BB1:%.*]] [
|
||||
; CHECK-NEXT: i32 0, label [[BB2:%.*]]
|
||||
; CHECK-NEXT: ]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: br label [[BB2]]
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[X]], [[BB0:%.*]] ], [ 0, [[BB1]] ]
|
||||
; CHECK-NEXT: [[FOO:%.*]] = add i32 [[COND]], [[X]]
|
||||
; CHECK-NEXT: ret i32 [[FOO]]
|
||||
;
|
||||
bb0:
|
||||
switch i32 %x, label %bb1 [ i32 0, label %bb2]
|
||||
bb1:
|
||||
br label %bb2
|
||||
bb2:
|
||||
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
%foo = add i32 %cond, %x
|
||||
ret i32 %foo
|
||||
}
|
||||
|
||||
|
||||
define double @fcmp_oeq_not_zero(double %x, double %y) {
|
||||
; CHECK-LABEL: @fcmp_oeq_not_zero(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y:%.*]], 2.000000e+00
|
||||
; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Y]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[RETURN:%.*]]
|
||||
; CHECK: if:
|
||||
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Y_0]]
|
||||
; CHECK-NEXT: br label [[RETURN]]
|
||||
; CHECK: return:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = phi double [ [[DIV]], [[IF]] ], [ [[X]], [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: ret double [[RETVAL]]
|
||||
;
|
||||
entry:
|
||||
%cmp = fcmp oeq double %y, 2.0
|
||||
br i1 %cmp, label %if, label %return
|
||||
|
||||
if:
|
||||
%div = fdiv double %x, %y
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %if ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
}
|
||||
|
||||
define double @fcmp_une_not_zero(double %x, double %y) {
|
||||
; CHECK-LABEL: @fcmp_une_not_zero(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[Y:%.*]], 2.000000e+00
|
||||
; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Y]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[ELSE:%.*]]
|
||||
; CHECK: else:
|
||||
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Y_0]]
|
||||
; CHECK-NEXT: br label [[RETURN]]
|
||||
; CHECK: return:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = phi double [ [[DIV]], [[ELSE]] ], [ [[X]], [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: ret double [[RETVAL]]
|
||||
;
|
||||
entry:
|
||||
%cmp = fcmp une double %y, 2.0
|
||||
br i1 %cmp, label %return, label %else
|
||||
|
||||
else:
|
||||
%div = fdiv double %x, %y
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %else ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
}
|
||||
|
||||
define double @fcmp_oeq_zero(double %x, double %y) {
|
||||
; CHECK-LABEL: @fcmp_oeq_zero(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y:%.*]], 0.000000e+00
|
||||
; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Y]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[RETURN:%.*]]
|
||||
; CHECK: if:
|
||||
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Y_0]]
|
||||
; CHECK-NEXT: br label [[RETURN]]
|
||||
; CHECK: return:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = phi double [ [[DIV]], [[IF]] ], [ [[X]], [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: ret double [[RETVAL]]
|
||||
;
|
||||
entry:
|
||||
%cmp = fcmp oeq double %y, 0.0
|
||||
br i1 %cmp, label %if, label %return
|
||||
|
||||
if:
|
||||
%div = fdiv double %x, %y
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %if ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
}
|
||||
|
||||
define double @fcmp_une_zero(double %x, double %y) {
|
||||
; CHECK-LABEL: @fcmp_une_zero(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[Y:%.*]], -0.000000e+00
|
||||
; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Y]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[ELSE:%.*]]
|
||||
; CHECK: else:
|
||||
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Y_0]]
|
||||
; CHECK-NEXT: br label [[RETURN]]
|
||||
; CHECK: return:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = phi double [ [[DIV]], [[ELSE]] ], [ [[X]], [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: ret double [[RETVAL]]
|
||||
;
|
||||
entry:
|
||||
%cmp = fcmp une double %y, -0.0
|
||||
br i1 %cmp, label %return, label %else
|
||||
|
||||
else:
|
||||
%div = fdiv double %x, %y
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %else ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
}
|
||||
|
||||
|
||||
define double @fcmp_oeq_maybe_zero(double %x, double %y, double %z1, double %z2) {
|
||||
; CHECK-LABEL: @fcmp_oeq_maybe_zero(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[Z:%.*]] = fadd double [[Z1:%.*]], [[Z2:%.*]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y:%.*]], [[Z]]
|
||||
; CHECK: [[Z_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Z]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[RETURN:%.*]]
|
||||
; CHECK: if:
|
||||
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Z_0]]
|
||||
; CHECK-NEXT: br label [[RETURN]]
|
||||
; CHECK: return:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = phi double [ [[DIV]], [[IF]] ], [ [[X]], [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: ret double [[RETVAL]]
|
||||
;
|
||||
entry:
|
||||
%z = fadd double %z1, %z2
|
||||
%cmp = fcmp oeq double %y, %z
|
||||
br i1 %cmp, label %if, label %return
|
||||
|
||||
if:
|
||||
%div = fdiv double %x, %z
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %if ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
}
|
||||
|
||||
define double @fcmp_une_maybe_zero(double %x, double %y, double %z1, double %z2) {
|
||||
; CHECK-LABEL: @fcmp_une_maybe_zero(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[Z:%.*]] = fadd double [[Z1:%.*]], [[Z2:%.*]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[Y:%.*]], [[Z]]
|
||||
; CHECK: [[Z_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Z]])
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[ELSE:%.*]]
|
||||
; CHECK: else:
|
||||
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Z_0]]
|
||||
; CHECK-NEXT: br label [[RETURN]]
|
||||
; CHECK: return:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = phi double [ [[DIV]], [[ELSE]] ], [ [[X]], [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: ret double [[RETVAL]]
|
||||
;
|
||||
entry:
|
||||
%z = fadd double %z1, %z2
|
||||
%cmp = fcmp une double %y, %z
|
||||
br i1 %cmp, label %return, label %else
|
||||
|
||||
else:
|
||||
%div = fdiv double %x, %z
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %else ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -print-predicateinfo -analyze < %s 2>&1 | FileCheck %s
|
||||
; RUN: opt -print-predicateinfo < %s 2>&1 | FileCheck %s
|
||||
|
||||
declare void @foo(i1)
|
||||
declare void @bar(i32)
|
||||
|
@ -10,6 +10,10 @@ define void @testor(i32 %x, i32 %y) {
|
|||
; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
|
||||
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
|
||||
; CHECK-NEXT: [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
|
||||
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK-NEXT: br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]]
|
||||
; CHECK: oneof:
|
||||
; CHECK-NEXT: call void @foo(i1 [[XZ]])
|
||||
|
@ -18,10 +22,6 @@ define void @testor(i32 %x, i32 %y) {
|
|||
; CHECK-NEXT: call void @bar(i32 [[Y]])
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: neither:
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[YZ_0]])
|
||||
; CHECK-NEXT: call void @bar(i32 [[X_0]])
|
||||
|
@ -53,12 +53,12 @@ define void @testand(i32 %x, i32 %y) {
|
|||
; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
|
||||
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
|
||||
; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
|
||||
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
|
||||
; CHECK: both:
|
||||
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[YZ_0]])
|
||||
; CHECK-NEXT: call void @bar(i32 [[X_0]])
|
||||
|
@ -96,12 +96,12 @@ define void @testandsame(i32 %x, i32 %y) {
|
|||
; CHECK-NEXT: [[XGT:%.*]] = icmp sgt i32 [[X:%.*]], 0
|
||||
; CHECK-NEXT: [[XLT:%.*]] = icmp slt i32 [[X]], 100
|
||||
; CHECK-NEXT: [[Z:%.*]] = and i1 [[XGT]], [[XLT]]
|
||||
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
|
||||
; CHECK: both:
|
||||
; CHECK: [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XLT]])
|
||||
; CHECK: [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XGT]])
|
||||
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
|
||||
; CHECK: [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X_0]])
|
||||
; CHECK: [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XGT]])
|
||||
; CHECK: [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XLT]])
|
||||
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
|
||||
; CHECK: both:
|
||||
; CHECK-NEXT: call void @foo(i1 [[XGT_0]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[XLT_0]])
|
||||
; CHECK-NEXT: call void @bar(i32 [[X_0_1]])
|
||||
|
@ -138,12 +138,12 @@ define void @testandassume(i32 %x, i32 %y) {
|
|||
; CHECK: [[TMP3:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
|
||||
; CHECK: [[TMP4:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[Z]])
|
||||
; CHECK: [[DOT0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP1]])
|
||||
; CHECK: [[DOT01:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP2]])
|
||||
; CHECK: [[DOT02:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP3]])
|
||||
; CHECK: [[DOT03:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP4]])
|
||||
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
|
||||
; CHECK: both:
|
||||
; CHECK: [[DOT03:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP4]])
|
||||
; CHECK: [[DOT02:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP3]])
|
||||
; CHECK: [[DOT01:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP2]])
|
||||
; CHECK: [[DOT0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP1]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[DOT0]])
|
||||
; CHECK-NEXT: call void @foo(i1 [[DOT02]])
|
||||
; CHECK-NEXT: call void @bar(i32 [[DOT01]])
|
||||
|
|
Loading…
Reference in New Issue