forked from OSchip/llvm-project
[SimpleLoopUnswitch] Freeze individual OR/AND operands.
In some cases, it is not enough to freeze the final AND/OR operation when chaining a number of invariant conditions together. After creating a chain of ANDs/ORs, we assume all unswitched operands to be either true or false. But if any of the operands is poison, the rest of the operands could have any value after branching on the frozen condition. To avoid that, freeze individual operands, if needed. In some cases this may lead to unnecessary freezes, but it seems required at least for some cases (see trivial-unswitch-freeze-individual-conditions.ll) Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D124554
This commit is contained in:
parent
34f97a3709
commit
5387a38c38
|
@ -204,13 +204,19 @@ static bool areLoopExitPHIsLoopInvariant(Loop &L, BasicBlock &ExitingBB,
|
|||
/// branch on a single value.
|
||||
static void buildPartialUnswitchConditionalBranch(
|
||||
BasicBlock &BB, ArrayRef<Value *> Invariants, bool Direction,
|
||||
BasicBlock &UnswitchedSucc, BasicBlock &NormalSucc, bool InsertFreeze) {
|
||||
BasicBlock &UnswitchedSucc, BasicBlock &NormalSucc, bool InsertFreeze,
|
||||
Instruction *I, AssumptionCache *AC, DominatorTree &DT) {
|
||||
IRBuilder<> IRB(&BB);
|
||||
|
||||
Value *Cond = Direction ? IRB.CreateOr(Invariants) :
|
||||
IRB.CreateAnd(Invariants);
|
||||
if (InsertFreeze)
|
||||
Cond = IRB.CreateFreeze(Cond, Cond->getName() + ".fr");
|
||||
SmallVector<Value *> FrozenInvariants;
|
||||
for (Value *Inv : Invariants) {
|
||||
if (InsertFreeze && !isGuaranteedNotToBeUndefOrPoison(Inv, AC, I, &DT))
|
||||
Inv = IRB.CreateFreeze(Inv, Inv->getName() + ".fr");
|
||||
FrozenInvariants.push_back(Inv);
|
||||
}
|
||||
|
||||
Value *Cond = Direction ? IRB.CreateOr(FrozenInvariants)
|
||||
: IRB.CreateAnd(FrozenInvariants);
|
||||
IRB.CreateCondBr(Cond, Direction ? &UnswitchedSucc : &NormalSucc,
|
||||
Direction ? &NormalSucc : &UnswitchedSucc);
|
||||
}
|
||||
|
@ -572,10 +578,7 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|||
" condition!");
|
||||
buildPartialUnswitchConditionalBranch(
|
||||
*OldPH, Invariants, ExitDirection, *UnswitchedBB, *NewPH,
|
||||
FreezeLoopUnswitchCond && any_of(Invariants, [&](Value *C) {
|
||||
return !isGuaranteedNotToBeUndefOrPoison(C, nullptr,
|
||||
OldPH->getTerminator(), &DT);
|
||||
}));
|
||||
FreezeLoopUnswitchCond, OldPH->getTerminator(), nullptr, DT);
|
||||
}
|
||||
|
||||
// Update the dominator tree with the added edge.
|
||||
|
@ -2318,11 +2321,9 @@ static void unswitchNontrivialInvariants(
|
|||
buildPartialInvariantUnswitchConditionalBranch(
|
||||
*SplitBB, Invariants, Direction, *ClonedPH, *LoopPH, L, MSSAU);
|
||||
else {
|
||||
buildPartialUnswitchConditionalBranch(
|
||||
*SplitBB, Invariants, Direction, *ClonedPH, *LoopPH,
|
||||
InsertFreeze && any_of(Invariants, [&](Value *C) {
|
||||
return !isGuaranteedNotToBeUndefOrPoison(C, &AC, BI, &DT);
|
||||
}));
|
||||
buildPartialUnswitchConditionalBranch(*SplitBB, Invariants, Direction,
|
||||
*ClonedPH, *LoopPH, InsertFreeze,
|
||||
BI, &AC, DT);
|
||||
}
|
||||
DTUpdates.push_back({DominatorTree::Insert, SplitBB, ClonedPH});
|
||||
|
||||
|
|
|
@ -6,13 +6,15 @@ declare void @some_func()
|
|||
define i32 @need_freeze_of_individual_or_conditions1(i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4) {
|
||||
; CHECK-LABEL: @need_freeze_of_individual_or_conditions1(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4:%.*]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR:%.*]] = freeze i1 [[TMP0]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||
; CHECK-NEXT: [[COND4_FR:%.*]] = freeze i1 [[COND4:%.*]]
|
||||
; CHECK-NEXT: [[COND1_FR:%.*]] = freeze i1 [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4_FR]], [[COND1_FR]]
|
||||
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[COND2:%.*]], [[COND3:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR2:%.*]] = freeze i1 [[TMP1]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR2]], label [[ENTRY_SPLIT_SPLIT:%.*]], label [[EXIT_SPLIT1:%.*]]
|
||||
; 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: loop.header:
|
||||
|
@ -50,13 +52,14 @@ exit:
|
|||
define i32 @need_freeze_of_individual_or_conditions2(i1 noundef %cond1, i1 %cond2, i1 %cond3, i1 %cond4) {
|
||||
; CHECK-LABEL: @need_freeze_of_individual_or_conditions2(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4:%.*]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR:%.*]] = freeze i1 [[TMP0]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||
; CHECK-NEXT: [[COND4_FR:%.*]] = freeze i1 [[COND4:%.*]]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4_FR]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[COND2:%.*]], [[COND3:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR2:%.*]] = freeze i1 [[TMP1]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR2]], label [[ENTRY_SPLIT_SPLIT:%.*]], label [[EXIT_SPLIT1:%.*]]
|
||||
; 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: loop.header:
|
||||
|
@ -94,13 +97,14 @@ exit:
|
|||
define i32 @need_freeze_of_individual_or_conditions3(i1 %cond1, i1 %cond2, i1 %cond3, i1 noundef %cond4) {
|
||||
; CHECK-LABEL: @need_freeze_of_individual_or_conditions3(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4:%.*]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR:%.*]] = freeze i1 [[TMP0]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||
; CHECK-NEXT: [[COND1_FR:%.*]] = freeze i1 [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND4:%.*]], [[COND1_FR]]
|
||||
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[COND2:%.*]], [[COND3:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR2:%.*]] = freeze i1 [[TMP1]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR2]], label [[ENTRY_SPLIT_SPLIT:%.*]], label [[EXIT_SPLIT1:%.*]]
|
||||
; 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: loop.header:
|
||||
|
@ -138,9 +142,10 @@ exit:
|
|||
define i32 @need_freeze_of_individual_and_conditions1(i1 %cond1, i1 %cond4) {
|
||||
; CHECK-LABEL: @need_freeze_of_individual_and_conditions1(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR:%.*]] = freeze i1 [[TMP0]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK-NEXT: [[COND4_FR:%.*]] = freeze i1 [[COND4:%.*]]
|
||||
; CHECK-NEXT: [[COND1_FR:%.*]] = freeze i1 [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4_FR]], [[COND1_FR]]
|
||||
; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
||||
; CHECK: loop.header:
|
||||
|
@ -172,9 +177,9 @@ exit:
|
|||
define i32 @need_freeze_of_individual_and_conditions2(i1 noundef %cond1, i1 %cond4) {
|
||||
; CHECK-LABEL: @need_freeze_of_individual_and_conditions2(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR:%.*]] = freeze i1 [[TMP0]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK-NEXT: [[COND4_FR:%.*]] = freeze i1 [[COND4:%.*]]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4_FR]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
||||
; CHECK: loop.header:
|
||||
|
@ -206,9 +211,9 @@ exit:
|
|||
define i32 @need_freeze_of_individual_and_conditions3(i1 %cond1, i1 noundef %cond4) {
|
||||
; CHECK-LABEL: @need_freeze_of_individual_and_conditions3(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR:%.*]] = freeze i1 [[TMP0]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK-NEXT: [[COND1_FR:%.*]] = freeze i1 [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND1_FR]]
|
||||
; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
||||
; CHECK: loop.header:
|
||||
|
|
|
@ -152,11 +152,14 @@ exit:
|
|||
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-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND2:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3:%.*]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[DOTFR:%.*]] = freeze i1 [[TMP2]]
|
||||
; CHECK-NEXT: br i1 [[DOTFR]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
|
||||
; CHECK-NEXT: [[COND4_FR:%.*]] = freeze i1 [[COND4:%.*]]
|
||||
; CHECK-NEXT: [[COND2_FR:%.*]] = freeze i1 [[COND2:%.*]]
|
||||
; CHECK-NEXT: [[COND3_FR:%.*]] = freeze i1 [[COND3:%.*]]
|
||||
; CHECK-NEXT: [[COND1_FR:%.*]] = freeze i1 [[COND1:%.*]]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4_FR]], [[COND2_FR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3_FR]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1_FR]]
|
||||
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[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:%.*]]
|
||||
|
|
|
@ -591,11 +591,14 @@ define i32 @test_partial_condition_unswitch_or(i32* %var, i1 %cond1, i1 %cond2,
|
|||
entry:
|
||||
br label %loop_begin
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: %[[INV_OR1:.*]] = or i1 %cond4, %cond2
|
||||
; CHECK-NEXT: %[[INV_OR2:.*]] = or i1 %[[INV_OR1]], %cond3
|
||||
; CHECK-NEXT: %[[INV_OR3:.*]] = or i1 %[[INV_OR2]], %cond1
|
||||
; CHECK-NEXT: [[FROZEN:%.+]] = freeze i1 %[[INV_OR3]]
|
||||
; CHECK-NEXT: br i1 [[FROZEN]], label %loop_exit.split, label %entry.split
|
||||
; CHECK-NEXT: %[[C4_FR:.+]] = freeze i1 %cond4
|
||||
; CHECK-NEXT: %[[C2_FR:.+]] = freeze i1 %cond2
|
||||
; CHECK-NEXT: %[[C3_FR:.+]] = freeze i1 %cond3
|
||||
; CHECK-NEXT: %[[C1_FR:.+]] = freeze i1 %cond1
|
||||
; CHECK-NEXT: %[[INV_OR1:.*]] = or i1 %[[C4_FR]], %[[C2_FR]]
|
||||
; CHECK-NEXT: %[[INV_OR2:.*]] = or i1 %[[INV_OR1]], %[[C3_FR]]
|
||||
; CHECK-NEXT: %[[INV_OR3:.*]] = or i1 %[[INV_OR2]], %[[C1_FR]]
|
||||
; CHECK-NEXT: br i1 %[[INV_OR3]], label %loop_exit.split, label %entry.split
|
||||
;
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: br label %loop_begin
|
||||
|
|
Loading…
Reference in New Issue