forked from OSchip/llvm-project
Revert "[SimpleLoopUnswitch] Collect either logical ANDs/ORs but not both."
This reverts commit db7a87ed4f
.
This seems to cause a PPC buildbot failure:
https://lab.llvm.org/buildbot#builders/93/builds/8787
This commit is contained in:
parent
a097c4ce95
commit
7211d5ce07
|
@ -116,23 +116,13 @@ static cl::opt<bool> FreezeLoopUnswitchCond(
|
||||||
cl::desc("If enabled, the freeze instruction will be added to condition "
|
cl::desc("If enabled, the freeze instruction will be added to condition "
|
||||||
"of loop unswitch to prevent miscompilation."));
|
"of loop unswitch to prevent miscompilation."));
|
||||||
|
|
||||||
// Helper to skip (select x, true, false), which matches both a logical AND and
|
|
||||||
// OR and can confuse code that tries to determine if \p Cond is either a
|
|
||||||
// logical AND or OR but not both.
|
|
||||||
static Value *skipTrivialSelect(Value *Cond) {
|
|
||||||
Value *CondNext;
|
|
||||||
while (match(Cond, m_Select(m_Value(CondNext), m_One(), m_Zero())))
|
|
||||||
Cond = CondNext;
|
|
||||||
return Cond;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Collect all of the loop invariant input values transitively used by the
|
/// Collect all of the loop invariant input values transitively used by the
|
||||||
/// homogeneous instruction graph from a given root.
|
/// homogeneous instruction graph from a given root.
|
||||||
///
|
///
|
||||||
/// This essentially walks from a root recursively through loop variant operands
|
/// This essentially walks from a root recursively through loop variant operands
|
||||||
/// which have perform the same logical operation (AND or OR) and finds all
|
/// which have the exact same opcode and finds all inputs which are loop
|
||||||
/// inputs which are loop invariant. For some operations these can be
|
/// invariant. For some operations these can be re-associated and unswitched out
|
||||||
/// re-associated and unswitched out of the loop entirely.
|
/// of the loop entirely.
|
||||||
static TinyPtrVector<Value *>
|
static TinyPtrVector<Value *>
|
||||||
collectHomogenousInstGraphLoopInvariants(Loop &L, Instruction &Root,
|
collectHomogenousInstGraphLoopInvariants(Loop &L, Instruction &Root,
|
||||||
LoopInfo &LI) {
|
LoopInfo &LI) {
|
||||||
|
@ -162,7 +152,7 @@ collectHomogenousInstGraphLoopInvariants(Loop &L, Instruction &Root,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not an instruction with the same opcode, nothing we can do.
|
// If not an instruction with the same opcode, nothing we can do.
|
||||||
Instruction *OpI = dyn_cast<Instruction>(skipTrivialSelect(OpV));
|
Instruction *OpI = dyn_cast<Instruction>(OpV);
|
||||||
|
|
||||||
if (OpI && ((IsRootAnd && match(OpI, m_LogicalAnd())) ||
|
if (OpI && ((IsRootAnd && match(OpI, m_LogicalAnd())) ||
|
||||||
(IsRootOr && match(OpI, m_LogicalOr())))) {
|
(IsRootOr && match(OpI, m_LogicalOr())))) {
|
||||||
|
@ -464,8 +454,7 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
||||||
Invariants.push_back(BI.getCondition());
|
Invariants.push_back(BI.getCondition());
|
||||||
FullUnswitch = true;
|
FullUnswitch = true;
|
||||||
} else {
|
} else {
|
||||||
if (auto *CondInst =
|
if (auto *CondInst = dyn_cast<Instruction>(BI.getCondition()))
|
||||||
dyn_cast<Instruction>(skipTrivialSelect(BI.getCondition())))
|
|
||||||
Invariants = collectHomogenousInstGraphLoopInvariants(L, *CondInst, LI);
|
Invariants = collectHomogenousInstGraphLoopInvariants(L, *CondInst, LI);
|
||||||
if (Invariants.empty()) {
|
if (Invariants.empty()) {
|
||||||
LLVM_DEBUG(dbgs() << " Couldn't find invariant inputs!\n");
|
LLVM_DEBUG(dbgs() << " Couldn't find invariant inputs!\n");
|
||||||
|
@ -499,9 +488,8 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
||||||
// is a graph of `or` operations, or the exit block is along the false edge
|
// is a graph of `or` operations, or the exit block is along the false edge
|
||||||
// and the condition is a graph of `and` operations.
|
// and the condition is a graph of `and` operations.
|
||||||
if (!FullUnswitch) {
|
if (!FullUnswitch) {
|
||||||
Value *Cond = skipTrivialSelect(BI.getCondition());
|
if (ExitDirection ? !match(BI.getCondition(), m_LogicalOr())
|
||||||
if (ExitDirection ? !match(Cond, m_LogicalOr())
|
: !match(BI.getCondition(), m_LogicalAnd())) {
|
||||||
: !match(Cond, m_LogicalAnd())) {
|
|
||||||
LLVM_DEBUG(dbgs() << " Branch condition is in improper form for "
|
LLVM_DEBUG(dbgs() << " Branch condition is in improper form for "
|
||||||
"non-full unswitch!\n");
|
"non-full unswitch!\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -581,11 +569,11 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
||||||
// Only unswitching a subset of inputs to the condition, so we will need to
|
// Only unswitching a subset of inputs to the condition, so we will need to
|
||||||
// build a new branch that merges the invariant inputs.
|
// build a new branch that merges the invariant inputs.
|
||||||
if (ExitDirection)
|
if (ExitDirection)
|
||||||
assert(match(skipTrivialSelect(BI.getCondition()), m_LogicalOr()) &&
|
assert(match(BI.getCondition(), m_LogicalOr()) &&
|
||||||
"Must have an `or` of `i1`s or `select i1 X, true, Y`s for the "
|
"Must have an `or` of `i1`s or `select i1 X, true, Y`s for the "
|
||||||
"condition!");
|
"condition!");
|
||||||
else
|
else
|
||||||
assert(match(skipTrivialSelect(BI.getCondition()), m_LogicalAnd()) &&
|
assert(match(BI.getCondition(), m_LogicalAnd()) &&
|
||||||
"Must have an `and` of `i1`s or `select i1 X, Y, false`s for the"
|
"Must have an `and` of `i1`s or `select i1 X, Y, false`s for the"
|
||||||
" condition!");
|
" condition!");
|
||||||
buildPartialUnswitchConditionalBranch(
|
buildPartialUnswitchConditionalBranch(
|
||||||
|
@ -2083,14 +2071,14 @@ static void unswitchNontrivialInvariants(
|
||||||
bool Direction = true;
|
bool Direction = true;
|
||||||
int ClonedSucc = 0;
|
int ClonedSucc = 0;
|
||||||
if (!FullUnswitch) {
|
if (!FullUnswitch) {
|
||||||
Value *Cond = skipTrivialSelect(BI->getCondition());
|
Value *Cond = BI->getCondition();
|
||||||
(void)Cond;
|
(void)Cond;
|
||||||
assert(((match(Cond, m_LogicalAnd()) ^ match(Cond, m_LogicalOr())) ||
|
assert(((match(Cond, m_LogicalAnd()) ^ match(Cond, m_LogicalOr())) ||
|
||||||
PartiallyInvariant) &&
|
PartiallyInvariant) &&
|
||||||
"Only `or`, `and`, an `select`, partially invariant instructions "
|
"Only `or`, `and`, an `select`, partially invariant instructions "
|
||||||
"can combine invariants being unswitched.");
|
"can combine invariants being unswitched.");
|
||||||
if (!match(Cond, m_LogicalOr())) {
|
if (!match(BI->getCondition(), m_LogicalOr())) {
|
||||||
if (match(Cond, m_LogicalAnd()) ||
|
if (match(BI->getCondition(), m_LogicalAnd()) ||
|
||||||
(PartiallyInvariant && !PartialIVInfo.KnownValue->isOneValue())) {
|
(PartiallyInvariant && !PartialIVInfo.KnownValue->isOneValue())) {
|
||||||
Direction = false;
|
Direction = false;
|
||||||
ClonedSucc = 1;
|
ClonedSucc = 1;
|
||||||
|
@ -2768,16 +2756,22 @@ static bool unswitchBestCondition(
|
||||||
BI->getSuccessor(0) == BI->getSuccessor(1))
|
BI->getSuccessor(0) == BI->getSuccessor(1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Value *Cond = skipTrivialSelect(BI->getCondition());
|
// If BI's condition is 'select _, true, false', simplify it to confuse
|
||||||
|
// matchers
|
||||||
|
Value *Cond = BI->getCondition(), *CondNext;
|
||||||
|
while (match(Cond, m_Select(m_Value(CondNext), m_One(), m_Zero())))
|
||||||
|
Cond = CondNext;
|
||||||
|
BI->setCondition(Cond);
|
||||||
|
|
||||||
if (isa<Constant>(Cond))
|
if (isa<Constant>(Cond))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (L.isLoopInvariant(Cond)) {
|
if (L.isLoopInvariant(BI->getCondition())) {
|
||||||
UnswitchCandidates.push_back({BI, {Cond}});
|
UnswitchCandidates.push_back({BI, {BI->getCondition()}});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction &CondI = *cast<Instruction>(Cond);
|
Instruction &CondI = *cast<Instruction>(BI->getCondition());
|
||||||
if (match(&CondI, m_CombineOr(m_LogicalAnd(), m_LogicalOr()))) {
|
if (match(&CondI, m_CombineOr(m_LogicalAnd(), m_LogicalOr()))) {
|
||||||
TinyPtrVector<Value *> Invariants =
|
TinyPtrVector<Value *> Invariants =
|
||||||
collectHomogenousInstGraphLoopInvariants(L, CondI, LI);
|
collectHomogenousInstGraphLoopInvariants(L, CondI, LI);
|
||||||
|
@ -2919,11 +2913,10 @@ static bool unswitchBestCondition(
|
||||||
// its cost.
|
// its cost.
|
||||||
if (!FullUnswitch) {
|
if (!FullUnswitch) {
|
||||||
auto &BI = cast<BranchInst>(TI);
|
auto &BI = cast<BranchInst>(TI);
|
||||||
Value *Cond = skipTrivialSelect(BI.getCondition());
|
if (match(BI.getCondition(), m_LogicalAnd())) {
|
||||||
if (match(Cond, m_LogicalAnd())) {
|
|
||||||
if (SuccBB == BI.getSuccessor(1))
|
if (SuccBB == BI.getSuccessor(1))
|
||||||
continue;
|
continue;
|
||||||
} else if (match(Cond, m_LogicalOr())) {
|
} else if (match(BI.getCondition(), m_LogicalOr())) {
|
||||||
if (SuccBB == BI.getSuccessor(0))
|
if (SuccBB == BI.getSuccessor(0))
|
||||||
continue;
|
continue;
|
||||||
} else if ((PartialIVInfo.KnownValue->isOneValue() &&
|
} else if ((PartialIVInfo.KnownValue->isOneValue() &&
|
||||||
|
|
|
@ -2346,7 +2346,7 @@ define i32 @test_partial_unswitch_all_conds_guaranteed_non_poison(i1 noundef %c.
|
||||||
; CHECK: loop:
|
; CHECK: loop:
|
||||||
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @a()
|
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @a()
|
||||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 true, i1 true, i1 false
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 true, i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 [[SEL]], label [[LOOP]], label [[EXIT_SPLIT:%.*]]
|
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[EXIT_SPLIT:%.*]]
|
||||||
; CHECK: exit.split:
|
; CHECK: exit.split:
|
||||||
; CHECK-NEXT: br label [[EXIT]]
|
; CHECK-NEXT: br label [[EXIT]]
|
||||||
; CHECK: exit:
|
; CHECK: exit:
|
||||||
|
|
|
@ -16,7 +16,7 @@ define void @foo() {
|
||||||
; CHECK-NEXT: br label [[HEADER:%.*]]
|
; CHECK-NEXT: br label [[HEADER:%.*]]
|
||||||
; CHECK: header:
|
; CHECK: header:
|
||||||
; CHECK-NEXT: [[VAL:%.*]] = select i1 true, i1 true, i1 false
|
; CHECK-NEXT: [[VAL:%.*]] = select i1 true, i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 [[VAL]], label [[EXIT:%.*]], label [[HEADER]]
|
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[HEADER]]
|
||||||
; CHECK: exit:
|
; CHECK: exit:
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
|
|
|
@ -4277,7 +4277,7 @@ loop_begin:
|
||||||
; CHECK-NEXT: %[[V2:.*]] = load i1, i1* %ptr2
|
; CHECK-NEXT: %[[V2:.*]] = load i1, i1* %ptr2
|
||||||
; CHECK-NEXT: %[[AND1:.*]] = select i1 %[[V1]], i1 true, i1 false
|
; CHECK-NEXT: %[[AND1:.*]] = select i1 %[[V1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: %[[AND2:.*]] = select i1 %[[AND1]], i1 true, i1 false
|
; CHECK-NEXT: %[[AND2:.*]] = select i1 %[[AND1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 %[[AND2]], label %loop_a, label %loop_b
|
; CHECK-NEXT: br i1 %[[V1]], label %loop_a, label %loop_b
|
||||||
|
|
||||||
loop_a:
|
loop_a:
|
||||||
call i32 @a()
|
call i32 @a()
|
||||||
|
@ -4357,7 +4357,7 @@ loop_begin:
|
||||||
; CHECK-NEXT: %[[V2:.*]] = load i1, i1* %ptr2
|
; CHECK-NEXT: %[[V2:.*]] = load i1, i1* %ptr2
|
||||||
; CHECK-NEXT: %[[AND1:.*]] = select i1 %[[V1]], i1 true, i1 false
|
; CHECK-NEXT: %[[AND1:.*]] = select i1 %[[V1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: %[[AND2:.*]] = select i1 %[[AND1]], i1 true, i1 false
|
; CHECK-NEXT: %[[AND2:.*]] = select i1 %[[AND1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 %[[AND2]], label %loop_b, label %loop_a
|
; CHECK-NEXT: br i1 %[[V1]], label %loop_b, label %loop_a
|
||||||
|
|
||||||
loop_a:
|
loop_a:
|
||||||
call i32 @a()
|
call i32 @a()
|
||||||
|
|
|
@ -11,9 +11,14 @@ define i32 @need_freeze_of_individual_or_conditions1(i1 %cond1, i1 %cond2, i1 %c
|
||||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4_FR]], [[COND1_FR]]
|
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4_FR]], [[COND1_FR]]
|
||||||
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||||
; CHECK: entry.split:
|
; CHECK: entry.split:
|
||||||
|
; CHECK-NEXT: [[COND2_FR:%.*]] = freeze i1 [[COND2:%.*]]
|
||||||
|
; CHECK-NEXT: [[COND3_FR:%.*]] = freeze i1 [[COND3:%.*]]
|
||||||
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[COND2_FR]], [[COND3_FR]]
|
||||||
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_SPLIT:%.*]], label [[EXIT_SPLIT1:%.*]]
|
||||||
|
; CHECK: entry.split.split:
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
||||||
; CHECK: loop.header:
|
; CHECK: loop.header:
|
||||||
; CHECK-NEXT: [[OR:%.*]] = or i1 [[COND2:%.*]], [[COND3:%.*]]
|
; CHECK-NEXT: [[OR:%.*]] = or i1 true, true
|
||||||
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[OR]], true
|
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[OR]], true
|
||||||
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 false
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 [[AND2]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
|
; CHECK-NEXT: br i1 [[AND2]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
|
||||||
|
@ -21,6 +26,8 @@ define i32 @need_freeze_of_individual_or_conditions1(i1 %cond1, i1 %cond2, i1 %c
|
||||||
; CHECK-NEXT: call void @some_func()
|
; CHECK-NEXT: call void @some_func()
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
||||||
; CHECK: exit:
|
; CHECK: exit:
|
||||||
|
; CHECK-NEXT: br label [[EXIT_SPLIT1]]
|
||||||
|
; CHECK: exit.split1:
|
||||||
; CHECK-NEXT: br label [[EXIT_SPLIT]]
|
; CHECK-NEXT: br label [[EXIT_SPLIT]]
|
||||||
; CHECK: exit.split:
|
; CHECK: exit.split:
|
||||||
; CHECK-NEXT: ret i32 0
|
; CHECK-NEXT: ret i32 0
|
||||||
|
@ -49,9 +56,14 @@ define i32 @need_freeze_of_individual_or_conditions2(i1 noundef %cond1, i1 %cond
|
||||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4_FR]], [[COND1:%.*]]
|
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4_FR]], [[COND1:%.*]]
|
||||||
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||||
; CHECK: entry.split:
|
; CHECK: entry.split:
|
||||||
|
; CHECK-NEXT: [[COND2_FR:%.*]] = freeze i1 [[COND2:%.*]]
|
||||||
|
; CHECK-NEXT: [[COND3_FR:%.*]] = freeze i1 [[COND3:%.*]]
|
||||||
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[COND2_FR]], [[COND3_FR]]
|
||||||
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_SPLIT:%.*]], label [[EXIT_SPLIT1:%.*]]
|
||||||
|
; CHECK: entry.split.split:
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
||||||
; CHECK: loop.header:
|
; CHECK: loop.header:
|
||||||
; CHECK-NEXT: [[OR:%.*]] = or i1 [[COND2:%.*]], [[COND3:%.*]]
|
; CHECK-NEXT: [[OR:%.*]] = or i1 true, true
|
||||||
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[OR]], true
|
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[OR]], true
|
||||||
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 false
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 [[AND2]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
|
; CHECK-NEXT: br i1 [[AND2]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
|
||||||
|
@ -59,6 +71,8 @@ define i32 @need_freeze_of_individual_or_conditions2(i1 noundef %cond1, i1 %cond
|
||||||
; CHECK-NEXT: call void @some_func()
|
; CHECK-NEXT: call void @some_func()
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
||||||
; CHECK: exit:
|
; CHECK: exit:
|
||||||
|
; CHECK-NEXT: br label [[EXIT_SPLIT1]]
|
||||||
|
; CHECK: exit.split1:
|
||||||
; CHECK-NEXT: br label [[EXIT_SPLIT]]
|
; CHECK-NEXT: br label [[EXIT_SPLIT]]
|
||||||
; CHECK: exit.split:
|
; CHECK: exit.split:
|
||||||
; CHECK-NEXT: ret i32 0
|
; CHECK-NEXT: ret i32 0
|
||||||
|
@ -87,9 +101,14 @@ define i32 @need_freeze_of_individual_or_conditions3(i1 %cond1, i1 %cond2, i1 %c
|
||||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4:%.*]], [[COND1_FR]]
|
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4:%.*]], [[COND1_FR]]
|
||||||
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||||
; CHECK: entry.split:
|
; CHECK: entry.split:
|
||||||
|
; CHECK-NEXT: [[COND2_FR:%.*]] = freeze i1 [[COND2:%.*]]
|
||||||
|
; CHECK-NEXT: [[COND3_FR:%.*]] = freeze i1 [[COND3:%.*]]
|
||||||
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[COND2_FR]], [[COND3_FR]]
|
||||||
|
; CHECK-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT_SPLIT:%.*]], label [[EXIT_SPLIT1:%.*]]
|
||||||
|
; CHECK: entry.split.split:
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
||||||
; CHECK: loop.header:
|
; CHECK: loop.header:
|
||||||
; CHECK-NEXT: [[OR:%.*]] = or i1 [[COND2:%.*]], [[COND3:%.*]]
|
; CHECK-NEXT: [[OR:%.*]] = or i1 true, true
|
||||||
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[OR]], true
|
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[OR]], true
|
||||||
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 false
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 [[AND2]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
|
; CHECK-NEXT: br i1 [[AND2]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
|
||||||
|
@ -97,6 +116,8 @@ define i32 @need_freeze_of_individual_or_conditions3(i1 %cond1, i1 %cond2, i1 %c
|
||||||
; CHECK-NEXT: call void @some_func()
|
; CHECK-NEXT: call void @some_func()
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
||||||
; CHECK: exit:
|
; CHECK: exit:
|
||||||
|
; CHECK-NEXT: br label [[EXIT_SPLIT1]]
|
||||||
|
; CHECK: exit.split1:
|
||||||
; CHECK-NEXT: br label [[EXIT_SPLIT]]
|
; CHECK-NEXT: br label [[EXIT_SPLIT]]
|
||||||
; CHECK: exit.split:
|
; CHECK: exit.split:
|
||||||
; CHECK-NEXT: ret i32 0
|
; CHECK-NEXT: ret i32 0
|
||||||
|
|
|
@ -8,15 +8,20 @@ declare void @some_func()
|
||||||
define void @test_select_logical_and_or_with_and_1(i1 noundef %cond1, i1 noundef %cond2) {
|
define void @test_select_logical_and_or_with_and_1(i1 noundef %cond1, i1 noundef %cond2) {
|
||||||
; CHECK-LABEL: @test_select_logical_and_or_with_and_1(
|
; CHECK-LABEL: @test_select_logical_and_or_with_and_1(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
|
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]]
|
||||||
|
; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||||
|
; CHECK: entry.split:
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
||||||
; CHECK: loop.header:
|
; CHECK: loop.header:
|
||||||
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]]
|
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, false
|
||||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 [[SEL]], label [[EXIT:%.*]], label [[LOOP_LATCH:%.*]]
|
; CHECK-NEXT: br i1 [[SEL]], label [[EXIT:%.*]], label [[LOOP_LATCH:%.*]]
|
||||||
; CHECK: loop.latch:
|
; CHECK: loop.latch:
|
||||||
; CHECK-NEXT: call void @some_func()
|
; CHECK-NEXT: call void @some_func()
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
||||||
; CHECK: exit:
|
; CHECK: exit:
|
||||||
|
; CHECK-NEXT: br label [[EXIT_SPLIT]]
|
||||||
|
; CHECK: exit.split:
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
entry:
|
entry:
|
||||||
|
@ -109,15 +114,20 @@ exit:
|
||||||
define void @test_select_logical_and_or_with_or_2(i1 noundef %cond1, i1 noundef %cond2) {
|
define void @test_select_logical_and_or_with_or_2(i1 noundef %cond1, i1 noundef %cond2) {
|
||||||
; CHECK-LABEL: @test_select_logical_and_or_with_or_2(
|
; CHECK-LABEL: @test_select_logical_and_or_with_or_2(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
|
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]]
|
||||||
|
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||||
|
; CHECK: entry.split:
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
||||||
; CHECK: loop.header:
|
; CHECK: loop.header:
|
||||||
; CHECK-NEXT: [[COND_AND1:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]]
|
; CHECK-NEXT: [[COND_AND1:%.*]] = or i1 true, true
|
||||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
|
||||||
; CHECK-NEXT: br i1 [[SEL]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
|
; CHECK-NEXT: br i1 [[SEL]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
|
||||||
; CHECK: loop.latch:
|
; CHECK: loop.latch:
|
||||||
; CHECK-NEXT: call void @some_func()
|
; CHECK-NEXT: call void @some_func()
|
||||||
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
; CHECK-NEXT: br label [[LOOP_HEADER]]
|
||||||
; CHECK: exit:
|
; CHECK: exit:
|
||||||
|
; CHECK-NEXT: br label [[EXIT_SPLIT]]
|
||||||
|
; CHECK: exit.split:
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
entry:
|
entry:
|
||||||
|
@ -137,6 +147,8 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
; Check that loop unswitch looks through a combination of or and select instructions.
|
; Check that loop unswitch looks through a combination of or and select instructions.
|
||||||
|
; Note that cond6 can be unswitched because `select i1 %cond_or5, i1 true, i1 false` is
|
||||||
|
; both logical-or and logical-and.
|
||||||
define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4, i1 %cond5, i1 %cond6) {
|
define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4, i1 %cond5, i1 %cond6) {
|
||||||
; CHECK-LABEL: @test_partial_condition_unswitch_or_select(
|
; CHECK-LABEL: @test_partial_condition_unswitch_or_select(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
|
@ -149,6 +161,9 @@ define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %
|
||||||
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1_FR]]
|
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1_FR]]
|
||||||
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||||
; CHECK: entry.split:
|
; CHECK: entry.split:
|
||||||
|
; CHECK-NEXT: [[COND6_FR:%.*]] = freeze i1 [[COND6:%.*]]
|
||||||
|
; CHECK-NEXT: br i1 [[COND6_FR]], label [[LOOP_EXIT_SPLIT1:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]]
|
||||||
|
; CHECK: entry.split.split:
|
||||||
; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]]
|
; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]]
|
||||||
; CHECK: loop_begin:
|
; CHECK: loop_begin:
|
||||||
; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4
|
; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4
|
||||||
|
@ -157,7 +172,7 @@ define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %
|
||||||
; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false
|
; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false
|
||||||
; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
|
; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
|
||||||
; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
|
; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
|
||||||
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 [[COND6:%.*]], [[VAR_COND]]
|
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, [[VAR_COND]]
|
||||||
; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
|
; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
|
||||||
; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
|
; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
|
||||||
; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
|
; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
|
||||||
|
@ -166,6 +181,8 @@ define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %
|
||||||
; CHECK-NEXT: call void @some_func() #[[ATTR0:[0-9]+]]
|
; CHECK-NEXT: call void @some_func() #[[ATTR0:[0-9]+]]
|
||||||
; CHECK-NEXT: br label [[LOOP_BEGIN]]
|
; CHECK-NEXT: br label [[LOOP_BEGIN]]
|
||||||
; CHECK: loop_exit:
|
; CHECK: loop_exit:
|
||||||
|
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT1]]
|
||||||
|
; CHECK: loop_exit.split1:
|
||||||
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]]
|
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]]
|
||||||
; CHECK: loop_exit.split:
|
; CHECK: loop_exit.split:
|
||||||
; CHECK-NEXT: ret i32 0
|
; CHECK-NEXT: ret i32 0
|
||||||
|
@ -194,8 +211,6 @@ loop_exit:
|
||||||
ret i32 0
|
ret i32 0
|
||||||
}
|
}
|
||||||
|
|
||||||
; Same as test_partial_condition_unswitch_or_select, but with arguments marked
|
|
||||||
; as noundef.
|
|
||||||
define i32 @test_partial_condition_unswitch_or_select_noundef(i32* noundef %var, i1 noundef %cond1, i1 noundef %cond2, i1 noundef %cond3, i1 noundef %cond4, i1 noundef %cond5, i1 noundef %cond6) {
|
define i32 @test_partial_condition_unswitch_or_select_noundef(i32* noundef %var, i1 noundef %cond1, i1 noundef %cond2, i1 noundef %cond3, i1 noundef %cond4, i1 noundef %cond5, i1 noundef %cond6) {
|
||||||
; CHECK-LABEL: @test_partial_condition_unswitch_or_select_noundef(
|
; CHECK-LABEL: @test_partial_condition_unswitch_or_select_noundef(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
|
@ -204,6 +219,8 @@ define i32 @test_partial_condition_unswitch_or_select_noundef(i32* noundef %var,
|
||||||
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]]
|
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]]
|
||||||
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||||
; CHECK: entry.split:
|
; CHECK: entry.split:
|
||||||
|
; CHECK-NEXT: br i1 [[COND6:%.*]], label [[LOOP_EXIT_SPLIT1:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]]
|
||||||
|
; CHECK: entry.split.split:
|
||||||
; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]]
|
; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]]
|
||||||
; CHECK: loop_begin:
|
; CHECK: loop_begin:
|
||||||
; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4
|
; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4
|
||||||
|
@ -212,7 +229,7 @@ define i32 @test_partial_condition_unswitch_or_select_noundef(i32* noundef %var,
|
||||||
; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false
|
; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false
|
||||||
; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
|
; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
|
||||||
; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
|
; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
|
||||||
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 [[COND6:%.*]], [[VAR_COND]]
|
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, [[VAR_COND]]
|
||||||
; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
|
; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
|
||||||
; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
|
; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
|
||||||
; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
|
; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
|
||||||
|
@ -221,6 +238,8 @@ define i32 @test_partial_condition_unswitch_or_select_noundef(i32* noundef %var,
|
||||||
; CHECK-NEXT: call void @some_func() #[[ATTR0]]
|
; CHECK-NEXT: call void @some_func() #[[ATTR0]]
|
||||||
; CHECK-NEXT: br label [[LOOP_BEGIN]]
|
; CHECK-NEXT: br label [[LOOP_BEGIN]]
|
||||||
; CHECK: loop_exit:
|
; CHECK: loop_exit:
|
||||||
|
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT1]]
|
||||||
|
; CHECK: loop_exit.split1:
|
||||||
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]]
|
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]]
|
||||||
; CHECK: loop_exit.split:
|
; CHECK: loop_exit.split:
|
||||||
; CHECK-NEXT: ret i32 0
|
; CHECK-NEXT: ret i32 0
|
||||||
|
|
Loading…
Reference in New Issue