/// Remove a loop if it is dead.
///
-/// A loop is considered dead either if it does not impact the observable
-/// behavior of the program other than finite running time, or if it is
-/// required to make progress by an attribute such as 'mustprogress' or
-/// 'llvm.loop.mustprogress' and does not make any. This may remove
-/// infinite loops that have been required to make progress.
+/// A loop is considered dead if it does not impact the observable behavior of
+/// the program other than finite running time. This never removes a loop that
+/// might be infinite (unless it is never executed), as doing so could change
+/// the halting/non-halting nature of a program.
///
/// This entire process relies pretty heavily on LoopSimplify form and LCSSA in
/// order to make various safety checks work.
: 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.
+ // Don't remove loops for which we can't solve the trip count.
+ // They could be infinite, in which case we'd be changing program behavior.
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");
+ if (isa<SCEVCouldNotCompute>(S)) {
+ LLVM_DEBUG(dbgs() << "Could not compute SCEV MaxBackedgeTakenCount.\n");
return Changed ? LoopDeletionResult::Modified
: LoopDeletionResult::Unmodified;
}
static const char *LLVMLoopDisableNonforced = "llvm.loop.disable_nonforced";
static const char *LLVMLoopDisableLICM = "llvm.licm.disable";
-static const char *LLVMLoopMustProgress = "llvm.loop.mustprogress";
bool llvm::formDedicatedExitBlocks(Loop *L, DominatorTree *DT, LoopInfo *LI,
MemorySSAUpdater *MSSAU,
return getBooleanLoopAttribute(L, LLVMLoopDisableLICM);
}
-bool llvm::hasMustProgress(const Loop *L) {
- return getBooleanLoopAttribute(L, LLVMLoopMustProgress);
-}
-
TransformationMode llvm::hasUnrollTransformation(Loop *L) {
if (getBooleanLoopAttribute(L, "llvm.loop.unroll.disable"))
return TM_SuppressedByUser;
IRBuilder<> Builder(OldBr);
auto *ExitBlock = L->getUniqueExitBlock();
- DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
if (ExitBlock) {
assert(ExitBlock && "Should have a unique exit block!");
assert(L->hasDedicatedExits() && "Loop should have dedicated exits!");
"Should have exactly one value and that's from the preheader!");
}
+ DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
if (DT) {
DTU.applyUpdates({{DominatorTree::Insert, Preheader, ExitBlock}});
if (MSSA) {
Builder.CreateBr(ExitBlock);
// Remove the old branch.
Preheader->getTerminator()->eraseFromParent();
+
+ if (DT) {
+ DTU.applyUpdates({{DominatorTree::Delete, Preheader, L->getHeader()}});
+ if (MSSA) {
+ MSSAU->applyUpdates(
+ {{DominatorTree::Delete, Preheader, L->getHeader()}}, *DT);
+ SmallSetVector<BasicBlock *, 8> DeadBlockSet(L->block_begin(),
+ L->block_end());
+ MSSAU->removeBlocks(DeadBlockSet);
+ if (VerifyMemorySSA)
+ MSSA->verifyMemorySSA();
+ }
+ }
} else {
assert(L->hasNoExitBlocks() &&
"Loop should have either zero or one exit blocks.");
-
Builder.SetInsertPoint(OldBr);
Builder.CreateUnreachable();
Preheader->getTerminator()->eraseFromParent();
}
- if (DT) {
- DTU.applyUpdates({{DominatorTree::Delete, Preheader, L->getHeader()}});
- if (MSSA) {
- MSSAU->applyUpdates({{DominatorTree::Delete, Preheader, L->getHeader()}},
- *DT);
- SmallSetVector<BasicBlock *, 8> DeadBlockSet(L->block_begin(),
- L->block_end());
- MSSAU->removeBlocks(DeadBlockSet);
- if (VerifyMemorySSA)
- MSSA->verifyMemorySSA();
- }
- }
-
// Use a map to unique and a vector to guarantee deterministic ordering.
llvm::SmallDenseSet<std::pair<DIVariable *, DIExpression *>, 4> DeadDebugSet;
llvm::SmallVector<DbgVariableIntrinsic *, 4> DeadDebugInst;
+++ /dev/null
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
-; RUN: opt < %s -loop-deletion -verify-dom-info -S | FileCheck %s
-
-;; Original C Code:
-;; void unknown_tripcount_mustprogress_attr_mustprogress_loopmd(int a, int b) {
-;; for (; a < b;) ;
-;; for (;;) ;
-;; }
-
-define void @unknown_tripcount_mustprogress_attr_mustprogress_loopmd(i32 %a, i32 %b) #0 {
-; CHECK: Function Attrs: mustprogress
-; CHECK-LABEL: define {{[^@]+}}@unknown_tripcount_mustprogress_attr_mustprogress_loopmd
-; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) [[ATTR0:#.*]] {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[FOR_END:%.*]]
-; CHECK: for.end:
-; CHECK-NEXT: unreachable
-;
-entry:
- br label %for.cond
-for.cond:
- %cmp = icmp slt i32 %a, %b
- br i1 %cmp, label %for.body, label %for.end
-for.body:
- br label %for.cond, !llvm.loop !2
-for.end:
- br label %for.cond1
-for.cond1:
- br label %for.cond1
-}
-
-;; Original C Code:
-;; void unknown_tripcount_mustprogress_attr_no_mustprogress_loopmd(int a, int b) {
-;; for (; a < b;) ;
-;; for (;;) ;
-;; }
-;; => Removed mustprogress loop attribute
-
-define void @unknown_tripcount_mustprogress_attr_no_mustprogess_loopmd(i32 %a, i32 %b) #0 {
-; CHECK: Function Attrs: mustprogress
-; CHECK-LABEL: define {{[^@]+}}@unknown_tripcount_mustprogress_attr_no_mustprogess_loopmd
-; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) [[ATTR0]] {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[FOR_END:%.*]]
-; CHECK: for.end:
-; CHECK-NEXT: unreachable
-;
-entry:
- br label %for.cond
-for.cond:
- %cmp = icmp slt i32 %a, %b
- br i1 %cmp, label %for.body, label %for.end
-for.body:
- br label %for.cond
-for.end:
- br label %for.cond1
-for.cond1:
- br label %for.cond1
-}
-
-;; Original C Code:
-;; void known_tripcount_no_mustprogress_attr_no_mustprogress_loopmd() {
-;; for (int i = 0; i < 5; i++) ;
-;; }
-
-define void @known_tripcount_no_mustprogress_attr_no_mustprogress_loopmd() {
-; CHECK-LABEL: define {{[^@]+}}@known_tripcount_no_mustprogress_attr_no_mustprogress_loopmd() {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[FOR_END:%.*]]
-; CHECK: for.end:
-; CHECK-NEXT: ret void
-;
-entry:
- br label %for.cond
-for.cond:
- %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
- %cmp = icmp slt i32 %i.0, 5
- br i1 %cmp, label %for.body, label %for.end
-for.body:
- br label %for.inc
-for.inc:
- %inc = add nsw i32 %i.0, 1
- br label %for.cond
-for.end:
- ret void
-}
-
-;; Original C Code:
-;; void known_tripcount_no_mustprogress_attr_mustprogress_loopmd() {
-;; for (int i = 0; i < 5; i++) ;
-;; }
-;; => Added mustprogress loop attribute
-
-define void @known_tripcount_no_mustprogress_attr_mustprogress_loopmd() {
-; CHECK-LABEL: define {{[^@]+}}@known_tripcount_no_mustprogress_attr_mustprogress_loopmd() {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[FOR_END:%.*]]
-; CHECK: for.end:
-; CHECK-NEXT: ret void
-;
-entry:
- br label %for.cond
-for.cond:
- %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
- %cmp = icmp slt i32 %i.0, 5
- br i1 %cmp, label %for.body, label %for.end
-for.body:
- br label %for.inc
-for.inc:
- %inc = add nsw i32 %i.0, 1
- br label %for.cond, !llvm.loop !4
-for.end:
- ret void
-}
-
-;; Original C Code:
-;; void known_tripcount_mustprogress_attr_no_mustprogress_loopmd() {
-;; for (int i = 0; i < 5; i++) ;
-;; }
-;; => Added mustprogress function attribute
-
-define void @known_tripcount_mustprogress_attr_no_mustprogress_loopmd() #0 {
-; CHECK: Function Attrs: mustprogress
-; CHECK-LABEL: define {{[^@]+}}@known_tripcount_mustprogress_attr_no_mustprogress_loopmd
-; CHECK-SAME: () [[ATTR0]] {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[FOR_END:%.*]]
-; CHECK: for.end:
-; CHECK-NEXT: ret void
-;
-entry:
- br label %for.cond
-for.cond:
- %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
- %cmp = icmp slt i32 %i.0, 5
- br i1 %cmp, label %for.body, label %for.end
-for.body:
- br label %for.inc
-for.inc:
- %inc = add nsw i32 %i.0, 1
- br label %for.cond
-for.end:
- ret void
-}
-
-;; Original C Code:
-;; void known_tripcount_mustprogress_attr_mustprogress_loopmd() {
-;; for (int i = 0; i < 5; i++) ;
-;; }
-;; => Added mustprogress function and mustprogress loop attribute
-
-define void @known_tripcount_mustprogress_attr_mustprogress_loopmd() #0 {
-; CHECK: Function Attrs: mustprogress
-; CHECK-LABEL: define {{[^@]+}}@known_tripcount_mustprogress_attr_mustprogress_loopmd
-; CHECK-SAME: () [[ATTR0]] {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[FOR_END:%.*]]
-; CHECK: for.end:
-; CHECK-NEXT: ret void
-;
-entry:
- br label %for.cond
-for.cond:
- %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
- %cmp = icmp slt i32 %i.0, 5
- br i1 %cmp, label %for.body, label %for.end
-for.body:
- br label %for.inc
-for.inc:
- %inc = add nsw i32 %i.0, 1
- br label %for.cond, !llvm.loop !5
-for.end:
- ret void
-}
-
-;; Original C Code:
-;; void unknown_tripcount_no_mustprogress_attr_mustprogress_loopmd(int a, int b) {
-;; for (; a < b;) ;
-;; }
-;; => Added mustprogress loop attribute
-
-define void @unknown_tripcount_no_mustprogress_attr_mustprogress_loopmd(i32 %a, i32 %b) {
-; CHECK-LABEL: define {{[^@]+}}@unknown_tripcount_no_mustprogress_attr_mustprogress_loopmd
-; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[FOR_END:%.*]]
-; CHECK: for.end:
-; CHECK-NEXT: ret void
-;
-entry:
- br label %for.cond
-for.cond:
- %cmp = icmp slt i32 %a, %b
- br i1 %cmp, label %for.body, label %for.end
-for.body:
- br label %for.cond, !llvm.loop !6
-for.end:
- ret void
-}
-
-;; Original C Code:
-;; void unknown_tripcount_no_mustprogress_attr_no_mustprogress_loopmd(int a, int b) {
-;; for (; a < b;) ;
-;; }
-
-define void @unknown_tripcount_no_mustprogress_attr_no_mustprogress_loopmd(i32 %a, i32 %b) {
-; CHECK-LABEL: define {{[^@]+}}@unknown_tripcount_no_mustprogress_attr_no_mustprogress_loopmd
-; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
-; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[FOR_COND:%.*]]
-; CHECK: for.cond:
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], [[B]]
-; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
-; CHECK: for.body:
-; CHECK-NEXT: br label [[FOR_COND]]
-; CHECK: for.end:
-; CHECK-NEXT: ret void
-;
-entry:
- br label %for.cond
-for.cond:
- %cmp = icmp slt i32 %a, %b
- br i1 %cmp, label %for.body, label %for.end
-for.body:
- br label %for.cond
-for.end:
- ret void
-}
-
-; CHECK: attributes [[ATTR0]] = { mustprogress }
-
-attributes #0 = { mustprogress }
-!2 = distinct !{!2, !3}
-!3 = !{!"llvm.loop.mustprogress"}
-!4 = distinct !{!4, !3}
-!5 = distinct !{!5, !3}
-!6 = distinct !{!6, !3}