forked from OSchip/llvm-project
[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:
parent
b564b12bc6
commit
ca4ed1e7ae
|
@ -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
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue