diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h index fa8405a6191eb..2df3c9049c7d6 100644 --- a/llvm/include/llvm/Transforms/Utils/Local.h +++ b/llvm/include/llvm/Transforms/Utils/Local.h @@ -262,16 +262,22 @@ CallInst *changeToCall(InvokeInst *II, DomTreeUpdater *DTU = nullptr); /// that has an associated llvm.dbg.declare intrinsic. void ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, StoreInst *SI, DIBuilder &Builder); +void ConvertDebugDeclareToDebugValue(DPValue *DPV, StoreInst *SI, + DIBuilder &Builder); /// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value /// that has an associated llvm.dbg.declare intrinsic. void ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, LoadInst *LI, DIBuilder &Builder); +void ConvertDebugDeclareToDebugValue(DPValue *DPV, LoadInst *LI, + DIBuilder &Builder); /// Inserts a llvm.dbg.value intrinsic after a phi that has an associated /// llvm.dbg.declare intrinsic. void ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, PHINode *LI, DIBuilder &Builder); +void ConvertDebugDeclareToDebugValue(DPValue *DPV, PHINode *LI, + DIBuilder &Builder); /// Lowers llvm.dbg.declare intrinsics into appropriate set of /// llvm.dbg.value intrinsics. @@ -302,12 +308,12 @@ void replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress, /// cannot be salvaged changes its debug uses to undef. void salvageDebugInfo(Instruction &I); - /// Implementation of salvageDebugInfo, applying only to instructions in /// \p Insns, rather than all debug users from findDbgUsers( \p I). /// Mark undef if salvaging cannot be completed. void salvageDebugInfoForDbgValues(Instruction &I, - ArrayRef Insns); + ArrayRef Insns, + ArrayRef DPInsns); /// Given an instruction \p I and DIExpression \p DIExpr operating on /// it, append the effects of \p I to the DIExpression operand list diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index a41bcff58e529..7037f5f524ee0 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -985,8 +985,9 @@ void BasicBlock::insertDPValueAfter(DPValue *DPV, Instruction *I) { assert(I->getParent() == this); iterator NextIt = std::next(I->getIterator()); - DPMarker *NextMarker = - (NextIt == end()) ? getTrailingDPValues() : NextIt->DbgMarker; + DPMarker *NextMarker = getMarker(NextIt); + if (!NextMarker) + NextMarker = createMarker(NextIt); NextMarker->insertDPValue(DPV, true); } diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 2e0b185769041..5940ab735e747 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3921,6 +3921,7 @@ bool InstCombinerImpl::tryToSinkInstruction(Instruction *I, // For all debug values in the destination block, the sunk instruction // will still be available, so they do not need to be dropped. SmallVector DbgUsersToSalvage; + SmallVector DPValuesToSalvage; for (auto &DbgUser : DbgUsers) if (DbgUser->getParent() != DestBlock) DbgUsersToSalvage.push_back(DbgUser); @@ -3964,7 +3965,10 @@ bool InstCombinerImpl::tryToSinkInstruction(Instruction *I, // Perform salvaging without the clones, then sink the clones. if (!DIIClones.empty()) { - salvageDebugInfoForDbgValues(*I, DbgUsersToSalvage); + // RemoveDIs: pass in empty vector of DPValues until we get to instrumenting + // this pass. + SmallVector DummyDPValues; + salvageDebugInfoForDbgValues(*I, DbgUsersToSalvage, DummyDPValues); // The clones are in reverse order of original appearance, reverse again to // maintain the original order. for (auto &DIIClone : llvm::reverse(DIIClones)) { diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index aacf66bfe38eb..db63b74f78493 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -69,6 +69,7 @@ #include "llvm/IR/Value.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" @@ -86,6 +87,8 @@ using namespace llvm; using namespace llvm::PatternMatch; +extern cl::opt UseNewDbgInfoFormat; + #define DEBUG_TYPE "local" STATISTIC(NumRemoved, "Number of unreachable basic blocks removed"); @@ -608,10 +611,13 @@ void llvm::RecursivelyDeleteTriviallyDeadInstructions( bool llvm::replaceDbgUsesWithUndef(Instruction *I) { SmallVector DbgUsers; - findDbgUsers(DbgUsers, I); + SmallVector DPUsers; + findDbgUsers(DbgUsers, I, &DPUsers); for (auto *DII : DbgUsers) DII->setKillLocation(); - return !DbgUsers.empty(); + for (auto *DPV : DPUsers) + DPV->setKillLocation(); + return !DbgUsers.empty() || !DPUsers.empty(); } /// areAllUsesEqual - Check whether the uses of a value are all the same. @@ -1566,12 +1572,18 @@ static bool PhiHasDebugValue(DILocalVariable *DIVar, // is removed by LowerDbgDeclare(), we need to make sure that we are // not inserting the same dbg.value intrinsic over and over. SmallVector DbgValues; - findDbgValues(DbgValues, APN); + SmallVector DPValues; + findDbgValues(DbgValues, APN, &DPValues); for (auto *DVI : DbgValues) { assert(is_contained(DVI->getValues(), APN)); if ((DVI->getVariable() == DIVar) && (DVI->getExpression() == DIExpr)) return true; } + for (auto *DPV : DPValues) { + assert(is_contained(DPV->location_ops(), APN)); + if ((DPV->getVariable() == DIVar) && (DPV->getExpression() == DIExpr)) + return true; + } return false; } @@ -1607,6 +1619,67 @@ static bool valueCoversEntireFragment(Type *ValTy, DbgVariableIntrinsic *DII) { // Could not determine size of variable. Conservatively return false. return false; } +// RemoveDIs: duplicate implementation of the above, using DPValues, the +// replacement for dbg.values. +static bool valueCoversEntireFragment(Type *ValTy, DPValue *DPV) { + const DataLayout &DL = DPV->getModule()->getDataLayout(); + TypeSize ValueSize = DL.getTypeAllocSizeInBits(ValTy); + if (std::optional FragmentSize = DPV->getFragmentSizeInBits()) + return TypeSize::isKnownGE(ValueSize, TypeSize::Fixed(*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 + // intead. + if (DPV->isAddressOfVariable()) { + // DPV should have exactly 1 location when it is an address. + assert(DPV->getNumVariableLocationOps() == 1 && + "address of variable must have exactly 1 location operand."); + if (auto *AI = + dyn_cast_or_null(DPV->getVariableLocationOp(0))) { + if (std::optional FragmentSize = AI->getAllocationSizeInBits(DL)) { + return TypeSize::isKnownGE(ValueSize, *FragmentSize); + } + } + } + // Could not determine size of variable. Conservatively return false. + return false; +} + +static void insertDbgValueOrDPValue(DIBuilder &Builder, Value *DV, + DILocalVariable *DIVar, + DIExpression *DIExpr, + const DebugLoc &NewLoc, + BasicBlock::iterator Instr) { + if (!UseNewDbgInfoFormat) { + auto *DbgVal = Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, NewLoc, + (Instruction *)nullptr); + DbgVal->insertBefore(Instr); + } else { + // RemoveDIs: if we're using the new debug-info format, allocate a + // DPValue directly instead of a dbg.value intrinsic. + ValueAsMetadata *DVAM = ValueAsMetadata::get(DV); + DPValue *DV = new DPValue(DVAM, DIVar, DIExpr, NewLoc.get()); + Instr->getParent()->insertDPValueBefore(DV, Instr); + } +} + +static void insertDbgValueOrDPValueAfter(DIBuilder &Builder, Value *DV, + DILocalVariable *DIVar, + DIExpression *DIExpr, + const DebugLoc &NewLoc, + BasicBlock::iterator Instr) { + if (!UseNewDbgInfoFormat) { + auto *DbgVal = Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, NewLoc, + (Instruction *)nullptr); + DbgVal->insertAfter(&*Instr); + } else { + // RemoveDIs: if we're using the new debug-info format, allocate a + // DPValue directly instead of a dbg.value intrinsic. + ValueAsMetadata *DVAM = ValueAsMetadata::get(DV); + DPValue *DV = new DPValue(DVAM, DIVar, DIExpr, NewLoc.get()); + Instr->getParent()->insertDPValueAfter(DV, &*Instr); + } +} /// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value /// that has an associated llvm.dbg.declare intrinsic. @@ -1636,7 +1709,8 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, DIExpr->isDeref() || (!DIExpr->startsWithDeref() && valueCoversEntireFragment(DV->getType(), DII)); if (CanConvert) { - Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, NewLoc, SI); + insertDbgValueOrDPValue(Builder, DV, DIVar, DIExpr, NewLoc, + SI->getIterator()); return; } @@ -1648,7 +1722,19 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, // know which part) we insert an dbg.value intrinsic to indicate that we // know nothing about the variable's content. DV = UndefValue::get(DV->getType()); - Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, NewLoc, SI); + insertDbgValueOrDPValue(Builder, DV, DIVar, DIExpr, NewLoc, + SI->getIterator()); +} + +// RemoveDIs: duplicate the getDebugValueLoc method using DPValues instead of +// dbg.value intrinsics. +static DebugLoc getDebugValueLocDPV(DPValue *DPV) { + // Original dbg.declare must have a location. + const DebugLoc &DeclareLoc = DPV->getDebugLoc(); + MDNode *Scope = DeclareLoc.getScope(); + DILocation *InlinedAt = DeclareLoc.getInlinedAt(); + // Produce an unknown location with the correct scope / inlinedAt fields. + return DILocation::get(DPV->getContext(), 0, 0, Scope, InlinedAt); } /// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value @@ -1674,9 +1760,40 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, // 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. - Instruction *DbgValue = Builder.insertDbgValueIntrinsic( - LI, DIVar, DIExpr, NewLoc, (Instruction *)nullptr); - DbgValue->insertAfter(LI); + insertDbgValueOrDPValueAfter(Builder, LI, DIVar, DIExpr, NewLoc, + LI->getIterator()); +} + +void llvm::ConvertDebugDeclareToDebugValue(DPValue *DPV, StoreInst *SI, + DIBuilder &Builder) { + assert(DPV->isAddressOfVariable()); + auto *DIVar = DPV->getVariable(); + assert(DIVar && "Missing variable"); + auto *DIExpr = DPV->getExpression(); + Value *DV = SI->getValueOperand(); + + DebugLoc NewLoc = getDebugValueLocDPV(DPV); + + if (!valueCoversEntireFragment(DV->getType(), DPV)) { + // FIXME: If storing to a part of the variable described by the dbg.declare, + // then we want to insert a DPValue.value for the corresponding fragment. + LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to DPValue: " << *DPV + << '\n'); + // For now, when there is a store to parts of the variable (but we do not + // know which part) we insert an DPValue record to indicate that we know + // nothing about the variable's content. + DV = UndefValue::get(DV->getType()); + ValueAsMetadata *DVAM = ValueAsMetadata::get(DV); + DPValue *NewDPV = new DPValue(DVAM, DIVar, DIExpr, NewLoc.get()); + SI->getParent()->insertDPValueBefore(NewDPV, SI->getIterator()); + return; + } + + assert(UseNewDbgInfoFormat); + // Create a DPValue directly and insert. + ValueAsMetadata *DVAM = ValueAsMetadata::get(DV); + DPValue *NewDPV = new DPValue(DVAM, DIVar, DIExpr, NewLoc.get()); + SI->getParent()->insertDPValueBefore(NewDPV, SI->getIterator()); } /// Inserts a llvm.dbg.value intrinsic after a phi that has an associated @@ -1707,8 +1824,38 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *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()) - Builder.insertDbgValueIntrinsic(APN, DIVar, DIExpr, NewLoc, &*InsertionPt); + if (InsertionPt != BB->end()) { + insertDbgValueOrDPValue(Builder, APN, DIVar, DIExpr, NewLoc, InsertionPt); + } +} + +void llvm::ConvertDebugDeclareToDebugValue(DPValue *DPV, LoadInst *LI, + DIBuilder &Builder) { + auto *DIVar = DPV->getVariable(); + auto *DIExpr = DPV->getExpression(); + assert(DIVar && "Missing variable"); + + if (!valueCoversEntireFragment(LI->getType(), DPV)) { + // FIXME: If only referring to a part of the variable described by the + // dbg.declare, then we want to insert a DPValue for the corresponding + // fragment. + LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to DPValue: " << *DPV + << '\n'); + return; + } + + DebugLoc NewLoc = getDebugValueLocDPV(DPV); + + // 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. + assert(UseNewDbgInfoFormat); + + // Create a DPValue directly and insert. + ValueAsMetadata *LIVAM = ValueAsMetadata::get(LI); + DPValue *DV = new DPValue(LIVAM, DIVar, DIExpr, NewLoc.get()); + LI->getParent()->insertDPValueAfter(DV, LI); } /// Determine whether this alloca is either a VLA or an array. @@ -1721,6 +1868,36 @@ static bool isArray(AllocaInst *AI) { static bool isStructure(AllocaInst *AI) { return AI->getAllocatedType() && AI->getAllocatedType()->isStructTy(); } +void llvm::ConvertDebugDeclareToDebugValue(DPValue *DPV, PHINode *APN, + DIBuilder &Builder) { + auto *DIVar = DPV->getVariable(); + auto *DIExpr = DPV->getExpression(); + assert(DIVar && "Missing variable"); + + if (PhiHasDebugValue(DIVar, DIExpr, APN)) + return; + + if (!valueCoversEntireFragment(APN->getType(), DPV)) { + // FIXME: If only referring to a part of the variable described by the + // dbg.declare, then we want to insert a DPValue for the corresponding + // fragment. + LLVM_DEBUG(dbgs() << "Failed to convert dbg.declare to DPValue: " << *DPV + << '\n'); + return; + } + + BasicBlock *BB = APN->getParent(); + auto InsertionPt = BB->getFirstInsertionPt(); + + DebugLoc NewLoc = getDebugValueLocDPV(DPV); + + // The block may be a catchswitch block, which does not have a valid + // insertion point. + // FIXME: Insert DPValue markers in the successors when appropriate. + if (InsertionPt != BB->end()) { + insertDbgValueOrDPValue(Builder, APN, DIVar, DIExpr, NewLoc, InsertionPt); + } +} /// LowerDbgDeclare - Lowers llvm.dbg.declare intrinsics into appropriate set /// of llvm.dbg.value intrinsics. @@ -1777,8 +1954,8 @@ bool llvm::LowerDbgDeclare(Function &F) { DebugLoc NewLoc = getDebugValueLoc(DDI); auto *DerefExpr = DIExpression::append(DDI->getExpression(), dwarf::DW_OP_deref); - DIB.insertDbgValueIntrinsic(AI, DDI->getVariable(), DerefExpr, - NewLoc, CI); + insertDbgValueOrDPValue(DIB, AI, DDI->getVariable(), DerefExpr, + NewLoc, CI->getIterator()); } } else if (BitCastInst *BI = dyn_cast(U)) { if (BI->getType()->isPointerTy()) @@ -1878,44 +2055,60 @@ bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress, return !DbgDeclares.empty(); } -static void replaceOneDbgValueForAlloca(DbgValueInst *DVI, Value *NewAddress, - DIBuilder &Builder, int Offset) { - const DebugLoc &Loc = DVI->getDebugLoc(); - auto *DIVar = DVI->getVariable(); - auto *DIExpr = DVI->getExpression(); +static void updateOneDbgValueForAlloca(const DebugLoc &Loc, + DILocalVariable *DIVar, + DIExpression *DIExpr, Value *NewAddress, + DbgValueInst *DVI, DPValue *DPV, + DIBuilder &Builder, int Offset) { assert(DIVar && "Missing variable"); - // This is an alloca-based llvm.dbg.value. The first thing it should do with - // the alloca pointer is dereference it. Otherwise we don't know how to handle - // it and give up. + // This is an alloca-based dbg.value/DPValue. The first thing it should do + // with the alloca pointer is dereference it. Otherwise we don't know how to + // handle it and give up. if (!DIExpr || DIExpr->getNumElements() < 1 || DIExpr->getElement(0) != dwarf::DW_OP_deref) return; // Insert the offset before the first deref. - // We could just change the offset argument of dbg.value, but it's unsigned... if (Offset) DIExpr = DIExpression::prepend(DIExpr, 0, Offset); - Builder.insertDbgValueIntrinsic(NewAddress, DIVar, DIExpr, Loc, DVI); - DVI->eraseFromParent(); + if (DVI) { + DVI->setExpression(DIExpr); + DVI->replaceVariableLocationOp(0u, NewAddress); + } else { + assert(DPV); + DPV->setExpression(DIExpr); + DPV->replaceVariableLocationOp(0u, NewAddress); + } } void llvm::replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, int Offset) { - if (auto *L = LocalAsMetadata::getIfExists(AI)) - if (auto *MDV = MetadataAsValue::getIfExists(AI->getContext(), L)) - for (Use &U : llvm::make_early_inc_range(MDV->uses())) - if (auto *DVI = dyn_cast(U.getUser())) - replaceOneDbgValueForAlloca(DVI, NewAllocaAddress, Builder, Offset); + SmallVector DbgUsers; + SmallVector DPUsers; + findDbgValues(DbgUsers, AI, &DPUsers); + + // Attempt to replace dbg.values that use this alloca. + for (auto *DVI : DbgUsers) + updateOneDbgValueForAlloca(DVI->getDebugLoc(), DVI->getVariable(), + DVI->getExpression(), NewAllocaAddress, DVI, + nullptr, Builder, Offset); + + // Replace any DPValues that use this alloca. + for (DPValue *DPV : DPUsers) + updateOneDbgValueForAlloca(DPV->getDebugLoc(), DPV->getVariable(), + DPV->getExpression(), NewAllocaAddress, nullptr, + DPV, Builder, Offset); } /// Where possible to salvage debug information for \p I do so. /// If not possible mark undef. void llvm::salvageDebugInfo(Instruction &I) { SmallVector DbgUsers; - findDbgUsers(DbgUsers, &I); - salvageDebugInfoForDbgValues(I, DbgUsers); + SmallVector DPUsers; + findDbgUsers(DbgUsers, &I, &DPUsers); + salvageDebugInfoForDbgValues(I, DbgUsers, DPUsers); } /// Salvage the address component of \p DAI. @@ -1953,7 +2146,8 @@ static void salvageDbgAssignAddress(DbgAssignIntrinsic *DAI) { } void llvm::salvageDebugInfoForDbgValues( - Instruction &I, ArrayRef DbgUsers) { + Instruction &I, ArrayRef DbgUsers, + ArrayRef DPUsers) { // These are arbitrary chosen limits on the maximum number of values and the // maximum size of a debug expression we can salvage up to, used for // performance reasons. @@ -2019,12 +2213,70 @@ void llvm::salvageDebugInfoForDbgValues( LLVM_DEBUG(dbgs() << "SALVAGE: " << *DII << '\n'); Salvaged = true; } + // Duplicate of above block for DPValues. + for (auto *DPV : DPUsers) { + // Do not add DW_OP_stack_value for DbgDeclare and DbgAddr, because they + // are implicitly pointing out the value as a DWARF memory location + // description. + bool StackValue = DPV->getType() == DPValue::LocationType::Value; + auto DPVLocation = DPV->location_ops(); + assert( + is_contained(DPVLocation, &I) && + "DbgVariableIntrinsic must use salvaged instruction as its location"); + SmallVector AdditionalValues; + // 'I' may appear more than once in DPV's location ops, and each use of 'I' + // must be updated in the DIExpression and potentially have additional + // values added; thus we call salvageDebugInfoImpl for each 'I' instance in + // DPVLocation. + Value *Op0 = nullptr; + DIExpression *SalvagedExpr = DPV->getExpression(); + auto LocItr = find(DPVLocation, &I); + while (SalvagedExpr && LocItr != DPVLocation.end()) { + SmallVector Ops; + unsigned LocNo = std::distance(DPVLocation.begin(), LocItr); + uint64_t CurrentLocOps = SalvagedExpr->getNumLocationOperands(); + Op0 = salvageDebugInfoImpl(I, CurrentLocOps, Ops, AdditionalValues); + if (!Op0) + break; + SalvagedExpr = + DIExpression::appendOpsToArg(SalvagedExpr, Ops, LocNo, StackValue); + LocItr = std::find(++LocItr, DPVLocation.end(), &I); + } + // salvageDebugInfoImpl should fail on examining the first element of + // DbgUsers, or none of them. + if (!Op0) + break; + + DPV->replaceVariableLocationOp(&I, Op0); + bool IsValidSalvageExpr = + SalvagedExpr->getNumElements() <= MaxExpressionSize; + if (AdditionalValues.empty() && IsValidSalvageExpr) { + DPV->setExpression(SalvagedExpr); + } else if (DPV->getType() == DPValue::LocationType::Value && + IsValidSalvageExpr && + DPV->getNumVariableLocationOps() + AdditionalValues.size() <= + MaxDebugArgs) { + DPV->addVariableLocationOps(AdditionalValues, SalvagedExpr); + } else { + // Do not salvage using DIArgList for dbg.addr/dbg.declare, as it is + // currently only valid for stack value expressions. + // Also do not salvage if the resulting DIArgList would contain an + // unreasonably large number of values. + Value *Undef = UndefValue::get(I.getOperand(0)->getType()); + DPV->replaceVariableLocationOp(I.getOperand(0), Undef); + } + LLVM_DEBUG(dbgs() << "SALVAGE: " << DPV << '\n'); + Salvaged = true; + } if (Salvaged) return; for (auto *DII : DbgUsers) DII->setKillLocation(); + + for (auto *DPV : DPUsers) + DPV->setKillLocation(); } Value *getSalvageOpsForGEP(GetElementPtrInst *GEP, const DataLayout &DL, @@ -2239,16 +2491,20 @@ using DbgValReplacement = std::optional; /// changes are made. static bool rewriteDebugUsers( Instruction &From, Value &To, Instruction &DomPoint, DominatorTree &DT, - function_ref RewriteExpr) { + function_ref RewriteExpr, + function_ref RewriteDPVExpr) { // Find debug users of From. SmallVector Users; - findDbgUsers(Users, &From); - if (Users.empty()) + SmallVector DPUsers; + findDbgUsers(Users, &From, &DPUsers); + if (Users.empty() && DPUsers.empty()) return false; // Prevent use-before-def of To. bool Changed = false; + SmallPtrSet UndefOrSalvage; + SmallPtrSet UndefOrSalvageDPV; if (isa(&To)) { bool DomPointAfterFrom = From.getNextNonDebugInstruction() == &DomPoint; @@ -2266,6 +2522,32 @@ static bool rewriteDebugUsers( UndefOrSalvage.insert(DII); } } + + // DPValue implementation of the above. + // RemoveDIs misery: The above loop of intrinsic-users are ordered by the + // use-list of the corresponding metadata-as-value: in reverse order of when + // they were added. Wheras DPUsers are ordered by when they were added to + // the replaceable-metadata map, i.e., in the order they were added. Thus to + // have matching orders between the two, we have to reverse here. For + // RemoveDIs we might in the long run need to consider whether this implicit + // ordering is relied upon by any other part of LLVM. + for (auto *DPV : llvm::reverse(DPUsers)) { + Instruction *MarkedInstr = DPV->getMarker()->MarkedInstr; + Instruction *NextNonDebug = MarkedInstr; + // The next instruction might still be a dbg.declare, skip over it. + if (isa(NextNonDebug)) + NextNonDebug = NextNonDebug->getNextNonDebugInstruction(); + + if (DomPointAfterFrom && NextNonDebug == &DomPoint) { + LLVM_DEBUG(dbgs() << "MOVE: " << *DPV << '\n'); + DPV->removeFromParent(); + // Ensure there's a marker. + DomPoint.getParent()->insertDPValueAfter(DPV, &DomPoint); + Changed = true; + } else if (!DT.dominates(&DomPoint, MarkedInstr)) { + UndefOrSalvageDPV.insert(DPV); + } + } } // Update debug users without use-before-def risk. @@ -2282,8 +2564,21 @@ static bool rewriteDebugUsers( LLVM_DEBUG(dbgs() << "REWRITE: " << *DII << '\n'); Changed = true; } + for (auto *DPV : DPUsers) { + if (UndefOrSalvageDPV.count(DPV)) + continue; - if (!UndefOrSalvage.empty()) { + DbgValReplacement DVR = RewriteDPVExpr(*DPV); + if (!DVR) + continue; + + DPV->replaceVariableLocationOp(&From, &To); + DPV->setExpression(*DVR); + LLVM_DEBUG(dbgs() << "REWRITE: " << DPV << '\n'); + Changed = true; + } + + if (!UndefOrSalvage.empty() || !UndefOrSalvageDPV.empty()) { // Try to salvage the remaining debug users. salvageDebugInfo(From); Changed = true; @@ -2331,12 +2626,15 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To, auto Identity = [&](DbgVariableIntrinsic &DII) -> DbgValReplacement { return DII.getExpression(); }; + auto IdentityDPV = [&](DPValue &DPV) -> DbgValReplacement { + return DPV.getExpression(); + }; // Handle no-op conversions. Module &M = *From.getModule(); const DataLayout &DL = M.getDataLayout(); if (isBitCastSemanticsPreserving(DL, FromTy, ToTy)) - return rewriteDebugUsers(From, To, DomPoint, DT, Identity); + return rewriteDebugUsers(From, To, DomPoint, DT, Identity, IdentityDPV); // Handle integer-to-integer widening and narrowing. // FIXME: Use DW_OP_convert when it's available everywhere. @@ -2348,7 +2646,7 @@ 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); + return rewriteDebugUsers(From, To, DomPoint, DT, Identity, IdentityDPV); // The width of the result has shrunk. Use sign/zero extension to describe // the source variable's high bits. @@ -2364,7 +2662,22 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To, return DIExpression::appendExt(DII.getExpression(), ToBits, FromBits, Signed); }; - return rewriteDebugUsers(From, To, DomPoint, DT, SignOrZeroExt); + // RemoveDIs: duplicate implementation working on DPValues rather than on + // dbg.value intrinsics. + auto SignOrZeroExtDPV = [&](DPValue &DPV) -> DbgValReplacement { + DILocalVariable *Var = DPV.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(DPV.getExpression(), ToBits, FromBits, + Signed); + }; + return rewriteDebugUsers(From, To, DomPoint, DT, SignOrZeroExt, + SignOrZeroExtDPV); } // TODO: Floating-point conversions, vectors. @@ -2378,12 +2691,17 @@ llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) { // Delete the instructions backwards, as it has a reduced likelihood of // having to update as many def-use and use-def chains. Instruction *EndInst = BB->getTerminator(); // Last not to be deleted. + // RemoveDIs: erasing debug-info must be done manually. + EndInst->dropDbgValues(); while (EndInst != &BB->front()) { // Delete the next to last instruction. Instruction *Inst = &*--EndInst->getIterator(); if (!Inst->use_empty() && !Inst->getType()->isTokenTy()) Inst->replaceAllUsesWith(PoisonValue::get(Inst->getType())); if (Inst->isEHPad() || Inst->getType()->isTokenTy()) { + // EHPads can't have DPValues attached to them, but it might be possible + // for things with token type. + Inst->dropDbgValues(); EndInst = Inst; continue; } @@ -2391,6 +2709,8 @@ llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) { ++NumDeadDbgInst; else ++NumDeadInst; + // RemoveDIs: erasing debug-info must be done manually. + Inst->dropDbgValues(); Inst->eraseFromParent(); } return {NumDeadInst, NumDeadDbgInst}; @@ -3121,9 +3441,12 @@ void llvm::copyRangeMetadata(const DataLayout &DL, const LoadInst &OldLI, void llvm::dropDebugUsers(Instruction &I) { SmallVector DbgUsers; - findDbgUsers(DbgUsers, &I); + SmallVector DPUsers; + findDbgUsers(DbgUsers, &I, &DPUsers); for (auto *DII : DbgUsers) DII->eraseFromParent(); + for (auto *DPV : DPUsers) + DPV->eraseFromParent(); } void llvm::hoistAllInstructionsInto(BasicBlock *DomBlock, Instruction *InsertPt, @@ -3155,6 +3478,8 @@ void llvm::hoistAllInstructionsInto(BasicBlock *DomBlock, Instruction *InsertPt, I->dropUBImplyingAttrsAndMetadata(); if (I->isUsedByMetadata()) dropDebugUsers(*I); + // RemoveDIs: drop debug-info too as the following code does. + I->dropDbgValues(); if (I->isDebugOrPseudoInst()) { // Remove DbgInfo and pseudo probe Intrinsics. II = I->eraseFromParent(); diff --git a/llvm/test/DebugInfo/salvage-cast-debug-info.ll b/llvm/test/DebugInfo/salvage-cast-debug-info.ll index c196bcd052673..4676aee3d4e48 100644 --- a/llvm/test/DebugInfo/salvage-cast-debug-info.ll +++ b/llvm/test/DebugInfo/salvage-cast-debug-info.ll @@ -1,4 +1,5 @@ ; RUN: opt %s -passes=debugify,early-cse -earlycse-debug-hash -S | FileCheck %s +; RUN: opt %s -passes=debugify,early-cse -earlycse-debug-hash -S --try-experimental-debuginfo-iterators | FileCheck %s define i32 @foo(i64 %nose, i32 %more) { ; CHECK-LABEL: @foo( ; CHECK: call void @llvm.dbg.value(metadata i64 %nose, metadata [[V1:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned diff --git a/llvm/test/DebugInfo/salvage-gep.ll b/llvm/test/DebugInfo/salvage-gep.ll index 4d7448ff3f4b6..01191da1ed8fa 100644 --- a/llvm/test/DebugInfo/salvage-gep.ll +++ b/llvm/test/DebugInfo/salvage-gep.ll @@ -1,4 +1,5 @@ ; RUN: opt %s -passes=dce -S | FileCheck %s +; RUN: opt %s -passes=dce -S --try-experimental-debuginfo-iterators | FileCheck %s ; Tests the salvaging of GEP instructions, specifically struct indexing, ; non-constant array indexing, and non-constant array indexing into an array of diff --git a/llvm/test/Transforms/InstCombine/debuginfo-dce.ll b/llvm/test/Transforms/InstCombine/debuginfo-dce.ll index 1049d8380aad9..257222cb70c23 100644 --- a/llvm/test/Transforms/InstCombine/debuginfo-dce.ll +++ b/llvm/test/Transforms/InstCombine/debuginfo-dce.ll @@ -1,4 +1,5 @@ ; RUN: opt -passes=instcombine %s -S -o - | FileCheck %s +; RUN: opt -passes=instcombine %s -S -o - --try-experimental-debuginfo-iterators | FileCheck %s ; Verify that the eliminated instructions (bitcast, gep, load) are salvaged into ; a DIExpression. ; diff --git a/llvm/test/Transforms/InstCombine/salvage-dbg-declare.ll b/llvm/test/Transforms/InstCombine/salvage-dbg-declare.ll index e7805618edf6f..8554296a406d8 100644 --- a/llvm/test/Transforms/InstCombine/salvage-dbg-declare.ll +++ b/llvm/test/Transforms/InstCombine/salvage-dbg-declare.ll @@ -1,4 +1,5 @@ ; RUN: opt -passes=instcombine -S -o - %s | FileCheck %s +; RUN: opt -passes=instcombine -S -o - %s --try-experimental-debuginfo-iterators | FileCheck %s declare dso_local i32 @bar(ptr) diff --git a/llvm/test/Transforms/Mem2Reg/ConvertDebugInfo.ll b/llvm/test/Transforms/Mem2Reg/ConvertDebugInfo.ll index 02d048dc4821e..ac3bf8f8d78e4 100644 --- a/llvm/test/Transforms/Mem2Reg/ConvertDebugInfo.ll +++ b/llvm/test/Transforms/Mem2Reg/ConvertDebugInfo.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -passes=mem2reg -S | FileCheck %s +; RUN: opt < %s -passes=mem2reg -S --try-experimental-debuginfo-iterators | FileCheck %s define double @testfunc(i32 %i, double %j) nounwind ssp !dbg !1 { entry: diff --git a/llvm/test/Transforms/Mem2Reg/ConvertDebugInfo2.ll b/llvm/test/Transforms/Mem2Reg/ConvertDebugInfo2.ll index 588b14f22c39b..97ff751bb73af 100644 --- a/llvm/test/Transforms/Mem2Reg/ConvertDebugInfo2.ll +++ b/llvm/test/Transforms/Mem2Reg/ConvertDebugInfo2.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -passes=mem2reg <%s | FileCheck %s +; RUN: opt -S -passes=mem2reg <%s --try-experimental-debuginfo-iterators | FileCheck %s declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone diff --git a/llvm/test/Transforms/Mem2Reg/dbg-inline-scope-for-phi.ll b/llvm/test/Transforms/Mem2Reg/dbg-inline-scope-for-phi.ll index 2b3905b9a7bd8..53a33c8ad8d4e 100644 --- a/llvm/test/Transforms/Mem2Reg/dbg-inline-scope-for-phi.ll +++ b/llvm/test/Transforms/Mem2Reg/dbg-inline-scope-for-phi.ll @@ -1,4 +1,5 @@ ; RUN: opt -S < %s -passes='function(mem2reg),require' | FileCheck %s +; RUN: opt -S < %s -passes='function(mem2reg),require' --try-experimental-debuginfo-iterators | FileCheck %s target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.13.0" diff --git a/llvm/test/Transforms/Mem2Reg/dbg_declare_to_value_conversions.ll b/llvm/test/Transforms/Mem2Reg/dbg_declare_to_value_conversions.ll index 04d963841acf7..8012c2b97a6b6 100644 --- a/llvm/test/Transforms/Mem2Reg/dbg_declare_to_value_conversions.ll +++ b/llvm/test/Transforms/Mem2Reg/dbg_declare_to_value_conversions.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -passes='mem2reg' -S | FileCheck %s +; RUN: opt < %s -passes='mem2reg' -S --try-experimental-debuginfo-iterators | FileCheck %s target datalayout = "e-p:64:64" ; An intrinsic without any expressions should always be converted. diff --git a/llvm/test/Transforms/Mem2Reg/debug-alloca-phi-2.ll b/llvm/test/Transforms/Mem2Reg/debug-alloca-phi-2.ll index 871543bb44c2c..e4c638d39ccff 100644 --- a/llvm/test/Transforms/Mem2Reg/debug-alloca-phi-2.ll +++ b/llvm/test/Transforms/Mem2Reg/debug-alloca-phi-2.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -passes=mem2reg -S | FileCheck %s +; RUN: opt < %s -passes=mem2reg -S --try-experimental-debuginfo-iterators | FileCheck %s source_filename = "bugpoint-output.bc" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.12.0" diff --git a/llvm/test/Transforms/Mem2Reg/debug-alloca-phi.ll b/llvm/test/Transforms/Mem2Reg/debug-alloca-phi.ll index 3202c18869eb9..01f45e9c081d3 100644 --- a/llvm/test/Transforms/Mem2Reg/debug-alloca-phi.ll +++ b/llvm/test/Transforms/Mem2Reg/debug-alloca-phi.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -passes=mem2reg -S | FileCheck %s +; RUN: opt < %s -passes=mem2reg -S --try-experimental-debuginfo-iterators | FileCheck %s source_filename = "bugpoint-output.bc" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.12.0" diff --git a/llvm/test/Transforms/Mem2Reg/debug-alloca-vla-1.ll b/llvm/test/Transforms/Mem2Reg/debug-alloca-vla-1.ll index 8aa9df286427e..9b29f981b26c1 100644 --- a/llvm/test/Transforms/Mem2Reg/debug-alloca-vla-1.ll +++ b/llvm/test/Transforms/Mem2Reg/debug-alloca-vla-1.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=mem2reg -S | FileCheck %s +; RUN: opt < %s -passes=mem2reg -S --try-experimental-debuginfo-iterators | FileCheck %s ; Testing conversion from dbg.declare to dbg.value when the variable is a VLA. ; diff --git a/llvm/test/Transforms/Mem2Reg/debug-alloca-vla-2.ll b/llvm/test/Transforms/Mem2Reg/debug-alloca-vla-2.ll index 972ec66b906b8..894e9555ee6eb 100644 --- a/llvm/test/Transforms/Mem2Reg/debug-alloca-vla-2.ll +++ b/llvm/test/Transforms/Mem2Reg/debug-alloca-vla-2.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=mem2reg -S | FileCheck %s +; RUN: opt < %s -passes=mem2reg -S --try-experimental-debuginfo-iterators | FileCheck %s ; Testing conversion from dbg.declare to dbg.value when the variable is a VLA. ; diff --git a/llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll b/llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll index 7d05212708d13..ef9b86db52f2b 100644 --- a/llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll +++ b/llvm/test/Transforms/Reassociate/undef_intrinsics_when_deleting_instructions.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -passes=reassociate -S | FileCheck %s +; RUN: opt < %s -passes=reassociate -S --try-experimental-debuginfo-iterators | FileCheck %s ; Check that reassociate pass now undefs debug intrinsics that reference a value ; that gets dropped and cannot be salvaged. diff --git a/llvm/test/Transforms/SROA/dbg-inline.ll b/llvm/test/Transforms/SROA/dbg-inline.ll index 336ebb4efc8da..454ca13230bfa 100644 --- a/llvm/test/Transforms/SROA/dbg-inline.ll +++ b/llvm/test/Transforms/SROA/dbg-inline.ll @@ -4,6 +4,11 @@ ; RUN: opt < %s -passes='sroa' -S | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG ; RUN: opt < %s -passes='sroa' -S | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG + +;; Duplicate copies for RemoveDIs, eliminating debug intrinsics. +; RUN: opt < %s -passes='sroa' -S --try-experimental-debuginfo-iterators | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG +; RUN: opt < %s -passes='sroa' -S --try-experimental-debuginfo-iterators | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG + source_filename = "/tmp/inlinesplit.cpp" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.15.0" diff --git a/llvm/test/Transforms/SROA/dbg-single-piece.ll b/llvm/test/Transforms/SROA/dbg-single-piece.ll index c60be8d74054e..9df1a835b42e5 100644 --- a/llvm/test/Transforms/SROA/dbg-single-piece.ll +++ b/llvm/test/Transforms/SROA/dbg-single-piece.ll @@ -1,6 +1,11 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes='sroa' %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG ; RUN: opt -passes='sroa' %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG + +;; Duplicate copies for RemoveDIs project, eliminating debug intrinsics +; RUN: opt -passes='sroa' %s -S --try-experimental-debuginfo-iterators | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG +; RUN: opt -passes='sroa' %s -S --try-experimental-debuginfo-iterators | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" %foo = type { [8 x i8], [8 x i8] } diff --git a/llvm/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll b/llvm/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll index c118c486e5aa9..b5d862b03b623 100644 --- a/llvm/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll +++ b/llvm/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll @@ -1,4 +1,5 @@ ; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s +; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - --try-experimental-debuginfo-iterators | FileCheck %s ; Test llvm.dbg.value for dynamic allocas moved onto the unsafe stack. ; In the dynamic alloca case, the dbg.value does not change with the exception diff --git a/llvm/test/Transforms/SafeStack/X86/debug-loc.ll b/llvm/test/Transforms/SafeStack/X86/debug-loc.ll index 8501f7446f99f..41240f7d7a916 100644 --- a/llvm/test/Transforms/SafeStack/X86/debug-loc.ll +++ b/llvm/test/Transforms/SafeStack/X86/debug-loc.ll @@ -1,4 +1,5 @@ ; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s +; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - --try-experimental-debuginfo-iterators | FileCheck %s ; Test debug location for the local variables moved onto the unsafe stack. diff --git a/llvm/test/Transforms/SafeStack/X86/debug-loc2.ll b/llvm/test/Transforms/SafeStack/X86/debug-loc2.ll index 05b66a5175cc7..a7164ef0f45c3 100644 --- a/llvm/test/Transforms/SafeStack/X86/debug-loc2.ll +++ b/llvm/test/Transforms/SafeStack/X86/debug-loc2.ll @@ -1,4 +1,5 @@ ; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s +; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - --try-experimental-debuginfo-iterators | FileCheck %s ; Test llvm.dbg.value for the local variables moved onto the unsafe stack. ; SafeStack rewrites them relative to the unsafe stack pointer (base address of diff --git a/llvm/test/Transforms/SimplifyCFG/tail-merge-noreturn.ll b/llvm/test/Transforms/SimplifyCFG/tail-merge-noreturn.ll index d44efce15ada2..5af708a2d0d8d 100644 --- a/llvm/test/Transforms/SimplifyCFG/tail-merge-noreturn.ll +++ b/llvm/test/Transforms/SimplifyCFG/tail-merge-noreturn.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -sink-common-insts -S < %s | FileCheck %s +; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -sink-common-insts -S < %s --try-experimental-debuginfo-iterators | FileCheck %s ; Test that we tail merge noreturn call blocks and phi constants properly. diff --git a/llvm/test/Transforms/Util/salvage-debuginfo.ll b/llvm/test/Transforms/Util/salvage-debuginfo.ll index 566104e9e358b..5058095491bbb 100644 --- a/llvm/test/Transforms/Util/salvage-debuginfo.ll +++ b/llvm/test/Transforms/Util/salvage-debuginfo.ll @@ -1,5 +1,7 @@ ; RUN: opt -passes=adce %s -S -o - | FileCheck %s ; RUN: opt -passes=bdce %s -S -o - | FileCheck %s +; RUN: opt -passes=adce %s -S -o - --try-experimental-debuginfo-iterators | FileCheck %s +; RUN: opt -passes=bdce %s -S -o - --try-experimental-debuginfo-iterators | FileCheck %s target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx" define void @f(i32) !dbg !8 {