[llvm] b002b38 - [DebugInfo][RemoveDIs] Add new behind-the-scenes plumbing for debug-info

Jeremy Morse via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 9 07:33:59 PST 2023


Author: Jeremy Morse
Date: 2023-11-09T15:25:39Z
New Revision: b002b38fd9f9bd66c7364eb4e9d639da9a5a66c7

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

LOG: [DebugInfo][RemoveDIs] Add new behind-the-scenes plumbing for debug-info

This is the "central" patch to the removing-debug-intrinsics project: it
changes the instruction movement APIs (insert, move, splice) to interpret
the "Head" bits we're attaching to BasicBlock::iterators, and updates
debug-info records in the background to preserve the ordering of debug-info
(which is in DPValue objects instead of dbg.values). The cost is the
complexity of this patch, plus memory. The benefit is that LLVM developers
can cease thinking about whether they're moving debug-info or not, because
it'll happen behind the scenes.

All that complexity appears in BasicBlock::spliceDebugInfo, see the diagram
there for how we now manually shuffle debug-info around. Each potential
splice configuration gets tested in the added unit tests.

The rest of this patch applies the same reasoning in a variety of
scenarios. When moveBefore (and it's siblings) are used to move
instructions around, the caller has to indicate whether they intend for
debug-info to move too (is it a "Preserving" call or not), and then the
"Head" bits used to determine where debug-info moves to. Similar reasoning
is needed for insertBefore.

Differential Revision: https://reviews.llvm.org/D154353

Added: 
    llvm/unittests/IR/BasicBlockDbgInfoTest.cpp

Modified: 
    llvm/include/llvm/IR/BasicBlock.h
    llvm/include/llvm/IR/Instruction.h
    llvm/lib/IR/BasicBlock.cpp
    llvm/lib/IR/DebugProgramInstruction.cpp
    llvm/lib/IR/Instruction.cpp
    llvm/unittests/IR/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h
index aede5e6c69464ab..ec916acc25151c8 100644
--- a/llvm/include/llvm/IR/BasicBlock.h
+++ b/llvm/include/llvm/IR/BasicBlock.h
@@ -19,6 +19,7 @@
 #include "llvm/ADT/ilist_node.h"
 #include "llvm/ADT/iterator.h"
 #include "llvm/ADT/iterator_range.h"
+#include "llvm/IR/DebugProgramInstruction.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/DebugProgramInstruction.h"
 #include "llvm/IR/SymbolTableListTraits.h"
@@ -118,6 +119,28 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
 
   void dumpDbgValues() const;
 
+  /// Return the DPMarker for the position given by \p It, so that DPValues can
+  /// be inserted there. This will either be nullptr if not present, a DPMarker,
+  /// or TrailingDPValues if It is end().
+  DPMarker *getMarker(InstListType::iterator It);
+
+  /// Return the DPMarker for the position that comes after \p I. \see
+  /// BasicBlock::getMarker, this can be nullptr, a DPMarker, or
+  /// TrailingDPValues if there is no next instruction.
+  DPMarker *getNextMarker(Instruction *I);
+
+  /// Insert a DPValue into a block at the position given by \p I.
+  void insertDPValueAfter(DPValue *DPV, Instruction *I);
+
+  /// Insert a DPValue into a block at the position given by \p Here.
+  void insertDPValueBefore(DPValue *DPV, InstListType::iterator Here);
+
+  /// Eject any debug-info trailing at the end of a block. DPValues can
+  /// transiently be located "off the end" of a block if the blocks terminator
+  /// is temporarily removed. Once a terminator is re-inserted this method will
+  /// move such DPValues back to the right place (ahead of the terminator).
+  void flushTerminatorDbgValues();
+
 private:
   void setParent(Function *parent);
 
@@ -154,6 +177,19 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
   friend class llvm::ilist_node_with_parent<llvm::Instruction, llvm::BasicBlock,
                                             ilist_iterator_bits<true>>;
 
+  // Friendly methods that need to access us for the maintenence of
+  // debug-info attachments.
+  friend void Instruction::insertBefore(BasicBlock::iterator InsertPos);
+  friend void Instruction::insertAfter(Instruction *InsertPos);
+  friend void Instruction::insertBefore(BasicBlock &BB,
+                                        InstListType::iterator InsertPos);
+  friend void Instruction::moveBeforeImpl(BasicBlock &BB,
+                                          InstListType::iterator I,
+                                          bool Preserve);
+  friend iterator_range<DPValue::self_iterator> Instruction::cloneDebugInfoFrom(
+      const Instruction *From, std::optional<DPValue::self_iterator> FromHere,
+      bool InsertAtHead);
+
   /// Creates a new BasicBlock.
   ///
   /// If the Parent parameter is specified, the basic block is automatically
@@ -478,6 +514,21 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
     return &BasicBlock::InstList;
   }
 
+  /// Dedicated function for splicing debug-info: when we have an empty
+  /// splice (i.e. zero instructions), the caller may still intend any
+  /// debug-info in between the two "positions" to be spliced.
+  void spliceDebugInfoEmptyBlock(BasicBlock::iterator ToIt, BasicBlock *FromBB,
+                                 BasicBlock::iterator FromBeginIt,
+                                 BasicBlock::iterator FromEndIt);
+
+  /// Perform any debug-info specific maintenence for the given splice
+  /// activity. In the DPValue debug-info representation, debug-info is not
+  /// in instructions, and so it does not automatically move from one block
+  /// to another.
+  void spliceDebugInfo(BasicBlock::iterator ToIt, BasicBlock *FromBB,
+                       BasicBlock::iterator FromBeginIt,
+                       BasicBlock::iterator FromEndIt);
+
 public:
   /// Returns a pointer to the symbol table if one exists.
   ValueSymbolTable *getValueSymbolTable();

diff  --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 7f694219b15a7b9..58fc32237367d93 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -59,6 +59,38 @@ class Instruction : public User,
   /// debugging information present.
   DPMarker *DbgMarker = nullptr;
 
+  /// Clone any debug-info attached to \p From onto this instruction. Used to
+  /// copy debugging information from one block to another, when copying entire
+  /// blocks. \see DebugProgramInstruction.h , because the ordering of DPValues
+  /// is still important, fine grain control of which instructions are moved and
+  /// where they go is necessary.
+  /// \p From The instruction to clone debug-info from.
+  /// \p from_here Optional iterator to limit DPValues cloned to be a range from
+  ///    from_here to end().
+  /// \p InsertAtHead Whether the cloned DPValues should be placed at the end
+  ///    or the beginning of existing DPValues attached to this.
+  /// \returns A range over the newly cloned DPValues.
+  iterator_range<simple_ilist<DPValue>::iterator> cloneDebugInfoFrom(
+      const Instruction *From,
+      std::optional<simple_ilist<DPValue>::iterator> FromHere = std::nullopt,
+      bool InsertAtHead = false);
+
+  /// Return a range over the DPValues attached to this instruction.
+  iterator_range<simple_ilist<DPValue>::iterator> getDbgValueRange() const;
+
+  /// Returns true if any DPValues are attached to this instruction.
+  bool hasDbgValues() const;
+
+  /// Erase any DPValues attached to this instruction.
+  void dropDbgValues();
+
+  /// Erase a single DPValue \p I that is attached to this instruction.
+  void dropOneDbgValue(DPValue *I);
+
+  /// Handle the debug-info implications of this instruction being removed. Any
+  /// attached DPValues need to "fall" down onto the next instruction.
+  void handleMarkerRemoval();
+
 protected:
   // The 15 first bits of `Value::SubclassData` are available for subclasses of
   // `Instruction` to use.
@@ -135,9 +167,7 @@ class Instruction : public User,
   /// Insert an unlinked instruction into a basic block immediately before
   /// the specified instruction.
   void insertBefore(Instruction *InsertPos);
-  void insertBefore(InstListType::iterator InsertPos) {
-    insertBefore(&*InsertPos);
-  }
+  void insertBefore(InstListType::iterator InsertPos);
 
   /// Insert an unlinked instruction into a basic block immediately after the
   /// specified instruction.
@@ -148,9 +178,7 @@ class Instruction : public User,
   InstListType::iterator insertInto(BasicBlock *ParentBB,
                                     InstListType::iterator It);
 
