//=====-- DebugProgramInstruction.cpp - Implement DbgRecords/DbgMarkers --====// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugProgramInstruction.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/IntrinsicInst.h" namespace llvm { template DbgRecordParamRef::DbgRecordParamRef(const T *Param) : Ref(const_cast(Param)) {} template DbgRecordParamRef::DbgRecordParamRef(const MDNode *Param) : Ref(const_cast(Param)) {} template T *DbgRecordParamRef::get() const { return cast(Ref); } template class DbgRecordParamRef; template class DbgRecordParamRef; template class DbgRecordParamRef; DbgVariableRecord::DbgVariableRecord(const DbgVariableIntrinsic *DVI) : DbgRecord(ValueKind, DVI->getDebugLoc()), DebugValueUser({DVI->getRawLocation(), nullptr, nullptr}), Variable(DVI->getVariable()), Expression(DVI->getExpression()), AddressExpression() { switch (DVI->getIntrinsicID()) { case Intrinsic::dbg_value: Type = LocationType::Value; break; case Intrinsic::dbg_declare: Type = LocationType::Declare; break; case Intrinsic::dbg_assign: { Type = LocationType::Assign; const DbgAssignIntrinsic *Assign = static_cast(DVI); resetDebugValue(1, Assign->getRawAddress()); AddressExpression = Assign->getAddressExpression(); setAssignId(Assign->getAssignID()); break; } default: llvm_unreachable( "Trying to create a DbgVariableRecord with an invalid intrinsic type!"); } } DbgVariableRecord::DbgVariableRecord(const DbgVariableRecord &DVR) : DbgRecord(ValueKind, DVR.getDebugLoc()), DebugValueUser(DVR.DebugValues), Type(DVR.getType()), Variable(DVR.getVariable()), Expression(DVR.getExpression()), AddressExpression(DVR.AddressExpression) {} DbgVariableRecord::DbgVariableRecord(Metadata *Location, DILocalVariable *DV, DIExpression *Expr, const DILocation *DI, LocationType Type) : DbgRecord(ValueKind, DI), DebugValueUser({Location, nullptr, nullptr}), Type(Type), Variable(DV), Expression(Expr) {} DbgVariableRecord::DbgVariableRecord(Metadata *Value, DILocalVariable *Variable, DIExpression *Expression, DIAssignID *AssignID, Metadata *Address, DIExpression *AddressExpression, const DILocation *DI) : DbgRecord(ValueKind, DI), DebugValueUser({Value, Address, AssignID}), Type(LocationType::Assign), Variable(Variable), Expression(Expression), AddressExpression(AddressExpression) {} void DbgRecord::deleteRecord() { switch (RecordKind) { case ValueKind: delete cast(this); return; case LabelKind: delete cast(this); return; } llvm_unreachable("unsupported DbgRecord kind"); } void DbgRecord::print(raw_ostream &O, bool IsForDebug) const { switch (RecordKind) { case ValueKind: cast(this)->print(O, IsForDebug); return; case LabelKind: cast(this)->print(O, IsForDebug); return; }; llvm_unreachable("unsupported DbgRecord kind"); } void DbgRecord::print(raw_ostream &O, ModuleSlotTracker &MST, bool IsForDebug) const { switch (RecordKind) { case ValueKind: cast(this)->print(O, MST, IsForDebug); return; case LabelKind: cast(this)->print(O, MST, IsForDebug); return; }; llvm_unreachable("unsupported DbgRecord kind"); } bool DbgRecord::isIdenticalToWhenDefined(const DbgRecord &R) const { if (RecordKind != R.RecordKind) return false; switch (RecordKind) { case ValueKind: return cast(this)->isIdenticalToWhenDefined( *cast(&R)); case LabelKind: return cast(this)->getLabel() == cast(R).getLabel(); }; llvm_unreachable("unsupported DbgRecord kind"); } bool DbgRecord::isEquivalentTo(const DbgRecord &R) const { return getDebugLoc() == R.getDebugLoc() && isIdenticalToWhenDefined(R); } DbgInfoIntrinsic * DbgRecord::createDebugIntrinsic(Module *M, Instruction *InsertBefore) const { switch (RecordKind) { case ValueKind: return cast(this)->createDebugIntrinsic(M, InsertBefore); case LabelKind: return cast(this)->createDebugIntrinsic(M, InsertBefore); }; llvm_unreachable("unsupported DbgRecord kind"); } DbgLabelRecord::DbgLabelRecord(MDNode *Label, MDNode *DL) : DbgRecord(LabelKind, DebugLoc(DL)), Label(Label) { assert(Label && "Unexpected nullptr"); assert((isa(Label) || Label->isTemporary()) && "Label type must be or resolve to a DILabel"); } DbgLabelRecord::DbgLabelRecord(DILabel *Label, DebugLoc DL) : DbgRecord(LabelKind, DL), Label(Label) { assert(Label && "Unexpected nullptr"); } DbgLabelRecord *DbgLabelRecord::createUnresolvedDbgLabelRecord(MDNode *Label, MDNode *DL) { return new DbgLabelRecord(Label, DL); } DbgVariableRecord::DbgVariableRecord(DbgVariableRecord::LocationType Type, Metadata *Val, MDNode *Variable, MDNode *Expression, MDNode *AssignID, Metadata *Address, MDNode *AddressExpression, MDNode *DI) : DbgRecord(ValueKind, DebugLoc(DI)), DebugValueUser({Val, Address, AssignID}), Type(Type), Variable(Variable), Expression(Expression), AddressExpression(AddressExpression) {} DbgVariableRecord *DbgVariableRecord::createUnresolvedDbgVariableRecord( DbgVariableRecord::LocationType Type, Metadata *Val, MDNode *Variable, MDNode *Expression, MDNode *AssignID, Metadata *Address, MDNode *AddressExpression, MDNode *DI) { return new DbgVariableRecord(Type, Val, Variable, Expression, AssignID, Address, AddressExpression, DI); } DbgVariableRecord * DbgVariableRecord::createDbgVariableRecord(Value *Location, DILocalVariable *DV, DIExpression *Expr, const DILocation *DI) { return new DbgVariableRecord(ValueAsMetadata::get(Location), DV, Expr, DI, LocationType::Value); } DbgVariableRecord *DbgVariableRecord::createDbgVariableRecord( Value *Location, DILocalVariable *DV, DIExpression *Expr, const DILocation *DI, DbgVariableRecord &InsertBefore) { auto *NewDbgVariableRecord = createDbgVariableRecord(Location, DV, Expr, DI); NewDbgVariableRecord->insertBefore(&InsertBefore); return NewDbgVariableRecord; } DbgVariableRecord *DbgVariableRecord::createDVRDeclare(Value *Address, DILocalVariable *DV, DIExpression *Expr, const DILocation *DI) { return new DbgVariableRecord(ValueAsMetadata::get(Address), DV, Expr, DI, LocationType::Declare); } DbgVariableRecord * DbgVariableRecord::createDVRDeclare(Value *Address, DILocalVariable *DV, DIExpression *Expr, const DILocation *DI, DbgVariableRecord &InsertBefore) { auto *NewDVRDeclare = createDVRDeclare(Address, DV, Expr, DI); NewDVRDeclare->insertBefore(&InsertBefore); return NewDVRDeclare; } DbgVariableRecord *DbgVariableRecord::createDVRAssign( Value *Val, DILocalVariable *Variable, DIExpression *Expression, DIAssignID *AssignID, Value *Address, DIExpression *AddressExpression, const DILocation *DI) { return new DbgVariableRecord(ValueAsMetadata::get(Val), Variable, Expression, AssignID, ValueAsMetadata::get(Address), AddressExpression, DI); } DbgVariableRecord *DbgVariableRecord::createLinkedDVRAssign( Instruction *LinkedInstr, Value *Val, DILocalVariable *Variable, DIExpression *Expression, Value *Address, DIExpression *AddressExpression, const DILocation *DI) { auto *Link = LinkedInstr->getMetadata(LLVMContext::MD_DIAssignID); assert(Link && "Linked instruction must have DIAssign metadata attached"); auto *NewDVRAssign = DbgVariableRecord::createDVRAssign( Val, Variable, Expression, cast(Link), Address, AddressExpression, DI); LinkedInstr->getParent()->insertDbgRecordAfter(NewDVRAssign, LinkedInstr); return NewDVRAssign; } iterator_range DbgVariableRecord::location_ops() const { auto *MD = getRawLocation(); // If a Value has been deleted, the "location" for this DbgVariableRecord will // be replaced by nullptr. Return an empty range. if (!MD) return {location_op_iterator(static_cast(nullptr)), location_op_iterator(static_cast(nullptr))}; // If operand is ValueAsMetadata, return a range over just that operand. if (auto *VAM = dyn_cast(MD)) return {location_op_iterator(VAM), location_op_iterator(VAM + 1)}; // If operand is DIArgList, return a range over its args. if (auto *AL = dyn_cast(MD)) return {location_op_iterator(AL->args_begin()), location_op_iterator(AL->args_end())}; // Operand is an empty metadata tuple, so return empty iterator. assert(cast(MD)->getNumOperands() == 0); return {location_op_iterator(static_cast(nullptr)), location_op_iterator(static_cast(nullptr))}; } unsigned DbgVariableRecord::getNumVariableLocationOps() const { if (hasArgList()) return cast(getRawLocation())->getArgs().size(); return 1; } Value *DbgVariableRecord::getVariableLocationOp(unsigned OpIdx) const { auto *MD = getRawLocation(); if (!MD) return nullptr; if (auto *AL = dyn_cast(MD)) return AL->getArgs()[OpIdx]->getValue(); if (isa(MD)) return nullptr; assert(isa(MD) && "Attempted to get location operand from DbgVariableRecord with none."); auto *V = cast(MD); assert(OpIdx == 0 && "Operand Index must be 0 for a debug intrinsic with a " "single location operand."); return V->getValue(); } static ValueAsMetadata *getAsMetadata(Value *V) { return isa(V) ? dyn_cast( cast(V)->getMetadata()) : ValueAsMetadata::get(V); } void DbgVariableRecord::replaceVariableLocationOp(Value *OldValue, Value *NewValue, bool AllowEmpty) { assert(NewValue && "Values must be non-null"); bool DbgAssignAddrReplaced = isDbgAssign() && OldValue == getAddress(); if (DbgAssignAddrReplaced) setAddress(NewValue); auto Locations = location_ops(); auto OldIt = find(Locations, OldValue); if (OldIt == Locations.end()) { if (AllowEmpty || DbgAssignAddrReplaced) return; llvm_unreachable("OldValue must be a current location"); } if (!hasArgList()) { // Set our location to be the MAV wrapping the new Value. setRawLocation(isa(NewValue) ? cast(NewValue)->getMetadata() : ValueAsMetadata::get(NewValue)); return; } // We must be referring to a DIArgList, produce a new operands vector with the // old value replaced, generate a new DIArgList and set it as our location. SmallVector MDs; ValueAsMetadata *NewOperand = getAsMetadata(NewValue); for (auto *VMD : Locations) MDs.push_back(VMD == *OldIt ? NewOperand : getAsMetadata(VMD)); setRawLocation(DIArgList::get(getVariableLocationOp(0)->getContext(), MDs)); } void DbgVariableRecord::replaceVariableLocationOp(unsigned OpIdx, Value *NewValue) { assert(OpIdx < getNumVariableLocationOps() && "Invalid Operand Index"); if (!hasArgList()) { setRawLocation(isa(NewValue) ? cast(NewValue)->getMetadata() : ValueAsMetadata::get(NewValue)); return; } SmallVector MDs; ValueAsMetadata *NewOperand = getAsMetadata(NewValue); for (unsigned Idx = 0; Idx < getNumVariableLocationOps(); ++Idx) MDs.push_back(Idx == OpIdx ? NewOperand : getAsMetadata(getVariableLocationOp(Idx))); setRawLocation(DIArgList::get(getVariableLocationOp(0)->getContext(), MDs)); } void DbgVariableRecord::addVariableLocationOps(ArrayRef NewValues, DIExpression *NewExpr) { assert(NewExpr->hasAllLocationOps(getNumVariableLocationOps() + NewValues.size()) && "NewExpr for debug variable intrinsic does not reference every " "location operand."); assert(!is_contained(NewValues, nullptr) && "New values must be non-null"); setExpression(NewExpr); SmallVector MDs; for (auto *VMD : location_ops()) MDs.push_back(getAsMetadata(VMD)); for (auto *VMD : NewValues) MDs.push_back(getAsMetadata(VMD)); setRawLocation(DIArgList::get(getVariableLocationOp(0)->getContext(), MDs)); } void DbgVariableRecord::setKillLocation() { // TODO: When/if we remove duplicate values from DIArgLists, we don't need // this set anymore. SmallPtrSet RemovedValues; for (Value *OldValue : location_ops()) { if (!RemovedValues.insert(OldValue).second) continue; Value *Poison = PoisonValue::get(OldValue->getType()); replaceVariableLocationOp(OldValue, Poison); } } bool DbgVariableRecord::isKillLocation() const { return (!hasArgList() && isa(getRawLocation())) || (getNumVariableLocationOps() == 0 && !getExpression()->isComplex()) || any_of(location_ops(), [](Value *V) { return isa(V); }); } std::optional DbgVariableRecord::getFragment() const { return getExpression()->getFragmentInfo(); } std::optional DbgVariableRecord::getFragmentSizeInBits() const { if (auto Fragment = getExpression()->getFragmentInfo()) return Fragment->SizeInBits; return getVariable()->getSizeInBits(); } DbgRecord *DbgRecord::clone() const { switch (RecordKind) { case ValueKind: return cast(this)->clone(); case LabelKind: return cast(this)->clone(); }; llvm_unreachable("unsupported DbgRecord kind"); } DbgVariableRecord *DbgVariableRecord::clone() const { return new DbgVariableRecord(*this); } DbgLabelRecord *DbgLabelRecord::clone() const { return new DbgLabelRecord(getLabel(), getDebugLoc()); } DbgVariableIntrinsic * DbgVariableRecord::createDebugIntrinsic(Module *M, Instruction *InsertBefore) const { [[maybe_unused]] DICompileUnit *Unit = getDebugLoc()->getScope()->getSubprogram()->getUnit(); assert(M && Unit && "Cannot clone from BasicBlock that is not part of a Module or " "DICompileUnit!"); LLVMContext &Context = getDebugLoc()->getContext(); Function *IntrinsicFn; // Work out what sort of intrinsic we're going to produce. switch (getType()) { case DbgVariableRecord::LocationType::Declare: IntrinsicFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_declare); break; case DbgVariableRecord::LocationType::Value: IntrinsicFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_value); break; case DbgVariableRecord::LocationType::Assign: IntrinsicFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_assign); break; case DbgVariableRecord::LocationType::End: case DbgVariableRecord::LocationType::Any: llvm_unreachable("Invalid LocationType"); } // Create the intrinsic from this DbgVariableRecord's information, optionally // insert into the target location. DbgVariableIntrinsic *DVI; assert(getRawLocation() && "DbgVariableRecord's RawLocation should be non-null."); if (isDbgAssign()) { Value *AssignArgs[] = { MetadataAsValue::get(Context, getRawLocation()), MetadataAsValue::get(Context, getVariable()), MetadataAsValue::get(Context, getExpression()), MetadataAsValue::get(Context, getAssignID()), MetadataAsValue::get(Context, getRawAddress()), MetadataAsValue::get(Context, getAddressExpression())}; DVI = cast(CallInst::Create( IntrinsicFn->getFunctionType(), IntrinsicFn, AssignArgs)); } else { Value *Args[] = {MetadataAsValue::get(Context, getRawLocation()), MetadataAsValue::get(Context, getVariable()), MetadataAsValue::get(Context, getExpression())}; DVI = cast( CallInst::Create(IntrinsicFn->getFunctionType(), IntrinsicFn, Args)); } DVI->setTailCall(); DVI->setDebugLoc(getDebugLoc()); if (InsertBefore) DVI->insertBefore(InsertBefore); return DVI; } DbgLabelInst * DbgLabelRecord::createDebugIntrinsic(Module *M, Instruction *InsertBefore) const { auto *LabelFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_label); Value *Args[] = { MetadataAsValue::get(getDebugLoc()->getContext(), getLabel())}; DbgLabelInst *DbgLabel = cast( CallInst::Create(LabelFn->getFunctionType(), LabelFn, Args)); DbgLabel->setTailCall(); DbgLabel->setDebugLoc(getDebugLoc()); if (InsertBefore) DbgLabel->insertBefore(InsertBefore); return DbgLabel; } Value *DbgVariableRecord::getAddress() const { auto *MD = getRawAddress(); if (auto *V = dyn_cast_or_null(MD)) return V->getValue(); // When the value goes to null, it gets replaced by an empty MDNode. assert(!MD || !cast(MD)->getNumOperands() && "Expected an empty MDNode"); return nullptr; } DIAssignID *DbgVariableRecord::getAssignID() const { return cast(DebugValues[2]); } void DbgVariableRecord::setAssignId(DIAssignID *New) { resetDebugValue(2, New); } void DbgVariableRecord::setKillAddress() { resetDebugValue( 1, ValueAsMetadata::get(UndefValue::get(getAddress()->getType()))); } bool DbgVariableRecord::isKillAddress() const { Value *Addr = getAddress(); return !Addr || isa(Addr); } const Instruction *DbgRecord::getInstruction() const { return Marker->MarkedInstr; } const BasicBlock *DbgRecord::getParent() const { return Marker->MarkedInstr->getParent(); } BasicBlock *DbgRecord::getParent() { return Marker->MarkedInstr->getParent(); } BasicBlock *DbgRecord::getBlock() { return Marker->getParent(); } const BasicBlock *DbgRecord::getBlock() const { return Marker->getParent(); } Function *DbgRecord::getFunction() { return getBlock()->getParent(); } const Function *DbgRecord::getFunction() const { return getBlock()->getParent(); } Module *DbgRecord::getModule() { return getFunction()->getParent(); } const Module *DbgRecord::getModule() const { return getFunction()->getParent(); } LLVMContext &DbgRecord::getContext() { return getBlock()->getContext(); } const LLVMContext &DbgRecord::getContext() const { return getBlock()->getContext(); } void DbgRecord::insertBefore(DbgRecord *InsertBefore) { assert(!getMarker() && "Cannot insert a DbgRecord that is already has a DbgMarker!"); assert(InsertBefore->getMarker() && "Cannot insert a DbgRecord before a DbgRecord that does not have a " "DbgMarker!"); InsertBefore->getMarker()->insertDbgRecord(this, InsertBefore); } void DbgRecord::insertAfter(DbgRecord *InsertAfter) { assert(!getMarker() && "Cannot insert a DbgRecord that is already has a DbgMarker!"); assert(InsertAfter->getMarker() && "Cannot insert a DbgRecord after a DbgRecord that does not have a " "DbgMarker!"); InsertAfter->getMarker()->insertDbgRecordAfter(this, InsertAfter); } void DbgRecord::moveBefore(DbgRecord *MoveBefore) { assert(getMarker() && "Canot move a DbgRecord that does not currently have a DbgMarker!"); removeFromParent(); insertBefore(MoveBefore); } void DbgRecord::moveAfter(DbgRecord *MoveAfter) { assert(getMarker() && "Canot move a DbgRecord that does not currently have a DbgMarker!"); removeFromParent(); insertAfter(MoveAfter); } /////////////////////////////////////////////////////////////////////////////// // An empty, global, DbgMarker for the purpose of describing empty ranges of // DbgRecords. DbgMarker DbgMarker::EmptyDbgMarker; void DbgMarker::dropDbgRecords() { while (!StoredDbgRecords.empty()) { auto It = StoredDbgRecords.begin(); DbgRecord *DR = &*It; StoredDbgRecords.erase(It); DR->deleteRecord(); } } void DbgMarker::dropOneDbgRecord(DbgRecord *DR) { assert(DR->getMarker() == this); StoredDbgRecords.erase(DR->getIterator()); DR->deleteRecord(); } const BasicBlock *DbgMarker::getParent() const { return MarkedInstr->getParent(); } BasicBlock *DbgMarker::getParent() { return MarkedInstr->getParent(); } void DbgMarker::removeMarker() { // Are there any DbgRecords in this DbgMarker? If not, nothing to preserve. Instruction *Owner = MarkedInstr; if (StoredDbgRecords.empty()) { eraseFromParent(); Owner->DebugMarker = nullptr; return; } // The attached DbgRecords need to be preserved; attach them to the next // instruction. If there isn't a next instruction, put them on the // "trailing" list. DbgMarker *NextMarker = Owner->getParent()->getNextMarker(Owner); if (NextMarker) { NextMarker->absorbDebugValues(*this, true); eraseFromParent(); } else { // We can avoid a deallocation -- just store this marker onto the next // instruction. Unless we're at the end of the block, in which case this // marker becomes the trailing marker of a degenerate block. BasicBlock::iterator NextIt = std::next(Owner->getIterator()); if (NextIt == getParent()->end()) { getParent()->setTrailingDbgRecords(this); MarkedInstr = nullptr; } else { NextIt->DebugMarker = this; MarkedInstr = &*NextIt; } } Owner->DebugMarker = nullptr; } void DbgMarker::removeFromParent() { MarkedInstr->DebugMarker = nullptr; MarkedInstr = nullptr; } void DbgMarker::eraseFromParent() { if (MarkedInstr) removeFromParent(); dropDbgRecords(); delete this; } iterator_range DbgMarker::getDbgRecordRange() { return make_range(StoredDbgRecords.begin(), StoredDbgRecords.end()); } iterator_range DbgMarker::getDbgRecordRange() const { return make_range(StoredDbgRecords.begin(), StoredDbgRecords.end()); } void DbgRecord::removeFromParent() { getMarker()->StoredDbgRecords.erase(getIterator()); Marker = nullptr; } void DbgRecord::eraseFromParent() { removeFromParent(); deleteRecord(); } void DbgMarker::insertDbgRecord(DbgRecord *New, bool InsertAtHead) { auto It = InsertAtHead ? StoredDbgRecords.begin() : StoredDbgRecords.end(); StoredDbgRecords.insert(It, *New); New->setMarker(this); } void DbgMarker::insertDbgRecord(DbgRecord *New, DbgRecord *InsertBefore) { assert(InsertBefore->getMarker() == this && "DbgRecord 'InsertBefore' must be contained in this DbgMarker!"); StoredDbgRecords.insert(InsertBefore->getIterator(), *New); New->setMarker(this); } void DbgMarker::insertDbgRecordAfter(DbgRecord *New, DbgRecord *InsertAfter) { assert(InsertAfter->getMarker() == this && "DbgRecord 'InsertAfter' must be contained in this DbgMarker!"); StoredDbgRecords.insert(++(InsertAfter->getIterator()), *New); New->setMarker(this); } void DbgMarker::absorbDebugValues(DbgMarker &Src, bool InsertAtHead) { auto It = InsertAtHead ? StoredDbgRecords.begin() : StoredDbgRecords.end(); for (DbgRecord &DVR : Src.StoredDbgRecords) DVR.setMarker(this); StoredDbgRecords.splice(It, Src.StoredDbgRecords); } void DbgMarker::absorbDebugValues( iterator_range Range, DbgMarker &Src, bool InsertAtHead) { for (DbgRecord &DR : Range) DR.setMarker(this); auto InsertPos = (InsertAtHead) ? StoredDbgRecords.begin() : StoredDbgRecords.end(); StoredDbgRecords.splice(InsertPos, Src.StoredDbgRecords, Range.begin(), Range.end()); } iterator_range::iterator> DbgMarker::cloneDebugInfoFrom( DbgMarker *From, std::optional::iterator> from_here, bool InsertAtHead) { DbgRecord *First = nullptr; // Work out what range of DbgRecords to clone: normally all the contents of // the "From" marker, optionally we can start from the from_here position down // to end(). auto Range = make_range(From->StoredDbgRecords.begin(), From->StoredDbgRecords.end()); if (from_here.has_value()) Range = make_range(*from_here, From->StoredDbgRecords.end()); // Clone each DbgVariableRecord and insert into StoreDbgVariableRecords; // optionally place them at the start or the end of the list. auto Pos = (InsertAtHead) ? StoredDbgRecords.begin() : StoredDbgRecords.end(); for (DbgRecord &DR : Range) { DbgRecord *New = DR.clone(); New->setMarker(this); StoredDbgRecords.insert(Pos, *New); if (!First) First = New; } if (!First) return {StoredDbgRecords.end(), StoredDbgRecords.end()}; if (InsertAtHead) // If InsertAtHead is set, we cloned a range onto the front of of the // StoredDbgRecords collection, return that range. return {StoredDbgRecords.begin(), Pos}; else // We inserted a block at the end, return that range. return {First->getIterator(), StoredDbgRecords.end()}; } } // end namespace llvm