diff --git a/llvm/include/llvm/IR/DebugInfo.h b/llvm/include/llvm/IR/DebugInfo.h index e634f4bd2f5aa..55b8ce0998413 100644 --- a/llvm/include/llvm/IR/DebugInfo.h +++ b/llvm/include/llvm/IR/DebugInfo.h @@ -58,6 +58,7 @@ DISubprogram *getDISubprogram(const MDNode *Scope); /// Produce a DebugLoc to use for each dbg.declare that is promoted to a /// dbg.value. DebugLoc getDebugValueLoc(DbgVariableIntrinsic *DII); +DebugLoc getDebugValueLoc(DPValue *DPV); /// Strip debug info in the module if it exists. /// @@ -223,6 +224,11 @@ inline AssignmentMarkerRange getAssignmentMarkers(const Instruction *Inst) { else return make_range(Value::user_iterator(), Value::user_iterator()); } +inline SmallVector getDPVAssignmentMarkers(const Instruction *Inst) { + if (auto *ID = Inst->getMetadata(LLVMContext::MD_DIAssignID)) + return cast(ID)->getAllDPValueUsers(); + return {}; +} /// Delete the llvm.dbg.assign intrinsics linked to \p Inst. void deleteAssignmentMarkers(const Instruction *Inst); @@ -244,7 +250,11 @@ void deleteAll(Function *F); /// Result contains a zero-sized fragment if there's no intersect. bool calculateFragmentIntersect( const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, - uint64_t SliceSizeInBits, const DbgAssignIntrinsic *DAI, + uint64_t SliceSizeInBits, const DbgAssignIntrinsic *DbgAssign, + std::optional &Result); +bool calculateFragmentIntersect( + const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, + uint64_t SliceSizeInBits, const DPValue *DPVAssign, std::optional &Result); /// Helper struct for trackAssignments, below. We don't use the similar @@ -259,6 +269,8 @@ struct VarRecord { VarRecord(DbgVariableIntrinsic *DVI) : Var(DVI->getVariable()), DL(getDebugValueLoc(DVI)) {} + VarRecord(DPValue *DPV) + : Var(DPV->getVariable()), DL(getDebugValueLoc(DPV)) {} VarRecord(DILocalVariable *Var, DILocation *DL) : Var(Var), DL(DL) {} friend bool operator<(const VarRecord &LHS, const VarRecord &RHS) { return std::tie(LHS.Var, LHS.DL) < std::tie(RHS.Var, RHS.DL); diff --git a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp index eb372655e5f16..497d9391a3b95 100644 --- a/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp +++ b/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugProgramInstruction.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" @@ -81,6 +82,19 @@ template <> struct llvm::DenseMapInfo { } }; +using VarLocInsertPt = PointerUnion; + +namespace std { +template <> struct hash { + using argument_type = VarLocInsertPt; + using result_type = std::size_t; + + result_type operator()(const argument_type &Arg) const { + return std::hash()(Arg.getOpaqueValue()); + } +}; +} // namespace std + /// Helper class to build FunctionVarLocs, since that class isn't easy to /// modify. TODO: There's not a great deal of value in the split, it could be /// worth merging the two classes. @@ -89,8 +103,7 @@ class FunctionVarLocsBuilder { UniqueVector Variables; // Use an unordered_map so we don't invalidate iterators after // insert/modifications. - std::unordered_map> - VarLocsBeforeInst; + std::unordered_map> VarLocsBeforeInst; SmallVector SingleLocVars; @@ -109,7 +122,7 @@ class FunctionVarLocsBuilder { /// Return ptr to wedge of defs or nullptr if no defs come just before /p /// Before. - const SmallVectorImpl *getWedge(const Instruction *Before) const { + const SmallVectorImpl *getWedge(VarLocInsertPt Before) const { auto R = VarLocsBeforeInst.find(Before); if (R == VarLocsBeforeInst.end()) return nullptr; @@ -117,7 +130,7 @@ class FunctionVarLocsBuilder { } /// Replace the defs that come just before /p Before with /p Wedge. - void setWedge(const Instruction *Before, SmallVector &&Wedge) { + void setWedge(VarLocInsertPt Before, SmallVector &&Wedge) { VarLocsBeforeInst[Before] = std::move(Wedge); } @@ -133,7 +146,7 @@ class FunctionVarLocsBuilder { } /// Add a def to the wedge of defs just before /p Before. - void addVarLoc(Instruction *Before, DebugVariable Var, DIExpression *Expr, + void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr, DebugLoc DL, RawLocationWrapper R) { VarLocInfo VarLoc; VarLoc.VariableID = insertVariable(Var); @@ -201,15 +214,31 @@ void FunctionVarLocs::init(FunctionVarLocsBuilder &Builder) { SingleVarLocEnd = VarLocRecords.size(); // Insert a contiguous block of VarLocInfos for each instruction, mapping it - // to the start and end position in the vector with VarLocsBeforeInst. + // to the start and end position in the vector with VarLocsBeforeInst. This + // block includes VarLocs for any DPValues attached to that instruction. for (auto &P : Builder.VarLocsBeforeInst) { + // Process VarLocs attached to a DPValue alongside their marker Instruction. + if (isa(P.first)) + continue; + const Instruction *I = cast(P.first); unsigned BlockStart = VarLocRecords.size(); + // Any VarLocInfos attached to a DPValue should now be remapped to their + // marker Instruction, in order of DPValue appearance and prior to any + // VarLocInfos attached directly to that instruction. + for (const DPValue &DPV : I->getDbgValueRange()) { + // Even though DPV defines a variable location, VarLocsBeforeInst can + // still be empty if that VarLoc was redundant. + if (!Builder.VarLocsBeforeInst.count(&DPV)) + continue; + for (const VarLocInfo &VarLoc : Builder.VarLocsBeforeInst[&DPV]) + VarLocRecords.emplace_back(VarLoc); + } for (const VarLocInfo &VarLoc : P.second) VarLocRecords.emplace_back(VarLoc); unsigned BlockEnd = VarLocRecords.size(); // Record the start and end indices. if (BlockEnd != BlockStart) - VarLocsBeforeInst[P.first] = {BlockStart, BlockEnd}; + VarLocsBeforeInst[I] = {BlockStart, BlockEnd}; } // Copy the Variables vector from the builder's UniqueVector. @@ -370,7 +399,7 @@ class MemLocFragmentFill { unsigned SizeInBits; DebugLoc DL; }; - using InsertMap = MapVector>; + using InsertMap = MapVector>; /// BBInsertBeforeMap holds a description for the set of location defs to be /// inserted after the analysis is complete. It is updated during the dataflow @@ -590,7 +619,7 @@ class MemLocFragmentFill { return /*Changed=*/false; } - void insertMemLoc(BasicBlock &BB, Instruction &Before, unsigned Var, + void insertMemLoc(BasicBlock &BB, VarLocInsertPt Before, unsigned Var, unsigned StartBit, unsigned EndBit, unsigned Base, DebugLoc DL) { assert(StartBit < EndBit && "Cannot create fragment of size <= 0"); @@ -603,7 +632,7 @@ class MemLocFragmentFill { assert(Base && "Expected a non-zero ID for Base address"); Loc.Base = Base; Loc.DL = DL; - BBInsertBeforeMap[&BB][&Before].push_back(Loc); + BBInsertBeforeMap[&BB][Before].push_back(Loc); LLVM_DEBUG(dbgs() << "Add mem def for " << Aggregates[Var].first->getName() << " bits [" << StartBit << ", " << EndBit << ")\n"); } @@ -612,7 +641,7 @@ class MemLocFragmentFill { /// in \p FragMap starts before \p StartBit or ends after \p EndBit (which /// indicates - assuming StartBit->EndBit has just been inserted - that the /// slice has been coalesced in the map). - void coalesceFragments(BasicBlock &BB, Instruction &Before, unsigned Var, + void coalesceFragments(BasicBlock &BB, VarLocInsertPt Before, unsigned Var, unsigned StartBit, unsigned EndBit, unsigned Base, DebugLoc DL, const FragsInMemMap &FragMap) { if (!CoalesceAdjacentFragments) @@ -633,7 +662,7 @@ class MemLocFragmentFill { Base, DL); } - void addDef(const VarLocInfo &VarLoc, Instruction &Before, BasicBlock &BB, + void addDef(const VarLocInfo &VarLoc, VarLocInsertPt Before, BasicBlock &BB, VarFragMap &LiveSet) { DebugVariable DbgVar = FnVarLocs->getVariable(VarLoc.VariableID); if (skipVariable(DbgVar.getVariable())) @@ -802,7 +831,7 @@ class MemLocFragmentFill { for (auto &I : BB) { if (const auto *Locs = FnVarLocs->getWedge(&I)) { for (const VarLocInfo &Loc : *Locs) { - addDef(Loc, I, *I.getParent(), LiveSet); + addDef(Loc, &I, *I.getParent(), LiveSet); } } } @@ -923,7 +952,7 @@ class MemLocFragmentFill { for (auto &Pair : BBInsertBeforeMap) { InsertMap &Map = Pair.second; for (auto &Pair : Map) { - Instruction *InsertBefore = Pair.first; + auto InsertBefore = Pair.first; assert(InsertBefore && "should never be null"); auto FragMemLocs = Pair.second; auto &Ctx = Fn.getContext(); @@ -1056,11 +1085,12 @@ class AssignmentTrackingLowering { UntaggedStoreAssignmentMap UntaggedStoreVars; // Machinery to defer inserting dbg.values. - using InsertMap = MapVector>; - InsertMap InsertBeforeMap; + using InstInsertMap = MapVector>; + InstInsertMap InsertBeforeMap; /// Clear the location definitions currently cached for insertion after /p /// After. void resetInsertionPoint(Instruction &After); + void resetInsertionPoint(DPValue &After); void emitDbgValue(LocKind Kind, const DbgVariableIntrinsic *Source, Instruction *After); @@ -1418,6 +1448,24 @@ const char *locStr(AssignmentTrackingLowering::LocKind Loc) { } #endif +VarLocInsertPt getNextNode(const DPValue *DPV) { + auto NextIt = ++(DPV->getIterator()); + if (NextIt == DPV->getMarker()->getDbgValueRange().end()) + return DPV->getMarker()->MarkedInstr; + return &*NextIt; +} +VarLocInsertPt getNextNode(const Instruction *Inst) { + const Instruction *Next = Inst->getNextNode(); + if (!Next->hasDbgValues()) + return Next; + return &*Next->getDbgValueRange().begin(); +} +VarLocInsertPt getNextNode(VarLocInsertPt InsertPt) { + if (isa(InsertPt)) + return getNextNode(cast(InsertPt)); + return getNextNode(cast(InsertPt)); +} + void AssignmentTrackingLowering::emitDbgValue( AssignmentTrackingLowering::LocKind Kind, const DbgVariableIntrinsic *Source, Instruction *After) { @@ -1430,7 +1478,7 @@ void AssignmentTrackingLowering::emitDbgValue( PoisonValue::get(Type::getInt1Ty(Source->getContext()))); // Find a suitable insert point. - Instruction *InsertBefore = After->getNextNode(); + auto InsertBefore = getNextNode(After); assert(InsertBefore && "Shouldn't be inserting after a terminator"); VariableID Var = getVariableID(DebugVariable(Source)); @@ -1538,8 +1586,9 @@ void AssignmentTrackingLowering::processUntaggedInstruction( Ops.push_back(dwarf::DW_OP_deref); DIE = DIExpression::prependOpcodes(DIE, Ops, /*StackValue=*/false, /*EntryValue=*/false); - // Find a suitable insert point. - Instruction *InsertBefore = I.getNextNode(); + // Find a suitable insert point, before the next instruction or DPValue + // after I. + auto InsertBefore = getNextNode(&I); assert(InsertBefore && "Shouldn't be inserting after a terminator"); // Get DILocation for this unrecorded assignment. @@ -1710,8 +1759,8 @@ void AssignmentTrackingLowering::processDbgValue(DbgValueInst &DVI, emitDbgValue(LocKind::Val, &DVI, &DVI); } -static bool hasZeroSizedFragment(DbgVariableIntrinsic &DVI) { - if (auto F = DVI.getExpression()->getFragmentInfo()) +template static bool hasZeroSizedFragment(T &DbgValue) { + if (auto F = DbgValue.getExpression()->getFragmentInfo()) return F->SizeInBits == 0; return false; } diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 312d670d5b30e..fcd3f77f8f6e2 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -163,6 +163,18 @@ DebugLoc llvm::getDebugValueLoc(DbgVariableIntrinsic *DII) { return DILocation::get(DII->getContext(), 0, 0, Scope, InlinedAt); } +DebugLoc llvm::getDebugValueLoc(DPValue *DPV) { + // Original dbg.declare must have a location. + const DebugLoc &DeclareLoc = DPV->getDebugLoc(); + MDNode *Scope = DeclareLoc.getScope(); + DILocation *InlinedAt = DeclareLoc.getInlinedAt(); + // Because no machine insts can come from debug intrinsics, only the scope + // and inlinedAt is significant. Zero line numbers are used in case this + // DebugLoc leaks into any adjacent instructions. Produce an unknown location + // with the correct scope / inlinedAt fields. + return DILocation::get(DPV->getContext(), 0, 0, Scope, InlinedAt); +} + //===----------------------------------------------------------------------===// // DebugInfoFinder implementations. //===----------------------------------------------------------------------===// @@ -1779,11 +1791,14 @@ AssignmentMarkerRange at::getAssignmentMarkers(DIAssignID *ID) { void at::deleteAssignmentMarkers(const Instruction *Inst) { auto Range = getAssignmentMarkers(Inst); - if (Range.empty()) + SmallVector DPVAssigns = getDPVAssignmentMarkers(Inst); + if (Range.empty() && DPVAssigns.empty()) return; SmallVector ToDelete(Range.begin(), Range.end()); for (auto *DAI : ToDelete) DAI->eraseFromParent(); + for (auto *DPV : DPVAssigns) + DPV->eraseFromParent(); } void at::RAUW(DIAssignID *Old, DIAssignID *New) { @@ -1813,9 +1828,34 @@ void at::deleteAll(Function *F) { DAI->eraseFromParent(); } -bool at::calculateFragmentIntersect( +/// Get the FragmentInfo for the variable if it exists, otherwise return a +/// FragmentInfo that covers the entire variable if the variable size is +/// known, otherwise return a zero-sized fragment. +static DIExpression::FragmentInfo +getFragmentOrEntireVariable(const DPValue *DPV) { + DIExpression::FragmentInfo VariableSlice(0, 0); + // Get the fragment or variable size, or zero. + if (auto Sz = DPV->getFragmentSizeInBits()) + VariableSlice.SizeInBits = *Sz; + if (auto Frag = DPV->getExpression()->getFragmentInfo()) + VariableSlice.OffsetInBits = Frag->OffsetInBits; + return VariableSlice; +} + +static DIExpression::FragmentInfo +getFragmentOrEntireVariable(const DbgVariableIntrinsic *DVI) { + DIExpression::FragmentInfo VariableSlice(0, 0); + // Get the fragment or variable size, or zero. + if (auto Sz = DVI->getFragmentSizeInBits()) + VariableSlice.SizeInBits = *Sz; + if (auto Frag = DVI->getExpression()->getFragmentInfo()) + VariableSlice.OffsetInBits = Frag->OffsetInBits; + return VariableSlice; +} +template +bool calculateFragmentIntersectImpl( const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, - uint64_t SliceSizeInBits, const DbgAssignIntrinsic *DAI, + uint64_t SliceSizeInBits, const T *AssignRecord, std::optional &Result) { // There are multiple offsets at play in this function, so let's break it // down. Starting with how variables may be stored in allocas: @@ -1844,7 +1884,7 @@ bool at::calculateFragmentIntersect( // dbg.assign, that has been killed, if any. // // calculateFragmentIntersect(..., SliceOffsetInBits=0, - // SliceSizeInBits=32, Dest=%dest, DAI=dbg.assign) + // SliceSizeInBits=32, Dest=%dest, Assign=dbg.assign) // // Drawing the store (s) in memory followed by the shortened version ($), // then the dbg.assign (d), with the fragment information on a seperate scale @@ -1857,7 +1897,8 @@ bool at::calculateFragmentIntersect( // | | // s[######] - Original stores 64 bits to Dest. // $----[##] - DSE says the lower 32 bits are dead, to be removed. - // d [##] - DAI's address-modifying expression adds 4 bytes to dest. + // d [##] - Assign's address-modifying expression adds 4 bytes to + // dest. // Variable | | // Fragment 128| // Offsets 159 @@ -1872,10 +1913,10 @@ bool at::calculateFragmentIntersect( // // 3. That offset along with the store size (32) represents the bits of the // variable that'd be affected by the store. Call it SliceOfVariable. - // Intersect that with DAI's fragment info: - // SliceOfVariable ∩ DAI_fragment = none + // Intersect that with Assign's fragment info: + // SliceOfVariable ∩ Assign_fragment = none // - // In this case: none of the dead bits of the store affect DAI. + // In this case: none of the dead bits of the store affect Assign. // // # Example 2 // Similar example with the same goal. This time the upper 16 bits @@ -1886,7 +1927,7 @@ bool at::calculateFragmentIntersect( // !DIExpression(DW_OP_plus_uconst, 4)) // // calculateFragmentIntersect(..., SliceOffsetInBits=48, - // SliceSizeInBits=16, Dest=%dest, DAI=dbg.assign) + // SliceSizeInBits=16, Dest=%dest, Assign=dbg.assign) // // Memory // offset @@ -1895,7 +1936,8 @@ bool at::calculateFragmentIntersect( // | | // s[######] - Original stores 64 bits to Dest. // $[####]-- - DSE says the upper 16 bits are dead, to be removed. - // d [##] - DAI's address-modifying expression adds 4 bytes to dest. + // d [##] - Assign's address-modifying expression adds 4 bytes to + // dest. // Variable | | // Fragment 128| // Offsets 159 @@ -1904,13 +1946,14 @@ bool at::calculateFragmentIntersect( // 1. SliceOffsetInBits:48 + VarFrag.OffsetInBits:128 = 176 // 2. 176 - (expression_offset:32 + (d.address - dest):0) = 144 // 3. SliceOfVariable offset = 144, size = 16: - // SliceOfVariable ∩ DAI_fragment = (offset: 144, size: 16) - // SliceOfVariable tells us the bits of the variable described by DAI that are - // affected by the DSE. - if (DAI->isKillAddress()) + // SliceOfVariable ∩ Assign_fragment = (offset: 144, size: 16) + // SliceOfVariable tells us the bits of the variable described by Assign that + // are affected by the DSE. + if (AssignRecord->isKillAddress()) return false; - DIExpression::FragmentInfo VarFrag = DAI->getFragmentOrEntireVariable(); + DIExpression::FragmentInfo VarFrag = + getFragmentOrEntireVariable(AssignRecord); if (VarFrag.SizeInBits == 0) return false; // Variable size is unknown. @@ -1918,12 +1961,14 @@ bool at::calculateFragmentIntersect( // address-modifying expression. int64_t PointerOffsetInBits; { - auto DestOffsetInBytes = DAI->getAddress()->getPointerOffsetFrom(Dest, DL); + auto DestOffsetInBytes = + AssignRecord->getAddress()->getPointerOffsetFrom(Dest, DL); if (!DestOffsetInBytes) return false; // Can't calculate difference in addresses. int64_t ExprOffsetInBytes; - if (!DAI->getAddressExpression()->extractIfOffset(ExprOffsetInBytes)) + if (!AssignRecord->getAddressExpression()->extractIfOffset( + ExprOffsetInBytes)) return false; int64_t PointerOffsetInBytes = *DestOffsetInBytes + ExprOffsetInBytes; @@ -1937,7 +1982,8 @@ bool at::calculateFragmentIntersect( if (NewOffsetInBits < 0) return false; // Fragment offsets can only be positive. DIExpression::FragmentInfo SliceOfVariable(SliceSizeInBits, NewOffsetInBits); - // Intersect the variable slice with DAI's fragment to trim it down to size. + // Intersect the variable slice with AssignRecord's fragment to trim it down + // to size. DIExpression::FragmentInfo TrimmedSliceOfVariable = DIExpression::FragmentInfo::intersect(SliceOfVariable, VarFrag); if (TrimmedSliceOfVariable == VarFrag) @@ -1946,6 +1992,20 @@ bool at::calculateFragmentIntersect( Result = TrimmedSliceOfVariable; return true; } +bool at::calculateFragmentIntersect( + const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, + uint64_t SliceSizeInBits, const DbgAssignIntrinsic *DbgAssign, + std::optional &Result) { + return calculateFragmentIntersectImpl(DL, Dest, SliceOffsetInBits, + SliceSizeInBits, DbgAssign, Result); +} +bool at::calculateFragmentIntersect( + const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, + uint64_t SliceSizeInBits, const DPValue *DPVAssign, + std::optional &Result) { + return calculateFragmentIntersectImpl(DL, Dest, SliceOffsetInBits, + SliceSizeInBits, DPVAssign, Result); +} /// Collect constant properies (base, size, offset) of \p StoreDest. /// Return std::nullopt if any properties are not constants or the @@ -2194,7 +2254,9 @@ bool AssignmentTrackingPass::runOnFunction(Function &F) { for (auto &P : DbgDeclares) { const AllocaInst *Alloca = P.first; auto Markers = at::getAssignmentMarkers(Alloca); + SmallVector DPMarkers = at::getDPVAssignmentMarkers(Alloca); (void)Markers; + (void)DPMarkers; for (DbgDeclareInst *DDI : P.second) { // Assert that the alloca that DDI uses is now linked to a dbg.assign // describing the same variable (i.e. check that this dbg.declare has @@ -2203,9 +2265,15 @@ bool AssignmentTrackingPass::runOnFunction(Function &F) { // fragment. e.g. if the alloca is smaller than the variable, then // trackAssignments will create an alloca-sized fragment for the // dbg.assign. - assert(llvm::any_of(Markers, [DDI](DbgAssignIntrinsic *DAI) { - return DebugVariableAggregate(DAI) == DebugVariableAggregate(DDI); - })); + assert(llvm::any_of(Markers, + [DDI](DbgAssignIntrinsic *DAI) { + return DebugVariableAggregate(DAI) == + DebugVariableAggregate(DDI); + }) || + llvm::any_of(DPMarkers, [DDI](DPValue *DPV) { + return DebugVariableAggregate(DPV) == + DebugVariableAggregate(DDI); + })); // Delete DDI because the variable location is now tracked using // assignment tracking. DDI->eraseFromParent(); diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index d1b42f28923f5..2a1ac85ee55bf 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1724,20 +1724,6 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII, SI->getIterator()); } -namespace llvm { -// RemoveDIs: duplicate the getDebugValueLoc method using DPValues instead of -// dbg.value intrinsics. In llvm namespace so that it overloads the -// DbgVariableIntrinsic version. -static DebugLoc getDebugValueLoc(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); -} -} // namespace llvm - /// 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,