-  void insertBefore(BasicBlock &BB, InstListType::iterator InsertPos) {
-    insertInto(&BB, InsertPos);
-  }
+  void insertBefore(BasicBlock &BB, InstListType::iterator InsertPos);
 
   /// Unlink this instruction from its current basic block and insert it into
   /// the basic block that MovePos lives in, right before MovePos.
@@ -161,28 +189,28 @@ class Instruction : public User,
   /// means that any adjacent debug-info should move with this instruction.
   /// This method is currently a no-op placeholder, but it will become meaningful
   /// when the "RemoveDIs" project is enabled.
-  void moveBeforePreserving(Instruction *MovePos) {
-    moveBefore(MovePos);
-  }
+  void moveBeforePreserving(Instruction *MovePos);
 
+private:
+  /// RemoveDIs project: all other moves implemented with this method,
+  /// centralising debug-info updates into one place.
+  void moveBeforeImpl(BasicBlock &BB, InstListType::iterator I, bool Preserve);
+
+public:
   /// Unlink this instruction and insert into BB before I.
   ///
   /// \pre I is a valid iterator into BB.
   void moveBefore(BasicBlock &BB, InstListType::iterator I);
 
   /// (See other overload for moveBeforePreserving).
-  void moveBeforePreserving(BasicBlock &BB, InstListType::iterator I) {
-    moveBefore(BB, I);
-  }
+  void moveBeforePreserving(BasicBlock &BB, InstListType::iterator I);
 
   /// Unlink this instruction from its current basic block and insert it into
   /// the basic block that MovePos lives in, right after MovePos.
   void moveAfter(Instruction *MovePos);
 
   /// See \ref moveBeforePreserving .
-  void moveAfterPreserving(Instruction *MovePos) {
-    moveAfter(MovePos);
-  }
+  void moveAfterPreserving(Instruction *MovePos);
 
   /// Given an instruction Other in the same basic block as this instruction,
   /// return true if this instruction comes before Other. In this worst case,

diff  --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index d238b651a69a068..19f2a9af9fa13cc 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -661,18 +661,6 @@ BasicBlock *BasicBlock::splitBasicBlockBefore(iterator I, const Twine &BBName) {
   return New;
 }
 
