Skip to content

Commit

Permalink
Loop peeling: check that latch is conditional branch
Browse files Browse the repository at this point in the history
Loop peeling assumes that the loop's latch is a conditional branch.  Add
a check to canPeel that explicitly checks for this, and testcases that
otherwise fail an assertion when trying to peel a loop whose back-edge
is a switch case or the non-unwind edge of an invoke.

Reviewed By: skatkov, fhahn

Differential Revision: https://reviews.llvm.org/D94995
  • Loading branch information
JosephTremoulet committed Jan 20, 2021
1 parent e377c8e commit 40cd262
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
7 changes: 6 additions & 1 deletion llvm/lib/Transforms/Utils/LoopPeel.cpp
Expand Up @@ -115,7 +115,12 @@ bool llvm::canPeel(Loop *L) {
// This can be an indication of two different things:
// 1) The loop is not rotated.
// 2) The loop contains irreducible control flow that involves the latch.
if (L->getLoopLatch() != L->getExitingBlock())
const BasicBlock *Latch = L->getLoopLatch();
if (Latch != L->getExitingBlock())
return false;

// Peeling is only supported if the latch is a branch.
if (!isa<BranchInst>(Latch->getTerminator()))
return false;

return true;
Expand Down
64 changes: 64 additions & 0 deletions llvm/test/Transforms/LoopUnroll/peel-loop-conditions.ll
Expand Up @@ -1140,5 +1140,69 @@ for.end:
ret void
}

; Invoke is not a conditional branch that we can optimize,
; so this shouldn't be peeled at all. This is a reproducer
; for a bug where evaluating the loop would fail an assertion.
define void @test17() personality i8* undef{
; CHECK-LABEL: @test17(
; CHECK-NEXT: body:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[CONST:%.*]] = phi i64 [ -33, [[LOOP]] ], [ -20, [[BODY:%.*]] ]
; CHECK-NEXT: invoke void @f1()
; CHECK-NEXT: to label [[LOOP]] unwind label [[EH_UNW_LOOPEXIT:%.*]]
; CHECK: eh.Unw.loopexit:
; CHECK-NEXT: [[LPAD_LOOPEXIT:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: ret void
;
body:
br label %loop

loop:
%const = phi i64 [ -33, %loop ], [ -20, %body ]
invoke void @f1()
to label %loop unwind label %eh.Unw.loopexit

eh.Unw.loopexit:
%lpad.loopexit = landingpad { i8*, i32 }
catch i8* null
ret void
}

; Testcase reduced from PR48812. We expect no peeling
; because the latch terminator is a switch.
define void @test18(i32* %p) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: init:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[CONST:%.*]] = phi i32 [ 40, [[INIT:%.*]] ], [ 0, [[LATCH:%.*]] ]
; CHECK-NEXT: br label [[LATCH]]
; CHECK: latch:
; CHECK-NEXT: [[CONTROL:%.*]] = load volatile i32, i32* [[P:%.*]], align 4
; CHECK-NEXT: switch i32 [[CONTROL]], label [[EXIT:%.*]] [
; CHECK-NEXT: i32 2, label [[LOOP]]
; CHECK-NEXT: ]
; CHECK: exit:
; CHECK-NEXT: ret void
;
init:
br label %loop

loop:
%const = phi i32 [ 40, %init ], [ 0, %latch ]
br label %latch

latch:
%control = load volatile i32, i32* %p
switch i32 %control, label %exit [
i32 2, label %loop
]

exit:
ret void
}

declare void @init()
declare void @sink()

0 comments on commit 40cd262

Please sign in to comment.