[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:
Florian Hahn 2022-05-01 20:11:05 +01:00
parent 34f97a3709
commit 5387a38c38
No known key found for this signature in database
GPG Key ID: CF59919C6547A668
4 changed files with 63 additions and 51 deletions

View File

@ -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});

View File

@ -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:

View File

@ -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:%.*]]

View File

@ -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