1; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -keep-loops=false -S < %s | FileCheck %s 2; RUN: opt -passes='simplifycfg<no-keep-loops>' -S < %s | FileCheck %s 3 4define void @test1(i32 %n) #0 { 5entry: 6 %n.addr = alloca i32, align 4 7 %count = alloca i32, align 4 8 store i32 %n, ptr %n.addr, align 4 9 store i32 0, ptr %count, align 4 10 br label %while.cond 11 12while.cond: ; preds = %if.end, %entry 13 %0 = load i32, ptr %count, align 4 14 %1 = load i32, ptr %n.addr, align 4 15 %cmp = icmp ule i32 %0, %1 16 br i1 %cmp, label %while.body, label %while.end 17 18while.body: ; preds = %while.cond 19 %2 = load i32, ptr %count, align 4 20 %rem = urem i32 %2, 2 21 %cmp1 = icmp eq i32 %rem, 0 22 br i1 %cmp1, label %if.then, label %if.else 23 24if.then: ; preds = %while.body 25 %3 = load i32, ptr %count, align 4 26 %add = add i32 %3, 1 27 store i32 %add, ptr %count, align 4 28 br label %if.end 29 30; CHECK: if.then: 31; CHECK: br label %while.cond, !llvm.loop !1 32 33if.else: ; preds = %while.body 34 %4 = load i32, ptr %count, align 4 35 %add2 = add i32 %4, 2 36 store i32 %add2, ptr %count, align 4 37 br label %if.end 38 39; CHECK: if.else: 40; CHECK: br label %while.cond, !llvm.loop !1 41 42if.end: ; preds = %if.else, %if.then 43 br label %while.cond, !llvm.loop !1 44 45while.end: ; preds = %while.cond 46 ret void 47} 48 49; Test that empty loop latch `while.cond.loopexit` will not be folded into its successor if its 50; predecessor blocks are also loop latches. 51; 52; The test case is constructed based on the following C++ code. 53; While the C++ code itself might have the inner-loop unrolled (e.g., with -O3), 54; the loss of inner-loop unroll metadata is a bug. 55; Under some optimization pipelines (e.g., FullLoopUnroll pass is skipped in ThinLTO prelink stage), 56; and in real-world C++ code (e.g., with larger loop body), failing to 57; preserve loop unroll metadata could cause missed loop unroll. 58; 59; constexpr int kUnroll = 5; 60; int sum(int a, int b, int step, const int remainder, int* input) { 61; int i = a, j = b; 62; int sum = 0; 63; while(j - i > remainder) { 64; i += step; 65; #pragma unroll 66; for (int k = 0; k < kUnroll; k++) { 67; asm volatile ("add %w0, %w1\n" : "=r"(sum) : "r"(input[k + i]):"cc"); 68; } 69; } 70; return sum; 71; } 72define i32 @test2(i32 %a, i32 %b, i32 %step, i32 %remainder, ptr %input) { 73entry: 74 br label %while.cond 75 76while.cond.loopexit: ; preds = %for.body 77 br label %while.cond, !llvm.loop !3 78 79while.cond: ; preds = %while.cond.loopexit, %entry 80 %i.0 = phi i32 [ %a, %entry ], [ %add, %while.cond.loopexit ] 81 %sum.0 = phi i32 [ 0, %entry ], [ %1, %while.cond.loopexit ] 82 %sub = sub nsw i32 %b, %i.0 83 %cmp = icmp sgt i32 %sub, %remainder 84 br i1 %cmp, label %while.body, label %while.end 85 86while.body: ; preds = %while.cond 87 %add = add nsw i32 %i.0, %step 88 br label %for.body 89 90for.body: ; preds = %while.body, %for.body 91 %k.07 = phi i32 [ 0, %while.body ], [ %inc, %for.body ] 92 %add2 = add nsw i32 %k.07, %add 93 %idxprom = sext i32 %add2 to i64 94 %arrayidx = getelementptr inbounds i32, ptr %input, i64 %idxprom 95 %0 = load i32, ptr %arrayidx, align 4 96 %1 = tail call i32 asm sideeffect "add ${0:w}, ${1:w}\0A", "=r,r,~{cc}"(i32 %0) 97 %inc = add nuw nsw i32 %k.07, 1 98 %cmp1 = icmp ult i32 %inc, 5 99 br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !5 100 101while.end: ; preds = %while.cond 102 %sum.0.lcssa = phi i32 [ %sum.0, %while.cond ] 103 ret i32 %sum.0.lcssa 104} 105 106; Test that the condition tested above does not trigger when the loop metadata consists only of debug locations, 107; i.e.the empty loop latch `while.cond.loopexit` *will* be folded into its successor if its 108; predecessor blocks are also loop latches and any loop metadata attached to it consists of debug information. 109; 110define i32 @test3(i32 %a, i32 %b, i32 %step, i32 %remainder, ptr %input) !dbg !7 { 111entry: 112 br label %while.cond 113 114;CHECK-LABEL: @test3( 115;CHECK-NOT: while.cond.loopexit 116while.cond.loopexit: ; preds = %for.body 117 br label %while.cond, !llvm.loop !10 118 119while.cond: ; preds = %while.cond.loopexit, %entry 120 %i.0 = phi i32 [ %a, %entry ], [ %add, %while.cond.loopexit ] 121 %sum.0 = phi i32 [ 0, %entry ], [ %1, %while.cond.loopexit ] 122 %sub = sub nsw i32 %b, %i.0 123 %cmp = icmp sgt i32 %sub, %remainder 124 br i1 %cmp, label %while.body, label %while.end 125 126while.body: ; preds = %while.cond 127 %add = add nsw i32 %i.0, %step 128 br label %for.body 129 130for.body: ; preds = %while.body, %for.body 131 %k.07 = phi i32 [ 0, %while.body ], [ %inc, %for.body ] 132 %add2 = add nsw i32 %k.07, %add 133 %idxprom = sext i32 %add2 to i64 134 %arrayidx = getelementptr inbounds i32, ptr %input, i64 %idxprom 135 %0 = load i32, ptr %arrayidx, align 4 136 %1 = tail call i32 asm sideeffect "add ${0:w}, ${1:w}\0A", "=r,r,~{cc}"(i32 %0) 137 %inc = add nuw nsw i32 %k.07, 1 138 %cmp1 = icmp ult i32 %inc, 5 139 br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !5 140 141while.end: ; preds = %while.cond 142 %sum.0.lcssa = phi i32 [ %sum.0, %while.cond ] 143 ret i32 %sum.0.lcssa 144} 145 146!llvm.module.flags = !{!0} 147 148!0 = !{i32 2, !"Debug Info Version", i32 3} 149!1 = distinct !{!1, !2} 150!2 = !{!"llvm.loop.distribute.enable", i1 true} 151!3 = distinct !{!3, !4} 152!4 = !{!"llvm.loop.mustprogress"} 153!5 = distinct !{!5, !4, !6} 154!6 = !{!"llvm.loop.unroll.enable"} 155!7 = distinct !DISubprogram(name: "test3", scope: !8, file: !8, spFlags: DISPFlagDefinition, unit: !9) 156!8 = !DIFile(filename: "preserve-llvm-loop-metadata.ll", directory: "/") 157!9 = distinct !DICompileUnit(language: DW_LANG_C99, file: !8, isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug) 158!10 = distinct !{!10, !11, !13} 159!11 = !DILocation(line: 8, column: 4, scope: !12) 160!12 = distinct !DILexicalBlock(scope: !7, file: !8, line: 8, column: 2) 161!13 = !DILocation(line: 9, column: 23, scope: !12) 162 163; CHECK: !1 = distinct !{!1, !2} 164; CHECK: !2 = !{!"llvm.loop.distribute.enable", i1 true} 165; CHECK: !3 = distinct !{!3, !4} 166; CHECK: !4 = !{!"llvm.loop.mustprogress"} 167; CHECK: !5 = distinct !{!5, !4, !6} 168; CHECK: !6 = !{!"llvm.loop.unroll.enable"} 169; CHECK-NOT: !10 = distinct !{!10, !11, !13} 170