mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 12:56:06 +00:00

Rename the function to reflect its correct behavior and to be consistent with `Module::getOrInsertFunction`. This is also in preparation of adding a new `Intrinsic::getDeclaration` that will have behavior similar to `Module::getFunction` (i.e, just lookup, no creation).
728 lines
26 KiB
C++
728 lines
26 KiB
C++
//=====-- 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 <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 DbgRecordParamRef<DIExpression>;
|
|
template class DbgRecordParamRef<DILabel>;
|
|
template class DbgRecordParamRef<DILocalVariable>;
|
|
|
|
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, MDNode *DL)
|
|
: DbgRecord(LabelKind, DebugLoc(DL)), 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,
|
|
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<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");
|
|
}
|
|
|
|
// 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);
|
|
|
|
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);
|
|
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[2]);
|
|
}
|
|
|
|
void DbgVariableRecord::setAssignId(DIAssignID *New) {
|
|
resetDebugValue(2, 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;
|
|
}
|
|
|
|
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<DbgRecord::self_iterator> DbgMarker::getDbgRecordRange() {
|
|
return make_range(StoredDbgRecords.begin(), StoredDbgRecords.end());
|
|
}
|
|
iterator_range<DbgRecord::const_self_iterator>
|
|
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<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()};
|
|
}
|
|
|
|
} // end namespace llvm
|