mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-15 12:39:19 +00:00
[LoopDeletion] Consider infinite loops alive, unless mustprogress.
The current loop or any of its sub-loops may be infinite. Unless the function or the loops are marked as mustprogress, this in itself makes the loop *not* dead. This patch moves the logic to check whether the current loop is finite or mustprogress to `isLoopDead` and also extends it to check the sub-loops. This should fix PR50511. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D103382
This commit is contained in:
parent
1b14f3951a
commit
1b84acb23a
@ -100,6 +100,30 @@ static bool isLoopDead(Loop *L, ScalarEvolution &SE,
|
||||
return I.mayHaveSideEffects() && !I.isDroppable();
|
||||
}))
|
||||
return false;
|
||||
|
||||
// The loop or any of its sub-loops looping infinitely is legal. The loop can
|
||||
// only be considered dead if either
|
||||
// a. the function is mustprogress.
|
||||
// b. all (sub-)loops are mustprogress or have a known trip-count.
|
||||
if (L->getHeader()->getParent()->mustProgress())
|
||||
return true;
|
||||
|
||||
SmallVector<Loop *, 8> WorkList;
|
||||
WorkList.push_back(L);
|
||||
while (!WorkList.empty()) {
|
||||
Loop *Current = WorkList.pop_back_val();
|
||||
if (hasMustProgress(Current))
|
||||
continue;
|
||||
|
||||
const SCEV *S = SE.getConstantMaxBackedgeTakenCount(Current);
|
||||
if (isa<SCEVCouldNotCompute>(S)) {
|
||||
LLVM_DEBUG(
|
||||
dbgs() << "Could not compute SCEV MaxBackedgeTakenCount and was "
|
||||
"not required to make progress.\n");
|
||||
return false;
|
||||
}
|
||||
WorkList.append(Current->begin(), Current->end());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -230,17 +254,6 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT,
|
||||
: LoopDeletionResult::Unmodified;
|
||||
}
|
||||
|
||||
// Don't remove loops for which we can't solve the trip count unless the loop
|
||||
// was required to make progress but has been determined to be dead.
|
||||
const SCEV *S = SE.getConstantMaxBackedgeTakenCount(L);
|
||||
if (isa<SCEVCouldNotCompute>(S) &&
|
||||
!L->getHeader()->getParent()->mustProgress() && !hasMustProgress(L)) {
|
||||
LLVM_DEBUG(dbgs() << "Could not compute SCEV MaxBackedgeTakenCount and was "
|
||||
"not required to make progress.\n");
|
||||
return Changed ? LoopDeletionResult::Modified
|
||||
: LoopDeletionResult::Unmodified;
|
||||
}
|
||||
|
||||
LLVM_DEBUG(dbgs() << "Loop is invariant, delete it!");
|
||||
ORE.emit([&]() {
|
||||
return OptimizationRemark(DEBUG_TYPE, "Invariant", L->getStartLoc(),
|
||||
|
@ -158,7 +158,19 @@ exit:
|
||||
; function/loop is mustprogress. Test case from PR50511.
|
||||
define void @inner_loop_may_be_infinite(i1 %c1, i1 %c2) {
|
||||
; CHECK-LABEL: @inner_loop_may_be_infinite(
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK-NEXT: br label [[LOOP1:%.*]]
|
||||
; CHECK: loop1:
|
||||
; CHECK-NEXT: br i1 [[C1:%.*]], label [[LOOP1_LATCH:%.*]], label [[LOOP2_PREHEADER:%.*]]
|
||||
; CHECK: loop2.preheader:
|
||||
; CHECK-NEXT: br label [[LOOP2:%.*]]
|
||||
; CHECK: loop2:
|
||||
; CHECK-NEXT: br i1 [[C2:%.*]], label [[LOOP1_LATCH_LOOPEXIT:%.*]], label [[LOOP2]]
|
||||
; CHECK: loop1.latch.loopexit:
|
||||
; CHECK-NEXT: br label [[LOOP1_LATCH]]
|
||||
; CHECK: loop1.latch:
|
||||
; CHECK-NEXT: br i1 false, label [[LOOP1_LATCH_LOOP1_CRIT_EDGE:%.*]], label [[EXIT:%.*]]
|
||||
; CHECK: loop1.latch.loop1_crit_edge:
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
@ -256,7 +268,21 @@ exit:
|
||||
; mustprogress and can be removed.
|
||||
define void @loop2_mustprogress_but_not_sibling_loop(i1 %c1, i1 %c2, i1 %c3) {
|
||||
; CHECK-LABEL: @loop2_mustprogress_but_not_sibling_loop(
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK-NEXT: br label [[LOOP1:%.*]]
|
||||
; CHECK: loop1:
|
||||
; CHECK-NEXT: br i1 [[C1:%.*]], label [[LOOP1_LATCH:%.*]], label [[LOOP2_PREHEADER:%.*]]
|
||||
; CHECK: loop2.preheader:
|
||||
; CHECK-NEXT: br label [[LOOP3_PREHEADER:%.*]]
|
||||
; CHECK: loop3.preheader:
|
||||
; CHECK-NEXT: br label [[LOOP3:%.*]]
|
||||
; CHECK: loop3:
|
||||
; CHECK-NEXT: br i1 [[C3:%.*]], label [[LOOP1_LATCH_LOOPEXIT:%.*]], label [[LOOP3]]
|
||||
; CHECK: loop1.latch.loopexit:
|
||||
; CHECK-NEXT: br label [[LOOP1_LATCH]]
|
||||
; CHECK: loop1.latch:
|
||||
; CHECK-NEXT: br i1 false, label [[LOOP1_LATCH_LOOP1_CRIT_EDGE:%.*]], label [[EXIT:%.*]]
|
||||
; CHECK: loop1.latch.loop1_crit_edge:
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
@ -281,7 +307,27 @@ exit:
|
||||
define void @loop2_finite_but_child_is_not(i1 %c1, i1 %c2, i1 %c3) {
|
||||
; CHECK-LABEL: @loop2_finite_but_child_is_not(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK-NEXT: br label [[LOOP1:%.*]]
|
||||
; CHECK: loop1:
|
||||
; CHECK-NEXT: [[IV1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV1_NEXT:%.*]], [[LOOP1_LATCH:%.*]] ]
|
||||
; CHECK-NEXT: br i1 [[C1:%.*]], label [[LOOP1_LATCH]], label [[LOOP2_PREHEADER:%.*]]
|
||||
; CHECK: loop2.preheader:
|
||||
; CHECK-NEXT: br label [[LOOP2:%.*]]
|
||||
; CHECK: loop2:
|
||||
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[LOOP2_LATCH:%.*]] ], [ 0, [[LOOP2_PREHEADER]] ]
|
||||
; CHECK-NEXT: br label [[LOOP3:%.*]]
|
||||
; CHECK: loop3:
|
||||
; CHECK-NEXT: br i1 [[C2:%.*]], label [[LOOP2_LATCH]], label [[LOOP3]]
|
||||
; CHECK: loop2.latch:
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[IV]], 200
|
||||
; CHECK-NEXT: br i1 [[C]], label [[LOOP1_LATCH_LOOPEXIT:%.*]], label [[LOOP2]]
|
||||
; CHECK: loop1.latch.loopexit:
|
||||
; CHECK-NEXT: br label [[LOOP1_LATCH]]
|
||||
; CHECK: loop1.latch:
|
||||
; CHECK-NEXT: [[IV1_NEXT]] = add nuw i32 [[IV1]], 1
|
||||
; CHECK-NEXT: [[C4:%.*]] = icmp ult i32 [[IV1_NEXT]], 200
|
||||
; CHECK-NEXT: br i1 [[C4]], label [[LOOP1]], label [[EXIT:%.*]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
@ -317,7 +317,21 @@ exit:
|
||||
define void @test9(i64 %n) {
|
||||
; CHECK-LABEL: @test9(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK-NEXT: br label [[L1:%.*]]
|
||||
; CHECK: L1.loopexit:
|
||||
; CHECK-NEXT: br label [[L1_LOOPEXIT_SPLIT:%.*]]
|
||||
; CHECK: L1.loopexit.split:
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK: L1:
|
||||
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[L2_PREHEADER:%.*]]
|
||||
; CHECK: L2.preheader:
|
||||
; CHECK-NEXT: br label [[L3_PREHEADER:%.*]]
|
||||
; CHECK: L3.preheader:
|
||||
; CHECK-NEXT: [[Y_L2_LCSSA:%.*]] = phi i64 [ undef, [[L2_PREHEADER]] ]
|
||||
; CHECK-NEXT: br label [[L3:%.*]]
|
||||
; CHECK: L3:
|
||||
; CHECK-NEXT: [[COND2:%.*]] = icmp slt i64 [[Y_L2_LCSSA]], [[N:%.*]]
|
||||
; CHECK-NEXT: br i1 [[COND2]], label [[L3]], label [[L1_LOOPEXIT:%.*]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
Loading…
x
Reference in New Issue
Block a user