[llvm] c672ba7 - [DebugInfo][RemoveDIs] Instrument inliner for non-instr debug-info (#72884)

via llvm-commits llvm-commits at lists.llvm.org
Sun Nov 26 13:24:34 PST 2023


Author: Jeremy Morse
Date: 2023-11-26T21:24:29Z
New Revision: c672ba7dde3a6ec2f6c89fcb207c9a6a8474cedc

URL: https://github.com/llvm/llvm-project/commit/c672ba7dde3a6ec2f6c89fcb207c9a6a8474cedc
DIFF: https://github.com/llvm/llvm-project/commit/c672ba7dde3a6ec2f6c89fcb207c9a6a8474cedc.diff

LOG: [DebugInfo][RemoveDIs] Instrument inliner for non-instr debug-info (#72884)

With intrinsics representing debug-info, we just clone all the
intrinsics when inlining a function and don't think about it any
further. With non-instruction debug-info however we need to be a bit
more careful and manually move the debug-info from one place to another.
For the most part, this means keeping a "cursor" during block cloning of
where we last copied debug-info from, and performing debug-info copying
whenever we successfully clone another instruction.

There are several utilities in LLVM for doing this, all of which now
need to manually call cloneDebugInfo. The testing story for this is not
well covered as we could rely on normal instruction-cloning mechanisms
to do all the hard stuff. Thus, I've added a few tests to explicitly
test dbg.value behaviours, ahead of them becoming not-instructions.

Added: 
    llvm/test/DebugInfo/Generic/inline-alloca-ordering.ll
    llvm/test/DebugInfo/Generic/inline-dbg-values.ll
    llvm/test/Transforms/JumpThreading/guard-split-debuginfo.ll

Modified: 
    llvm/include/llvm/IR/DebugInfo.h
    llvm/lib/IR/DebugInfo.cpp
    llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp
    llvm/lib/Transforms/Scalar/JumpThreading.cpp
    llvm/lib/Transforms/Utils/CloneFunction.cpp
    llvm/lib/Transforms/Utils/CloneModule.cpp
    llvm/lib/Transforms/Utils/InlineFunction.cpp
    llvm/test/DebugInfo/Generic/inline-debug-loc.ll
    llvm/test/Transforms/CallSiteSplitting/callsite-split-preserve-debug.ll
    llvm/test/Transforms/Inline/alloca-dbgdeclare.ll
    llvm/test/Transforms/Inline/delete-function-with-metadata-use.ll
    llvm/test/Transforms/Inline/ignore-debug-info.ll
    llvm/test/Transforms/Inline/inline-skip-use-empty-alloca.ll
    llvm/test/Transforms/Inline/local-as-metadata-undominated-use.ll
    llvm/test/Transforms/Inline/no-inline-line-tables.ll
    llvm/test/Transforms/LoopUnroll/debug-info.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/DebugInfo.h b/llvm/include/llvm/IR/DebugInfo.h
index 5d6e8c2fd28da61..2a581eb5f09d9f8 100644
--- a/llvm/include/llvm/IR/DebugInfo.h
+++ b/llvm/include/llvm/IR/DebugInfo.h
@@ -102,10 +102,12 @@ class DebugInfoFinder {
   /// Process a single instruction and collect debug info anchors.
   void processInstruction(const Module &M, const Instruction &I);
 
-  /// Process DbgVariableIntrinsic.
-  void processVariable(const Module &M, const DbgVariableIntrinsic &DVI);
+  /// Process a DILocalVariable.
+  void processVariable(const Module &M, const DILocalVariable *DVI);
   /// Process debug info location.
   void processLocation(const Module &M, const DILocation *Loc);
+  // Process a DPValue, much like a DbgVariableIntrinsic.
+  void processDPValue(const Module &M, const DPValue &DPV);
 
   /// Process subprogram.
   void processSubprogram(DISubprogram *SP);

diff  --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp
index 95dfc28ca29bbd0..3fe940e19295b01 100644
--- a/llvm/lib/IR/DebugInfo.cpp
+++ b/llvm/lib/IR/DebugInfo.cpp
@@ -205,10 +205,13 @@ void DebugInfoFinder::processCompileUnit(DICompileUnit *CU) {
 void DebugInfoFinder::processInstruction(const Module &M,
                                          const Instruction &I) {
   if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I))
-    processVariable(M, *DVI);
+    processVariable(M, DVI->getVariable());
 
   if (auto DbgLoc = I.getDebugLoc())
     processLocation(M, DbgLoc.get());
+
+  for (const DPValue &DPV : I.getDbgValueRange())
+    processDPValue(M, DPV);
 }
 
 void DebugInfoFinder::processLocation(const Module &M, const DILocation *Loc) {
@@ -218,6 +221,11 @@ void DebugInfoFinder::processLocation(const Module &M, const DILocation *Loc) {
   processLocation(M, Loc->getInlinedAt());
 }
 
+void DebugInfoFinder::processDPValue(const Module &M, const DPValue &DPV) {
+  processVariable(M, DPV.getVariable());
+  processLocation(M, DPV.getDebugLoc().get());
+}
+
 void DebugInfoFinder::processType(DIType *DT) {
   if (!addType(DT))
     return;
@@ -292,15 +300,7 @@ void DebugInfoFinder::processSubprogram(DISubprogram *SP) {
 }
 
 void DebugInfoFinder::processVariable(const Module &M,
-                                      const DbgVariableIntrinsic &DVI) {
-  auto *N = dyn_cast<MDNode>(DVI.getVariable());
-  if (!N)
-    return;
-
-  auto *DV = dyn_cast<DILocalVariable>(N);
-  if (!DV)
-    return;
-
+                                      const DILocalVariable *DV) {
   if (!NodesSeen.insert(DV).second)
     return;
   processScope(DV->getScope());

diff  --git a/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp b/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp
index a0ee6d89131635a..47af299dbd473dd 100644
--- a/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp
+++ b/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp
@@ -402,6 +402,7 @@ static void splitCallSite(CallBase &CB,
       NewPN->insertBefore(&*TailBB->begin());
       CurrentI->replaceAllUsesWith(NewPN);
     }
+    CurrentI->dropDbgValues();
     CurrentI->eraseFromParent();
     // We are done once we handled the first original instruction in TailBB.
     if (CurrentI == OriginalBegin)

diff  --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index d7d503427ec3d20..59a8b8ad494566c 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -3118,8 +3118,8 @@ bool JumpThreadingPass::threadGuard(BasicBlock *BB, IntrinsicInst *Guard,
     if (!isa<PHINode>(&*BI))
       ToRemove.push_back(&*BI);
 
-  Instruction *InsertionPoint = &*BB->getFirstInsertionPt();
-  assert(InsertionPoint && "Empty block?");
+  BasicBlock::iterator InsertionPoint = BB->getFirstInsertionPt();
+  assert(InsertionPoint != BB->end() && "Empty block?");
   // Substitute with Phis & remove.
   for (auto *Inst : reverse(ToRemove)) {
     if (!Inst->use_empty()) {
@@ -3129,6 +3129,7 @@ bool JumpThreadingPass::threadGuard(BasicBlock *BB, IntrinsicInst *Guard,
       NewPN->insertBefore(InsertionPoint);
       Inst->replaceAllUsesWith(NewPN);
     }
+    Inst->dropDbgValues();
     Inst->eraseFromParent();
   }
   return true;

diff  --git a/llvm/lib/Transforms/Utils/CloneFunction.cpp b/llvm/lib/Transforms/Utils/CloneFunction.cpp
index 9ff4f01a9809e5d..abf0ab4e9b202ac 100644
--- a/llvm/lib/Transforms/Utils/CloneFunction.cpp
+++ b/llvm/lib/Transforms/Utils/CloneFunction.cpp
@@ -94,6 +94,7 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc,
                              const char *NameSuffix, ClonedCodeInfo *CodeInfo,
                              ValueMapTypeRemapper *TypeMapper,
                              ValueMaterializer *Materializer) {
+  NewFunc->setIsNewDbgInfoFormat(OldFunc->IsNewDbgInfoFormat);
   assert(NameSuffix && "NameSuffix cannot be null!");
 
 #ifndef NDEBUG
@@ -271,9 +272,13 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc,
            BB = cast<BasicBlock>(VMap[&OldFunc->front()])->getIterator(),
            BE = NewFunc->end();
        BB != BE; ++BB)
-    // Loop over all instructions, fixing each one as we find it...
-    for (Instruction &II : *BB)
+    // Loop over all instructions, fixing each one as we find it, and any
+    // attached debug-info records.
+    for (Instruction &II : *BB) {
       RemapInstruction(&II, VMap, RemapFlag, TypeMapper, Materializer);
+      RemapDPValueRange(II.getModule(), II.getDbgValueRange(), VMap, RemapFlag,
+                        TypeMapper, Materializer);
+    }
 
   // Only update !llvm.dbg.cu for DifferentModule (not CloneModule). In the
   // same module, the compile unit will already be listed (or not). When
@@ -331,6 +336,7 @@ Function *llvm::CloneFunction(Function *F, ValueToValueMapTy &VMap,
   // Create the new function...
   Function *NewF = Function::Create(FTy, F->getLinkage(), F->getAddressSpace(),
                                     F->getName(), F->getParent());
+  NewF->setIsNewDbgInfoFormat(F->IsNewDbgInfoFormat);
 
   // Loop over the arguments, copying the names of the mapped arguments over...
   Function::arg_iterator DestI = NewF->arg_begin();
@@ -496,6 +502,22 @@ void PruningFunctionCloner::CloneBlock(
   bool hasCalls = false, hasDynamicAllocas = false, hasStaticAllocas = false;
   bool hasMemProfMetadata = false;
 
+  // Keep a cursor pointing at the last place we cloned debug-info records from.
+  BasicBlock::const_iterator DbgCursor = StartingInst;
+  auto CloneDbgRecordsToHere =
+      [NewBB, &DbgCursor](Instruction *NewInst, BasicBlock::const_iterator II) {
+        if (!NewBB->IsNewDbgInfoFormat)
+          return;
+
+        // Clone debug-info records onto this instruction. Iterate through any
+        // source-instructions we've cloned and then subsequently optimised
+        // away, so that their debug-info doesn't go missing.
+        for (; DbgCursor != II; ++DbgCursor)
+          NewInst->cloneDebugInfoFrom(&*DbgCursor, std::nullopt, false);
+        NewInst->cloneDebugInfoFrom(&*II);
+        DbgCursor = std::next(II);
+      };
+
   // Loop over all instructions, and copy them over, DCE'ing as we go.  This
   // loop doesn't include the terminator.
   for (BasicBlock::const_iterator II = StartingInst, IE = --BB->end(); II != IE;
@@ -545,6 +567,8 @@ void PruningFunctionCloner::CloneBlock(
       hasMemProfMetadata |= II->hasMetadata(LLVMContext::MD_memprof);
     }
 
+    CloneDbgRecordsToHere(NewInst, II);
+
     if (CodeInfo) {
       CodeInfo->OrigVMap[&*II] = NewInst;
       if (auto *CB = dyn_cast<CallBase>(&*II))
@@ -602,6 +626,9 @@ void PruningFunctionCloner::CloneBlock(
     if (OldTI->hasName())
       NewInst->setName(OldTI->getName() + NameSuffix);
     NewInst->insertInto(NewBB, NewBB->end());
+
+    CloneDbgRecordsToHere(NewInst, OldTI->getIterator());
+
     VMap[OldTI] = NewInst; // Add instruction map to value.
 
     if (CodeInfo) {
@@ -613,6 +640,13 @@ void PruningFunctionCloner::CloneBlock(
 
     // Recursively clone any reachable successor blocks.
     append_range(ToClone, successors(BB->getTerminator()));
+  } else {
+    // If we didn't create a new terminator, clone DPValues from the old
+    // terminator onto the new terminator.
+    Instruction *NewInst = NewBB->getTerminator();
+    assert(NewInst);
+
+    CloneDbgRecordsToHere(NewInst, OldTI->getIterator());
   }
 
   if (CodeInfo) {
@@ -850,12 +884,22 @@ void llvm::CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
                        TypeMapper, Materializer);
   }
 
+  // Do the same for DPValues, touching all the instructions in the cloned
+  // range of blocks.
+  Function::iterator Begin = cast<BasicBlock>(VMap[StartingBB])->getIterator();
+  for (BasicBlock &BB : make_range(Begin, NewFunc->end())) {
+    for (Instruction &I : BB) {
+      RemapDPValueRange(I.getModule(), I.getDbgValueRange(), VMap,
+                        ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges,
+                        TypeMapper, Materializer);
+    }
+  }
+
   // Simplify conditional branches and switches with a constant operand. We try
   // to prune these out when cloning, but if the simplification required
   // looking through PHI nodes, those are only available after forming the full
   // basic block. That may leave some here, and we still want to prune the dead
   // code as early as possible.
-  Function::iterator Begin = cast<BasicBlock>(VMap[StartingBB])->getIterator();
   for (BasicBlock &BB : make_range(Begin, NewFunc->end()))
     ConstantFoldTerminator(&BB);
 
@@ -944,10 +988,15 @@ void llvm::CloneAndPruneFunctionInto(
 void llvm::remapInstructionsInBlocks(ArrayRef<BasicBlock *> Blocks,
                                      ValueToValueMapTy &VMap) {
   // Rewrite the code to refer to itself.
-  for (auto *BB : Blocks)
-    for (auto &Inst : *BB)
+  for (auto *BB : Blocks) {
+    Module *M = BB->getModule();
+    for (auto &Inst : *BB) {
+      RemapDPValueRange(Inst.getModule(), Inst.getDbgValueRange(), VMap,
+                        RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
       RemapInstruction(&Inst, VMap,
                        RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
+    }
+  }
 }
 
 /// Clones a loop \p OrigLoop.  Returns the loop and the blocks in \p
@@ -1071,6 +1120,7 @@ BasicBlock *llvm::DuplicateInstructionsInSplitBetween(
     Instruction *New = BI->clone();
     New->setName(BI->getName());
     New->insertBefore(NewTerm);
+    New->cloneDebugInfoFrom(&*BI);
     ValueMapping[&*BI] = New;
 
     // Remap operands to patch up intra-block references.

diff  --git a/llvm/lib/Transforms/Utils/CloneModule.cpp b/llvm/lib/Transforms/Utils/CloneModule.cpp
index aae0a280afeb5c7..00e40fe73d90b63 100644
--- a/llvm/lib/Transforms/Utils/CloneModule.cpp
+++ b/llvm/lib/Transforms/Utils/CloneModule.cpp
@@ -61,6 +61,7 @@ std::unique_ptr<Module> llvm::CloneModule(
   New->setDataLayout(M.getDataLayout());
   New->setTargetTriple(M.getTargetTriple());
   New->setModuleInlineAsm(M.getModuleInlineAsm());
+  New->IsNewDbgInfoFormat = M.IsNewDbgInfoFormat;
 
   // Loop over all of the global variables, making corresponding globals in the
   // new module.  Here we add them to the VMap and to the new Module.  We

diff  --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp
index 6f369737295fe3f..39d5f6e53c1de48 100644
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -1666,48 +1666,71 @@ static void fixupLineNumbers(Function *Fn, Function::iterator FI,
   // the call site location instead.
   bool NoInlineLineTables = Fn->hasFnAttribute("no-inline-line-tables");
 
-  for (; FI != Fn->end(); ++FI) {
-    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end();
-         BI != BE; ++BI) {
-      // Loop metadata needs to be updated so that the start and end locs
-      // reference inlined-at locations.
-      auto updateLoopInfoLoc = [&Ctx, &InlinedAtNode,
-                                &IANodes](Metadata *MD) -> Metadata * {
-        if (auto *Loc = dyn_cast_or_null<DILocation>(MD))
-          return inlineDebugLoc(Loc, InlinedAtNode, Ctx, IANodes).get();
-        return MD;
-      };
-      updateLoopMetadataDebugLocations(*BI, updateLoopInfoLoc);
-
-      if (!NoInlineLineTables)
-        if (DebugLoc DL = BI->getDebugLoc()) {
-          DebugLoc IDL =
-              inlineDebugLoc(DL, InlinedAtNode, BI->getContext(), IANodes);
-          BI->setDebugLoc(IDL);
-          continue;
-        }
+  // Helper-util for updating the metadata attached to an instruction.
+  auto UpdateInst = [&](Instruction &I) {
+    // Loop metadata needs to be updated so that the start and end locs
+    // reference inlined-at locations.
+    auto updateLoopInfoLoc = [&Ctx, &InlinedAtNode,
+                              &IANodes](Metadata *MD) -> Metadata * {
+      if (auto *Loc = dyn_cast_or_null<DILocation>(MD))
+        return inlineDebugLoc(Loc, InlinedAtNode, Ctx, IANodes).get();
+      return MD;
+    };
+    updateLoopMetadataDebugLocations(I, updateLoopInfoLoc);
+
+    if (!NoInlineLineTables)
+      if (DebugLoc DL = I.getDebugLoc()) {
+        DebugLoc IDL =
+            inlineDebugLoc(DL, InlinedAtNode, I.getContext(), IANodes);
+        I.setDebugLoc(IDL);
+        return;
+      }
 
-      if (CalleeHasDebugInfo && !NoInlineLineTables)
-        continue;
+    if (CalleeHasDebugInfo && !NoInlineLineTables)
+      return;
 
-      // If the inlined instruction has no line number, or if inline info
-      // is not being generated, make it look as if it originates from the call
-      // location. This is important for ((__always_inline, __nodebug__))
-      // functions which must use caller location for all instructions in their
-      // function body.
+    // If the inlined instruction has no line number, or if inline info
+    // is not being generated, make it look as if it originates from the call
+    // location. This is important for ((__always_inline, __nodebug__))
+    // functions which must use caller location for all instructions in their
+    // function body.
 
-      // Don't update static allocas, as they may get moved later.
-      if (auto *AI = dyn_cast<AllocaInst>(BI))
-        if (allocaWouldBeStaticInEntry(AI))
-          continue;
+    // Don't update static allocas, as they may get moved later.
+    if (auto *AI = dyn_cast<AllocaInst>(&I))
+      if (allocaWouldBeStaticInEntry(AI))
+        return;
 
-      // Do not force a debug loc for pseudo probes, since they do not need to
-      // be debuggable, and also they are expected to have a zero/null dwarf
-      // discriminator at this point which could be violated otherwise.
-      if (isa<PseudoProbeInst>(BI))
-        continue;
+    // Do not force a debug loc for pseudo probes, since they do not need to
+    // be debuggable, and also they are expected to have a zero/null dwarf
+    // discriminator at this point which could be violated otherwise.
+    if (isa<PseudoProbeInst>(I))
+      return;
+
+    I.setDebugLoc(TheCallDL);
+  };
 
-      BI->setDebugLoc(TheCallDL);
+  // Helper-util for updating debug-info records attached to instructions.
+  auto UpdateDPV = [&](DPValue *DPV) {
+    assert(DPV->getDebugLoc() && "Debug Value must have debug loc");
+    if (NoInlineLineTables) {
+      DPV->setDebugLoc(TheCallDL);
+      return;
+    }
+    DebugLoc DL = DPV->getDebugLoc();
+    DebugLoc IDL =
+        inlineDebugLoc(DL, InlinedAtNode,
+                       DPV->getMarker()->getParent()->getContext(), IANodes);
+    DPV->setDebugLoc(IDL);
+  };
+
+  // Iterate over all instructions, updating metadata and debug-info records.
+  for (; FI != Fn->end(); ++FI) {
+    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE;
+         ++BI) {
+      UpdateInst(*BI);
+      for (DPValue &DPV : BI->getDbgValueRange()) {
+        UpdateDPV(&DPV);
+      }
     }
 
     // Remove debug info intrinsics if we're not keeping inline info.
@@ -1717,11 +1740,12 @@ static void fixupLineNumbers(Function *Fn, Function::iterator FI,
         if (isa<DbgInfoIntrinsic>(BI)) {
           BI = BI->eraseFromParent();
           continue;
+        } else {
+          BI->dropDbgValues();
         }
         ++BI;
       }
     }
-
   }
 }
 
@@ -2402,6 +2426,7 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
       // Transfer all of the allocas over in a block.  Using splice means
       // that the instructions aren't removed from the symbol table, then
       // reinserted.
+      I.setTailBit(true);
       Caller->getEntryBlock().splice(InsertPoint, &*FirstNewBlock,
                                      AI->getIterator(), I);
     }

diff  --git a/llvm/test/DebugInfo/Generic/inline-alloca-ordering.ll b/llvm/test/DebugInfo/Generic/inline-alloca-ordering.ll
new file mode 100644
index 000000000000000..9ff3d80af80d1ef
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/inline-alloca-ordering.ll
@@ -0,0 +1,64 @@
+; RUN: opt %s --passes=inline -o - -S | FileCheck %s --implicit-check-not=dbg.value
+; RUN: opt %s --passes=inline -o - -S --try-experimental-debuginfo-iterators | FileCheck %s --implicit-check-not=dbg.value
+
+;; The inliner, specially, hoists all alloca instructions into the entry block
+;; of the calling function. Ensure that it doesn't accidentally transfer the
+;; dbg.value intrinsic from after the alloca to somewhere else. There should be
+;; one dbg.value in the resulting block after the call to ext, and before the
+;; call to init.
+;;
+;; This becomes significant in the context of non-instruction debug-info. When
+;; splicing segments of instructions around, it's typically the range from one
+;; "real" instruction to another, implicitly including all the dbg.values that
+;; come before the ending instruction. The inliner is a (unique!) location in
+;; LLVM that builds a range of only a single instruction kind (allocas) and thus
+;; doesn't transfer the dbg.value to the entry block. This needs Special
+;; Handling once we get rid of debug-intrinsics.
+
+; CHECK: declare void @llvm.dbg.value(metadata,
+
+; CHECK:    define i32 @bar()
+; CHECK-NEXT: %1 = alloca [65 x i32], align 16
+; CHECK-NEXT: call void @ext()
+; CHECK-NEXT: call void @llvm.lifetime.start.p0(
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 0, metadata !10, metadata !DIExpression()), !dbg !12
+; CHECK-NEXT: call void @init(ptr %1)
+
+declare void @ext()
+declare void @init(ptr)
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+define internal i32 @foo() !dbg !4 {
+  %1 = alloca [65 x i32], align 16
+  call void @llvm.dbg.value(metadata i32 0, metadata !11, metadata !DIExpression()), !dbg !14
+  call void @init(ptr %1)
+  %2 = load i32, ptr %1, align 4
+  ret i32 %2
+}
+
+define i32 @bar() !dbg !16 {
+  call void @ext()
+  %1 = call i32 @foo(), !dbg !17
+  ret i32 %1
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "a.cc", directory: "/tmp")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !1, file: !1, line: 3, type: !5, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null, !7}
+!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!8 = !{i32 2, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{!"clang"}
+!11 = !DILocalVariable(name: "i", arg: 1, scope: !4, file: !1, line: 3, type: !7)
+!12 = !DIExpression()
+!14 = !DILocation(line: 4, column: 7, scope: !15)
+!15 = distinct !DILexicalBlock(scope: !4, file: !1, line: 4, column: 7)
+!16 = distinct !DISubprogram(name: "bar", linkageName: "bar", scope: !1, file: !1, line: 3, type: !5, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!17 = !DILocation(line: 4, column: 7, scope: !16)

diff  --git a/llvm/test/DebugInfo/Generic/inline-dbg-values.ll b/llvm/test/DebugInfo/Generic/inline-dbg-values.ll
new file mode 100644
index 000000000000000..7d580d6fba37a94
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/inline-dbg-values.ll
@@ -0,0 +1,154 @@
+; RUN: opt -passes='cgscc(inline)' -S %s -o - -S | FileCheck %s --implicit-check-not=dbg.value
+; RUN: opt -passes='cgscc(inline)' -S %s -o - -S --try-experimental-debuginfo-iterators | FileCheck %s --implicit-check-not=dbg.value
+
+;; Test that dbg.value intrinsics are inlined, remapped, and have their
+;; dilocation updated just like normal instructions. This becomes
+;; important when debug-info records case to be instructions.
+;;
+;; test should be inlined into test2
+
+; CHECK: declare void @llvm.dbg.value(metadata,
+
+; CHECK: define i32 @test2
+; CHECK-NEXT: entry:
+; CHECK:      %k.addr.i = alloca i32, align 4
+; CHECK:      %k2.i = alloca i32, align 4
+; CHECK:      %0 = load i32, ptr @global_var, align 4, !dbg !9
+; CHECK:      store i32 %0, ptr %k.addr.i, align 4
+; CHECK-NEXT: call void @llvm.dbg.value(metadata ptr %k.addr.i, metadata ![[KVAR:[0-9]+]], metadata !DIExpression()), !dbg ![[KLINE:[0-9]+]]
+; CHECK-NEXT: call void @llvm.dbg.value(metadata ptr %k2.i, metadata ![[K2VAR:[0-9]+]], metadata !DIExpression()), !dbg ![[GLINE:[0-9]+]]
+; CHECK-NEXT: %1 = load i32, ptr %k.addr.i, align 4,
+;;
+;; dbg.values in this block should be remapped to the local load, but also
+;; the Argument to the calling test2 function.
+;;
+; CHECK: if.then.i:
+; CHECK-NEXT: %3 = load i32, ptr %k2.i,
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %3, metadata ![[KVAR]], metadata !DIExpression()), !dbg ![[KLINE]]
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %foo, metadata ![[K2VAR]], metadata !DIExpression()), !dbg ![[GLINE]]
+;
+;; Similarly, the end block should retain remapped dbg.values, with the second
+;; referring to the @global_var load in the entry block. Check that we clone
+;; from the terminator correctly.
+;
+; CHECK: if.end.i:
+; CHECK-NEXT:  store i32 0, ptr %retval.i, align 4,
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i32 0, metadata ![[KVAR]], metadata !DIExpression()), !dbg ![[KLINE]]
+; CHECK-NEXT:  call void @llvm.dbg.value(metadata i32 %0, metadata ![[K2VAR]], metadata !DIExpression()), !dbg ![[GLINE]]
+; CHECK-NEXT:  br label %test.exit,
+;
+;; More or less the same checks again in the exit block, this time at the head
+;; of the block, and on a terminator that gets elided.
+;
+; CHECK: test.exit:
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %0, metadata ![[KVAR]], metadata !DIExpression()), !dbg ![[KLINE]]
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %bar, metadata ![[K2VAR]], metadata !DIExpression()), !dbg ![[GLINE]]
+; CHECK-NEXT: %4 = load i32, ptr %retval.i, align 4,
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 1, metadata ![[KVAR]], metadata !DIExpression()), !dbg ![[KLINE]]
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 1, metadata ![[K2VAR]], metadata !DIExpression()), !dbg ![[GLINE]]
+;
+;; Test that the metadata maps onto the correct things, and that the DILocations
+;; attached to the intrinsics have been inlined.
+;
+; CHECK-DAG: ![[TEST2SP:[0-9]+]] = distinct !DISubprogram(name: "test2",
+; CHECK-DAG: ![[INLINESITEBLOCK:[0-9]+]] = distinct !DILexicalBlock(scope: ![[TEST2SP]],
+; CHECK-DAG: ![[TESTSP:[0-9]+]] = distinct !DISubprogram(name: "test",
+; CHECK-DAG: ![[KVAR]] = !DILocalVariable(name: "k",
+; CHECK-DAG: ![[K2VAR]] = !DILocalVariable(name: "k2",
+; CHECK-DAG: ![[KLINE]] = !DILocation(line: 4, scope: ![[TESTSP]], inlinedAt: ![[INLINESITE:[0-9]+]])
+; CHECK-DAG: ![[INLINESITE]] = distinct !DILocation(line: 14, scope: ![[INLINESITEBLOCK]])
+; CHECK-DAG: ![[GLINE]] = !DILocation(line: 5, scope: ![[TESTSP]], inlinedAt: ![[INLINESITE:[0-9]+]])
+
+target triple = "x86_64--"
+
+ at global_var = external global i32
+
+define internal i32 @test(i32 %k, i32 %foo, i32 %bar)  !dbg !4 {
+entry:
+  %retval = alloca i32, align 4
+  %k.addr = alloca i32, align 4
+  %k2 = alloca i32, align 4
+  store i32 %k, ptr %k.addr, align 4
+  call void @llvm.dbg.value(metadata ptr %k.addr, metadata !13, metadata !DIExpression()), !dbg !14
+  call void @llvm.dbg.value(metadata ptr %k2, metadata !15, metadata !DIExpression()), !dbg !16
+  %0 = load i32, ptr %k.addr, align 4, !dbg !16
+  %call = call i32 @_Z8test_exti(i32 %0), !dbg !16
+  store i32 %call, ptr %k2, align 4, !dbg !16
+  %1 = load i32, ptr %k2, align 4, !dbg !17
+  %cmp = icmp sgt i32 %1, 100, !dbg !17
+  br i1 %cmp, label %if.then, label %if.end, !dbg !17
+
+if.then:                                          ; preds = %entry
+  %2 = load i32, ptr %k2, align 4, !dbg !18
+  call void @llvm.dbg.value(metadata i32 %2, metadata !13, metadata !DIExpression()), !dbg !14
+  call void @llvm.dbg.value(metadata i32 %foo, metadata !15, metadata !DIExpression()), !dbg !16
+  store i32 %2, ptr %retval, !dbg !18
+  br label %return, !dbg !18
+
+if.end:                                           ; preds = %entry
+  store i32 0, ptr %retval, !dbg !19
+  call void @llvm.dbg.value(metadata i32 0, metadata !13, metadata !DIExpression()), !dbg !14
+  call void @llvm.dbg.value(metadata i32 %k, metadata !15, metadata !DIExpression()), !dbg !16
+  br label %return, !dbg !19
+
+return:                                           ; preds = %if.end, %if.then
+  call void @llvm.dbg.value(metadata i32 %k, metadata !13, metadata !DIExpression()), !dbg !14
+  call void @llvm.dbg.value(metadata i32 %bar, metadata !15, metadata !DIExpression()), !dbg !16
+  %3 = load i32, ptr %retval, !dbg !20
+  call void @llvm.dbg.value(metadata i32 1, metadata !13, metadata !DIExpression()), !dbg !14
+  call void @llvm.dbg.value(metadata i32 1, metadata !15, metadata !DIExpression()), !dbg !16
+  ret i32 %3, !dbg !20
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+declare i32 @_Z8test_exti(i32)
+
+define i32 @test2(i32 %foo, i32 %bar) !dbg !10 {
+entry:
+  %exn.slot = alloca ptr
+  %ehselector.slot = alloca i32
+  %e = alloca i32, align 4
+  %0 = load i32, ptr @global_var, align 4, !dbg !21
+  %call = call i32 @test(i32 %0, i32 %foo, i32 %bar), !dbg !21
+  br label %try.cont, !dbg !23
+
+try.cont:                                         ; preds = %catch, %invoke.cont
+  store i32 1, ptr @global_var, align 4, !dbg !29
+  ret i32 0, !dbg !30
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!31}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.3 ", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "<unknown>", directory: "")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "test", linkageName: "_Z4testi", line: 4, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 4, file: !5, scope: !6, type: !7, retainedNodes: !2)
+!5 = !DIFile(filename: "test.cpp", directory: "")
+!6 = !DIFile(filename: "test.cpp", directory: "")
+!7 = !DISubroutineType(types: !8)
+!8 = !{!9, !9}
+!9 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!10 = distinct !DISubprogram(name: "test2", linkageName: "_Z5test2v", line: 11, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 11, file: !5, scope: !6, type: !11, retainedNodes: !2)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!9}
+!13 = !DILocalVariable(name: "k", line: 4, arg: 1, scope: !4, file: !6, type: !9)
+!14 = !DILocation(line: 4, scope: !4)
+!15 = !DILocalVariable(name: "k2", line: 5, scope: !4, file: !6, type: !9)
+!16 = !DILocation(line: 5, scope: !4)
+!17 = !DILocation(line: 6, scope: !4)
+!18 = !DILocation(line: 7, scope: !4)
+!19 = !DILocation(line: 8, scope: !4)
+!20 = !DILocation(line: 9, scope: !4)
+!21 = !DILocation(line: 14, scope: !22)
+!22 = distinct !DILexicalBlock(line: 13, column: 0, file: !5, scope: !10)
+!23 = !DILocation(line: 15, scope: !22)
+!24 = !DILocalVariable(name: "e", line: 16, scope: !10, file: !6, type: !9)
+!25 = !DILocation(line: 16, scope: !10)
+!26 = !DILocation(line: 17, scope: !27)
+!27 = distinct !DILexicalBlock(line: 16, column: 0, file: !5, scope: !10)
+!28 = !DILocation(line: 18, scope: !27)
+!29 = !DILocation(line: 19, scope: !10)
+!30 = !DILocation(line: 20, scope: !10)
+!31 = !{i32 1, !"Debug Info Version", i32 3}

diff  --git a/llvm/test/DebugInfo/Generic/inline-debug-loc.ll b/llvm/test/DebugInfo/Generic/inline-debug-loc.ll
index 37e124b537b4d6c..0a704bade1e3813 100644
--- a/llvm/test/DebugInfo/Generic/inline-debug-loc.ll
+++ b/llvm/test/DebugInfo/Generic/inline-debug-loc.ll
@@ -1,4 +1,5 @@
 ; RUN: opt -passes='cgscc(inline)' -S < %s | FileCheck %s
+; RUN: opt -passes='cgscc(inline)' -S < %s --try-experimental-debuginfo-iterators | FileCheck %s
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 

diff  --git a/llvm/test/Transforms/CallSiteSplitting/callsite-split-preserve-debug.ll b/llvm/test/Transforms/CallSiteSplitting/callsite-split-preserve-debug.ll
index d14896cf9d0b5ca..e185286304a686f 100644
--- a/llvm/test/Transforms/CallSiteSplitting/callsite-split-preserve-debug.ll
+++ b/llvm/test/Transforms/CallSiteSplitting/callsite-split-preserve-debug.ll
@@ -1,10 +1,20 @@
-; RUN: opt -passes=callsite-splitting -S < %s | FileCheck %s
+; RUN: opt -passes=callsite-splitting -S < %s | FileCheck %s --implicit-check-not=dbg.value
+; RUN: opt -passes=callsite-splitting -S < %s --try-experimental-debuginfo-iterators | FileCheck %s --implicit-check-not=dbg.value
+
+;; Test that DebugLocs are preserved, and that dbg.values are duplicated.
+
+; CHECK: declare void @llvm.dbg.value(metadata,
 
 ; CHECK-LABEL: @test1
-; CHECK:         [[R1:%.+]] = call i32 @callee(i32 0, i32 %dd), !dbg [[DBG1:!.*]]
-; CHECK:         [[R2:%.+]] = call i32 @callee(i32 1, i32 %dd), !dbg [[DBG1]]
+; CHECK:         call void @llvm.dbg.value(metadata i32 0,
+; CHECK-NEXT:    [[R1:%.+]] = call i32 @callee(i32 0, i32 %dd), !dbg [[DBG1:!.*]]
+; CHECK:         call void @llvm.dbg.value(metadata i32 0,
+; CHECK-NEXT:    [[R2:%.+]] = call i32 @callee(i32 1, i32 %dd), !dbg [[DBG1]]
 ; CHECK-LABEL: CallSite:
 ; CHECK-NEXT:    phi i32 [ [[R2]], %land.rhs.split ], [ [[R1]], %entry.split ], !dbg [[DBG1]]
+; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 1,
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
 
 define i32 @test1(ptr dereferenceable(4) %cc, i32 %dd) !dbg !6 {
 entry:
@@ -15,18 +25,23 @@ land.rhs:                                         ; preds = %entry
 
 CallSite:                                         ; preds = %land.rhs, %entry
   %pv = phi i32 [ 0, %entry ], [ 1, %land.rhs ]
+  call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !18
   %call = call i32 @callee(i32 %pv, i32 %dd), !dbg !18
+  call void @llvm.dbg.value(metadata i32 1, metadata !9, metadata !DIExpression()), !dbg !18
   ret i32 %call
 }
 
 ; CHECK-LABEL: @test2
 ; CHECK:         [[LV1:%.*]] = load i32, ptr %ptr, align 4, !dbg [[DBG_LV:!.*]]
+; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 0,
 ; CHECK-NEXT:    [[R1:%.+]] = call i32 @callee(i32 0, i32 10), !dbg [[DBG_CALL:!.*]]
 ; CHECK:         [[LV2:%.*]] = load i32, ptr %ptr, align 4, !dbg [[DBG_LV]]
+; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 0,
 ; CHECK-NEXT:    [[R2:%.+]] = call i32 @callee(i32 0, i32 %i), !dbg [[DBG_CALL]]
 ; CHECK-LABEL: CallSite:
 ; CHECK-NEXT:    phi i32 [ [[LV1]], %Header.split ], [ [[LV2]], %TBB.split ], !dbg [[DBG_LV]]
 ; CHECK-NEXT:    phi i32 [ [[R1]], %Header.split ], [ [[R2]], %TBB.split ], !dbg [[DBG_CALL]]
+; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 1,
 
 define void @test2(ptr %ptr, i32 %i) !dbg !19 {
 Header:
@@ -38,7 +53,9 @@ TBB:                                              ; preds = %Header
 
 CallSite:                                         ; preds = %TBB, %Header
   %lv = load i32, ptr %ptr, align 4, !dbg !25
+  call void @llvm.dbg.value(metadata i32 0, metadata !21, metadata !DIExpression()), !dbg !26
   %cv = call i32 @callee(i32 0, i32 %i), !dbg !26
+  call void @llvm.dbg.value(metadata i32 1, metadata !21, metadata !DIExpression()), !dbg !26
   %sub = sub nsw i32 %lv, %cv
   br label %End
 

diff  --git a/llvm/test/Transforms/Inline/alloca-dbgdeclare.ll b/llvm/test/Transforms/Inline/alloca-dbgdeclare.ll
index 7fc1bdd8ed68db4..9592333aeb5420d 100644
--- a/llvm/test/Transforms/Inline/alloca-dbgdeclare.ll
+++ b/llvm/test/Transforms/Inline/alloca-dbgdeclare.ll
@@ -1,5 +1,8 @@
 ; RUN: opt -passes=inline -S < %s | FileCheck %s
 ; RUN: opt -passes='cgscc(inline)' -S < %s | FileCheck %s
+
+; RUN: opt -passes=inline -S < %s --try-experimental-debuginfo-iterators | FileCheck %s
+; RUN: opt -passes='cgscc(inline)' -S < %s --try-experimental-debuginfo-iterators | FileCheck %s
 ; struct A {
 ;   int arg0;
 ;   double arg1[2];

diff  --git a/llvm/test/Transforms/Inline/delete-function-with-metadata-use.ll b/llvm/test/Transforms/Inline/delete-function-with-metadata-use.ll
index 8176135a5b538d5..8399cd63847ed7e 100644
--- a/llvm/test/Transforms/Inline/delete-function-with-metadata-use.ll
+++ b/llvm/test/Transforms/Inline/delete-function-with-metadata-use.ll
@@ -1,4 +1,5 @@
 ; RUN: opt -passes=inline < %s -S | FileCheck %s
+; RUN: opt -passes=inline < %s -S --try-experimental-debuginfo-iterators | FileCheck %s
 
 ; CHECK: define {{.*}}@f1
 ; CHECK-NOT: define

diff  --git a/llvm/test/Transforms/Inline/ignore-debug-info.ll b/llvm/test/Transforms/Inline/ignore-debug-info.ll
index 7ccf7e86bac2ad8..ff697b5c8ab32d9 100644
--- a/llvm/test/Transforms/Inline/ignore-debug-info.ll
+++ b/llvm/test/Transforms/Inline/ignore-debug-info.ll
@@ -3,6 +3,9 @@
 ; RUN: opt < %s -S -passes='cgscc(inline)' -inline-threshold=2 | FileCheck %s
 ; RUN: opt < %s -S -strip-debug -passes='cgscc(inline)' -inline-threshold=2 | FileCheck %s
 ;
+; RUN: opt < %s -S -passes=inline -inline-threshold=2 --try-experimental-debuginfo-iterators | FileCheck %s
+; RUN: opt < %s -S -passes='cgscc(inline)' -inline-threshold=2 --try-experimental-debuginfo-iterators | FileCheck %s
+;
 ; The purpose of this test is to check that debug info doesn't influence
 ; inlining decisions.
 

diff  --git a/llvm/test/Transforms/Inline/inline-skip-use-empty-alloca.ll b/llvm/test/Transforms/Inline/inline-skip-use-empty-alloca.ll
index e2660e2648b7637..ea298a4556f4302 100644
--- a/llvm/test/Transforms/Inline/inline-skip-use-empty-alloca.ll
+++ b/llvm/test/Transforms/Inline/inline-skip-use-empty-alloca.ll
@@ -1,5 +1,7 @@
 ; RUN: opt < %s -S -passes=inline | FileCheck %s
 ; RUN: opt < %s -S -strip-debug -passes=inline | FileCheck %s
+;
+; RUN: opt < %s -S -passes=inline --try-experimental-debuginfo-iterators | FileCheck %s
 
 ; https://bugs.llvm.org/show_bug.cgi?id=43291
 ; The purpose of this test is to check if there is use_empty in the inner loop when scanning

diff  --git a/llvm/test/Transforms/Inline/local-as-metadata-undominated-use.ll b/llvm/test/Transforms/Inline/local-as-metadata-undominated-use.ll
index 2a9e55a83e51476..83f9a3a778d7f58 100644
--- a/llvm/test/Transforms/Inline/local-as-metadata-undominated-use.ll
+++ b/llvm/test/Transforms/Inline/local-as-metadata-undominated-use.ll
@@ -1,5 +1,7 @@
 ; RUN: opt -passes=inline -S < %s | FileCheck %s
 ; RUN: opt -passes='cgscc(inline)' -S < %s | FileCheck %s
+;
+; RUN: opt -passes=inline -S < %s --try-experimental-debuginfo-iterators | FileCheck %s
 
 ; Make sure the inliner doesn't crash when a metadata-bridged SSA operand is an
 ; undominated use.

diff  --git a/llvm/test/Transforms/Inline/no-inline-line-tables.ll b/llvm/test/Transforms/Inline/no-inline-line-tables.ll
index e298088d1fce594..4aeb94da776e973 100644
--- a/llvm/test/Transforms/Inline/no-inline-line-tables.ll
+++ b/llvm/test/Transforms/Inline/no-inline-line-tables.ll
@@ -1,4 +1,5 @@
 ; RUN: opt < %s -passes=inline -S | FileCheck %s
+; RUN: opt < %s -passes=inline -S --try-experimental-debuginfo-iterators | FileCheck %s
 
 ; This tests that functions with the attribute `no-inline-line-tables` have the
 ; correct debug information when they are inlined.

diff  --git a/llvm/test/Transforms/JumpThreading/guard-split-debuginfo.ll b/llvm/test/Transforms/JumpThreading/guard-split-debuginfo.ll
new file mode 100644
index 000000000000000..05ff74939449cd5
--- /dev/null
+++ b/llvm/test/Transforms/JumpThreading/guard-split-debuginfo.ll
@@ -0,0 +1,80 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=jump-threading %s -o - -S | FileCheck %s
+; RUN: opt -S -passes=jump-threading %s -o - -S --try-experimental-debuginfo-iterators | FileCheck %s
+
+; Test that debug-info records in the Merge block, to be copied by
+; DuplicateInstructionsInSplitBetween, get duplicated into the relevant
+; parent blocks. And that ino jump-threading, the old dbg.value gets
+; deleted.
+
+declare void @llvm.experimental.guard(i1, ...)
+
+declare i32 @f1()
+declare i32 @f2()
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+define i32 @branch_implies_guard(i32 %a) !dbg !7 {
+; CHECK-LABEL: @branch_implies_guard(
+; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[A:%.*]], 10
+; CHECK-NEXT:    br i1 [[COND]], label [[T1_SPLIT:%.*]], label [[F1_SPLIT:%.*]], !dbg [[DBG12:![0-9]+]]
+; CHECK:       T1.split:
+; CHECK-NEXT:    [[V1:%.*]] = call i32 @f1(), !dbg [[DBG12]]
+; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 0, metadata [[META13:![0-9]+]], metadata !DIExpression()), !dbg [[DBG14:![0-9]+]]
+; CHECK-NEXT:    [[RETVAL3:%.*]] = add i32 [[V1]], 10, !dbg [[DBG12]]
+; CHECK-NEXT:    [[CONDGUARD4:%.*]] = icmp slt i32 [[A]], 20, !dbg [[DBG12]]
+; CHECK-NEXT:    br label [[MERGE:%.*]]
+; CHECK:       F1.split:
+; CHECK-NEXT:    [[V2:%.*]] = call i32 @f2(), !dbg [[DBG12]]
+; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 0, metadata [[META13]], metadata !DIExpression()), !dbg [[DBG14]]
+; CHECK-NEXT:    [[RETVAL1:%.*]] = add i32 [[V2]], 10, !dbg [[DBG12]]
+; CHECK-NEXT:    [[CONDGUARD2:%.*]] = icmp slt i32 [[A]], 20, !dbg [[DBG12]]
+; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD2]]) [ "deopt"() ]
+; CHECK-NEXT:    br label [[MERGE]]
+; CHECK:       Merge:
+; CHECK-NEXT:    [[RETPHI:%.*]] = phi i32 [ [[V1]], [[T1_SPLIT]] ], [ [[V2]], [[F1_SPLIT]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = phi i32 [ [[RETVAL3]], [[T1_SPLIT]] ], [ [[RETVAL1]], [[F1_SPLIT]] ]
+; CHECK-NEXT:    ret i32 [[TMP1]], !dbg [[DBG12]]
+;
+  %cond = icmp slt i32 %a, 10
+  br i1 %cond, label %T1, label %F1, !dbg !26
+
+T1:
+  %v1 = call i32 @f1(), !dbg !26
+  br label %Merge
+
+F1:
+  %v2 = call i32 @f2(), !dbg !26
+  br label %Merge
+
+Merge:
+  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
+  call void @llvm.dbg.value(metadata i32 0, metadata !12, metadata !DIExpression()), !dbg !13
+  %retVal = add i32 %retPhi, 10, !dbg !26
+  %condGuard = icmp slt i32 %a, 20, !dbg !26
+  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
+  ret i32 %retVal, !dbg !26
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/out.c")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!""}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !11, !11}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed)
+!12 = !DILocalVariable(name: "bar", arg: 1, scope: !7, file: !1, line: 3, type: !11)
+!13 = !DILocation(line: 0, scope: !7)
+!14 = !DILocalVariable(name: "baz", arg: 2, scope: !7, file: !1, line: 3, type: !11)
+!19 = distinct !DILexicalBlock(scope: !7, file: !1, line: 8, column: 7)
+!26 = !DILocation(line: 13, column: 3, scope: !7)
+

diff  --git a/llvm/test/Transforms/LoopUnroll/debug-info.ll b/llvm/test/Transforms/LoopUnroll/debug-info.ll
index 65553ee3af5427f..2188cea3b881148 100644
--- a/llvm/test/Transforms/LoopUnroll/debug-info.ll
+++ b/llvm/test/Transforms/LoopUnroll/debug-info.ll
@@ -1,4 +1,5 @@
 ; RUN: opt %s -S -o - -passes=loop-unroll | FileCheck %s
+; RUN: opt %s -S -o - -passes=loop-unroll --try-experimental-debuginfo-iterators | FileCheck %s
 ; generated at -O3 from:
 ; void f() {
 ;   for (int i = 1; i <=32; i <<=2 )


        


More information about the llvm-commits mailing list