-void BasicBlock::splice(BasicBlock::iterator ToIt, BasicBlock *FromBB,
-                        BasicBlock::iterator FromBeginIt,
-                        BasicBlock::iterator FromEndIt) {
-#ifdef EXPENSIVE_CHECKS
-  // Check that FromBeginIt is befor FromEndIt.
-  auto FromBBEnd = FromBB->end();
-  for (auto It = FromBeginIt; It != FromEndIt; ++It)
-    assert(It != FromBBEnd && "FromBeginIt not before FromEndIt!");
-#endif // EXPENSIVE_CHECKS
-  getInstList().splice(ToIt, FromBB->getInstList(), FromBeginIt, FromEndIt);
-}
-
 BasicBlock::iterator BasicBlock::erase(BasicBlock::iterator FromIt,
                                        BasicBlock::iterator ToIt) {
   return InstList.erase(FromIt, ToIt);
@@ -744,6 +732,274 @@ void BasicBlock::renumberInstructions() {
   NumInstrRenumberings++;
 }
 
+void BasicBlock::flushTerminatorDbgValues() {
+  // If we erase the terminator in a block, any DPValues will sink and "fall
+  // off the end", existing after any terminator that gets inserted. With
+  // dbg.value intrinsics we would just insert the terminator at end() and
+  // the dbg.values would come before the terminator. With DPValues, we must
+  // do this manually.
+  // To get out of this unfortunate form, whenever we insert a terminator,
+  // check whether there's anything trailing at the end and move those DPValues
+  // in front of the terminator.
+
+  // Do nothing if we're not in new debug-info format.
+  if (!IsNewDbgInfoFormat)
+    return;
+
+  // If there's no terminator, there's nothing to do.
+  Instruction *Term = getTerminator();
+  if (!Term)
+    return;
+
+  // Are there any dangling DPValues?
+  DPMarker *TrailingDPValues = getTrailingDPValues();
+  if (!TrailingDPValues)
+    return;
+
+  // Transfer DPValues from the trailing position onto the terminator.
+  Term->DbgMarker->absorbDebugValues(*TrailingDPValues, false);
+  deleteTrailingDPValues();
+}
+
+void BasicBlock::spliceDebugInfoEmptyBlock(BasicBlock::iterator Dest,
+                                           BasicBlock *Src,
+                                           BasicBlock::iterator First,
+                                           BasicBlock::iterator Last) {
+  // Imagine the folowing:
+  //
+  //   bb1:
+  //     dbg.value(...
+  //     ret i32 0
+  //
+  // If an optimisation pass attempts to splice the contents of the block from
+  // BB1->begin() to BB1->getTerminator(), then the dbg.value will be
+  // transferred to the destination.
+  // However, in the "new" DPValue format for debug-info, that range is empty:
+  // begin() returns an iterator to the terminator, as there will only be a
+  // single instruction in the block. We must piece together from the bits set
+  // in the iterators whether there was the intention to transfer any debug
+  // info.
+
+  // If we're not in "new" debug-info format, do nothing.
+  if (!IsNewDbgInfoFormat)
+    return;
+
+  assert(First == Last);
+  bool InsertAtHead = Dest.getHeadBit();
+  bool ReadFromHead = First.getHeadBit();
+
+  // If the source block is completely empty, including no terminator, then
+  // transfer any trailing DPValues that are still hanging around. This can
+  // occur when a block is optimised away and the terminator has been moved
+  // somewhere else.
+  if (Src->empty()) {
+    assert(Dest != end() &&
+           "Transferring trailing DPValues to another trailing position");
+    DPMarker *SrcTrailingDPValues = Src->getTrailingDPValues();
+    if (!SrcTrailingDPValues)
+      return;
+
+    DPMarker *M = Dest->DbgMarker;
+    M->absorbDebugValues(*SrcTrailingDPValues, InsertAtHead);
+    Src->deleteTrailingDPValues();
+    return;
+  }
+
+  // There are instructions in this block; if the First iterator was
+  // with begin() / getFirstInsertionPt() then the caller intended debug-info
+  // at the start of the block to be transferred.
+  if (!Src->empty() && First == Src->begin() && ReadFromHead)
+    Dest->DbgMarker->absorbDebugValues(*First->DbgMarker, InsertAtHead);
+
+  return;
+}
+
+void BasicBlock::spliceDebugInfo(BasicBlock::iterator Dest, BasicBlock *Src,
+                                 BasicBlock::iterator First,
+                                 BasicBlock::iterator Last) {
+  // Find out where to _place_ these dbg.values; if InsertAtHead is specified,
+  // this will be at the start of Dest's debug value range, otherwise this is
+  // just Dest's marker.
+  bool InsertAtHead = Dest.getHeadBit();
+  bool ReadFromHead = First.getHeadBit();
+  // Use this flag to signal the abnormal case, where we don't want to copy the
+  // DPValues ahead of the "Last" position.
+  bool ReadFromTail = !Last.getTailBit();
+
+  /*
+    Here's an illustration of what we're about to do. We have two blocks, this
+    and Src, and two segments of list. Each instruction is marked by a capital
+    while potential DPValue debug-info is marked out by "-" characters and a few
+    other special characters (+:=) where I want to highlight what's going on.
+
+                                                 Dest
+                                                   |
+     this-block:    A----A----A                ====A----A----A----A---A---A
+      Src-block                ++++B---B---B---B:::C
+                                   |               |
+                                  First           Last
+
+    The splice method is going to take all the instructions from First up to
+    (but not including) Last and insert them in _front_ of Dest, forming one
+    long list. All the DPValues attached to instructions _between_ First and
+    Last need no maintenence. However, we have to do special things with the
+    DPValues marked with the +:= characters. We only have three positions:
+    should the "+" DPValues be transferred, and if so to where? Do we move the
+    ":" DPValues? Would they go in front of the "=" DPValues, or should the "="
+    DPValues go before "+" DPValues?
+
+    We're told which way it should be by the bits carried in the iterators. The
+    "Head" bit indicates whether the specified position is supposed to be at the
+    front of the attached DPValues (true) or not (false). The Tail bit is true
+    on the other end of a range: is the range intended to include DPValues up to
+    the end (false) or not (true).
+
+    FIXME: the tail bit doesn't need to be distinct from the head bit, we could
+    combine them.
+
+    Here are some examples of 
diff erent configurations:
+
+      Dest.Head = true, First.Head = true, Last.Tail = false
+
+      this-block:    A----A----A++++B---B---B---B:::====A----A----A----A---A---A
+                                    |                   |
+                                  First                Dest
+
+    Wheras if we didn't want to read from the Src list,
+
+      Dest.Head = true, First.Head = false, Last.Tail = false
+
+      this-block:    A----A----AB---B---B---B:::====A----A----A----A---A---A
+                                |                   |
+                              First                Dest
+
+    Or if we didn't want to insert at the head of Dest:
+
+      Dest.Head = false, First.Head = false, Last.Tail = false
+
+      this-block:    A----A----A====B---B---B---B:::A----A----A----A---A---A
+                                    |               |
+                                  First            Dest
+
+    Tests for these various configurations can be found in the unit test file
+    BasicBlockDbgInfoTest.cpp.
+
+   */
+
+  // Detach the marker at Dest -- this lets us move the "====" DPValues around.
+  DPMarker *DestMarker = nullptr;
+  if (Dest != end()) {
+    DestMarker = getMarker(Dest);
+    DestMarker->removeFromParent();
+    createMarker(&*Dest);
+  }
+
+  // If we're moving the tail range of DPValues (":::"), absorb them into the
+  // front of the DPValues at Dest.
+  if (ReadFromTail && Src->getMarker(Last)) {
+    DPMarker *OntoDest = getMarker(Dest);
+    DPMarker *FromLast = Src->getMarker(Last);
+    OntoDest->absorbDebugValues(*FromLast, true);
+  }
+
+  // If we're _not_ reading from the head of First, i.e. the "++++" DPValues,
+  // move their markers onto Last. They remain in the Src block. No action
+  // needed.
+  if (!ReadFromHead) {
+    DPMarker *OntoLast = Src->getMarker(Last);
+    DPMarker *FromFirst = Src->getMarker(First);
+    OntoLast->absorbDebugValues(*FromFirst,
+                                true); // Always insert at head of it.
+  }
+
+  // Finally, do something with the "====" DPValues we detached.
+  if (DestMarker) {
+    if (InsertAtHead) {
+      // Insert them at the end of the DPValues at Dest. The "::::" DPValues
+      // might be in front of them.
+      DPMarker *NewDestMarker = getMarker(Dest);
+      NewDestMarker->absorbDebugValues(*DestMarker, false);
+    } else {
+      // Insert them right at the start of the range we moved, ahead of First
+      // and the "++++" DPValues.
+      DPMarker *FirstMarker = getMarker(First);
+      FirstMarker->absorbDebugValues(*DestMarker, true);
+    }
+    DestMarker->eraseFromParent();
+  } else if (Dest == end() && !InsertAtHead) {
+    // In the rare circumstance where we insert at end(), and we did not
+    // generate the iterator with begin() / getFirstInsertionPt(), it means
+    // any trailing debug-info at the end of the block would "normally" have
+    // been pushed in front of "First". Move it there now.
+    DPMarker *FirstMarker = getMarker(First);
+    DPMarker *TrailingDPValues = getTrailingDPValues();
+    if (TrailingDPValues) {
+      FirstMarker->absorbDebugValues(*TrailingDPValues, true);
+      deleteTrailingDPValues();
+    }
+  }
+}
+
+void BasicBlock::splice(iterator Dest, BasicBlock *Src, iterator First,
+                        iterator Last) {
+  assert(Src->IsNewDbgInfoFormat == IsNewDbgInfoFormat);
+
+#ifdef EXPENSIVE_CHECKS
+  // Check that First is before Last.
+  auto FromBBEnd = Src->end();
+  for (auto It = First; It != Last; ++It)
+    assert(It != FromBBEnd && "FromBeginIt not before FromEndIt!");
+#endif // EXPENSIVE_CHECKS
+
+  // Lots of horrible special casing for empty transfers: the dbg.values between
+  // two positions could be spliced in dbg.value mode.
+  if (First == Last) {
+    spliceDebugInfoEmptyBlock(Dest, Src, First, Last);
+    return;
+  }
+
+  // Handle non-instr debug-info specific juggling.
+  if (IsNewDbgInfoFormat)
+    spliceDebugInfo(Dest, Src, First, Last);
+
+  // And move the instructions.
+  getInstList().splice(Dest, Src->getInstList(), First, Last);
+
+  flushTerminatorDbgValues();
+}
+
+void BasicBlock::insertDPValueAfter(DPValue *DPV, Instruction *I) {
+  assert(IsNewDbgInfoFormat);
+  assert(I->getParent() == this);
+
+  iterator NextIt = std::next(I->getIterator());
+  DPMarker *NextMarker =
+      (NextIt == end()) ? getTrailingDPValues() : NextIt->DbgMarker;
+  NextMarker->insertDPValue(DPV, true);
+}
+
+void BasicBlock::insertDPValueBefore(DPValue *DPV,
+                                     InstListType::iterator Where) {
+  // We should never directly insert at the end of the block, new DPValues
+  // shouldn't be generated at times when there's no terminator.
+  assert(Where != end());
+  assert(Where->getParent() == this);
+  bool InsertAtHead = Where.getHeadBit();
+  Where->DbgMarker->insertDPValue(DPV, InsertAtHead);
+}
+
+DPMarker *BasicBlock::getNextMarker(Instruction *I) {
+  return getMarker(std::next(I->getIterator()));
+}
+
+DPMarker *BasicBlock::getMarker(InstListType::iterator It) {
+  if (It == end()) {
+    DPMarker *DPM = getTrailingDPValues();
+    return DPM;
+  }
+  return It->DbgMarker;
+}
+
 #ifndef NDEBUG
 /// In asserts builds, this checks the numbering. In non-asserts builds, it
 /// is defined as a no-op inline function in BasicBlock.h.

diff  --git a/llvm/lib/IR/DebugProgramInstruction.cpp b/llvm/lib/IR/DebugProgramInstruction.cpp
index c307cd42a6336da..581d77a26acb80a 100644
--- a/llvm/lib/IR/DebugProgramInstruction.cpp
+++ b/llvm/lib/IR/DebugProgramInstruction.cpp
@@ -285,15 +285,10 @@ void DPMarker::removeMarker() {
   // The attached DPValues need to be preserved; attach them to the next
   // instruction. If there isn't a next instruction, put them on the
   // "trailing" list.
-  // (This logic gets refactored in a future patch, needed to break some
-  //  dependencies here).
-  BasicBlock::iterator NextInst = std::next(Owner->getIterator());
-  DPMarker *NextMarker;
-  if (NextInst == Owner->getParent()->end()) {
+  DPMarker *NextMarker = Owner->getParent()->getNextMarker(Owner);
+  if (NextMarker == nullptr) {
     NextMarker = new DPMarker();
     Owner->getParent()->setTrailingDPValues(NextMarker);
-  } else {
-    NextMarker = NextInst->DbgMarker;
   }
   NextMarker->absorbDebugValues(*this, true);
 

diff  --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 1b3c03348f41a70..b6bb00edae4ac9f 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -77,23 +77,45 @@ const Function *Instruction::getFunction() const {
 }
 
 void Instruction::removeFromParent() {
+  // Perform any debug-info maintenence required.
+  handleMarkerRemoval();
+
   getParent()->getInstList().remove(getIterator());
 }
 
+void Instruction::handleMarkerRemoval() {
+  if (!Parent->IsNewDbgInfoFormat || !DbgMarker)
+    return;
+
+  DbgMarker->removeMarker();
+}
+
 BasicBlock::iterator Instruction::eraseFromParent() {
+  handleMarkerRemoval();
   return getParent()->getInstList().erase(getIterator());
 }
 
+void Instruction::insertBefore(Instruction *InsertPos) {
+  insertBefore(InsertPos->getIterator());
+}
+
 /// Insert an unlinked instruction into a basic block immediately before the
 /// specified instruction.
-void Instruction::insertBefore(Instruction *InsertPos) {
-  insertInto(InsertPos->getParent(), InsertPos->getIterator());
+void Instruction::insertBefore(BasicBlock::iterator InsertPos) {
+  insertBefore(*InsertPos->getParent(), InsertPos);
 }
 
 /// Insert an unlinked instruction into a basic block immediately after the
 /// specified instruction.
 void Instruction::insertAfter(Instruction *InsertPos) {
-  insertInto(InsertPos->getParent(), std::next(InsertPos->getIterator()));
+  BasicBlock *DestParent = InsertPos->getParent();
+
+  DestParent->getInstList().insertAfter(InsertPos->getIterator(), this);
+
+  // No need to manually update DPValues: if we insert after an instruction
+  // position, then we can never have any DPValues on "this".
+  if (DestParent->IsNewDbgInfoFormat)
+    DestParent->createMarker(this);
 }
 
 BasicBlock::iterator Instruction::insertInto(BasicBlock *ParentBB,
@@ -101,22 +123,142 @@ BasicBlock::iterator Instruction::insertInto(BasicBlock *ParentBB,
   assert(getParent() == nullptr && "Expected detached instruction");
   assert((It == ParentBB->end() || It->getParent() == ParentBB) &&
          "It not in ParentBB");
-  return ParentBB->getInstList().insert(It, this);
+  insertBefore(*ParentBB, It);
+  return getIterator();
+}
+
+extern cl::opt<bool> UseNewDbgInfoFormat;
+
+void Instruction::insertBefore(BasicBlock &BB,
+                               InstListType::iterator InsertPos) {
+  assert(!DbgMarker);
+
+  BB.getInstList().insert(InsertPos, this);
+
+  if (!BB.IsNewDbgInfoFormat)
+    return;
+
+  BB.createMarker(this);
+
+  // We've inserted "this": if InsertAtHead is set then it comes before any
+  // DPValues attached to InsertPos. But if it's not set, then any DPValues
+  // should now come before "this".
+  bool InsertAtHead = InsertPos.getHeadBit();
+  if (!InsertAtHead) {
+    DPMarker *SrcMarker = BB.getMarker(InsertPos);
+    DbgMarker->absorbDebugValues(*SrcMarker, false);
+  }
+
+  // If we're inserting a terminator, check if we need to flush out
+  // TrailingDPValues.
+  if (isTerminator())
+    getParent()->flushTerminatorDbgValues();
 }
 
 /// Unlink this instruction from its current basic block and insert it into the
 /// basic block that MovePos lives in, right before MovePos.
 void Instruction::moveBefore(Instruction *MovePos) {
-  moveBefore(*MovePos->getParent(), MovePos->getIterator());
+  moveBeforeImpl(*MovePos->getParent(), MovePos->getIterator(), false);
+}
+
+void Instruction::moveBeforePreserving(Instruction *MovePos) {
+  moveBeforeImpl(*MovePos->getParent(), MovePos->getIterator(), true);
 }
 
 void Instruction::moveAfter(Instruction *MovePos) {
-  moveBefore(*MovePos->getParent(), ++MovePos->getIterator());
+  auto NextIt = std::next(MovePos->getIterator());
+  // We want this instruction to be moved to before NextIt in the instruction
+  // list, but before NextIt's debug value range.
+  NextIt.setHeadBit(true);
+  moveBeforeImpl(*MovePos->getParent(), NextIt, false);
+}
+
+void Instruction::moveAfterPreserving(Instruction *MovePos) {
+  auto NextIt = std::next(MovePos->getIterator());
+  // We want this instruction and its debug range to be moved to before NextIt
+  // in the instruction list, but before NextIt's debug value range.
+  NextIt.setHeadBit(true);
+  moveBeforeImpl(*MovePos->getParent(), NextIt, true);
 }
 
 void Instruction::moveBefore(BasicBlock &BB, InstListType::iterator I) {
+  moveBeforeImpl(BB, I, false);
+}
+
+void Instruction::moveBeforePreserving(BasicBlock &BB,
+                                       InstListType::iterator I) {
+  moveBeforeImpl(BB, I, true);
+}
+
+void Instruction::moveBeforeImpl(BasicBlock &BB, InstListType::iterator I,
+                              bool Preserve) {
   assert(I == BB.end() || I->getParent() == &BB);
-  BB.splice(I, getParent(), getIterator());
+  bool InsertAtHead = I.getHeadBit();
+
+  // If we've been given the "Preserve" flag, then just move the DPValues with
+  // the instruction, no more special handling needed.
+  if (BB.IsNewDbgInfoFormat && DbgMarker && !Preserve) {
+    if (I != this->getIterator()) {
+      // "this" is definitely moving; detach any existing DPValues.
+      handleMarkerRemoval();
+    }
+  }
+
+  // Move this single instruction. Use the list splice method directly, not
+  // the block splicer, which will do more debug-info things.
+  BB.getInstList().splice(I, getParent()->getInstList(), getIterator());
+
+  if (BB.IsNewDbgInfoFormat && !Preserve) {
+    if (!DbgMarker)
+      BB.createMarker(this);
+    DPMarker *NextMarker = getParent()->getNextMarker(this);
+
+    // If we're inserting at point I, and not in front of the DPValues attached
+    // there, then we should absorb the DPValues attached to I.
+    if (!InsertAtHead)
+      DbgMarker->absorbDebugValues(*NextMarker, false);
+  }
+
+  if (isTerminator())
+    getParent()->flushTerminatorDbgValues();
+}
+
+iterator_range<DPValue::self_iterator>
+Instruction::cloneDebugInfoFrom(const Instruction *From,
+                                std::optional<DPValue::self_iterator> FromHere,
+                                bool InsertAtHead) {
+  if (!From->DbgMarker)
+    return DPMarker::getEmptyDPValueRange();
+
+  assert(getParent()->IsNewDbgInfoFormat);
+  assert(getParent()->IsNewDbgInfoFormat ==
+         From->getParent()->IsNewDbgInfoFormat);
+
+  if (!DbgMarker)
+    getParent()->createMarker(this);
+
+  return DbgMarker->cloneDebugInfoFrom(From->DbgMarker, FromHere, InsertAtHead);
+}
+
+iterator_range<DPValue::self_iterator>
+Instruction::getDbgValueRange() const {
+  BasicBlock *Parent = const_cast<BasicBlock *>(getParent());
+  assert(Parent && "Instruction must be inserted to have DPValues");
+  if (!DbgMarker)
+    return DPMarker::getEmptyDPValueRange();
+
+  return DbgMarker->getDbgValueRange();
+}
+
+bool Instruction::hasDbgValues() const { return !getDbgValueRange().empty(); }
+
+void Instruction::dropDbgValues() {
+  if (DbgMarker)
+    DbgMarker->dropDPValues();
+}
+
+void Instruction::dropOneDbgValue(DPValue *DPV) {
+  DbgMarker->dropOneDPValue(DPV);
 }
 
 bool Instruction::comesBefore(const Instruction *Other) const {

diff  --git a/llvm/unittests/IR/BasicBlockDbgInfoTest.cpp b/llvm/unittests/IR/BasicBlockDbgInfoTest.cpp
new file mode 100644
index 000000000000000..481cd181d3848e7
--- /dev/null
+++ b/llvm/unittests/IR/BasicBlockDbgInfoTest.cpp
@@ -0,0 +1,1114 @@
+//===- llvm/unittest/IR/BasicBlockTest.cpp - BasicBlock unit tests --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/NoFolder.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+using namespace llvm;
+
+extern cl::opt<bool> UseNewDbgInfoFormat;
+
+// None of these tests are meaningful or do anything if we do not have the
+// experimental "head" bit compiled into ilist_iterator (aka
+// ilist_iterator_w_bits), thus there's no point compiling these tests in.
+#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
+
+static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
+  SMDiagnostic Err;
+  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
+  if (!Mod)
+    Err.print("BasicBlockDbgInfoTest", errs());
+  return Mod;
+}
+
+namespace {
+
+TEST(BasicBlockDbgInfoTest, MarkerOperations) {
+  LLVMContext C;
+  UseNewDbgInfoFormat = true;
+
+  std::unique_ptr<Module> M = parseIR(C, R"(
+    define i16 @f(i16 %a) !dbg !6 {
+      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+      %b = add i16 %a, 1, !dbg !11
+      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+      ret i16 0, !dbg !11
+    }
+    declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+    attributes #0 = { nounwind readnone speculatable willreturn }
+
+    !llvm.dbg.cu = !{!0}
+    !llvm.module.flags = !{!5}
+
+    !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+    !1 = !DIFile(filename: "t.ll", directory: "/")
+    !2 = !{}
+    !5 = !{i32 2, !"Debug Info Version", i32 3}
+    !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+    !7 = !DISubroutineType(types: !2)
+    !8 = !{!9}
+    !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+    !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
+    !11 = !DILocation(line: 1, column: 1, scope: !6)
+)");
+
+  // Fetch the entry block,
+  BasicBlock &BB = M->getFunction("f")->getEntryBlock();
+  // Convert the module to "new" form debug-info.
+  M->convertToNewDbgValues();
+  EXPECT_EQ(BB.size(), 2u);
+
+  // Fetch out our two markers,
+  Instruction *Instr1 = &*BB.begin();
+  Instruction *Instr2 = Instr1->getNextNode();
+  DPMarker *Marker1 = Instr1->DbgMarker;
+  DPMarker *Marker2 = Instr2->DbgMarker;
+  // There's no TrailingDPValues marker allocated yet.
+  DPMarker *EndMarker = nullptr;
+
+  // Check that the "getMarker" utilities operate as expected.
+  EXPECT_EQ(BB.getMarker(Instr1->getIterator()), Marker1);
+  EXPECT_EQ(BB.getMarker(Instr2->getIterator()), Marker2);
+  EXPECT_EQ(BB.getNextMarker(Instr1), Marker2);
+  EXPECT_EQ(BB.getNextMarker(Instr2), EndMarker); // Is nullptr.
+
+  // There should be two DPValues,
+  EXPECT_EQ(Marker1->StoredDPValues.size(), 1u);
+  EXPECT_EQ(Marker2->StoredDPValues.size(), 1u);
+
+  // Unlink them and try to re-insert them through the basic block.
+  DPValue *DPV1 = &*Marker1->StoredDPValues.begin();
+  DPValue *DPV2 = &*Marker2->StoredDPValues.begin();
+  DPV1->removeFromParent();
+  DPV2->removeFromParent();
+  EXPECT_TRUE(Marker1->StoredDPValues.empty());
+  EXPECT_TRUE(Marker2->StoredDPValues.empty());
+
+  // This should appear in Marker1.
+  BB.insertDPValueBefore(DPV1, BB.begin());
+  EXPECT_EQ(Marker1->StoredDPValues.size(), 1u);
+  EXPECT_EQ(DPV1, &*Marker1->StoredDPValues.begin());
+
+  // This should attach to Marker2.
+  BB.insertDPValueAfter(DPV2, &*BB.begin());
+  EXPECT_EQ(Marker2->StoredDPValues.size(), 1u);
+  EXPECT_EQ(DPV2, &*Marker2->StoredDPValues.begin());
+
+  // Now, how about removing instructions? That should cause any DPValues to
+  // "fall down".
+  Instr1->removeFromParent();
+  Marker1 = nullptr;
+  // DPValues should now be in Marker2.
+  EXPECT_EQ(BB.size(), 1u);
+  EXPECT_EQ(Marker2->StoredDPValues.size(), 2u);
+  // They should also be in the correct order.
+  SmallVector<DPValue *, 2> DPVs;
+  for (DPValue &DPV : Marker2->getDbgValueRange())
+    DPVs.push_back(&DPV);
+  EXPECT_EQ(DPVs[0], DPV1);
+  EXPECT_EQ(DPVs[1], DPV2);
+
+  // If we remove the end instruction, the DPValues should fall down into
+  // the trailing marker.
+  EXPECT_EQ(BB.getTrailingDPValues(), nullptr);
+  Instr2->removeFromParent();
+  EXPECT_TRUE(BB.empty());
+  EndMarker = BB.getTrailingDPValues();;
+  ASSERT_NE(EndMarker, nullptr);
+  EXPECT_EQ(EndMarker->StoredDPValues.size(), 2u);
+  // Again, these should arrive in the correct order.
+
+  DPVs.clear();
+  for (DPValue &DPV : EndMarker->getDbgValueRange())
+    DPVs.push_back(&DPV);
+  EXPECT_EQ(DPVs[0], DPV1);
+  EXPECT_EQ(DPVs[1], DPV2);
+
+  // Inserting a normal instruction at the beginning: shouldn't dislodge the
+  // DPValues. It's intended to not go at the start.
+  Instr1->insertBefore(BB, BB.begin());
+  EXPECT_EQ(EndMarker->StoredDPValues.size(), 2u);
+  Instr1->removeFromParent();
+
+  // Inserting at end(): should dislodge the DPValues, if they were dbg.values
+  // then they would sit "above" the new instruction.
+  Instr1->insertBefore(BB, BB.end());
+  EXPECT_EQ(Instr1->DbgMarker->StoredDPValues.size(), 2u);
+  // However we won't de-allocate the trailing marker until a terminator is
+  // inserted.
+  EXPECT_EQ(EndMarker->StoredDPValues.size(), 0u);
+  EXPECT_EQ(BB.getTrailingDPValues(), EndMarker);
+
+  // Remove Instr1: now the DPValues will fall down again,
+  Instr1->removeFromParent();
+  EndMarker = BB.getTrailingDPValues();;
+  EXPECT_EQ(EndMarker->StoredDPValues.size(), 2u);
+
+  // Inserting a terminator, however it's intended, should dislodge the
+  // trailing DPValues, as it's the clear intention of the caller that this be
+  // the final instr in the block, and DPValues aren't allowed to live off the
+  // end forever.
+  Instr2->insertBefore(BB, BB.begin());
+  EXPECT_EQ(Instr2->DbgMarker->StoredDPValues.size(), 2u);
+  EXPECT_EQ(BB.getTrailingDPValues(), nullptr);
+
+  // Teardown,
+  Instr1->insertBefore(BB, BB.begin());
+
+  UseNewDbgInfoFormat = false;
+}
+
+TEST(BasicBlockDbgInfoTest, HeadBitOperations) {
+  LLVMContext C;
+  UseNewDbgInfoFormat = true;
+
+  std::unique_ptr<Module> M = parseIR(C, R"(
+    define i16 @f(i16 %a) !dbg !6 {
+      %b = add i16 %a, 1, !dbg !11
+      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+      %c = add i16 %a, 1, !dbg !11
+      %d = add i16 %a, 1, !dbg !11
+      ret i16 0, !dbg !11
+    }
+    declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+    attributes #0 = { nounwind readnone speculatable willreturn }
+
+    !llvm.dbg.cu = !{!0}
+    !llvm.module.flags = !{!5}
+
+    !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+    !1 = !DIFile(filename: "t.ll", directory: "/")
+    !2 = !{}
+    !5 = !{i32 2, !"Debug Info Version", i32 3}
+    !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+    !7 = !DISubroutineType(types: !2)
+    !8 = !{!9}
+    !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+    !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
+    !11 = !DILocation(line: 1, column: 1, scope: !6)
+)");
+
+  // Test that the movement of debug-data when using moveBefore etc and
+  // insertBefore etc are governed by the "head" bit of iterators.
+  BasicBlock &BB = M->getFunction("f")->getEntryBlock();
+  // Convert the module to "new" form debug-info.
+  M->convertToNewDbgValues();
+
+  // Test that the head bit behaves as expected: it should be set when the
+  // code wants the _start_ of the block, but not otherwise.
+  EXPECT_TRUE(BB.getFirstInsertionPt().getHeadBit());
+  BasicBlock::iterator BeginIt = BB.begin();
+  EXPECT_TRUE(BeginIt.getHeadBit());
+  // If you launder the instruction pointer through dereferencing and then
+  // get the iterator again with getIterator, the head bit is lost. This is
+  // deliberate: if you're calling getIterator, then you're requesting an
+  // iterator for the position of _this_ instruction, not "the start of this
+  // block".
+  BasicBlock::iterator BeginIt2 = BeginIt->getIterator();
+  EXPECT_FALSE(BeginIt2.getHeadBit());
+
+  // Fetch some instruction pointers.
+  Instruction *BInst = &*BeginIt;
+  Instruction *CInst = BInst->getNextNode();
+  Instruction *DInst = CInst->getNextNode();
+  // CInst should have debug-info.
+  ASSERT_TRUE(CInst->DbgMarker);
+  EXPECT_FALSE(CInst->DbgMarker->StoredDPValues.empty());
+
+  // If we move "c" to the start of the block, just normally, then the DPValues
+  // should fall down to "d".
+  CInst->moveBefore(BB, BeginIt2);
+  EXPECT_TRUE(!CInst->DbgMarker || CInst->DbgMarker->StoredDPValues.empty());
+  ASSERT_TRUE(DInst->DbgMarker);
+  EXPECT_FALSE(DInst->DbgMarker->StoredDPValues.empty());
+
+  // Wheras if we move D to the start of the block with moveBeforePreserving,
+  // the DPValues should move with it.
+  DInst->moveBeforePreserving(BB, BB.begin());
+  EXPECT_FALSE(DInst->DbgMarker->StoredDPValues.empty());
+  EXPECT_EQ(&*BB.begin(), DInst);
+
+  // Similarly, moveAfterPreserving "D" to "C" should move DPValues with "D".
+  DInst->moveAfterPreserving(CInst);
+  EXPECT_FALSE(DInst->DbgMarker->StoredDPValues.empty());
+
+  // (move back to the start...)
+  DInst->moveBeforePreserving(BB, BB.begin());
+
+  // Current order of insts: "D -> C -> B -> Ret". DPValues on "D".
+  // If we move "C" to the beginning of the block, it should go before the
+  // DPValues. They'll stay on "D".
+  CInst->moveBefore(BB, BB.begin());
+  EXPECT_TRUE(!CInst->DbgMarker || CInst->DbgMarker->StoredDPValues.empty());
+  EXPECT_FALSE(DInst->DbgMarker->StoredDPValues.empty());
+  EXPECT_EQ(&*BB.begin(), CInst);
+  EXPECT_EQ(CInst->getNextNode(), DInst);
+
+  // Move back.
+  CInst->moveBefore(BInst);
+  EXPECT_EQ(&*BB.begin(), DInst);
+
+  // Current order of insts: "D -> C -> B -> Ret". DPValues on "D".
+  // Now move CInst to the position of DInst, but using getIterator instead of
+  // BasicBlock::begin. This signals that we want the "C" instruction to be
+  // immediately before "D", with any DPValues on "D" now moving to "C".
+  // It's the equivalent of moving an instruction to the position between a
+  // run of dbg.values and the next instruction.
+  CInst->moveBefore(BB, DInst->getIterator());
+  // CInst gains the DPValues.
+  EXPECT_TRUE(!DInst->DbgMarker || DInst->DbgMarker->StoredDPValues.empty());
+  EXPECT_FALSE(CInst->DbgMarker->StoredDPValues.empty());
+  EXPECT_EQ(&*BB.begin(), CInst);
+
+  UseNewDbgInfoFormat = false;
+}
+
+TEST(BasicBlockDbgInfoTest, InstrDbgAccess) {
+  LLVMContext C;
+  UseNewDbgInfoFormat = true;
+
+  std::unique_ptr<Module> M = parseIR(C, R"(
+    define i16 @f(i16 %a) !dbg !6 {
+      %b = add i16 %a, 1, !dbg !11
+      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+      %c = add i16 %a, 1, !dbg !11
+      %d = add i16 %a, 1, !dbg !11
+      ret i16 0, !dbg !11
+    }
+    declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+    attributes #0 = { nounwind readnone speculatable willreturn }
+
+    !llvm.dbg.cu = !{!0}
+    !llvm.module.flags = !{!5}
+
+    !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+    !1 = !DIFile(filename: "t.ll", directory: "/")
+    !2 = !{}
+    !5 = !{i32 2, !"Debug Info Version", i32 3}
+    !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+    !7 = !DISubroutineType(types: !2)
+    !8 = !{!9}
+    !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+    !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
+    !11 = !DILocation(line: 1, column: 1, scope: !6)
+)");
+
+  // Check that DPValues can be accessed from Instructions without digging
+  // into the depths of DPMarkers.
+  BasicBlock &BB = M->getFunction("f")->getEntryBlock();
+  // Convert the module to "new" form debug-info.
+  M->convertToNewDbgValues();
+
+  Instruction *BInst = &*BB.begin();
+  Instruction *CInst = BInst->getNextNode();
+  Instruction *DInst = CInst->getNextNode();
+
+  ASSERT_TRUE(BInst->DbgMarker);
+  ASSERT_TRUE(CInst->DbgMarker);
+  ASSERT_EQ(CInst->DbgMarker->StoredDPValues.size(), 1u);
+  DPValue *DPV1 = &*CInst->DbgMarker->StoredDPValues.begin();
+  ASSERT_TRUE(DPV1);
+  EXPECT_EQ(BInst->DbgMarker->StoredDPValues.size(), 0u);
+
+  // Clone DPValues from one inst to another. Other arguments to clone are
+  // tested in DPMarker test.
+  auto Range1 = BInst->cloneDebugInfoFrom(CInst);
+  EXPECT_EQ(BInst->DbgMarker->StoredDPValues.size(), 1u);
+  DPValue *DPV2 = &*BInst->DbgMarker->StoredDPValues.begin();
+  EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), 1u);
+  EXPECT_EQ(&*Range1.begin(), DPV2);
+  EXPECT_NE(DPV1, DPV2);
+
+  // We should be able to get a range over exactly the same information.
+  auto Range2 = BInst->getDbgValueRange();
+  EXPECT_EQ(Range1.begin(), Range2.begin());
+  EXPECT_EQ(Range1.end(), Range2.end());
+
+  // We should be able to query if there are DPValues,
+  EXPECT_TRUE(BInst->hasDbgValues());
+  EXPECT_TRUE(CInst->hasDbgValues());
+  EXPECT_FALSE(DInst->hasDbgValues());
+
+  // Dropping should be easy,
+  BInst->dropDbgValues();
+  EXPECT_FALSE(BInst->hasDbgValues());
+  EXPECT_EQ(BInst->DbgMarker->StoredDPValues.size(), 0u);
+
+  // And we should be able to drop individual DPValues.
+  CInst->dropOneDbgValue(DPV1);
+  EXPECT_FALSE(CInst->hasDbgValues());
+  EXPECT_EQ(CInst->DbgMarker->StoredDPValues.size(), 0u);
+
+  UseNewDbgInfoFormat = false;
+}
+
+/* Let's recall the big illustration from BasicBlock::spliceDebugInfo:
+
+                                               Dest
+                                                 |
+   this-block:    A----A----A                ====A----A----A----A---A---A
+    Src-block                ++++B---B---B---B:::C
+                                 |               |
+                                First           Last
+
+  in all it's glory. Depending on the bit-configurations for the iterator head
+  / tail bits on the three named iterators, there are eight ways for a splice to
+  occur. To save the amount of thinking needed to pack this into one unit test,
+  just test the same IR eight times with 
diff erence splices. The IR shall be
+  thus:
+
+    define i16 @f(i16 %a) !dbg !6 {
+    entry:
+      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+      %b = add i16 %a, 1, !dbg !11
+      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+      br label %exit, !dbg !11
+
+    exit:
+      call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+      %c = add i16 %b, 1, !dbg !11
+      ret i16 0, !dbg !11
+    }
+
+  The iterators will be:
+    Dest: exit block, "c" instruction.
+    First: entry block, "b" instruction.
+    Last: entry block, branch instruction.
+
+  The numbered configurations will be:
+
+       |    Dest-Head   |   First-Head   |   Last-tail
+   ----+----------------+----------------+------------
+    0  |      false     |     false      |     false
+    1  |      true      |     false      |     false
+    2  |      false     |     true       |     false
+    3  |      true      |     true       |     false
+    4  |      false     |     false      |     true
+    5  |      true      |     false      |     true
+    6  |      false     |     true       |     true
+    7  |      true      |     true       |     true
+
+  Each numbered test scenario will also have a short explanation indicating what
+  this bit configuration represents.
+*/
+
+static const std::string SpliceTestIR = R"(
+    define i16 @f(i16 %a) !dbg !6 {
+      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+      %b = add i16 %a, 1, !dbg !11
+      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+      br label %exit, !dbg !11
+
+    exit:
+      call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+      %c = add i16 %b, 1, !dbg !11
+      ret i16 0, !dbg !11
+    }
+    declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+    attributes #0 = { nounwind readnone speculatable willreturn }
+
+    !llvm.dbg.cu = !{!0}
+    !llvm.module.flags = !{!5}
+
+    !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+    !1 = !DIFile(filename: "t.ll", directory: "/")
+    !2 = !{}
+    !5 = !{i32 2, !"Debug Info Version", i32 3}
+    !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+    !7 = !DISubroutineType(types: !2)
+    !8 = !{!9}
+    !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+    !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
+    !11 = !DILocation(line: 1, column: 1, scope: !6)
+)";
+
+class DbgSpliceTest : public ::testing::Test {
+protected:
+  LLVMContext C;
+  std::unique_ptr<Module> M;
+  BasicBlock *BBEntry, *BBExit;
+  BasicBlock::iterator Dest, First, Last;
+  Instruction *BInst, *Branch, *CInst;
+  DPValue *DPVA, *DPVB, *DPVConst;
+
+  void SetUp() override {
+    UseNewDbgInfoFormat = true;
+    M = parseIR(C, SpliceTestIR.c_str());
+    M->convertToNewDbgValues();
+
+    BBEntry = &M->getFunction("f")->getEntryBlock();
+    BBExit = BBEntry->getNextNode();
+
+    Dest = BBExit->begin();
+    First = BBEntry->begin();
+    Last = BBEntry->getTerminator()->getIterator();
+    BInst = &*First;
+    Branch = &*Last;
+    CInst = &*Dest;
+
+    DPVA = &*BInst->DbgMarker->StoredDPValues.begin();
+    DPVB = &*Branch->DbgMarker->StoredDPValues.begin();
+    DPVConst = &*CInst->DbgMarker->StoredDPValues.begin();
+  }
+
+  void TearDown() override { UseNewDbgInfoFormat = false; }
+
+  bool InstContainsDPValue(Instruction *I, DPValue *DPV) {
+    for (DPValue &D : I->getDbgValueRange()) {
+      if (&D == DPV) {
+        // Confirm too that the links between the records are correct.
+        EXPECT_EQ(DPV->Marker, I->DbgMarker);
+        EXPECT_EQ(I->DbgMarker->MarkedInstr, I);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool CheckDPVOrder(Instruction *I, SmallVector<DPValue *> CheckVals) {
+    SmallVector<DPValue *> Vals;
+    for (DPValue &D : I->getDbgValueRange())
+      Vals.push_back(&D);
+
+    EXPECT_EQ(Vals.size(), CheckVals.size());
+    if (Vals.size() != CheckVals.size())
+      return false;
+
+    for (unsigned int I = 0; I < Vals.size(); ++I) {
+      EXPECT_EQ(Vals[I], CheckVals[I]);
+      // Provide another expectation failure to let us localise what goes wrong,
+      // by returning a flag to the caller.
+      if (Vals[I] != CheckVals[I])
+        return false;
+    }
+    return true;
+  }
+};
+
+TEST_F(DbgSpliceTest, DbgSpliceTest0) {
+  Dest.setHeadBit(false);
+  First.setHeadBit(false);
+  Last.setTailBit(false);
+
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from First, not including leading dbg.value, to Last, including the
+    trailing dbg.value. Place at Dest, between the constant dbg.value and %c.
+    %b, and the following dbg.value, should move, to:
+
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+
+  */
+  BBExit->splice(Dest, BBEntry, First, Last);
+  EXPECT_EQ(BInst->getParent(), BBExit);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+  EXPECT_EQ(Branch->getParent(), BBEntry);
+
+  // DPVB: should be on Dest, in exit block.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVB));
+
+  // DPVA, should have "fallen" onto the branch, remained in entry block.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVA));
+
+  // DPVConst should be on the moved %b instruction.
+  EXPECT_TRUE(InstContainsDPValue(BInst, DPVConst));
+}
+
+TEST_F(DbgSpliceTest, DbgSpliceTest1) {
+  Dest.setHeadBit(true);
+  First.setHeadBit(false);
+  Last.setTailBit(false);
+
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from First, not including leading dbg.value, to Last, including the
+    trailing dbg.value. Place at the head of Dest, i.e. at the very start of
+    BBExit, before any debug-info there. Becomes:
+
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+
+  */
+  BBExit->splice(Dest, BBEntry, First, Last);
+  EXPECT_EQ(BInst->getParent(), BBExit);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+  EXPECT_EQ(Branch->getParent(), BBEntry);
+
+  // DPVB: should be on CInst, in exit block.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVB));
+
+  // DPVA, should have "fallen" onto the branch, remained in entry block.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVA));
+
+  // DPVConst should be behind / after the moved instructions, remain on CInst.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVConst));
+
+  // Order of DPVB and DPVConst should be thus:
+  EXPECT_TRUE(CheckDPVOrder(CInst, {DPVB, DPVConst}));
+}
+
+TEST_F(DbgSpliceTest, DbgSpliceTest2) {
+  Dest.setHeadBit(false);
+  First.setHeadBit(true);
+  Last.setTailBit(false);
+
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from head of First, which includes the leading dbg.value, to Last,
+    including the trailing dbg.value. Place in front of Dest, but after any
+    debug-info there. Becomes:
+
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+
+  */
+  BBExit->splice(Dest, BBEntry, First, Last);
+  EXPECT_EQ(BInst->getParent(), BBExit);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+
+  // DPVB: should be on CInst, in exit block.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVB));
+
+  // DPVA, should have transferred with the spliced instructions, remains on
+  // the "b" inst.
+  EXPECT_TRUE(InstContainsDPValue(BInst, DPVA));
+
+  // DPVConst should be ahead of the moved instructions, ahead of BInst.
+  EXPECT_TRUE(InstContainsDPValue(BInst, DPVConst));
+
+  // Order of DPVA and DPVConst should be thus:
+  EXPECT_TRUE(CheckDPVOrder(BInst, {DPVConst, DPVA}));
+}
+
+TEST_F(DbgSpliceTest, DbgSpliceTest3) {
+  Dest.setHeadBit(true);
+  First.setHeadBit(true);
+  Last.setTailBit(false);
+
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from head of First, which includes the leading dbg.value, to Last,
+    including the trailing dbg.value. Place at head of Dest, before any
+    debug-info there. Becomes:
+
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+  */
+  BBExit->splice(Dest, BBEntry, First, Last);
+  EXPECT_EQ(BInst->getParent(), BBExit);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+
+  // DPVB: should be on CInst, in exit block.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVB));
+
+  // DPVA, should have transferred with the spliced instructions, remains on
+  // the "b" inst.
+  EXPECT_TRUE(InstContainsDPValue(BInst, DPVA));
+
+  // DPVConst should be behind the moved instructions, ahead of CInst.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVConst));
+
+  // Order of DPVB and DPVConst should be thus:
+  EXPECT_TRUE(CheckDPVOrder(CInst, {DPVB, DPVConst}));
+}
+
+TEST_F(DbgSpliceTest, DbgSpliceTest4) {
+  Dest.setHeadBit(false);
+  First.setHeadBit(false);
+  Last.setTailBit(true);
+
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from First, not including the leading dbg.value, to Last, but NOT
+    including the trailing dbg.value because the tail bit is set. Place at Dest,
+    after any debug-info there. Becomes:
+
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+  */
+  BBExit->splice(Dest, BBEntry, First, Last);
+  EXPECT_EQ(BInst->getParent(), BBExit);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+  EXPECT_EQ(Branch->getParent(), BBEntry);
+
+  // DPVB: should be on Branch as before, remain in entry block.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVB));
+
+  // DPVA, should have remained in entry block, falls onto Branch inst.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVA));
+
+  // DPVConst should be ahead of the moved instructions, BInst.
+  EXPECT_TRUE(InstContainsDPValue(BInst, DPVConst));
+
+  // Order of DPVA and DPVA should be thus:
+  EXPECT_TRUE(CheckDPVOrder(Branch, {DPVA, DPVB}));
+}
+
+TEST_F(DbgSpliceTest, DbgSpliceTest5) {
+  Dest.setHeadBit(true);
+  First.setHeadBit(false);
+  Last.setTailBit(true);
+
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from First, not including the leading dbg.value, to Last, but NOT
+    including the trailing dbg.value because the tail bit is set. Place at head
+    of Dest, before any debug-info there. Becomes:
+
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+First     %b = add i16 %a, 1, !dbg !11
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+  */
+  BBExit->splice(Dest, BBEntry, First, Last);
+  EXPECT_EQ(BInst->getParent(), BBExit);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+  EXPECT_EQ(Branch->getParent(), BBEntry);
+
+  // DPVB: should be on Branch as before, remain in entry block.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVB));
+
+  // DPVA, should have remained in entry block, falls onto Branch inst.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVA));
+
+  // DPVConst should be behind of the moved instructions, on CInst.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVConst));
+
+  // Order of DPVA and DPVB should be thus:
+  EXPECT_TRUE(CheckDPVOrder(Branch, {DPVA, DPVB}));
+}
+
+TEST_F(DbgSpliceTest, DbgSpliceTest6) {
+  Dest.setHeadBit(false);
+  First.setHeadBit(true);
+  Last.setTailBit(true);
+
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from First, including the leading dbg.value, to Last, but NOT
+    including the trailing dbg.value because the tail bit is set. Place at Dest,
+    after any debug-info there. Becomes:
+
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+  */
+  BBExit->splice(Dest, BBEntry, First, Last);
+  EXPECT_EQ(BInst->getParent(), BBExit);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+  EXPECT_EQ(Branch->getParent(), BBEntry);
+
+  // DPVB: should be on Branch as before, remain in entry block.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVB));
+
+  // DPVA, should have transferred to BBExit, on B inst.
+  EXPECT_TRUE(InstContainsDPValue(BInst, DPVA));
+
+  // DPVConst should be ahead of the moved instructions, on BInst.
+  EXPECT_TRUE(InstContainsDPValue(BInst, DPVConst));
+
+  // Order of DPVA and DPVConst should be thus:
+  EXPECT_TRUE(CheckDPVOrder(BInst, {DPVConst, DPVA}));
+}
+
+TEST_F(DbgSpliceTest, DbgSpliceTest7) {
+  Dest.setHeadBit(true);
+  First.setHeadBit(true);
+  Last.setTailBit(true);
+
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from First, including the leading dbg.value, to Last, but NOT
+    including the trailing dbg.value because the tail bit is set. Place at head
+    of Dest, before any debug-info there. Becomes:
+
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+  */
+  BBExit->splice(Dest, BBEntry, First, Last);
+  EXPECT_EQ(BInst->getParent(), BBExit);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+  EXPECT_EQ(Branch->getParent(), BBEntry);
+
+  // DPVB: should be on Branch as before, remain in entry block.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVB));
+
+  // DPVA, should have transferred to BBExit, on B inst.
+  EXPECT_TRUE(InstContainsDPValue(BInst, DPVA));
+
+  // DPVConst should be after of the moved instructions, on CInst.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVConst));
+}
+
+// But wait, there's more! What if you splice a range that is empty, but
+// implicitly contains debug-info? In the dbg.value design for debug-info,
+// this would be an explicit range, but in DPValue debug-info, it isn't.
+// Check that if we try to do that, with 
diff ering head-bit values, that
+// DPValues are transferred.
+// Test with empty transfers to Dest, with head bit set and not set.
+
+TEST_F(DbgSpliceTest, DbgSpliceEmpty0) {
+  Dest.setHeadBit(false);
+  First.setHeadBit(false);
+  Last.setHeadBit(false);
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from BBEntry.getFirstInsertionPt to First -- this implicitly is a
+    splice of DPVA, but the iterators are pointing at the same instruction. The
+    only 
diff erence is the setting of the head bit. Becomes;
+
+        define i16 @f(i16 %a) !dbg !6 {
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+  */
+  BBExit->splice(Dest, BBEntry, BBEntry->getFirstInsertionPt(), First);
+  EXPECT_EQ(BInst->getParent(), BBEntry);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+  EXPECT_EQ(Branch->getParent(), BBEntry);
+
+  // DPVB: should be on Branch as before, remain in entry block.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVB));
+
+  // DPVA, should have transferred to BBExit, on C inst.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVA));
+
+  // DPVConst should be ahead of the moved DPValue, on CInst.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVConst));
+
+  // Order of DPVA and DPVConst should be thus:
+  EXPECT_TRUE(CheckDPVOrder(CInst, {DPVConst, DPVA}));
+}
+
+TEST_F(DbgSpliceTest, DbgSpliceEmpty1) {
+  Dest.setHeadBit(true);
+  First.setHeadBit(false);
+  Last.setHeadBit(false);
+  /*
+        define i16 @f(i16 %a) !dbg !6 {
+BBEntry entry:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+    Splice from BBEntry.getFirstInsertionPt to First -- this implicitly is a
+    splice of DPVA, but the iterators are pointing at the same instruction. The
+    only 
diff erence is the setting of the head bit. Insert at head of Dest,
+    i.e. before DPVConst. Becomes;
+
+        define i16 @f(i16 %a) !dbg !6 {
+First     %b = add i16 %a, 1, !dbg !11
+DPVB      call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+Last      br label %exit, !dbg !11
+
+BBExit  exit:
+DPVA      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+DPVConst  call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11
+Dest      %c = add i16 %b, 1, !dbg !11
+          ret i16 0, !dbg !11
+        }
+
+  */
+  BBExit->splice(Dest, BBEntry, BBEntry->getFirstInsertionPt(), First);
+  EXPECT_EQ(BInst->getParent(), BBEntry);
+  EXPECT_EQ(CInst->getParent(), BBExit);
+  EXPECT_EQ(Branch->getParent(), BBEntry);
+
+  // DPVB: should be on Branch as before, remain in entry block.
+  EXPECT_TRUE(InstContainsDPValue(Branch, DPVB));
+
+  // DPVA, should have transferred to BBExit, on C inst.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVA));
+
+  // DPVConst should be ahead of the moved DPValue, on CInst.
+  EXPECT_TRUE(InstContainsDPValue(CInst, DPVConst));
+
+  // Order of DPVA and DPVConst should be thus:
+  EXPECT_TRUE(CheckDPVOrder(CInst, {DPVA, DPVConst}));
+}
+
+// If we splice new instructions into a block with trailing DPValues, then
+// the trailing DPValues should get flushed back out.
+TEST(BasicBlockDbgInfoTest, DbgSpliceTrailing) {
+  LLVMContext C;
+  UseNewDbgInfoFormat = true;
+
+  std::unique_ptr<Module> M = parseIR(C, R"(
+    define i16 @f(i16 %a) !dbg !6 {
+    entry:
+      call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+      br label %exit
+
+    exit:
+      %b = add i16 %a, 1, !dbg !11
+      ret i16 0, !dbg !11
+    }
+    declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+    attributes #0 = { nounwind readnone speculatable willreturn }
+
+    !llvm.dbg.cu = !{!0}
+    !llvm.module.flags = !{!5}
+
+    !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+    !1 = !DIFile(filename: "t.ll", directory: "/")
+    !2 = !{}
+    !5 = !{i32 2, !"Debug Info Version", i32 3}
+    !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+    !7 = !DISubroutineType(types: !2)
+    !8 = !{!9}
+    !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+    !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
+    !11 = !DILocation(line: 1, column: 1, scope: !6)
+)");
+
+  BasicBlock &Entry = M->getFunction("f")->getEntryBlock();
+  BasicBlock &Exit = *Entry.getNextNode();
+  M->convertToNewDbgValues();
+
+  // Begin by forcing entry block to have dangling DPValue.
+  Entry.getTerminator()->eraseFromParent();
+  ASSERT_NE(Entry.getTrailingDPValues(), nullptr);
+  EXPECT_TRUE(Entry.empty());
+
+  // Now transfer the entire contents of the exit block into the entry.
+  Entry.splice(Entry.end(), &Exit, Exit.begin(), Exit.end());
+
+  // The trailing DPValue should have been placed at the front of what's been
+  // spliced in.
+  Instruction *BInst = &*Entry.begin();
+  ASSERT_TRUE(BInst->DbgMarker);
+  EXPECT_EQ(BInst->DbgMarker->StoredDPValues.size(), 1u);
+
+  UseNewDbgInfoFormat = false;
+}
+
+} // End anonymous namespace.
+#endif // EXPERIMENTAL_DEBUGINFO_ITERATORS

diff  --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt
index f57039493f21fdc..5f553c01d67131c 100644
--- a/llvm/unittests/IR/CMakeLists.txt
+++ b/llvm/unittests/IR/CMakeLists.txt
@@ -14,6 +14,7 @@ add_llvm_unittest(IRTests
   AsmWriterTest.cpp
   AttributesTest.cpp
   BasicBlockTest.cpp
+  BasicBlockDbgInfoTest.cpp
   CFGBuilder.cpp
   ConstantRangeTest.cpp
   ConstantsTest.cpp


        


More information about the llvm-commits mailing list