1; RUN: opt -S -passes=loop-fusion -pass-remarks-missed=loop-fusion -disable-output < %s 2>&1 | FileCheck %s 2; REQUIRES: asserts 3 4target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" 5 6@B = common global [1024 x i32] zeroinitializer, align 16, !dbg !0 7 8; CHECK: remark: diagnostics_missed.c:18:3: [non_adjacent]: entry and for.end: Loops are not adjacent 9define void @non_adjacent(ptr noalias %A) !dbg !14 { 10entry: 11 br label %for.body 12 13for.cond.cleanup: ; preds = %for.inc 14 br label %for.end 15 16for.body: ; preds = %entry, %for.inc 17 %i.02 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] 18 %sub = add nsw i64 %i.02, -3 19 %add = add nuw nsw i64 %i.02, 3 20 %mul = mul nsw i64 %sub, %add 21 %rem = srem i64 %mul, %i.02 22 %conv = trunc i64 %rem to i32 23 %arrayidx = getelementptr inbounds i32, ptr %A, i64 %i.02 24 store i32 %conv, ptr %arrayidx, align 4 25 br label %for.inc 26 27for.inc: ; preds = %for.body 28 %inc = add nuw nsw i64 %i.02, 1, !dbg !26 29 %exitcond1 = icmp ne i64 %inc, 100 30 br i1 %exitcond1, label %for.body, label %for.cond.cleanup, !llvm.loop !28 31 32for.end: ; preds = %for.cond.cleanup 33 br label %for.body6 34 35for.cond.cleanup5: ; preds = %for.inc13 36 br label %for.end15 37 38for.body6: ; preds = %for.end, %for.inc13 39 %i1.01 = phi i64 [ 0, %for.end ], [ %inc14, %for.inc13 ] 40 %sub7 = add nsw i64 %i1.01, -3 41 %add8 = add nuw nsw i64 %i1.01, 3 42 %mul9 = mul nsw i64 %sub7, %add8 43 %rem10 = srem i64 %mul9, %i1.01 44 %conv11 = trunc i64 %rem10 to i32 45 %arrayidx12 = getelementptr inbounds [1024 x i32], ptr @B, i64 0, i64 %i1.01 46 store i32 %conv11, ptr %arrayidx12, align 4 47 br label %for.inc13 48 49for.inc13: ; preds = %for.body6 50 %inc14 = add nuw nsw i64 %i1.01, 1, !dbg !31 51 %exitcond = icmp ne i64 %inc14, 100 52 br i1 %exitcond, label %for.body6, label %for.cond.cleanup5, !llvm.loop !33 53 54for.end15: ; preds = %for.cond.cleanup5 55 ret void 56} 57 58; CHECK: remark: diagnostics_missed.c:28:3: [different_bounds]: entry and for.end: Loop trip counts are not the same 59define void @different_bounds(ptr noalias %A) !dbg !36 { 60entry: 61 br label %for.body 62 63for.cond.cleanup: ; preds = %for.inc 64 br label %for.end 65 66for.body: ; preds = %entry, %for.inc 67 %i.02 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] 68 %sub = add nsw i64 %i.02, -3 69 %add = add nuw nsw i64 %i.02, 3 70 %mul = mul nsw i64 %sub, %add 71 %rem = srem i64 %mul, %i.02 72 %conv = trunc i64 %rem to i32 73 %arrayidx = getelementptr inbounds i32, ptr %A, i64 %i.02 74 store i32 %conv, ptr %arrayidx, align 4 75 br label %for.inc 76 77for.inc: ; preds = %for.body 78 %inc = add nuw nsw i64 %i.02, 1, !dbg !43 79 %exitcond1 = icmp ne i64 %inc, 100 80 br i1 %exitcond1, label %for.body, label %for.cond.cleanup, !llvm.loop !45 81 82for.end: ; preds = %for.cond.cleanup 83 br label %for.body6 84 85for.cond.cleanup5: ; preds = %for.inc13 86 br label %for.end15 87 88for.body6: ; preds = %for.end, %for.inc13 89 %i1.01 = phi i64 [ 0, %for.end ], [ %inc14, %for.inc13 ] 90 %sub7 = add nsw i64 %i1.01, -3 91 %add8 = add nuw nsw i64 %i1.01, 3 92 %mul9 = mul nsw i64 %sub7, %add8 93 %rem10 = srem i64 %mul9, %i1.01 94 %conv11 = trunc i64 %rem10 to i32 95 %arrayidx12 = getelementptr inbounds [1024 x i32], ptr @B, i64 0, i64 %i1.01 96 store i32 %conv11, ptr %arrayidx12, align 4 97 br label %for.inc13 98 99for.inc13: ; preds = %for.body6 100 %inc14 = add nuw nsw i64 %i1.01, 1 101 %exitcond = icmp ne i64 %inc14, 200 102 br i1 %exitcond, label %for.body6, label %for.cond.cleanup5, !llvm.loop !48 103 104for.end15: ; preds = %for.cond.cleanup5 105 ret void 106} 107 108; CHECK: remark: diagnostics_missed.c:38:3: [negative_dependence]: entry and for.end: Dependencies prevent fusion 109define void @negative_dependence(ptr noalias %A) !dbg !51 { 110entry: 111 br label %for.body 112 113for.body: ; preds = %entry, %for.inc 114 %indvars.iv13 = phi i64 [ 0, %entry ], [ %indvars.iv.next2, %for.inc ] 115 %arrayidx = getelementptr inbounds i32, ptr %A, i64 %indvars.iv13 116 %tmp = trunc i64 %indvars.iv13 to i32 117 store i32 %tmp, ptr %arrayidx, align 4 118 br label %for.inc 119 120for.inc: ; preds = %for.body 121 %indvars.iv.next2 = add nuw nsw i64 %indvars.iv13, 1 122 %exitcond3 = icmp ne i64 %indvars.iv.next2, 100 123 br i1 %exitcond3, label %for.body, label %for.end, !llvm.loop !58 124 125for.end: ; preds = %for.inc 126 call void @llvm.dbg.value(metadata i32 0, metadata !56, metadata !DIExpression()), !dbg !61 127 br label %for.body5 128 129for.body5: ; preds = %for.end, %for.inc10 130 %indvars.iv2 = phi i64 [ 0, %for.end ], [ %indvars.iv.next, %for.inc10 ] 131 %indvars.iv.next = add nuw nsw i64 %indvars.iv2, 1 132 %arrayidx7 = getelementptr inbounds i32, ptr %A, i64 %indvars.iv.next 133 %tmp4 = load i32, ptr %arrayidx7, align 4 134 %mul = shl nsw i32 %tmp4, 1 135 %arrayidx9 = getelementptr inbounds [1024 x i32], ptr @B, i64 0, i64 %indvars.iv2 136 store i32 %mul, ptr %arrayidx9, align 4 137 br label %for.inc10 138 139for.inc10: ; preds = %for.body5 140 %exitcond = icmp ne i64 %indvars.iv.next, 100 141 br i1 %exitcond, label %for.body5, label %for.end12 142 143for.end12: ; preds = %for.inc10 144 ret void, !dbg !62 145} 146 147; CHECK: remark: diagnostics_missed.c:51:3: [sumTest]: entry and for.cond2.preheader: Dependencies prevent fusion 148define i32 @sumTest(ptr noalias %A) !dbg !63 { 149entry: 150 br label %for.body 151 152for.cond2.preheader: ; preds = %for.inc 153 br label %for.body5 154 155for.body: ; preds = %entry, %for.inc 156 %sum.04 = phi i32 [ 0, %entry ], [ %add, %for.inc ] 157 %indvars.iv13 = phi i64 [ 0, %entry ], [ %indvars.iv.next2, %for.inc ] 158 br label %for.inc 159 160for.inc: ; preds = %for.body 161 %arrayidx = getelementptr inbounds i32, ptr %A, i64 %indvars.iv13 162 %tmp = load i32, ptr %arrayidx, align 4 163 %add = add nsw i32 %sum.04, %tmp 164 %indvars.iv.next2 = add nuw nsw i64 %indvars.iv13, 1 165 %exitcond3 = icmp ne i64 %indvars.iv.next2, 100 166 br i1 %exitcond3, label %for.body, label %for.cond2.preheader, !llvm.loop !73 167 168for.body5: ; preds = %for.cond2.preheader, %for.inc10 169 %indvars.iv2 = phi i64 [ 0, %for.cond2.preheader ], [ %indvars.iv.next, %for.inc10 ] 170 %arrayidx7 = getelementptr inbounds i32, ptr %A, i64 %indvars.iv2 171 %tmp4 = load i32, ptr %arrayidx7, align 4 172 %div = sdiv i32 %tmp4, %add 173 %arrayidx9 = getelementptr inbounds [1024 x i32], ptr @B, i64 0, i64 %indvars.iv2 174 store i32 %div, ptr %arrayidx9, align 4 175 br label %for.inc10 176 177for.inc10: ; preds = %for.body5 178 %indvars.iv.next = add nuw nsw i64 %indvars.iv2, 1 179 %exitcond = icmp ne i64 %indvars.iv.next, 100 180 br i1 %exitcond, label %for.body5, label %for.end12 181 182for.end12: ; preds = %for.inc10 183 ret i32 %add, !dbg !76 184} 185 186; Function Attrs: nounwind readnone speculatable willreturn 187declare void @llvm.dbg.value(metadata, metadata, metadata) #0 188 189; CHECK: remark: diagnostics_missed.c:62:3: [unsafe_preheader]: for.first.preheader and for.second.preheader: Loop has a non-empty preheader with instructions that cannot be moved 190define void @unsafe_preheader(ptr noalias %A, ptr noalias %B) { 191for.first.preheader: 192 br label %for.first, !dbg !80 193 194for.first: 195 %i.02 = phi i64 [ 0, %for.first.preheader ], [ %inc, %for.first ] 196 %arrayidx = getelementptr inbounds i32, ptr %A, i64 %i.02 197 store i32 0, ptr %arrayidx, align 4 198 %inc = add nsw i64 %i.02, 1 199 %cmp = icmp slt i64 %inc, 100 200 br i1 %cmp, label %for.first, label %for.second.preheader 201 202for.second.preheader: 203 call void @bar() 204 br label %for.second 205 206for.second: 207 %j.01 = phi i64 [ 0, %for.second.preheader ], [ %inc6, %for.second ] 208 %arrayidx4 = getelementptr inbounds i32, ptr %B, i64 %j.01 209 store i32 0, ptr %arrayidx4, align 4 210 %inc6 = add nsw i64 %j.01, 1 211 %cmp2 = icmp slt i64 %inc6, 100 212 br i1 %cmp2, label %for.second, label %for.end 213 214for.end: 215 ret void 216} 217 218; CHECK: remark: diagnostics_missed.c:67:3: [unsafe_exitblock]: for.first.preheader and for.second.preheader: Candidate has a non-empty exit block with instructions that cannot be moved 219define void @unsafe_exitblock(ptr noalias %A, ptr noalias %B, i64 %N) { 220for.first.guard: 221 %cmp3 = icmp slt i64 0, %N 222 br i1 %cmp3, label %for.first.preheader, label %for.second.guard 223 224for.first.preheader: 225 br label %for.first, !dbg !83 226 227for.first: 228 %i.04 = phi i64 [ %inc, %for.first ], [ 0, %for.first.preheader ] 229 %arrayidx = getelementptr inbounds i32, ptr %A, i64 %i.04 230 store i32 0, ptr %arrayidx, align 4 231 %inc = add nsw i64 %i.04, 1 232 %cmp = icmp slt i64 %inc, %N 233 br i1 %cmp, label %for.first, label %for.first.exit 234 235for.first.exit: 236 call void @bar() 237 br label %for.second.guard 238 239for.second.guard: 240 %cmp21 = icmp slt i64 0, %N 241 br i1 %cmp21, label %for.second.preheader, label %for.end 242 243for.second.preheader: 244 br label %for.second 245 246for.second: 247 %j.02 = phi i64 [ %inc6, %for.second ], [ 0, %for.second.preheader ] 248 %arrayidx4 = getelementptr inbounds i32, ptr %B, i64 %j.02 249 store i32 0, ptr %arrayidx4, align 4 250 %inc6 = add nsw i64 %j.02, 1 251 %cmp2 = icmp slt i64 %inc6, %N 252 br i1 %cmp2, label %for.second, label %for.second.exit 253 254for.second.exit: 255 br label %for.end 256 257for.end: 258 ret void 259} 260 261; CHECK: remark: diagnostics_missed.c:72:3: [unsafe_guardblock]: for.first.preheader and for.second.preheader: Candidate has a non-empty guard block with instructions that cannot be moved 262define void @unsafe_guardblock(ptr noalias %A, ptr noalias %B, i64 %N) { 263for.first.guard: 264 %cmp3 = icmp slt i64 0, %N 265 br i1 %cmp3, label %for.first.preheader, label %for.second.guard 266 267for.first.preheader: 268 br label %for.first, !dbg !86 269 270for.first: 271 %i.04 = phi i64 [ %inc, %for.first ], [ 0, %for.first.preheader ] 272 %arrayidx = getelementptr inbounds i32, ptr %A, i64 %i.04 273 store i32 0, ptr %arrayidx, align 4 274 %inc = add nsw i64 %i.04, 1 275 %cmp = icmp slt i64 %inc, %N 276 br i1 %cmp, label %for.first, label %for.first.exit 277 278for.first.exit: 279 br label %for.second.guard 280 281for.second.guard: 282 call void @bar() 283 %cmp21 = icmp slt i64 0, %N 284 br i1 %cmp21, label %for.second.preheader, label %for.end 285 286for.second.preheader: 287 br label %for.second 288 289for.second: 290 %j.02 = phi i64 [ %inc6, %for.second ], [ 0, %for.second.preheader ] 291 %arrayidx4 = getelementptr inbounds i32, ptr %B, i64 %j.02 292 store i32 0, ptr %arrayidx4, align 4 293 %inc6 = add nsw i64 %j.02, 1 294 %cmp2 = icmp slt i64 %inc6, %N 295 br i1 %cmp2, label %for.second, label %for.second.exit 296 297for.second.exit: 298 br label %for.end 299 300for.end: 301 ret void 302} 303 304declare void @bar() 305 306attributes #0 = { nounwind readnone speculatable willreturn } 307 308!llvm.dbg.cu = !{!2} 309!llvm.module.flags = !{!10, !11, !12, !13} 310 311!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) 312!1 = distinct !DIGlobalVariable(name: "B", scope: !2, file: !3, line: 46, type: !6, isLocal: false, isDefinition: true) 313!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (git@github.ibm.com:compiler/llvm-project.git 23c4baaa9f5b33d2d52eda981d376c6b0a7a3180)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) 314!3 = !DIFile(filename: "diagnostics_missed.c", directory: "/tmp") 315!4 = !{} 316!5 = !{!0} 317!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32768, elements: !8) 318!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 319!8 = !{!9} 320!9 = !DISubrange(count: 1024) 321!10 = !{i32 2, !"Dwarf Version", i32 4} 322!11 = !{i32 2, !"Debug Info Version", i32 3} 323!12 = !{i32 1, !"wchar_size", i32 4} 324!13 = !{i32 7, !"PIC Level", i32 2} 325!14 = distinct !DISubprogram(name: "non_adjacent", scope: !3, file: !3, line: 17, type: !15, scopeLine: 17, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !19) 326!15 = !DISubroutineType(types: !16) 327!16 = !{null, !17} 328!17 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !18) 329!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) 330!19 = !{!20, !21, !24} 331!20 = !DILocalVariable(name: "A", arg: 1, scope: !14, file: !3, line: 17, type: !17) 332!21 = !DILocalVariable(name: "i", scope: !22, file: !3, line: 18, type: !23) 333!22 = distinct !DILexicalBlock(scope: !14, file: !3, line: 18, column: 3) 334!23 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) 335!24 = !DILocalVariable(name: "i", scope: !25, file: !3, line: 22, type: !23) 336!25 = distinct !DILexicalBlock(scope: !14, file: !3, line: 22, column: 3) 337!26 = !DILocation(line: 18, column: 30, scope: !27) 338!27 = distinct !DILexicalBlock(scope: !22, file: !3, line: 18, column: 3) 339!28 = distinct !{!28, !29, !30} 340!29 = !DILocation(line: 18, column: 3, scope: !22) 341!30 = !DILocation(line: 20, column: 3, scope: !22) 342!31 = !DILocation(line: 22, column: 30, scope: !32) 343!32 = distinct !DILexicalBlock(scope: !25, file: !3, line: 22, column: 3) 344!33 = distinct !{!33, !34, !35} 345!34 = !DILocation(line: 22, column: 3, scope: !25) 346!35 = !DILocation(line: 24, column: 3, scope: !25) 347!36 = distinct !DISubprogram(name: "different_bounds", scope: !3, file: !3, line: 27, type: !15, scopeLine: 27, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !37) 348!37 = !{!38, !39, !41} 349!38 = !DILocalVariable(name: "A", arg: 1, scope: !36, file: !3, line: 27, type: !17) 350!39 = !DILocalVariable(name: "i", scope: !40, file: !3, line: 28, type: !23) 351!40 = distinct !DILexicalBlock(scope: !36, file: !3, line: 28, column: 3) 352!41 = !DILocalVariable(name: "i", scope: !42, file: !3, line: 32, type: !23) 353!42 = distinct !DILexicalBlock(scope: !36, file: !3, line: 32, column: 3) 354!43 = !DILocation(line: 28, column: 30, scope: !44) 355!44 = distinct !DILexicalBlock(scope: !40, file: !3, line: 28, column: 3) 356!45 = distinct !{!45, !46, !47} 357!46 = !DILocation(line: 28, column: 3, scope: !40) 358!47 = !DILocation(line: 30, column: 3, scope: !40) 359!48 = distinct !{!48, !49, !50} 360!49 = !DILocation(line: 32, column: 3, scope: !42) 361!50 = !DILocation(line: 34, column: 3, scope: !42) 362!51 = distinct !DISubprogram(name: "negative_dependence", scope: !3, file: !3, line: 37, type: !15, scopeLine: 37, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !52) 363!52 = !{!53, !54, !56} 364!53 = !DILocalVariable(name: "A", arg: 1, scope: !51, file: !3, line: 37, type: !17) 365!54 = !DILocalVariable(name: "i", scope: !55, file: !3, line: 38, type: !7) 366!55 = distinct !DILexicalBlock(scope: !51, file: !3, line: 38, column: 3) 367!56 = !DILocalVariable(name: "i", scope: !57, file: !3, line: 42, type: !7) 368!57 = distinct !DILexicalBlock(scope: !51, file: !3, line: 42, column: 3) 369!58 = distinct !{!58, !59, !60} 370!59 = !DILocation(line: 38, column: 3, scope: !55) 371!60 = !DILocation(line: 40, column: 3, scope: !55) 372!61 = !DILocation(line: 0, scope: !57) 373!62 = !DILocation(line: 45, column: 1, scope: !51) 374!63 = distinct !DISubprogram(name: "sumTest", scope: !3, file: !3, line: 48, type: !64, scopeLine: 48, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !66) 375!64 = !DISubroutineType(types: !65) 376!65 = !{!7, !17} 377!66 = !{!67, !68, !69, !71} 378!67 = !DILocalVariable(name: "A", arg: 1, scope: !63, file: !3, line: 48, type: !17) 379!68 = !DILocalVariable(name: "sum", scope: !63, file: !3, line: 49, type: !7) 380!69 = !DILocalVariable(name: "i", scope: !70, file: !3, line: 51, type: !7) 381!70 = distinct !DILexicalBlock(scope: !63, file: !3, line: 51, column: 3) 382!71 = !DILocalVariable(name: "i", scope: !72, file: !3, line: 54, type: !7) 383!72 = distinct !DILexicalBlock(scope: !63, file: !3, line: 54, column: 3) 384!73 = distinct !{!73, !74, !75} 385!74 = !DILocation(line: 51, column: 3, scope: !70) 386!75 = !DILocation(line: 52, column: 15, scope: !70) 387!76 = !DILocation(line: 57, column: 3, scope: !63) 388!77 = distinct !DISubprogram(name: "unsafe_preheader", scope: !3, file: !3, line: 60, type: !15, scopeLine: 60, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !78) 389!78 = !{} 390!79 = distinct !DILexicalBlock(scope: !77, file: !3, line: 3, column: 5) 391!80 = !DILocation(line: 62, column: 3, scope: !79) 392!81 = distinct !DISubprogram(name: "unsafe_exitblock", scope: !3, file: !3, line: 65, type: !15, scopeLine: 60, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !78) 393!82 = distinct !DILexicalBlock(scope: !81, file: !3, line: 3, column: 5) 394!83 = !DILocation(line: 67, column: 3, scope: !82) 395!84 = distinct !DISubprogram(name: "unsafe_guardblock", scope: !3, file: !3, line: 70, type: !15, scopeLine: 60, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !78) 396!85 = distinct !DILexicalBlock(scope: !84, file: !3, line: 3, column: 5) 397!86 = !DILocation(line: 72, column: 3, scope: !85) 398