diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h index 730baa8cc0052..aa480aa8d9863 100644 --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -367,6 +367,10 @@ class Instruction : public User, /// Return true if this instruction has any metadata attached to it. bool hasMetadata() const { return DbgLoc || Value::hasMetadata(); } + // Return true if this instruction contains loop metadata other than + // a debug location + bool hasNonDebugLocLoopMetadata() const; + /// Return true if this instruction has metadata attached to it other than a /// debug location. bool hasMetadataOtherThanDebugLoc() const { return Value::hasMetadata(); } diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index 0137bb281e7ec..147cd84125c8d 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -12,6 +12,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/AttributeMask.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Constants.h" @@ -19,6 +20,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/MemoryModelRelaxationAnnotations.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" @@ -461,6 +463,29 @@ bool Instruction::hasPoisonGeneratingMetadata() const { hasMetadata(LLVMContext::MD_align); } +bool Instruction::hasNonDebugLocLoopMetadata() const { + // If there is no loop metadata at all, we also don't have + // non-debug loop metadata, obviously. + if (!hasMetadata(LLVMContext::MD_loop)) + return false; + + // If we do have loop metadata, retrieve it. + MDNode *LoopMD = getMetadata(LLVMContext::MD_loop); + + // Check if the existing operands are debug locations. This loop + // should terminate after at most three iterations. Skip + // the first item because it is a self-reference. + for (const MDOperand &Op : llvm::drop_begin(LoopMD->operands())) { + // check for debug location type by attempting a cast. + if (!dyn_cast(Op)) { + return true; + } + } + + // If we get here, then all we have is debug locations in the loop metadata. + return false; +} + void Instruction::dropPoisonGeneratingMetadata() { eraseMetadata(LLVMContext::MD_range); eraseMetadata(LLVMContext::MD_nonnull); diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index cdc3f0308fe59..a3af96d5af026 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1279,10 +1279,10 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, // | for.body <---- (md2) // |_______| |______| if (Instruction *TI = BB->getTerminator()) - if (TI->hasMetadata(LLVMContext::MD_loop)) + if (TI->hasNonDebugLocLoopMetadata()) for (BasicBlock *Pred : predecessors(BB)) if (Instruction *PredTI = Pred->getTerminator()) - if (PredTI->hasMetadata(LLVMContext::MD_loop)) + if (PredTI->hasNonDebugLocLoopMetadata()) return false; if (BBKillable) @@ -1345,12 +1345,15 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, } } - // If the unconditional branch we replaced contains llvm.loop metadata, we - // add the metadata to the branch instructions in the predecessors. + // If the unconditional branch we replaced contains non-debug llvm.loop + // metadata, we add the metadata to the branch instructions in the + // predecessors. if (Instruction *TI = BB->getTerminator()) - if (MDNode *LoopMD = TI->getMetadata(LLVMContext::MD_loop)) + if (TI->hasNonDebugLocLoopMetadata()) { + MDNode *LoopMD = TI->getMetadata(LLVMContext::MD_loop); for (BasicBlock *Pred : predecessors(BB)) Pred->getTerminator()->setMetadata(LLVMContext::MD_loop, LoopMD); + } if (BBKillable) { // Everything that jumped to BB now goes to Succ. diff --git a/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll b/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll index 6c255ff4fe876..a95b6ec15b129 100644 --- a/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll +++ b/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll @@ -28,7 +28,7 @@ if.then: ; preds = %while.body br label %if.end ; CHECK: if.then: -; CHECK: br label %while.cond, !llvm.loop !0 +; CHECK: br label %while.cond, !llvm.loop !1 if.else: ; preds = %while.body %4 = load i32, ptr %count, align 4 @@ -37,10 +37,10 @@ if.else: ; preds = %while.body br label %if.end ; CHECK: if.else: -; CHECK: br label %while.cond, !llvm.loop !0 +; CHECK: br label %while.cond, !llvm.loop !1 if.end: ; preds = %if.else, %if.then - br label %while.cond, !llvm.loop !0 + br label %while.cond, !llvm.loop !1 while.end: ; preds = %while.cond ret void @@ -74,7 +74,7 @@ entry: br label %while.cond while.cond.loopexit: ; preds = %for.body - br label %while.cond, !llvm.loop !2 + br label %while.cond, !llvm.loop !3 while.cond: ; preds = %while.cond.loopexit, %entry %i.0 = phi i32 [ %a, %entry ], [ %add, %while.cond.loopexit ] @@ -96,22 +96,74 @@ for.body: ; preds = %while.body, %for.bo %1 = tail call i32 asm sideeffect "add ${0:w}, ${1:w}\0A", "=r,r,~{cc}"(i32 %0) %inc = add nuw nsw i32 %k.07, 1 %cmp1 = icmp ult i32 %inc, 5 - br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !4 + br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !5 while.end: ; preds = %while.cond %sum.0.lcssa = phi i32 [ %sum.0, %while.cond ] ret i32 %sum.0.lcssa } -!0 = distinct !{!0, !1} -!1 = !{!"llvm.loop.distribute.enable", i1 true} -!2 = distinct !{!2, !3} -!3 = !{!"llvm.loop.mustprogress"} -!4 = distinct !{!4, !3, !5} -!5 = !{!"llvm.loop.unroll.enable"} -; CHECK: !0 = distinct !{!0, !1} -; CHECK: !1 = !{!"llvm.loop.distribute.enable", i1 true} -; CHECK: !2 = distinct !{!2, !3} -; CHECK: !3 = !{!"llvm.loop.mustprogress"} -; CHECK: !4 = distinct !{!4, !3, !5} -; CHECK: !5 = !{!"llvm.loop.unroll.enable"} +; Test that the condition tested above does not trigger when the loop metadata consists only of debug locations, +; i.e.the empty loop latch `while.cond.loopexit` *will* be folded into its successor if its +; predecessor blocks are also loop latches and any loop metadata attached to it consists of debug information. +; +define i32 @test3(i32 %a, i32 %b, i32 %step, i32 %remainder, ptr %input) !dbg !7 { +entry: + br label %while.cond + +;CHECK-LABEL: @test3( +;CHECK-NOT: while.cond.loopexit +while.cond.loopexit: ; preds = %for.body + br label %while.cond, !llvm.loop !10 + +while.cond: ; preds = %while.cond.loopexit, %entry + %i.0 = phi i32 [ %a, %entry ], [ %add, %while.cond.loopexit ] + %sum.0 = phi i32 [ 0, %entry ], [ %1, %while.cond.loopexit ] + %sub = sub nsw i32 %b, %i.0 + %cmp = icmp sgt i32 %sub, %remainder + br i1 %cmp, label %while.body, label %while.end + +while.body: ; preds = %while.cond + %add = add nsw i32 %i.0, %step + br label %for.body + +for.body: ; preds = %while.body, %for.body + %k.07 = phi i32 [ 0, %while.body ], [ %inc, %for.body ] + %add2 = add nsw i32 %k.07, %add + %idxprom = sext i32 %add2 to i64 + %arrayidx = getelementptr inbounds i32, ptr %input, i64 %idxprom + %0 = load i32, ptr %arrayidx, align 4 + %1 = tail call i32 asm sideeffect "add ${0:w}, ${1:w}\0A", "=r,r,~{cc}"(i32 %0) + %inc = add nuw nsw i32 %k.07, 1 + %cmp1 = icmp ult i32 %inc, 5 + br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !5 + +while.end: ; preds = %while.cond + %sum.0.lcssa = phi i32 [ %sum.0, %while.cond ] + ret i32 %sum.0.lcssa +} + +!llvm.module.flags = !{!0} + +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !{!1, !2} +!2 = !{!"llvm.loop.distribute.enable", i1 true} +!3 = distinct !{!3, !4} +!4 = !{!"llvm.loop.mustprogress"} +!5 = distinct !{!5, !4, !6} +!6 = !{!"llvm.loop.unroll.enable"} +!7 = distinct !DISubprogram(name: "test3", scope: !8, file: !8, spFlags: DISPFlagDefinition, unit: !9) +!8 = !DIFile(filename: "preserve-llvm-loop-metadata.ll", directory: "/") +!9 = distinct !DICompileUnit(language: DW_LANG_C99, file: !8, isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug) +!10 = distinct !{!10, !11, !13} +!11 = !DILocation(line: 8, column: 4, scope: !12) +!12 = distinct !DILexicalBlock(scope: !7, file: !8, line: 8, column: 2) +!13 = !DILocation(line: 9, column: 23, scope: !12) + +; CHECK: !1 = distinct !{!1, !2} +; CHECK: !2 = !{!"llvm.loop.distribute.enable", i1 true} +; CHECK: !3 = distinct !{!3, !4} +; CHECK: !4 = !{!"llvm.loop.mustprogress"} +; CHECK: !5 = distinct !{!5, !4, !6} +; CHECK: !6 = !{!"llvm.loop.unroll.enable"} +; CHECK-NOT: !10 = distinct !{!10, !11, !13}