[PredicateInfo] Generalize processing of conditions

Branch/assume conditions in PredicateInfo are currently handled in
a rather ad-hoc manner, with some arbitrary limitations. For example,
an `and` of two `icmp`s will be handled, but an `and` of an `icmp`
and some other condition will not. That also includes the case where
more than two conditions and and'ed together.

This patch makes the handling more general by looking through and/ors
up to a limit and considering all kinds of conditions (though operands
will only be taken for cmps of course).

Differential Revision: https://reviews.llvm.org/D94447
This commit is contained in:
Nikita Popov 2021-01-11 22:18:12 +01:00
parent b564b12bc6
commit ca4ed1e7ae
5 changed files with 243 additions and 220 deletions

View File

@ -53,6 +53,10 @@ static cl::opt<bool> VerifyPredicateInfo(
DEBUG_COUNTER(RenameCounter, "predicateinfo-rename",
"Controls which variables are renamed with predicateinfo");
// Maximum number of conditions considered for renaming for each branch/assume.
// This limits renaming of deep and/or chains.
static const unsigned MaxCondsPerBranch = 8;
namespace {
// Given a predicate info that is a type of branching terminator, get the
// branching block.
@ -367,6 +371,13 @@ void PredicateInfoBuilder::convertUsesToDFSOrdered(
}
}
bool shouldRename(Value *V) {
// Only want real values, not constants. Additionally, operands with one use
// are only being used in the comparison, which means they will not be useful
// for us to consider for predicateinfo.
return (isa<Instruction>(V) || isa<Argument>(V)) && !V->hasOneUse();
}
// Collect relevant operations from Comparison that we may want to insert copies
// for.
void collectCmpOps(CmpInst *Comparison, SmallVectorImpl<Value *> &CmpOperands) {
@ -374,15 +385,9 @@ void collectCmpOps(CmpInst *Comparison, SmallVectorImpl<Value *> &CmpOperands) {
auto *Op1 = Comparison->getOperand(1);
if (Op0 == Op1)
return;
CmpOperands.push_back(Comparison);
// Only want real values, not constants. Additionally, operands with one use
// are only being used in the comparison, which means they will not be useful
// for us to consider for predicateinfo.
//
if ((isa<Instruction>(Op0) || isa<Argument>(Op0)) && !Op0->hasOneUse())
CmpOperands.push_back(Op0);
if ((isa<Instruction>(Op1) || isa<Argument>(Op1)) && !Op1->hasOneUse())
CmpOperands.push_back(Op1);
CmpOperands.push_back(Op0);
CmpOperands.push_back(Op1);
}
// Add Op, PB to the list of value infos for Op, and mark Op to be renamed.
@ -400,38 +405,32 @@ void PredicateInfoBuilder::addInfoFor(SmallVectorImpl<Value *> &OpsToRename,
void PredicateInfoBuilder::processAssume(
IntrinsicInst *II, BasicBlock *AssumeBB,
SmallVectorImpl<Value *> &OpsToRename) {
// See if we have a comparison we support
SmallVector<Value *, 8> CmpOperands;
SmallVector<Value *, 2> ConditionsToProcess;
CmpInst::Predicate Pred;
Value *Operand = II->getOperand(0);
if (m_c_And(m_Cmp(Pred, m_Value(), m_Value()),
m_Cmp(Pred, m_Value(), m_Value()))
.match(II->getOperand(0))) {
ConditionsToProcess.push_back(cast<BinaryOperator>(Operand)->getOperand(0));
ConditionsToProcess.push_back(cast<BinaryOperator>(Operand)->getOperand(1));
ConditionsToProcess.push_back(Operand);
} else if (isa<CmpInst>(Operand)) {
SmallVector<Value *, 4> Worklist;
SmallPtrSet<Value *, 4> Visited;
Worklist.push_back(II->getOperand(0));
while (!Worklist.empty()) {
Value *Cond = Worklist.pop_back_val();
if (!Visited.insert(Cond).second)
continue;
if (Visited.size() > MaxCondsPerBranch)
break;
ConditionsToProcess.push_back(Operand);
}
for (auto Cond : ConditionsToProcess) {
if (auto *Cmp = dyn_cast<CmpInst>(Cond)) {
collectCmpOps(Cmp, CmpOperands);
// Now add our copy infos for our operands
for (auto *Op : CmpOperands) {
auto *PA = new PredicateAssume(Op, II, Cmp);
addInfoFor(OpsToRename, Op, PA);
Value *Op0, *Op1;
if (match(Cond, m_And(m_Value(Op0), m_Value(Op1)))) {
Worklist.push_back(Op1);
Worklist.push_back(Op0);
}
SmallVector<Value *, 4> Values;
Values.push_back(Cond);
if (auto *Cmp = dyn_cast<CmpInst>(Cond))
collectCmpOps(Cmp, Values);
for (Value *V : Values) {
if (shouldRename(V)) {
auto *PA = new PredicateAssume(V, II, Cond);
addInfoFor(OpsToRename, V, PA);
}
CmpOperands.clear();
} else if (auto *BinOp = dyn_cast<BinaryOperator>(Cond)) {
// Otherwise, it should be an AND.
assert(BinOp->getOpcode() == Instruction::And &&
"Should have been an AND");
auto *PA = new PredicateAssume(BinOp, II, BinOp);
addInfoFor(OpsToRename, BinOp, PA);
} else {
llvm_unreachable("Unknown type of condition");
}
}
}
@ -443,68 +442,46 @@ void PredicateInfoBuilder::processBranch(
SmallVectorImpl<Value *> &OpsToRename) {
BasicBlock *FirstBB = BI->getSuccessor(0);
BasicBlock *SecondBB = BI->getSuccessor(1);
SmallVector<BasicBlock *, 2> SuccsToProcess;
SuccsToProcess.push_back(FirstBB);
SuccsToProcess.push_back(SecondBB);
SmallVector<Value *, 2> ConditionsToProcess;
auto InsertHelper = [&](Value *Op, bool isAnd, bool isOr, Value *Cond) {
for (auto *Succ : SuccsToProcess) {
// Don't try to insert on a self-edge. This is mainly because we will
// eliminate during renaming anyway.
if (Succ == BranchBB)
continue;
bool TakenEdge = (Succ == FirstBB);
// For and, only insert on the true edge
// For or, only insert on the false edge
if ((isAnd && !TakenEdge) || (isOr && TakenEdge))
continue;
PredicateBase *PB =
new PredicateBranch(Op, BranchBB, Succ, Cond, TakenEdge);
addInfoFor(OpsToRename, Op, PB);
if (!Succ->getSinglePredecessor())
EdgeUsesOnly.insert({BranchBB, Succ});
}
};
for (BasicBlock *Succ : {FirstBB, SecondBB}) {
bool TakenEdge = Succ == FirstBB;
// Don't try to insert on a self-edge. This is mainly because we will
// eliminate during renaming anyway.
if (Succ == BranchBB)
continue;
// Match combinations of conditions.
CmpInst::Predicate Pred;
bool isAnd = false;
bool isOr = false;
SmallVector<Value *, 8> CmpOperands;
if (match(BI->getCondition(), m_And(m_Cmp(Pred, m_Value(), m_Value()),
m_Cmp(Pred, m_Value(), m_Value()))) ||
match(BI->getCondition(), m_Or(m_Cmp(Pred, m_Value(), m_Value()),
m_Cmp(Pred, m_Value(), m_Value())))) {
auto *BinOp = cast<BinaryOperator>(BI->getCondition());
if (BinOp->getOpcode() == Instruction::And)
isAnd = true;
else if (BinOp->getOpcode() == Instruction::Or)
isOr = true;
ConditionsToProcess.push_back(BinOp->getOperand(0));
ConditionsToProcess.push_back(BinOp->getOperand(1));
ConditionsToProcess.push_back(BI->getCondition());
} else if (isa<CmpInst>(BI->getCondition())) {
ConditionsToProcess.push_back(BI->getCondition());
}
for (auto Cond : ConditionsToProcess) {
if (auto *Cmp = dyn_cast<CmpInst>(Cond)) {
collectCmpOps(Cmp, CmpOperands);
// Now add our copy infos for our operands
for (auto *Op : CmpOperands)
InsertHelper(Op, isAnd, isOr, Cmp);
} else if (auto *BinOp = dyn_cast<BinaryOperator>(Cond)) {
// This must be an AND or an OR.
assert((BinOp->getOpcode() == Instruction::And ||
BinOp->getOpcode() == Instruction::Or) &&
"Should have been an AND or an OR");
// The actual value of the binop is not subject to the same restrictions
// as the comparison. It's either true or false on the true/false branch.
InsertHelper(BinOp, false, false, BinOp);
} else {
llvm_unreachable("Unknown type of condition");
SmallVector<Value *, 4> Worklist;
SmallPtrSet<Value *, 4> Visited;
Worklist.push_back(BI->getCondition());
while (!Worklist.empty()) {
Value *Cond = Worklist.pop_back_val();
if (!Visited.insert(Cond).second)
continue;
if (Visited.size() > MaxCondsPerBranch)
break;
Value *Op0, *Op1;
if (TakenEdge ? match(Cond, m_And(m_Value(Op0), m_Value(Op1)))
: match(Cond, m_Or(m_Value(Op0), m_Value(Op1)))) {
Worklist.push_back(Op1);
Worklist.push_back(Op0);
}
SmallVector<Value *, 4> Values;
Values.push_back(Cond);
if (auto *Cmp = dyn_cast<CmpInst>(Cond))
collectCmpOps(Cmp, Values);
for (Value *V : Values) {
if (shouldRename(V)) {
PredicateBase *PB =
new PredicateBranch(V, BranchBB, Succ, Cond, TakenEdge);
addInfoFor(OpsToRename, V, PB);
if (!Succ->getSinglePredecessor())
EdgeUsesOnly.insert({BranchBB, Succ});
}
}
}
CmpOperands.clear();
}
}
// Process a block terminating switch, and place relevant operations to be

View File

@ -106,7 +106,7 @@ define i32 @_Z1il(i32 %val, i1 %k) {
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: tail call void @llvm.assume(i1 [[K:%.*]])
; CHECK-NEXT: tail call void @llvm.assume(i1 [[K]])
; CHECK-NEXT: tail call void @llvm.assume(i1 true)
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL:%.*]], 50
; CHECK-NEXT: br i1 [[CMP]], label [[NEXT]], label [[MEH:%.*]]
; CHECK: meh:
@ -132,7 +132,7 @@ define i1 @_z1im(i32 %val, i1 %k, i1 %j) {
; CHECK-NEXT: br i1 [[J:%.*]], label [[NEXT:%.*]], label [[MEH:%.*]]
; CHECK: next:
; CHECK-NEXT: tail call void @llvm.assume(i1 [[K:%.*]])
; CHECK-NEXT: tail call void @llvm.assume(i1 [[K]])
; CHECK-NEXT: tail call void @llvm.assume(i1 true)
; CHECK-NEXT: br label [[MEH]]
; CHECK: meh:
; CHECK-NEXT: ret i1 [[K]]

View File

@ -966,8 +966,6 @@ true:
ret void
}
; TODO: Currently only the information of the AND used as branch condition is
; used.
define void @f18_conditions_chained_and(i32 %a, i32 %b) {
; CHECK-LABEL: @f18_conditions_chained_and(
; CHECK-NEXT: entry:
@ -978,18 +976,12 @@ define void @f18_conditions_chained_and(i32 %a, i32 %b) {
; CHECK-NEXT: [[BC_2:%.*]] = and i1 [[BC]], [[B_LT]]
; CHECK-NEXT: br i1 [[BC_2]], label [[TRUE:%.*]], label [[FALSE:%.*]]
; CHECK: true:
; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[A]], 0
; CHECK-NEXT: call void @use(i1 [[F_1]])
; CHECK-NEXT: [[F_2:%.*]] = icmp eq i32 [[A]], 20
; CHECK-NEXT: call void @use(i1 [[F_2]])
; CHECK-NEXT: [[F_3:%.*]] = icmp ugt i32 [[A]], 100
; CHECK-NEXT: call void @use(i1 [[F_3]])
; CHECK-NEXT: [[F_4:%.*]] = icmp ugt i32 [[B]], 100
; CHECK-NEXT: call void @use(i1 [[F_4]])
; CHECK-NEXT: [[T_1:%.*]] = icmp ult i32 [[A]], 100
; CHECK-NEXT: call void @use(i1 [[T_1]])
; CHECK-NEXT: [[T_2:%.*]] = icmp ne i32 [[A]], 20
; CHECK-NEXT: call void @use(i1 [[T_2]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[A]], 21
; CHECK-NEXT: call void @use(i1 [[C_1]])
; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i32 [[A]], 21

View File

@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -print-predicateinfo < %s 2>&1 | FileCheck %s
; RUN: opt -print-predicateinfo -disable-output < %s 2>&1 | FileCheck %s
@a = external global i32 ; <i32*> [#uses=7]
@ -98,11 +98,11 @@ 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: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[BOTH_ZERO:%.*]], label [[NOPE:%.*]]
; CHECK: both_zero:
; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
@ -138,8 +138,8 @@ define void @test4(i1 %b, i32 %x) {
; CHECK-NEXT: i32 2, label [[CASE0]]
; CHECK-NEXT: i32 3, label [[CASE3]]
; CHECK-NEXT: i32 4, label [[DEFAULT:%.*]]
; CHECK-NEXT: ] Edge: [label [[SW]],label %case1]
; CHECK-NEXT: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X:%.*]])
; CHECK-NEXT: ] Edge: [label [[SW]],label %case1], RenamedOp: [[X:%.*]] }
; CHECK-NEXT: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK-NEXT: switch i32 [[X]], label [[DEFAULT]] [
; CHECK-NEXT: i32 0, label [[CASE0]]
; CHECK-NEXT: i32 1, label [[CASE1]]

View File

@ -10,11 +10,11 @@ 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: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]]
; CHECK: oneof:
; CHECK-NEXT: call void @foo(i1 [[XZ]])
@ -54,11 +54,11 @@ 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: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
@ -98,11 +98,11 @@ 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: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK: [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XGT]])
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK: [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X_0]])
; CHECK: [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XLT]])
; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @foo(i1 [[XGT_0]])
@ -137,25 +137,25 @@ define void @testandassume(i32 %x, i32 %y) {
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
; CHECK-NEXT: call void @llvm.assume(i1 [[Z]])
; CHECK: [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK: [[TMP2:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
; CHECK: [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
; CHECK: [[TMP4:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK: [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
; CHECK: [[TMP1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
; CHECK: [[TMP2:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
; CHECK: [[TMP3:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK: [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
; CHECK: [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK: [[DOT0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP5]])
; CHECK: [[DOT01:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP4]])
; CHECK: [[DOT02:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP3]])
; CHECK: [[DOT03:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP2]])
; CHECK: [[DOT04:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP1]])
; CHECK-NEXT: br i1 [[TMP1]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: [[DOT01:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP4]])
; CHECK: [[DOT02:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP3]])
; CHECK: [[DOT03:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP2]])
; CHECK: [[DOT04:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP1]])
; CHECK-NEXT: br i1 [[TMP5]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @foo(i1 [[DOT0]])
; CHECK-NEXT: call void @foo(i1 [[DOT02]])
; CHECK-NEXT: call void @bar(i32 [[DOT01]])
; CHECK-NEXT: call void @bar(i32 [[DOT03]])
; CHECK-NEXT: call void @foo(i1 [[DOT01]])
; CHECK-NEXT: call void @foo(i1 [[DOT03]])
; CHECK-NEXT: call void @bar(i32 [[DOT02]])
; CHECK-NEXT: call void @bar(i32 [[DOT04]])
; CHECK-NEXT: ret void
; CHECK: nope:
; CHECK-NEXT: call void @foo(i1 [[DOT04]])
; CHECK-NEXT: call void @foo(i1 [[DOT0]])
; CHECK-NEXT: ret void
;
%xz = icmp eq i32 %x, 0
@ -182,8 +182,9 @@ define void @testorassume(i32 %x, i32 %y) {
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
; CHECK-NEXT: [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
; CHECK-NEXT: call void @llvm.assume(i1 [[Z]])
; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK: [[DOT0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP1]])
; CHECK-NEXT: br i1 [[TMP1]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @foo(i1 [[XZ]])
; CHECK-NEXT: call void @foo(i1 [[YZ]])
@ -191,7 +192,7 @@ define void @testorassume(i32 %x, i32 %y) {
; CHECK-NEXT: call void @bar(i32 [[Y]])
; CHECK-NEXT: ret void
; CHECK: nope:
; CHECK-NEXT: call void @foo(i1 [[Z_0]])
; CHECK-NEXT: call void @foo(i1 [[DOT0]])
; CHECK-NEXT: ret void
;
%xz = icmp eq i32 %x, 0
@ -214,18 +215,23 @@ define void @test_and_one_unknown_cond(i32 %x, i1 %c1) {
; CHECK-LABEL: @test_and_one_unknown_cond(
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[A:%.*]] = and i1 [[C1:%.*]], [[C2]]
; CHECK: [[A_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
; CHECK: [[A_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
; CHECK: [[C1_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C1]])
; CHECK: [[C2_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C2]])
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK-NEXT: br i1 [[A]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @bar(i32 [[X]])
; CHECK-NEXT: call void @foo(i1 [[C1]])
; CHECK-NEXT: call void @foo(i1 [[C2]])
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @bar(i32 [[X_0]])
; CHECK-NEXT: call void @foo(i1 [[C1_0]])
; CHECK-NEXT: call void @foo(i1 [[C2_0]])
; CHECK-NEXT: call void @foo(i1 [[A_0]])
; CHECK-NEXT: ret void
; CHECK: nope:
; CHECK-NEXT: call void @bar(i32 [[X]])
; CHECK-NEXT: call void @foo(i1 [[C1]])
; CHECK-NEXT: call void @foo(i1 [[C2]])
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[A_1]])
; CHECK-NEXT: ret void
;
%c2 = icmp eq i32 %x, 0
@ -251,18 +257,23 @@ define void @test_or_one_unknown_cond(i32 %x, i1 %c1) {
; CHECK-LABEL: @test_or_one_unknown_cond(
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[A:%.*]] = or i1 [[C1:%.*]], [[C2]]
; CHECK: [[A_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
; CHECK: [[A_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
; CHECK: [[C1_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C1]])
; CHECK: [[C2_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C2]])
; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK-NEXT: br i1 [[A]], label [[NOPE:%.*]], label [[BOTH_INVERTED:%.*]]
; CHECK: both_inverted:
; CHECK-NEXT: call void @bar(i32 [[X]])
; CHECK-NEXT: call void @foo(i1 [[C1]])
; CHECK-NEXT: call void @foo(i1 [[C2]])
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @bar(i32 [[X_0]])
; CHECK-NEXT: call void @foo(i1 [[C1_0]])
; CHECK-NEXT: call void @foo(i1 [[C2_0]])
; CHECK-NEXT: call void @foo(i1 [[A_1]])
; CHECK-NEXT: ret void
; CHECK: nope:
; CHECK-NEXT: call void @bar(i32 [[X]])
; CHECK-NEXT: call void @foo(i1 [[C1]])
; CHECK-NEXT: call void @foo(i1 [[C2]])
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[A_0]])
; CHECK-NEXT: ret void
;
%c2 = icmp eq i32 %x, 0
@ -288,20 +299,26 @@ define void @test_and_chain(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: @test_and_chain(
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C:%.*]]
; CHECK: [[AND2_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND2]])
; CHECK: [[AND2_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND2]])
; CHECK: [[AND1_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND1]])
; CHECK: [[A_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
; CHECK: [[B_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[B]])
; CHECK: [[C_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C]])
; CHECK-NEXT: br i1 [[AND2]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[B]])
; CHECK-NEXT: call void @foo(i1 [[C]])
; CHECK-NEXT: call void @foo(i1 [[AND1]])
; CHECK-NEXT: call void @foo(i1 [[AND2]])
; CHECK-NEXT: call void @foo(i1 [[A_0]])
; CHECK-NEXT: call void @foo(i1 [[B_0]])
; CHECK-NEXT: call void @foo(i1 [[C_0]])
; CHECK-NEXT: call void @foo(i1 [[AND1_0]])
; CHECK-NEXT: call void @foo(i1 [[AND2_0]])
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[B]])
; CHECK-NEXT: call void @foo(i1 [[C]])
; CHECK-NEXT: call void @foo(i1 [[AND1]])
; CHECK-NEXT: call void @foo(i1 [[AND2]])
; CHECK-NEXT: call void @foo(i1 [[AND2_1]])
; CHECK-NEXT: ret void
;
%and1 = and i1 %a, %b
@ -329,20 +346,26 @@ define void @test_or_chain(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: @test_or_chain(
; CHECK-NEXT: [[OR1:%.*]] = or i1 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[OR2:%.*]] = or i1 [[OR1]], [[C:%.*]]
; CHECK: [[OR2_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR2]])
; CHECK: [[OR2_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR2]])
; CHECK: [[OR1_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR1]])
; CHECK: [[A_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
; CHECK: [[B_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[B]])
; CHECK: [[C_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C]])
; CHECK-NEXT: br i1 [[OR2]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[B]])
; CHECK-NEXT: call void @foo(i1 [[C]])
; CHECK-NEXT: call void @foo(i1 [[OR1]])
; CHECK-NEXT: call void @foo(i1 [[OR2]])
; CHECK-NEXT: call void @foo(i1 [[OR2_0]])
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[B]])
; CHECK-NEXT: call void @foo(i1 [[C]])
; CHECK-NEXT: call void @foo(i1 [[OR1]])
; CHECK-NEXT: call void @foo(i1 [[OR2]])
; CHECK-NEXT: call void @foo(i1 [[A_0]])
; CHECK-NEXT: call void @foo(i1 [[B_0]])
; CHECK-NEXT: call void @foo(i1 [[C_0]])
; CHECK-NEXT: call void @foo(i1 [[OR1_0]])
; CHECK-NEXT: call void @foo(i1 [[OR2_1]])
; CHECK-NEXT: ret void
;
%or1 = or i1 %a, %b
@ -370,20 +393,24 @@ define void @test_and_or_mixed(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: @test_and_or_mixed(
; CHECK-NEXT: [[OR:%.*]] = or i1 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i1 [[OR]], [[C:%.*]]
; CHECK: [[AND_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND]])
; CHECK: [[AND_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND]])
; CHECK: [[OR_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR]])
; CHECK: [[C_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C]])
; CHECK-NEXT: br i1 [[AND]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[B]])
; CHECK-NEXT: call void @foo(i1 [[C]])
; CHECK-NEXT: call void @foo(i1 [[OR]])
; CHECK-NEXT: call void @foo(i1 [[AND]])
; CHECK-NEXT: call void @foo(i1 [[C_0]])
; CHECK-NEXT: call void @foo(i1 [[OR_0]])
; CHECK-NEXT: call void @foo(i1 [[AND_0]])
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[B]])
; CHECK-NEXT: call void @foo(i1 [[C]])
; CHECK-NEXT: call void @foo(i1 [[OR]])
; CHECK-NEXT: call void @foo(i1 [[AND]])
; CHECK-NEXT: call void @foo(i1 [[AND_1]])
; CHECK-NEXT: ret void
;
%or = or i1 %a, %b
@ -423,31 +450,38 @@ define void @test_deep_and_chain(i1 %a1) {
; CHECK-NEXT: [[A13:%.*]] = and i1 [[A12]], true
; CHECK-NEXT: [[A14:%.*]] = and i1 [[A13]], true
; CHECK-NEXT: [[A15:%.*]] = and i1 [[A14]], true
; CHECK: [[A15_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
; CHECK: [[A15_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
; CHECK: [[A14_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A14]])
; CHECK: [[A13_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A13]])
; CHECK: [[A12_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A12]])
; CHECK: [[A11_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A11]])
; CHECK: [[A10_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A10]])
; CHECK: [[A9_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A9]])
; CHECK: [[A8_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A8]])
; CHECK-NEXT: br i1 [[A15]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo(i1 [[A1]])
; CHECK-NEXT: call void @foo(i1 [[A2]])
; CHECK-NEXT: call void @foo(i1 [[A3]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A5]])
; CHECK-NEXT: call void @foo(i1 [[A6]])
; CHECK-NEXT: call void @foo(i1 [[A7]])
; CHECK-NEXT: call void @foo(i1 [[A8]])
; CHECK-NEXT: call void @foo(i1 [[A9]])
; CHECK-NEXT: call void @foo(i1 [[A10]])
; CHECK-NEXT: call void @foo(i1 [[A11]])
; CHECK-NEXT: call void @foo(i1 [[A12]])
; CHECK-NEXT: call void @foo(i1 [[A13]])
; CHECK-NEXT: call void @foo(i1 [[A14]])
; CHECK-NEXT: call void @foo(i1 [[A15]])
; CHECK-NEXT: call void @foo(i1 [[A8_0]])
; CHECK-NEXT: call void @foo(i1 [[A9_0]])
; CHECK-NEXT: call void @foo(i1 [[A10_0]])
; CHECK-NEXT: call void @foo(i1 [[A11_0]])
; CHECK-NEXT: call void @foo(i1 [[A12_0]])
; CHECK-NEXT: call void @foo(i1 [[A13_0]])
; CHECK-NEXT: call void @foo(i1 [[A14_0]])
; CHECK-NEXT: call void @foo(i1 [[A15_0]])
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: call void @foo(i1 [[A1]])
; CHECK-NEXT: call void @foo(i1 [[A2]])
; CHECK-NEXT: call void @foo(i1 [[A3]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A5]])
; CHECK-NEXT: call void @foo(i1 [[A6]])
; CHECK-NEXT: call void @foo(i1 [[A7]])
@ -458,7 +492,7 @@ define void @test_deep_and_chain(i1 %a1) {
; CHECK-NEXT: call void @foo(i1 [[A12]])
; CHECK-NEXT: call void @foo(i1 [[A13]])
; CHECK-NEXT: call void @foo(i1 [[A14]])
; CHECK-NEXT: call void @foo(i1 [[A15]])
; CHECK-NEXT: call void @foo(i1 [[A15_1]])
; CHECK-NEXT: ret void
;
%a2 = and i1 %a1, true
@ -482,7 +516,6 @@ if:
call void @foo(i1 %a2)
call void @foo(i1 %a3)
call void @foo(i1 %a4)
call void @foo(i1 %a4)
call void @foo(i1 %a5)
call void @foo(i1 %a6)
call void @foo(i1 %a7)
@ -501,7 +534,6 @@ else:
call void @foo(i1 %a2)
call void @foo(i1 %a3)
call void @foo(i1 %a4)
call void @foo(i1 %a4)
call void @foo(i1 %a5)
call void @foo(i1 %a6)
call void @foo(i1 %a7)
@ -532,31 +564,38 @@ define void @test_deep_and_tree(i1 %a1) {
; CHECK-NEXT: [[A13:%.*]] = and i1 [[A12]], [[A12]]
; CHECK-NEXT: [[A14:%.*]] = and i1 [[A13]], [[A13]]
; CHECK-NEXT: [[A15:%.*]] = and i1 [[A14]], [[A14]]
; CHECK: [[A15_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
; CHECK: [[A15_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
; CHECK: [[A14_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A14]])
; CHECK: [[A13_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A13]])
; CHECK: [[A12_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A12]])
; CHECK: [[A11_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A11]])
; CHECK: [[A10_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A10]])
; CHECK: [[A9_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A9]])
; CHECK: [[A8_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A8]])
; CHECK-NEXT: br i1 [[A15]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo(i1 [[A1]])
; CHECK-NEXT: call void @foo(i1 [[A2]])
; CHECK-NEXT: call void @foo(i1 [[A3]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A5]])
; CHECK-NEXT: call void @foo(i1 [[A6]])
; CHECK-NEXT: call void @foo(i1 [[A7]])
; CHECK-NEXT: call void @foo(i1 [[A8]])
; CHECK-NEXT: call void @foo(i1 [[A9]])
; CHECK-NEXT: call void @foo(i1 [[A10]])
; CHECK-NEXT: call void @foo(i1 [[A11]])
; CHECK-NEXT: call void @foo(i1 [[A12]])
; CHECK-NEXT: call void @foo(i1 [[A13]])
; CHECK-NEXT: call void @foo(i1 [[A14]])
; CHECK-NEXT: call void @foo(i1 [[A15]])
; CHECK-NEXT: call void @foo(i1 [[A8_0]])
; CHECK-NEXT: call void @foo(i1 [[A9_0]])
; CHECK-NEXT: call void @foo(i1 [[A10_0]])
; CHECK-NEXT: call void @foo(i1 [[A11_0]])
; CHECK-NEXT: call void @foo(i1 [[A12_0]])
; CHECK-NEXT: call void @foo(i1 [[A13_0]])
; CHECK-NEXT: call void @foo(i1 [[A14_0]])
; CHECK-NEXT: call void @foo(i1 [[A15_0]])
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: call void @foo(i1 [[A1]])
; CHECK-NEXT: call void @foo(i1 [[A2]])
; CHECK-NEXT: call void @foo(i1 [[A3]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A5]])
; CHECK-NEXT: call void @foo(i1 [[A6]])
; CHECK-NEXT: call void @foo(i1 [[A7]])
@ -567,7 +606,7 @@ define void @test_deep_and_tree(i1 %a1) {
; CHECK-NEXT: call void @foo(i1 [[A12]])
; CHECK-NEXT: call void @foo(i1 [[A13]])
; CHECK-NEXT: call void @foo(i1 [[A14]])
; CHECK-NEXT: call void @foo(i1 [[A15]])
; CHECK-NEXT: call void @foo(i1 [[A15_1]])
; CHECK-NEXT: ret void
;
%a2 = and i1 %a1, %a1
@ -591,7 +630,6 @@ if:
call void @foo(i1 %a2)
call void @foo(i1 %a3)
call void @foo(i1 %a4)
call void @foo(i1 %a4)
call void @foo(i1 %a5)
call void @foo(i1 %a6)
call void @foo(i1 %a7)
@ -610,7 +648,6 @@ else:
call void @foo(i1 %a2)
call void @foo(i1 %a3)
call void @foo(i1 %a4)
call void @foo(i1 %a4)
call void @foo(i1 %a5)
call void @foo(i1 %a6)
call void @foo(i1 %a7)
@ -641,13 +678,21 @@ define void @test_deep_or_tree(i1 %a1) {
; CHECK-NEXT: [[A13:%.*]] = or i1 [[A12]], [[A12]]
; CHECK-NEXT: [[A14:%.*]] = or i1 [[A13]], [[A13]]
; CHECK-NEXT: [[A15:%.*]] = or i1 [[A14]], [[A14]]
; CHECK: [[A15_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
; CHECK: [[A15_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
; CHECK: [[A14_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A14]])
; CHECK: [[A13_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A13]])
; CHECK: [[A12_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A12]])
; CHECK: [[A11_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A11]])
; CHECK: [[A10_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A10]])
; CHECK: [[A9_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A9]])
; CHECK: [[A8_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A8]])
; CHECK-NEXT: br i1 [[A15]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: call void @foo(i1 [[A1]])
; CHECK-NEXT: call void @foo(i1 [[A2]])
; CHECK-NEXT: call void @foo(i1 [[A3]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A5]])
; CHECK-NEXT: call void @foo(i1 [[A6]])
; CHECK-NEXT: call void @foo(i1 [[A7]])
@ -658,25 +703,24 @@ define void @test_deep_or_tree(i1 %a1) {
; CHECK-NEXT: call void @foo(i1 [[A12]])
; CHECK-NEXT: call void @foo(i1 [[A13]])
; CHECK-NEXT: call void @foo(i1 [[A14]])
; CHECK-NEXT: call void @foo(i1 [[A15]])
; CHECK-NEXT: call void @foo(i1 [[A15_0]])
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK-NEXT: call void @foo(i1 [[A1]])
; CHECK-NEXT: call void @foo(i1 [[A2]])
; CHECK-NEXT: call void @foo(i1 [[A3]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A5]])
; CHECK-NEXT: call void @foo(i1 [[A6]])
; CHECK-NEXT: call void @foo(i1 [[A7]])
; CHECK-NEXT: call void @foo(i1 [[A8]])
; CHECK-NEXT: call void @foo(i1 [[A9]])
; CHECK-NEXT: call void @foo(i1 [[A10]])
; CHECK-NEXT: call void @foo(i1 [[A11]])
; CHECK-NEXT: call void @foo(i1 [[A12]])
; CHECK-NEXT: call void @foo(i1 [[A13]])
; CHECK-NEXT: call void @foo(i1 [[A14]])
; CHECK-NEXT: call void @foo(i1 [[A15]])
; CHECK-NEXT: call void @foo(i1 [[A8_0]])
; CHECK-NEXT: call void @foo(i1 [[A9_0]])
; CHECK-NEXT: call void @foo(i1 [[A10_0]])
; CHECK-NEXT: call void @foo(i1 [[A11_0]])
; CHECK-NEXT: call void @foo(i1 [[A12_0]])
; CHECK-NEXT: call void @foo(i1 [[A13_0]])
; CHECK-NEXT: call void @foo(i1 [[A14_0]])
; CHECK-NEXT: call void @foo(i1 [[A15_1]])
; CHECK-NEXT: ret void
;
%a2 = or i1 %a1, %a1
@ -700,7 +744,6 @@ if:
call void @foo(i1 %a2)
call void @foo(i1 %a3)
call void @foo(i1 %a4)
call void @foo(i1 %a4)
call void @foo(i1 %a5)
call void @foo(i1 %a6)
call void @foo(i1 %a7)
@ -719,7 +762,6 @@ else:
call void @foo(i1 %a2)
call void @foo(i1 %a3)
call void @foo(i1 %a4)
call void @foo(i1 %a4)
call void @foo(i1 %a5)
call void @foo(i1 %a6)
call void @foo(i1 %a7)
@ -739,11 +781,16 @@ define void @test_assume_and_chain(i1 %a, i1 %b, i1 %c) {
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C:%.*]]
; CHECK-NEXT: call void @llvm.assume(i1 [[AND2]])
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[B]])
; CHECK-NEXT: call void @foo(i1 [[C]])
; CHECK-NEXT: call void @foo(i1 [[AND1]])
; CHECK-NEXT: call void @foo(i1 [[AND2]])
; CHECK: [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C]])
; CHECK: [[TMP2:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[B]])
; CHECK: [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
; CHECK: [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND1]])
; CHECK: [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND2]])
; CHECK-NEXT: call void @foo(i1 [[TMP3]])
; CHECK-NEXT: call void @foo(i1 [[TMP2]])
; CHECK-NEXT: call void @foo(i1 [[TMP1]])
; CHECK-NEXT: call void @foo(i1 [[TMP4]])
; CHECK-NEXT: call void @foo(i1 [[TMP5]])
; CHECK-NEXT: ret void
;
%and1 = and i1 %a, %b
@ -762,11 +809,12 @@ define void @test_assume_or_chain(i1 %a, i1 %b, i1 %c) {
; CHECK-NEXT: [[OR1:%.*]] = or i1 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[OR2:%.*]] = or i1 [[OR1]], [[C:%.*]]
; CHECK-NEXT: call void @llvm.assume(i1 [[OR2]])
; CHECK: [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR2]])
; CHECK-NEXT: call void @foo(i1 [[A]])
; CHECK-NEXT: call void @foo(i1 [[B]])
; CHECK-NEXT: call void @foo(i1 [[C]])
; CHECK-NEXT: call void @foo(i1 [[OR1]])
; CHECK-NEXT: call void @foo(i1 [[OR2]])
; CHECK-NEXT: call void @foo(i1 [[TMP1]])
; CHECK-NEXT: ret void
;
%or1 = or i1 %a, %b
@ -797,22 +845,29 @@ define void @test_assume_deep_and_tree(i1 %a1) {
; CHECK-NEXT: [[A14:%.*]] = and i1 [[A13]], [[A13]]
; CHECK-NEXT: [[A15:%.*]] = and i1 [[A14]], [[A14]]
; CHECK-NEXT: call void @llvm.assume(i1 [[A15]])
; CHECK: [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A8]])
; CHECK: [[TMP2:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A9]])
; CHECK: [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A10]])
; CHECK: [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A11]])
; CHECK: [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A12]])
; CHECK: [[TMP6:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A13]])
; CHECK: [[TMP7:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A14]])
; CHECK: [[TMP8:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
; CHECK-NEXT: call void @foo(i1 [[A1]])
; CHECK-NEXT: call void @foo(i1 [[A2]])
; CHECK-NEXT: call void @foo(i1 [[A3]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A4]])
; CHECK-NEXT: call void @foo(i1 [[A5]])
; CHECK-NEXT: call void @foo(i1 [[A6]])
; CHECK-NEXT: call void @foo(i1 [[A7]])
; CHECK-NEXT: call void @foo(i1 [[A8]])
; CHECK-NEXT: call void @foo(i1 [[A9]])
; CHECK-NEXT: call void @foo(i1 [[A10]])
; CHECK-NEXT: call void @foo(i1 [[A11]])
; CHECK-NEXT: call void @foo(i1 [[A12]])
; CHECK-NEXT: call void @foo(i1 [[A13]])
; CHECK-NEXT: call void @foo(i1 [[A14]])
; CHECK-NEXT: call void @foo(i1 [[A15]])
; CHECK-NEXT: call void @foo(i1 [[TMP1]])
; CHECK-NEXT: call void @foo(i1 [[TMP2]])
; CHECK-NEXT: call void @foo(i1 [[TMP3]])
; CHECK-NEXT: call void @foo(i1 [[TMP4]])
; CHECK-NEXT: call void @foo(i1 [[TMP5]])
; CHECK-NEXT: call void @foo(i1 [[TMP6]])
; CHECK-NEXT: call void @foo(i1 [[TMP7]])
; CHECK-NEXT: call void @foo(i1 [[TMP8]])
; CHECK-NEXT: ret void
;
%a2 = and i1 %a1, %a1
@ -834,7 +889,6 @@ define void @test_assume_deep_and_tree(i1 %a1) {
call void @foo(i1 %a2)
call void @foo(i1 %a3)
call void @foo(i1 %a4)
call void @foo(i1 %a4)
call void @foo(i1 %a5)
call void @foo(i1 %a6)
call void @foo(i1 %a7)