| //=====-- 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/DebugProgramInstruction.h" | |
| #include "llvm/IR/DIBuilder.h" | |
| #include "llvm/IR/DebugInfoMetadata.h" | |
| #include "llvm/IR/IntrinsicInst.h" | |
| #include "llvm/Support/Compiler.h" | |
| using namespace llvm; | |
| namespace llvm { | |
| template <typename T> | |
| DbgRecordParamRef<T>::DbgRecordParamRef(const T *Param) | |
| : Ref(const_cast<T *>(Param)) {} | |
| template <typename T> | |
| DbgRecordParamRef<T>::DbgRecordParamRef(const MDNode *Param) | |
| : Ref(const_cast<MDNode *>(Param)) {} | |
| template <typename T> T *DbgRecordParamRef<T>::get() const { | |
| return cast<T>(Ref); | |
| } | |
| template class LLVM_EXPORT_TEMPLATE DbgRecordParamRef<DIExpression>; | |
| template class LLVM_EXPORT_TEMPLATE DbgRecordParamRef<DILabel>; | |
| template class LLVM_EXPORT_TEMPLATE DbgRecordParamRef<DILocalVariable>; | |
| } // namespace llvm | |
| 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<const DbgAssignIntrinsic *>(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<DbgVariableRecord>(this); | |
| return; | |
| case LabelKind: | |
| delete cast<DbgLabelRecord>(this); | |
| return; | |
| } | |
| llvm_unreachable("unsupported DbgRecord kind"); | |
| } | |
| void DbgRecord::print(raw_ostream &O, bool IsForDebug) const { | |
| switch (RecordKind) { | |
| case ValueKind: | |
| cast<DbgVariableRecord>(this)->print(O, IsForDebug); | |
| return; | |
| case LabelKind: | |
| cast<DbgLabelRecord>(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<DbgVariableRecord>(this)->print(O, MST, IsForDebug); | |
| return; | |
| case LabelKind: | |
| cast<DbgLabelRecord>(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<DbgVariableRecord>(this)->isIdenticalToWhenDefined( | |
| *cast<DbgVariableRecord>(&R)); | |
| case LabelKind: | |
| return cast<DbgLabelRecord>(this)->getLabel() == | |
| cast<DbgLabelRecord>(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<DbgVariableRecord>(this)->createDebugIntrinsic(M, InsertBefore); | |
| case LabelKind: | |
| return cast<DbgLabelRecord>(this)->createDebugIntrinsic(M, InsertBefore); | |
| }; | |
| llvm_unreachable("unsupported DbgRecord kind"); | |
| } | |
| DbgLabelRecord::DbgLabelRecord(MDNode *Label) | |
| : DbgRecord(LabelKind, DebugLoc()), Label(Label) { | |
| assert(Label && "Unexpected nullptr"); | |
| assert((isa<DILabel>(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) { | |
| return new DbgLabelRecord(Label); | |
| } | |
| DbgVariableRecord::DbgVariableRecord(DbgVariableRecord::LocationType Type, | |
| Metadata *Val, MDNode *Variable, | |
| MDNode *Expression, MDNode *AssignID, | |
| Metadata *Address, | |
| MDNode *AddressExpression) | |
| : DbgRecord(ValueKind, DebugLoc()), | |
| 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) { | |
| return new DbgVariableRecord(Type, Val, Variable, Expression, AssignID, | |
| Address, AddressExpression); | |
| } | |
| 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::createDVRDeclareValue(Value *Address, DILocalVariable *DV, | |
| DIExpression *Expr, | |
| const DILocation *DI) { | |
| return new DbgVariableRecord(ValueAsMetadata::get(Address), DV, Expr, DI, | |
| LocationType::DeclareValue); | |
| } | |
| DbgVariableRecord *DbgVariableRecord::createDVRDeclareValue( | |
| Value *Address, DILocalVariable *DV, DIExpression *Expr, | |
| const DILocation *DI, DbgVariableRecord &InsertBefore) { | |
| auto *NewDVRCoro = createDVRDeclareValue(Address, DV, Expr, DI); | |
| NewDVRCoro->insertBefore(&InsertBefore); | |
| return NewDVRCoro; | |
| } | |
| 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<DIAssignID>(Link), Address, | |
| AddressExpression, DI); | |
| LinkedInstr->getParent()->insertDbgRecordAfter(NewDVRAssign, LinkedInstr); | |
| return NewDVRAssign; | |
| } | |
| iterator_range<DbgVariableRecord::location_op_iterator> | |
| 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<ValueAsMetadata *>(nullptr)), | |
| location_op_iterator(static_cast<ValueAsMetadata *>(nullptr))}; | |
| // If operand is ValueAsMetadata, return a range over just that operand. | |
| if (auto *VAM = dyn_cast<ValueAsMetadata>(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<DIArgList>(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<MDNode>(MD)->getNumOperands() == 0); | |
| return {location_op_iterator(static_cast<ValueAsMetadata *>(nullptr)), | |
| location_op_iterator(static_cast<ValueAsMetadata *>(nullptr))}; | |
| } | |
| unsigned DbgVariableRecord::getNumVariableLocationOps() const { | |
| if (hasArgList()) | |
| return cast<DIArgList>(getRawLocation())->getArgs().size(); | |
| return 1; | |
| } | |
| Value *DbgVariableRecord::getVariableLocationOp(unsigned OpIdx) const { | |
| auto *MD = getRawLocation(); | |
| if (!MD) | |
| return nullptr; | |
| if (auto *AL = dyn_cast<DIArgList>(MD)) | |
| return AL->getArgs()[OpIdx]->getValue(); | |
| if (isa<MDNode>(MD)) | |
| return nullptr; | |
| assert(isa<ValueAsMetadata>(MD) && | |
| "Attempted to get location operand from DbgVariableRecord with none."); | |
| auto *V = cast<ValueAsMetadata>(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<MetadataAsValue>(V) ? dyn_cast<ValueAsMetadata>( | |
| cast<MetadataAsValue>(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<MetadataAsValue>(NewValue) | |
| ? cast<MetadataAsValue>(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<ValueAsMetadata *, 4> 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<MetadataAsValue>(NewValue) | |
| ? cast<MetadataAsValue>(NewValue)->getMetadata() | |
| : ValueAsMetadata::get(NewValue)); | |
| return; | |
| } | |
| SmallVector<ValueAsMetadata *, 4> 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<Value *> 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<ValueAsMetadata *, 4> 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<Value *, 4> 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<MDNode>(getRawLocation())) || | |
| (getNumVariableLocationOps() == 0 && !getExpression()->isComplex()) || | |
| any_of(location_ops(), [](Value *V) { return isa<UndefValue>(V); }); | |
| } | |
| std::optional<DbgVariableFragmentInfo> DbgVariableRecord::getFragment() const { | |
| return getExpression()->getFragmentInfo(); | |
| } | |
| std::optional<uint64_t> DbgVariableRecord::getFragmentSizeInBits() const { | |
| if (auto Fragment = getExpression()->getFragmentInfo()) | |
| return Fragment->SizeInBits; | |
| return getVariable()->getSizeInBits(); | |
| } | |
| DbgRecord *DbgRecord::clone() const { | |
| switch (RecordKind) { | |
| case ValueKind: | |
| return cast<DbgVariableRecord>(this)->clone(); | |
| case LabelKind: | |
| return cast<DbgLabelRecord>(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::getOrInsertDeclaration(M, Intrinsic::dbg_declare); | |
| break; | |
| case DbgVariableRecord::LocationType::Value: | |
| IntrinsicFn = Intrinsic::getOrInsertDeclaration(M, Intrinsic::dbg_value); | |
| break; | |
| case DbgVariableRecord::LocationType::Assign: | |
| IntrinsicFn = Intrinsic::getOrInsertDeclaration(M, Intrinsic::dbg_assign); | |
| break; | |
| case DbgVariableRecord::LocationType::End: | |
| case DbgVariableRecord::LocationType::Any: | |
| llvm_unreachable("Invalid LocationType"); | |
| break; | |
| case DbgVariableRecord::LocationType::DeclareValue: | |
| llvm_unreachable( | |
| "#dbg_declare_value should never be converted to an intrinsic"); | |
| } | |
| // 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<DbgVariableIntrinsic>(CallInst::Create( | |
| IntrinsicFn->getFunctionType(), IntrinsicFn, AssignArgs)); | |
| } else { | |
| Value *Args[] = {MetadataAsValue::get(Context, getRawLocation()), | |
| MetadataAsValue::get(Context, getVariable()), | |
| MetadataAsValue::get(Context, getExpression())}; | |
| DVI = cast<DbgVariableIntrinsic>( | |
| CallInst::Create(IntrinsicFn->getFunctionType(), IntrinsicFn, Args)); | |
| } | |
| DVI->setTailCall(); | |
| DVI->setDebugLoc(getDebugLoc()); | |
| if (InsertBefore) | |
| DVI->insertBefore(InsertBefore->getIterator()); | |
| return DVI; | |
| } | |
| DbgLabelInst * | |
| DbgLabelRecord::createDebugIntrinsic(Module *M, | |
| Instruction *InsertBefore) const { | |
| auto *LabelFn = Intrinsic::getOrInsertDeclaration(M, Intrinsic::dbg_label); | |
| Value *Args[] = { | |
| MetadataAsValue::get(getDebugLoc()->getContext(), getLabel())}; | |
| DbgLabelInst *DbgLabel = cast<DbgLabelInst>( | |
| CallInst::Create(LabelFn->getFunctionType(), LabelFn, Args)); | |
| DbgLabel->setTailCall(); | |
| DbgLabel->setDebugLoc(getDebugLoc()); | |
| if (InsertBefore) | |
| DbgLabel->insertBefore(InsertBefore->getIterator()); | |
| return DbgLabel; | |
| } | |
| Value *DbgVariableRecord::getAddress() const { | |
| auto *MD = getRawAddress(); | |
| if (auto *V = dyn_cast_or_null<ValueAsMetadata>(MD)) | |
| return V->getValue(); | |
| // When the value goes to null, it gets replaced by an empty MDNode. | |
| assert((!MD || !cast<MDNode>(MD)->getNumOperands()) && | |
| "Expected an empty MDNode"); | |
| return nullptr; | |
| } | |
| DIAssignID *DbgVariableRecord::getAssignID() const { | |
| return cast<DIAssignID>(DebugValues[AssignIDIdx]); | |
| } | |
| void DbgVariableRecord::setAssignId(DIAssignID *New) { | |
| resetDebugValue(AssignIDIdx, New); | |
| } | |
| void DbgVariableRecord::setKillAddress() { | |
| resetDebugValue( | |
| 1, ValueAsMetadata::get(PoisonValue::get(getAddress()->getType()))); | |
| } | |
| bool DbgVariableRecord::isKillAddress() const { | |
| Value *Addr = getAddress(); | |
| return !Addr || isa<UndefValue>(Addr); | |
| } | |
| const Instruction *DbgRecord::getInstruction() const { | |
| return Marker->MarkedInstr; | |
| } | |
| Instruction *DbgRecord::getInstruction() { 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::insertBefore(self_iterator 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(self_iterator 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); | |
| } | |
| void DbgRecord::moveBefore(self_iterator MoveBefore) { | |
| assert(getMarker() && | |
| "Canot move a DbgRecord that does not currently have a DbgMarker!"); | |
| removeFromParent(); | |
| insertBefore(MoveBefore); | |
| } | |
| void DbgRecord::moveAfter(self_iterator 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<DbgRecord::self_iterator> DbgMarker::getDbgRecordRange() { | |
| return StoredDbgRecords; | |
| } | |
| iterator_range<DbgRecord::const_self_iterator> | |
| DbgMarker::getDbgRecordRange() const { | |
| return StoredDbgRecords; | |
| } | |
| 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<DbgRecord::self_iterator> 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<simple_ilist<DbgRecord>::iterator> DbgMarker::cloneDebugInfoFrom( | |
| DbgMarker *From, std::optional<simple_ilist<DbgRecord>::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()}; | |
| } |