--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
+; RUN: opt < %s -loop-deletion -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}
; Show recursive deletion of loops. Since we start with subloops and progress outward
; to parent loop, we first delete the loop L2. Now loop L1 becomes a non-loop since it's backedge
; from L2's preheader to L1's exit block is never taken. So, L1 gets deleted as well.
-define void @test8(i64 %n) {
+define void @test8(i64 %n) #0 {
; CHECK-LABEL: test8
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %exit
; deleted.
; In the next iteration, since L2 is never executed and has no subloops, we delete
; L2 as well. Finally, the outermost loop L1 is deleted.
-define void @test11(i64 %n) {
+define void @test11(i64 %n) #0 {
; CHECK-LABEL: test11
; CHECK-LABEL: entry:
; CHECK-NEXT: br label %exit
; 2 edges from a single exiting block to the exit block.
-define i64 @test12(i64 %n){
+define i64 @test12(i64 %n) #0 {
;CHECK-LABEL: @test12
; CHECK-NOT: L1:
; CHECK-NOT: L1Latch:
}
; multiple edges to exit block from the same exiting blocks
-define i64 @test13(i64 %n) {
+define i64 @test13(i64 %n) #0 {
; CHECK-LABEL: @test13
; CHECK-NOT: L1:
; CHECK-NOT: L1Latch:
%y.phi = phi i64 [ 10, %L1Block ], [ 10, %L1Block ], [ %y.next, %L1 ], [ 30, %L1Latch ], [ 30, %L1Latch ]
ret i64 %y.phi
}
+
+attributes #0 = { willreturn }