diff options
author | Jeremy Morse <jeremy.morse@sony.com> | 2023-09-20 15:15:27 +0100 |
---|---|---|
committer | Jeremy Morse <jeremy.morse@sony.com> | 2023-12-01 19:31:27 +0000 |
commit | 37f2f48c8f43b2b98869a6e5f009d3d2471ecdaf (patch) | |
tree | 801abd6f17458a95b9332639ae728f1807e15b22 /llvm/lib/IR/BasicBlock.cpp | |
parent | deca8055d4f590047730df4a6806e06d623ef1ff (diff) | |
download | llvm-37f2f48c8f43b2b98869a6e5f009d3d2471ecdaf.zip llvm-37f2f48c8f43b2b98869a6e5f009d3d2471ecdaf.tar.gz llvm-37f2f48c8f43b2b98869a6e5f009d3d2471ecdaf.tar.bz2 |
[DebugInfo][RemoveDIs] Handle a debug-info splicing corner case (#73810)
A large amount of complexity when it comes to shuffling DPValue objects
around is pushed into BasicBlock::spliceDebugInfo, and it gets
comprehensive testing there via the unit tests. It turns out that there's a
corner case though: splicing instructions and debug-info to the end()
iterator requires blocks of DPValues to be concatenated, but the DPValues
don't behave normally as they're dangling at the end of a block. While this
splicing-to-an-empty-block case is rare, and it's even rarer for it to
contain debug-info, it does happen occasionally.
Fix this by wrapping spliceDebugInfo with an outer layer that removes any
dangling DPValues in the destination block -- that way the main splicing
function (renamed to spliceDebugInfoImpl) doesn't need to worry about that
scenario. See the diagram in the added function for more info.
Diffstat (limited to 'llvm/lib/IR/BasicBlock.cpp')
-rw-r--r-- | llvm/lib/IR/BasicBlock.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index 0a8fddb..3ac5faf 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -829,6 +829,89 @@ void BasicBlock::spliceDebugInfoEmptyBlock(BasicBlock::iterator Dest, void BasicBlock::spliceDebugInfo(BasicBlock::iterator Dest, BasicBlock *Src, BasicBlock::iterator First, BasicBlock::iterator Last) { + /* Do a quick normalisation before calling the real splice implementation. We + might be operating on a degenerate basic block that has no instructions + in it, a legitimate transient state. In that case, Dest will be end() and + any DPValues temporarily stored in the TrailingDPValues map in LLVMContext. + We might illustrate it thus: + + Dest + | + this-block: ~~~~~~~~ + Src-block: ++++B---B---B---B:::C + | | + First Last + + However: does the caller expect the "~" DPValues to end up before or after + the spliced segment? This is communciated in the "Head" bit of Dest, which + signals whether the caller called begin() or end() on this block. + + If the head bit is set, then all is well, we leave DPValues trailing just + like how dbg.value instructions would trail after instructions spliced to + the beginning of this block. + + If the head bit isn't set, then try to jam the "~" DPValues onto the front + of the First instruction, then splice like normal, which joins the "~" + DPValues with the "+" DPValues. However if the "+" DPValues are supposed to + be left behind in Src, then: + * detach the "+" DPValues, + * move the "~" DPValues onto First, + * splice like normal, + * replace the "+" DPValues onto the Last position. + Complicated, but gets the job done. */ + + // If we're inserting at end(), and not in front of dangling DPValues, then + // move the DPValues onto "First". They'll then be moved naturally in the + // splice process. + DPMarker *MoreDanglingDPValues = nullptr; + DPMarker *OurTrailingDPValues = getTrailingDPValues(); + if (Dest == end() && !Dest.getHeadBit() && OurTrailingDPValues) { + // Are the "+" DPValues not supposed to move? If so, detach them + // temporarily. + if (!First.getHeadBit() && First->hasDbgValues()) { + MoreDanglingDPValues = Src->getMarker(First); + MoreDanglingDPValues->removeFromParent(); + } + + if (First->hasDbgValues()) { + DPMarker *CurMarker = Src->getMarker(First); + // Place them at the front, it would look like this: + // Dest + // | + // this-block: + // Src-block: ~~~~~~~~++++B---B---B---B:::C + // | | + // First Last + CurMarker->absorbDebugValues(*OurTrailingDPValues, true); + OurTrailingDPValues->eraseFromParent(); + } else { + // No current marker, create one and absorb in. (FIXME: we can avoid an + // allocation in the future). + DPMarker *CurMarker = Src->createMarker(&*First); + CurMarker->absorbDebugValues(*OurTrailingDPValues, false); + OurTrailingDPValues->eraseFromParent(); + } + deleteTrailingDPValues(); + First.setHeadBit(true); + } + + // Call the main debug-info-splicing implementation. + spliceDebugInfoImpl(Dest, Src, First, Last); + + // Do we have some "+" DPValues hanging around that weren't supposed to move, + // and we detached to make things easier? + if (!MoreDanglingDPValues) + return; + + // FIXME: we could avoid an allocation here sometimes. + DPMarker *LastMarker = Src->createMarker(Last); + LastMarker->absorbDebugValues(*MoreDanglingDPValues, true); + MoreDanglingDPValues->eraseFromParent(); +} + +void BasicBlock::spliceDebugInfoImpl(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. |