diff options
author | Jeremy Morse <jeremy.morse@sony.com> | 2023-11-26 22:57:40 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-26 22:57:40 +0000 |
commit | f0b5527b793413e40bfe1db799d9188e9180b53d (patch) | |
tree | b3440f286ac0d87e82d3c7a78d5c7c08aa4f19cf /llvm/lib/Transforms/Utils/LoopRotationUtils.cpp | |
parent | 1a08887784484f7ea49c66c188c73527e7764648 (diff) | |
download | llvm-f0b5527b793413e40bfe1db799d9188e9180b53d.zip llvm-f0b5527b793413e40bfe1db799d9188e9180b53d.tar.gz llvm-f0b5527b793413e40bfe1db799d9188e9180b53d.tar.bz2 |
[DebugInfo][RemoveDIs] Instrument loop-rotate for DPValues (#72997)
Loop-rotate manually maintains dbg.value intrinsics -- it also needs to
manually maintain the replacement for dbg.value intrinsics, DPValue
objects. For the most part this patch adds parallel implementations
using the new type Some extra juggling is needed when loop-rotate hoists
loop-invariant instructions out of the loop: the DPValues attached to
such an instruction need to get rotated but not hoisted. Exercised by
the new test function invariant_hoist in dbgvalue.ll.
There's also a "don't insert duplicate debug intrinsics" facility in
LoopRotate. The value and correctness of this isn't clear, but to
continue preserving behaviour that's now tested in the "tak_dup"
function in dbgvalue.ll.
Other things in this patch include a helper DebugVariable constructor
for DPValues, a insertDebugValuesForPHIs handler for RemoveDIs
(exercised by the new tests), and beefing up the dbg.value checking in
dbgvalue.ll to ensure that each record is tested (and that there's an
implicit check-not).
Diffstat (limited to 'llvm/lib/Transforms/Utils/LoopRotationUtils.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/LoopRotationUtils.cpp | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp b/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp index ae155ac..cbef27d 100644 --- a/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp +++ b/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp @@ -159,7 +159,8 @@ static void RewriteUsesOfClonedInstructions(BasicBlock *OrigHeader, // Replace MetadataAsValue(ValueAsMetadata(OrigHeaderVal)) uses in debug // intrinsics. SmallVector<DbgValueInst *, 1> DbgValues; - llvm::findDbgValues(DbgValues, OrigHeaderVal); + SmallVector<DPValue *, 1> DPValues; + llvm::findDbgValues(DbgValues, OrigHeaderVal, &DPValues); for (auto &DbgValue : DbgValues) { // The original users in the OrigHeader are already using the original // definitions. @@ -180,6 +181,29 @@ static void RewriteUsesOfClonedInstructions(BasicBlock *OrigHeader, NewVal = UndefValue::get(OrigHeaderVal->getType()); DbgValue->replaceVariableLocationOp(OrigHeaderVal, NewVal); } + + // RemoveDIs: duplicate implementation for non-instruction debug-info + // storage in DPValues. + for (DPValue *DPV : DPValues) { + // The original users in the OrigHeader are already using the original + // definitions. + BasicBlock *UserBB = DPV->getMarker()->getParent(); + if (UserBB == OrigHeader) + continue; + + // Users in the OrigPreHeader need to use the value to which the + // original definitions are mapped and anything else can be handled by + // the SSAUpdater. To avoid adding PHINodes, check if the value is + // available in UserBB, if not substitute undef. + Value *NewVal; + if (UserBB == OrigPreheader) + NewVal = OrigPreHeaderVal; + else if (SSA.HasValueForBlock(UserBB)) + NewVal = SSA.GetValueInMiddleOfBlock(UserBB); + else + NewVal = UndefValue::get(OrigHeaderVal->getType()); + DPV->replaceVariableLocationOp(OrigHeaderVal, NewVal); + } } } @@ -531,6 +555,18 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { break; } + // Duplicate implementation for DPValues, the non-instruction format of + // debug-info records in RemoveDIs. + auto makeHashDPV = [](const DPValue &D) -> DbgIntrinsicHash { + auto VarLocOps = D.location_ops(); + return {{hash_combine_range(VarLocOps.begin(), VarLocOps.end()), + D.getVariable()}, + D.getExpression()}; + }; + for (Instruction &I : llvm::drop_begin(llvm::reverse(*OrigPreheader))) + for (const DPValue &DPV : I.getDbgValueRange()) + DbgIntrinsics.insert(makeHashDPV(DPV)); + // Remember the local noalias scope declarations in the header. After the // rotation, they must be duplicated and the scope must be cloned. This // avoids unwanted interaction across iterations. @@ -539,6 +575,29 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { if (auto *Decl = dyn_cast<NoAliasScopeDeclInst>(&I)) NoAliasDeclInstructions.push_back(Decl); + Module *M = OrigHeader->getModule(); + + // Track the next DPValue to clone. If we have a sequence where an + // instruction is hoisted instead of being cloned: + // DPValue blah + // %foo = add i32 0, 0 + // DPValue xyzzy + // %bar = call i32 @foobar() + // where %foo is hoisted, then the DPValue "blah" will be seen twice, once + // attached to %foo, then when %foo his hoisted it will "fall down" onto the + // function call: + // DPValue blah + // DPValue xyzzy + // %bar = call i32 @foobar() + // causing it to appear attached to the call too. + // + // To avoid this, cloneDebugInfoFrom takes an optional "start cloning from + // here" position to account for this behaviour. We point it at any DPValues + // on the next instruction, here labelled xyzzy, before we hoist %foo. + // Later, we only only clone DPValues from that position (xyzzy) onwards, + // which avoids cloning DPValue "blah" multiple times. + std::optional<DPValue::self_iterator> NextDbgInst = std::nullopt; + while (I != E) { Instruction *Inst = &*I++; @@ -551,7 +610,17 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { if (L->hasLoopInvariantOperands(Inst) && !Inst->mayReadFromMemory() && !Inst->mayWriteToMemory() && !Inst->isTerminator() && !isa<DbgInfoIntrinsic>(Inst) && !isa<AllocaInst>(Inst)) { + + if (LoopEntryBranch->getParent()->IsNewDbgInfoFormat) { + auto DbgValueRange = + LoopEntryBranch->cloneDebugInfoFrom(Inst, NextDbgInst); + RemapDPValueRange(M, DbgValueRange, ValueMap, + RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); + } + + NextDbgInst = I->getDbgValueRange().begin(); Inst->moveBefore(LoopEntryBranch); + ++NumInstrsHoisted; continue; } @@ -562,6 +631,17 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { ++NumInstrsDuplicated; + if (LoopEntryBranch->getParent()->IsNewDbgInfoFormat) { + auto Range = C->cloneDebugInfoFrom(Inst, NextDbgInst); + // Erase anything we've seen before. + for (DPValue &DPV : make_early_inc_range(Range)) + if (DbgIntrinsics.count(makeHashDPV(DPV))) + DPV.eraseFromParent(); + RemapDPValueRange(M, Range, ValueMap, + RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); + NextDbgInst = std::nullopt; + } + // Eagerly remap the operands of the instruction. RemapInstruction(C, ValueMap, RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); @@ -676,6 +756,7 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { // OrigPreHeader's old terminator (the original branch into the loop), and // remove the corresponding incoming values from the PHI nodes in OrigHeader. LoopEntryBranch->eraseFromParent(); + OrigPreheader->flushTerminatorDbgValues(); // Update MemorySSA before the rewrite call below changes the 1:1 // instruction:cloned_instruction_or_value mapping. |