diff options
author | Jeremy Morse <jeremy.morse@sony.com> | 2025-07-16 14:13:53 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-16 14:13:53 +0100 |
commit | 5328c732a47705363cd289cb281cbd0d3ccbb8fc (patch) | |
tree | 6e3fafdc4edd881f9e3b9c60bd35bbda33caa311 /llvm/lib/Transforms/Utils/Local.cpp | |
parent | 9ea27b841cdf3c702b5e0bc696eb404492dbc79f (diff) | |
download | llvm-5328c732a47705363cd289cb281cbd0d3ccbb8fc.zip llvm-5328c732a47705363cd289cb281cbd0d3ccbb8fc.tar.gz llvm-5328c732a47705363cd289cb281cbd0d3ccbb8fc.tar.bz2 |
[DebugInfo] Strip more debug-intrinsic code from local utils (#149037)
SROA and a few other facilities use generic-lambdas and some overloaded
functions to deal with both intrinsics and debug-records at the same time.
As part of stripping out intrinsic support, delete a swathe of this code
from things in the Utils directory.
This is a large diff, but is mostly about removing functions that were
duplicated during the migration to debug records. I've taken a few
opportunities to replace comments about "intrinsics" with "records",
and replace generic lambdas with plain lambdas (I believe this makes
it more readable).
All of this is chipping away at intrinsic-specific code until we get to
removing parts of findDbgUsers, which is the final boss -- we can't
remove that until almost everything else is gone.
Diffstat (limited to 'llvm/lib/Transforms/Utils/Local.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/Local.cpp | 305 |
1 files changed, 19 insertions, 286 deletions
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index ccdaca9..72bc094 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -428,10 +428,6 @@ bool llvm::wouldInstructionBeTriviallyDead(const Instruction *I, if (I->isEHPad()) return false; - // We don't want debug info removed by anything this general. - if (isa<DbgVariableIntrinsic>(I)) - return false; - if (const DbgLabelInst *DLI = dyn_cast<DbgLabelInst>(I)) { if (DLI->getLabel()) return false; @@ -1632,33 +1628,6 @@ static bool PhiHasDebugValue(DILocalVariable *DIVar, /// describes an alloca'd variable, so we need to use the alloc size of the /// value when doing the comparison. E.g. an i1 value will be identified as /// covering an n-bit fragment, if the store size of i1 is at least n bits. -static bool valueCoversEntireFragment(Type *ValTy, DbgVariableIntrinsic *DII) { - const DataLayout &DL = DII->getDataLayout(); - TypeSize ValueSize = DL.getTypeAllocSizeInBits(ValTy); - if (std::optional<uint64_t> FragmentSize = - DII->getExpression()->getActiveBits(DII->getVariable())) - return TypeSize::isKnownGE(ValueSize, TypeSize::getFixed(*FragmentSize)); - - // We can't always calculate the size of the DI variable (e.g. if it is a - // VLA). Try to use the size of the alloca that the dbg intrinsic describes - // instead. - if (DII->isAddressOfVariable()) { - // DII should have exactly 1 location when it is an address. - assert(DII->getNumVariableLocationOps() == 1 && - "address of variable must have exactly 1 location operand."); - if (auto *AI = - dyn_cast_or_null<AllocaInst>(DII->getVariableLocationOp(0))) { - if (std::optional<TypeSize> FragmentSize = - AI->getAllocationSizeInBits(DL)) { - return TypeSize::isKnownGE(ValueSize, *FragmentSize); - } - } - } - // Could not determine size of variable. Conservatively return false. - return false; -} -// RemoveDIs: duplicate implementation of the above, using DbgVariableRecords, -// the replacement for dbg.values. static bool valueCoversEntireFragment(Type *ValTy, DbgVariableRecord *DVR) { const DataLayout &DL = DVR->getModule()->getDataLayout(); TypeSize ValueSize = DL.getTypeAllocSizeInBits(ValTy); @@ -1703,98 +1672,12 @@ static void insertDbgValueOrDbgVariableRecordAfter( insertDbgValueOrDbgVariableRecord(Builder, DV, DIVar, DIExpr, NewLoc, NextIt); } -/// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value -/// that has an associated llvm.dbg.declare intrinsic. -void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, - StoreInst *SI, DIBuilder &Builder) { - assert(DII->isAddressOfVariable() || isa<DbgAssignIntrinsic>(DII)); - auto *DIVar = DII->getVariable(); - assert(DIVar && "Missing variable"); - auto *DIExpr = DII->getExpression(); - Value *DV = SI->getValueOperand(); - - DebugLoc NewLoc = getDebugValueLoc(DII); - - // If the alloca describes the variable itself, i.e. the expression in the - // dbg.declare doesn't start with a dereference, we can perform the - // conversion if the value covers the entire fragment of DII. - // If the alloca describes the *address* of DIVar, i.e. DIExpr is - // *just* a DW_OP_deref, we use DV as is for the dbg.value. - // We conservatively ignore other dereferences, because the following two are - // not equivalent: - // dbg.declare(alloca, ..., !Expr(deref, plus_uconstant, 2)) - // dbg.value(DV, ..., !Expr(deref, plus_uconstant, 2)) - // The former is adding 2 to the address of the variable, whereas the latter - // is adding 2 to the value of the variable. As such, we insist on just a - // deref expression. - bool CanConvert = - DIExpr->isDeref() || (!DIExpr->startsWithDeref() && - valueCoversEntireFragment(DV->getType(), DII)); - if (CanConvert) { - insertDbgValueOrDbgVariableRecord(Builder, DV, DIVar, DIExpr, NewLoc, - SI->getIterator()); - return; - } - - // FIXME: If storing to a part of the variable described by the dbg.declare, - // then we want to insert a dbg.value for the corresponding fragment. - LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to dbg.value: " << *DII - << '\n'); - // For now, when there is a store to parts of the variable (but we do not - // know which part) we insert an dbg.value intrinsic to indicate that we - // know nothing about the variable's content. - DV = PoisonValue::get(DV->getType()); - insertDbgValueOrDbgVariableRecord(Builder, DV, DIVar, DIExpr, NewLoc, - SI->getIterator()); -} - static DIExpression *dropInitialDeref(const DIExpression *DIExpr) { int NumEltDropped = DIExpr->getElements()[0] == dwarf::DW_OP_LLVM_arg ? 3 : 1; return DIExpression::get(DIExpr->getContext(), DIExpr->getElements().drop_front(NumEltDropped)); } -void llvm::InsertDebugValueAtStoreLoc(DbgVariableIntrinsic *DII, StoreInst *SI, - DIBuilder &Builder) { - auto *DIVar = DII->getVariable(); - assert(DIVar && "Missing variable"); - auto *DIExpr = DII->getExpression(); - DIExpr = dropInitialDeref(DIExpr); - Value *DV = SI->getValueOperand(); - - DebugLoc NewLoc = getDebugValueLoc(DII); - - insertDbgValueOrDbgVariableRecord(Builder, DV, DIVar, DIExpr, NewLoc, - SI->getIterator()); -} - -/// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value -/// that has an associated llvm.dbg.declare intrinsic. -void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, - LoadInst *LI, DIBuilder &Builder) { - auto *DIVar = DII->getVariable(); - auto *DIExpr = DII->getExpression(); - assert(DIVar && "Missing variable"); - - if (!valueCoversEntireFragment(LI->getType(), DII)) { - // FIXME: If only referring to a part of the variable described by the - // dbg.declare, then we want to insert a dbg.value for the corresponding - // fragment. - LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to dbg.value: " - << *DII << '\n'); - return; - } - - DebugLoc NewLoc = getDebugValueLoc(DII); - - // We are now tracking the loaded value instead of the address. In the - // future if multi-location support is added to the IR, it might be - // preferable to keep tracking both the loaded value and the original - // address in case the alloca can not be elided. - insertDbgValueOrDbgVariableRecordAfter(Builder, LI, DIVar, DIExpr, NewLoc, - LI); -} - void llvm::ConvertDebugDeclareToDebugValue(DbgVariableRecord *DVR, StoreInst *SI, DIBuilder &Builder) { assert(DVR->isAddressOfVariable() || DVR->isDbgAssign()); @@ -1855,40 +1738,6 @@ void llvm::InsertDebugValueAtStoreLoc(DbgVariableRecord *DVR, StoreInst *SI, SI->getIterator()); } -/// Inserts a llvm.dbg.value intrinsic after a phi that has an associated -/// llvm.dbg.declare intrinsic. -void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, - PHINode *APN, DIBuilder &Builder) { - auto *DIVar = DII->getVariable(); - auto *DIExpr = DII->getExpression(); - assert(DIVar && "Missing variable"); - - if (PhiHasDebugValue(DIVar, DIExpr, APN)) - return; - - if (!valueCoversEntireFragment(APN->getType(), DII)) { - // FIXME: If only referring to a part of the variable described by the - // dbg.declare, then we want to insert a dbg.value for the corresponding - // fragment. - LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to dbg.value: " - << *DII << '\n'); - return; - } - - BasicBlock *BB = APN->getParent(); - auto InsertionPt = BB->getFirstInsertionPt(); - - DebugLoc NewLoc = getDebugValueLoc(DII); - - // The block may be a catchswitch block, which does not have a valid - // insertion point. - // FIXME: Insert dbg.value markers in the successors when appropriate. - if (InsertionPt != BB->end()) { - insertDbgValueOrDbgVariableRecord(Builder, APN, DIVar, DIExpr, NewLoc, - InsertionPt); - } -} - void llvm::ConvertDebugDeclareToDebugValue(DbgVariableRecord *DVR, LoadInst *LI, DIBuilder &Builder) { auto *DIVar = DVR->getVariable(); @@ -1981,7 +1830,7 @@ bool llvm::LowerDbgDeclare(Function &F) { if (Dbgs.empty() && DVRs.empty()) return Changed; - auto LowerOne = [&](auto *DDI) { + auto LowerOne = [&](DbgVariableRecord *DDI) { AllocaInst *AI = dyn_cast_or_null<AllocaInst>(DDI->getVariableLocationOp(0)); // If this is an alloca for a scalar variable, insert a dbg.value @@ -2036,7 +1885,6 @@ bool llvm::LowerDbgDeclare(Function &F) { Changed = true; }; - for_each(Dbgs, LowerOne); for_each(DVRs, LowerOne); if (Changed) @@ -2046,12 +1894,9 @@ bool llvm::LowerDbgDeclare(Function &F) { return Changed; } -// RemoveDIs: re-implementation of insertDebugValuesForPHIs, but which pulls the -// debug-info out of the block's DbgVariableRecords rather than dbg.value -// intrinsics. -static void -insertDbgVariableRecordsForPHIs(BasicBlock *BB, - SmallVectorImpl<PHINode *> &InsertedPHIs) { +/// Propagate dbg.value records through the newly inserted PHIs. +void llvm::insertDebugValuesForPHIs(BasicBlock *BB, + SmallVectorImpl<PHINode *> &InsertedPHIs) { assert(BB && "No BasicBlock to clone DbgVariableRecord(s) from."); if (InsertedPHIs.size() == 0) return; @@ -2113,76 +1958,12 @@ insertDbgVariableRecordsForPHIs(BasicBlock *BB, } } -/// Propagate dbg.value intrinsics through the newly inserted PHIs. -void llvm::insertDebugValuesForPHIs(BasicBlock *BB, - SmallVectorImpl<PHINode *> &InsertedPHIs) { - assert(BB && "No BasicBlock to clone dbg.value(s) from."); - if (InsertedPHIs.size() == 0) - return; - - insertDbgVariableRecordsForPHIs(BB, InsertedPHIs); - - // Map existing PHI nodes to their dbg.values. - ValueToValueMapTy DbgValueMap; - for (auto &I : *BB) { - if (auto DbgII = dyn_cast<DbgVariableIntrinsic>(&I)) { - for (Value *V : DbgII->location_ops()) - if (auto *Loc = dyn_cast_or_null<PHINode>(V)) - DbgValueMap.insert({Loc, DbgII}); - } - } - if (DbgValueMap.size() == 0) - return; - - // Map a pair of the destination BB and old dbg.value to the new dbg.value, - // so that if a dbg.value is being rewritten to use more than one of the - // inserted PHIs in the same destination BB, we can update the same dbg.value - // with all the new PHIs instead of creating one copy for each. - MapVector<std::pair<BasicBlock *, DbgVariableIntrinsic *>, - DbgVariableIntrinsic *> - NewDbgValueMap; - // Then iterate through the new PHIs and look to see if they use one of the - // previously mapped PHIs. If so, create a new dbg.value intrinsic that will - // propagate the info through the new PHI. If we use more than one new PHI in - // a single destination BB with the same old dbg.value, merge the updates so - // that we get a single new dbg.value with all the new PHIs. - for (auto *PHI : InsertedPHIs) { - BasicBlock *Parent = PHI->getParent(); - // Avoid inserting an intrinsic into an EH block. - if (Parent->getFirstNonPHIIt()->isEHPad()) - continue; - for (auto *VI : PHI->operand_values()) { - auto V = DbgValueMap.find(VI); - if (V != DbgValueMap.end()) { - auto *DbgII = cast<DbgVariableIntrinsic>(V->second); - auto [NewDI, Inserted] = NewDbgValueMap.try_emplace({Parent, DbgII}); - if (Inserted) - NewDI->second = cast<DbgVariableIntrinsic>(DbgII->clone()); - DbgVariableIntrinsic *NewDbgII = NewDI->second; - // If PHI contains VI as an operand more than once, we may - // replaced it in NewDbgII; confirm that it is present. - if (is_contained(NewDbgII->location_ops(), VI)) - NewDbgII->replaceVariableLocationOp(VI, PHI); - } - } - } - // Insert thew new dbg.values into their destination blocks. - for (auto DI : NewDbgValueMap) { - BasicBlock *Parent = DI.first.first; - auto *NewDbgII = DI.second; - auto InsertionPt = Parent->getFirstInsertionPt(); - assert(InsertionPt != Parent->end() && "Ill-formed basic block"); - NewDbgII->insertBefore(InsertionPt); - } -} - bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress, DIBuilder &Builder, uint8_t DIExprFlags, int Offset) { - TinyPtrVector<DbgDeclareInst *> DbgDeclares = findDbgDeclares(Address); TinyPtrVector<DbgVariableRecord *> DVRDeclares = findDVRDeclares(Address); - auto ReplaceOne = [&](auto *DII) { + auto ReplaceOne = [&](DbgVariableRecord *DII) { assert(DII->getVariable() && "Missing variable"); auto *DIExpr = DII->getExpression(); DIExpr = DIExpression::prepend(DIExpr, DIExprFlags, Offset); @@ -2190,10 +1971,9 @@ bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress, DII->replaceVariableLocationOp(Address, NewAddress); }; - for_each(DbgDeclares, ReplaceOne); for_each(DVRDeclares, ReplaceOne); - return !DbgDeclares.empty() || !DVRDeclares.empty(); + return !DVRDeclares.empty(); } static void updateOneDbgValueForAlloca(const DebugLoc &Loc, @@ -2645,7 +2425,6 @@ using DbgValReplacement = std::optional<DIExpression *>; /// changes are made. static bool rewriteDebugUsers( Instruction &From, Value &To, Instruction &DomPoint, DominatorTree &DT, - function_ref<DbgValReplacement(DbgVariableIntrinsic &DII)> RewriteExpr, function_ref<DbgValReplacement(DbgVariableRecord &DVR)> RewriteDVRExpr) { // Find debug users of From. SmallVector<DbgVariableIntrinsic *, 1> Users; @@ -2654,43 +2433,32 @@ static bool rewriteDebugUsers( if (Users.empty() && DPUsers.empty()) return false; + // Ignore intrinsic-users: they are no longer supported and should never + // appear. + assert(Users.empty()); + // Prevent use-before-def of To. bool Changed = false; - SmallPtrSet<DbgVariableIntrinsic *, 1> UndefOrSalvage; SmallPtrSet<DbgVariableRecord *, 1> UndefOrSalvageDVR; if (isa<Instruction>(&To)) { bool DomPointAfterFrom = From.getNextNode() == &DomPoint; - for (auto *DII : Users) { - // It's common to see a debug user between From and DomPoint. Move it - // after DomPoint to preserve the variable update without any reordering. - if (DomPointAfterFrom && DII->getNextNode() == &DomPoint) { - LLVM_DEBUG(dbgs() << "MOVE: " << *DII << '\n'); - DII->moveAfter(&DomPoint); - Changed = true; - - // Users which otherwise aren't dominated by the replacement value must - // be salvaged or deleted. - } else if (!DT.dominates(&DomPoint, DII)) { - UndefOrSalvage.insert(DII); - } - } - // DbgVariableRecord implementation of the above. for (auto *DVR : DPUsers) { Instruction *MarkedInstr = DVR->getMarker()->MarkedInstr; Instruction *NextNonDebug = MarkedInstr; - // The next instruction might still be a dbg.declare, skip over it. - if (isa<DbgVariableIntrinsic>(NextNonDebug)) - NextNonDebug = NextNonDebug->getNextNode(); + // It's common to see a debug user between From and DomPoint. Move it + // after DomPoint to preserve the variable update without any reordering. if (DomPointAfterFrom && NextNonDebug == &DomPoint) { LLVM_DEBUG(dbgs() << "MOVE: " << *DVR << '\n'); DVR->removeFromParent(); - // Ensure there's a marker. DomPoint.getParent()->insertDbgRecordAfter(DVR, &DomPoint); Changed = true; + + // Users which otherwise aren't dominated by the replacement value must + // be salvaged or deleted. } else if (!DT.dominates(&DomPoint, MarkedInstr)) { UndefOrSalvageDVR.insert(DVR); } @@ -2698,19 +2466,6 @@ static bool rewriteDebugUsers( } // Update debug users without use-before-def risk. - for (auto *DII : Users) { - if (UndefOrSalvage.count(DII)) - continue; - - DbgValReplacement DVRepl = RewriteExpr(*DII); - if (!DVRepl) - continue; - - DII->replaceVariableLocationOp(&From, &To); - DII->setExpression(*DVRepl); - LLVM_DEBUG(dbgs() << "REWRITE: " << *DII << '\n'); - Changed = true; - } for (auto *DVR : DPUsers) { if (UndefOrSalvageDVR.count(DVR)) continue; @@ -2725,7 +2480,7 @@ static bool rewriteDebugUsers( Changed = true; } - if (!UndefOrSalvage.empty() || !UndefOrSalvageDVR.empty()) { + if (!UndefOrSalvageDVR.empty()) { // Try to salvage the remaining debug users. salvageDebugInfo(From); Changed = true; @@ -2770,9 +2525,6 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To, Type *FromTy = From.getType(); Type *ToTy = To.getType(); - auto Identity = [&](DbgVariableIntrinsic &DII) -> DbgValReplacement { - return DII.getExpression(); - }; auto IdentityDVR = [&](DbgVariableRecord &DVR) -> DbgValReplacement { return DVR.getExpression(); }; @@ -2781,7 +2533,7 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To, Module &M = *From.getModule(); const DataLayout &DL = M.getDataLayout(); if (isBitCastSemanticsPreserving(DL, FromTy, ToTy)) - return rewriteDebugUsers(From, To, DomPoint, DT, Identity, IdentityDVR); + return rewriteDebugUsers(From, To, DomPoint, DT, IdentityDVR); // Handle integer-to-integer widening and narrowing. // FIXME: Use DW_OP_convert when it's available everywhere. @@ -2793,24 +2545,10 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To, // When the width of the result grows, assume that a debugger will only // access the low `FromBits` bits when inspecting the source variable. if (FromBits < ToBits) - return rewriteDebugUsers(From, To, DomPoint, DT, Identity, IdentityDVR); + return rewriteDebugUsers(From, To, DomPoint, DT, IdentityDVR); // The width of the result has shrunk. Use sign/zero extension to describe // the source variable's high bits. - auto SignOrZeroExt = [&](DbgVariableIntrinsic &DII) -> DbgValReplacement { - DILocalVariable *Var = DII.getVariable(); - - // Without knowing signedness, sign/zero extension isn't possible. - auto Signedness = Var->getSignedness(); - if (!Signedness) - return std::nullopt; - - bool Signed = *Signedness == DIBasicType::Signedness::Signed; - return DIExpression::appendExt(DII.getExpression(), ToBits, FromBits, - Signed); - }; - // RemoveDIs: duplicate implementation working on DbgVariableRecords rather - // than on dbg.value intrinsics. auto SignOrZeroExtDVR = [&](DbgVariableRecord &DVR) -> DbgValReplacement { DILocalVariable *Var = DVR.getVariable(); @@ -2823,8 +2561,7 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To, return DIExpression::appendExt(DVR.getExpression(), ToBits, FromBits, Signed); }; - return rewriteDebugUsers(From, To, DomPoint, DT, SignOrZeroExt, - SignOrZeroExtDVR); + return rewriteDebugUsers(From, To, DomPoint, DT, SignOrZeroExtDVR); } // TODO: Floating-point conversions, vectors. @@ -3800,10 +3537,6 @@ void llvm::remapDebugVariable(ValueToValueMapTy &Mapping, Instruction *Inst) { if (I != Mapping.end()) DA->setAddress(I->second); }; - if (auto DVI = dyn_cast<DbgVariableIntrinsic>(Inst)) - RemapDebugOperands(DVI, DVI->location_ops()); - if (auto DAI = dyn_cast<DbgAssignIntrinsic>(Inst)) - RemapAssignAddress(DAI); for (DbgVariableRecord &DVR : filterDbgVars(Inst->getDbgRecordRange())) { RemapDebugOperands(&DVR, DVR.location_ops()); if (DVR.isDbgAssign()) |