[DebugInfo][NFC] Represent DbgValues with multiple ops in IRefLDV

In preparation for allowing InstrRefBasedLDV to handle DBG_VALUE_LIST,
this patch updates the internal representation that it uses to represent
debug values to store a list of values. This is one of the more
significant changes in terms of line count, but is fairly simple and
should not affect the output of this pass.

Differential Revision: https://reviews.llvm.org/D128177
This commit is contained in:
Stephen Tozer 2022-06-17 16:20:06 +01:00
parent 96fd3f2d5b
commit b5ba5d2aab
3 changed files with 598 additions and 284 deletions

View File

@ -155,6 +155,8 @@ static cl::opt<unsigned>
cl::desc("livedebugvalues-stack-ws-limit"),
cl::init(250));
DbgOpID DbgOpID::UndefID = DbgOpID(0xffffffff);
/// Tracker for converting machine value locations and variable values into
/// variable locations (the output of LiveDebugValues), recorded as DBG_VALUEs
/// specifying block live-in locations and transfers within blocks.
@ -259,7 +261,7 @@ public:
/// object fields to track variable locations as we step through the block.
/// FIXME: could just examine mloctracker instead of passing in \p mlocs?
void
loadInlocs(MachineBasicBlock &MBB, ValueTable &MLocs,
loadInlocs(MachineBasicBlock &MBB, ValueTable &MLocs, DbgOpIDMap &DbgOpStore,
const SmallVectorImpl<std::pair<DebugVariable, DbgValue>> &VLocs,
unsigned NumLocs) {
ActiveMLocs.clear();
@ -284,9 +286,13 @@ public:
// Initialized the preferred-location map with illegal locations, to be
// filled in later.
for (const auto &VLoc : VLocs)
if (VLoc.second.Kind == DbgValue::Def)
ValueToLoc.insert({VLoc.second.ID, LocIdx::MakeIllegalLoc()});
for (const auto &VLoc : VLocs) {
if (VLoc.second.Kind == DbgValue::Def &&
!VLoc.second.getDbgOpID(0).isConst()) {
ValueToLoc.insert({DbgOpStore.find(VLoc.second.getDbgOpID(0)).ID,
LocIdx::MakeIllegalLoc()});
}
}
ActiveMLocs.reserve(VLocs.size());
ActiveVLocs.reserve(VLocs.size());
@ -320,14 +326,16 @@ public:
// Now map variables to their picked LocIdxes.
for (const auto &Var : VLocs) {
if (Var.second.Kind == DbgValue::Const) {
DbgOpID OpID = Var.second.getDbgOpID(0);
DbgOp Op = DbgOpStore.find(OpID);
if (Var.second.Kind == DbgValue::Def && OpID.isConst()) {
PendingDbgValues.push_back(
emitMOLoc(*Var.second.MO, Var.first, Var.second.Properties));
emitMOLoc(Op.MO, Var.first, Var.second.Properties));
continue;
}
// If the value has no location, we can't make a variable location.
const ValueIDNum &Num = Var.second.ID;
const ValueIDNum &Num = Op.ID;
auto ValuesPreferredLoc = ValueToLoc.find(Num);
if (ValuesPreferredLoc->second.isIllegal()) {
// If it's a def that occurs in this block, register it as a
@ -674,17 +682,43 @@ ValueIDNum ValueIDNum::EmptyValue = {UINT_MAX, UINT_MAX, UINT_MAX};
ValueIDNum ValueIDNum::TombstoneValue = {UINT_MAX, UINT_MAX, UINT_MAX - 1};
#ifndef NDEBUG
void DbgValue::dump(const MLocTracker *MTrack) const {
if (Kind == Const) {
MO->dump();
} else if (Kind == NoVal) {
dbgs() << "NoVal(" << BlockNo << ")";
} else if (Kind == VPHI) {
dbgs() << "VPHI(" << BlockNo << "," << MTrack->IDAsString(ID) << ")";
void ResolvedDbgOp::dump(const MLocTracker *MTrack) const {
if (IsConst) {
dbgs() << MO;
} else {
assert(Kind == Def);
dbgs() << MTrack->LocIdxToName(Loc);
}
}
void DbgOp::dump(const MLocTracker *MTrack) const {
if (IsConst) {
dbgs() << MO;
} else if (!isUndef()) {
dbgs() << MTrack->IDAsString(ID);
}
}
void DbgOpID::dump(const MLocTracker *MTrack, const DbgOpIDMap *OpStore) const {
if (!OpStore) {
dbgs() << "ID(" << asU32() << ")";
} else {
OpStore->find(*this).dump(MTrack);
}
}
void DbgValue::dump(const MLocTracker *MTrack,
const DbgOpIDMap *OpStore) const {
if (Kind == NoVal) {
dbgs() << "NoVal(" << BlockNo << ")";
} else if (Kind == VPHI || Kind == Def) {
if (Kind == VPHI)
dbgs() << "VPHI(" << BlockNo << ",";
else
dbgs() << "Def(";
for (unsigned Idx = 0; Idx < getDbgOpIDs().size(); ++Idx) {
getDbgOpID(Idx).dump(MTrack, OpStore);
if (Idx != 0)
dbgs() << ",";
}
dbgs() << ")";
}
if (Properties.Indirect)
dbgs() << " indir";
if (Properties.DIExpr)
@ -1076,8 +1110,9 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) {
// contribute to locations in this block, but don't propagate further.
// Interpret it like a DBG_VALUE $noreg.
if (MI.isDebugValueList()) {
SmallVector<DbgOpID> EmptyDebugOps;
if (VTracker)
VTracker->defVar(MI, Properties, None);
VTracker->defVar(MI, Properties, EmptyDebugOps);
if (TTracker)
TTracker->redefVar(MI, Properties, None);
return true;
@ -1094,16 +1129,21 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) {
// locations are already solved, and we report this DBG_VALUE and the value
// it refers to to VLocTracker.
if (VTracker) {
if (MO.isReg()) {
// Feed defVar the new variable location, or if this is a
// DBG_VALUE $noreg, feed defVar None.
if (MO.getReg())
VTracker->defVar(MI, Properties, MTracker->readReg(MO.getReg()));
else
VTracker->defVar(MI, Properties, None);
} else if (MO.isImm() || MO.isFPImm() || MO.isCImm()) {
VTracker->defVar(MI, MO);
SmallVector<DbgOpID> DebugOps;
// Feed defVar the new variable location, or if this is a DBG_VALUE $noreg,
// feed defVar None.
if (!MI.isUndefDebugValue()) {
// There should be no undef registers here, as we've screened for undef
// debug values.
if (MO.isReg()) {
DebugOps.push_back(DbgOpStore.insert(MTracker->readReg(MO.getReg())));
} else if (MO.isImm() || MO.isFPImm() || MO.isCImm()) {
DebugOps.push_back(DbgOpStore.insert(MO));
} else {
llvm_unreachable("Unexpected debug operand type.");
}
}
VTracker->defVar(MI, Properties, DebugOps);
}
// If performing final tracking of transfers, report this variable definition
@ -1287,8 +1327,11 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
// for DBG_INSTR_REFs as DBG_VALUEs (just, the former can refer to values that
// aren't immediately available).
DbgValueProperties Properties(Expr, false, false);
SmallVector<DbgOpID> DbgOpIDs;
if (NewID)
DbgOpIDs.push_back(DbgOpStore.insert(*NewID));
if (VTracker)
VTracker->defVar(MI, Properties, NewID);
VTracker->defVar(MI, Properties, DbgOpIDs);
// If we're on the final pass through the function, decompose this INSTR_REF
// into a plain DBG_VALUE.
@ -1334,6 +1377,7 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
// FoundLoc is None.
// (XXX -- could morph the DBG_INSTR_REF in the future).
MachineInstr *DbgMI = MTracker->emitLoc(FoundLoc, V, Properties);
TTracker->PendingDbgValues.push_back(DbgMI);
TTracker->flushDbgValues(MI.getIterator(), nullptr);
return true;
@ -2397,7 +2441,7 @@ Optional<ValueIDNum> InstrRefBasedLDV::pickVPHILoc(
return None;
const DbgValue &OutVal = *OutValIt->second;
if (OutVal.Kind == DbgValue::Const || OutVal.Kind == DbgValue::NoVal)
if (OutVal.getDbgOpID(0).isConst() || OutVal.Kind == DbgValue::NoVal)
// Consts and no-values cannot have locations we can join on.
return None;
@ -2410,8 +2454,8 @@ Optional<ValueIDNum> InstrRefBasedLDV::pickVPHILoc(
// present. Do the same for VPHIs where we know the VPHI value.
if (OutVal.Kind == DbgValue::Def ||
(OutVal.Kind == DbgValue::VPHI && OutVal.BlockNo != MBB.getNumber() &&
OutVal.ID != ValueIDNum::EmptyValue)) {
ValueIDNum ValToLookFor = OutVal.ID;
!OutVal.getDbgOpID(0).isUndef())) {
ValueIDNum ValToLookFor = DbgOpStore.find(OutVal.getDbgOpID(0)).ID;
// Search the live-outs of the predecessor for the specified value.
for (unsigned int I = 0; I < NumLocs; ++I) {
if (MOutLocs[ThisBBNum][I] == ValToLookFor)
@ -2543,7 +2587,7 @@ bool InstrRefBasedLDV::vlocJoin(
return false;
if (V.second->Kind == DbgValue::NoVal)
return false;
if (V.second->Kind == DbgValue::Const && FirstVal.Kind != DbgValue::Const)
if (!V.second->hasJoinableLocOps(FirstVal))
return false;
}
@ -2556,7 +2600,7 @@ bool InstrRefBasedLDV::vlocJoin(
// If both values are not equal but have equal non-empty IDs then they refer
// to the same value from different sources (e.g. one is VPHI and the other
// is Def), which does not cause disagreement.
if (V.second->ID != ValueIDNum::EmptyValue && V.second->ID == FirstVal.ID)
if (V.second->hasIdenticalValidLocOps(FirstVal))
continue;
// Eliminate if a backedge feeds a VPHI back into itself.
@ -2807,8 +2851,9 @@ void InstrRefBasedLDV::buildVLocValueMap(
pickVPHILoc(*MBB, Var, LiveOutIdx, MOutLocs, Preds);
if (ValueNum) {
InLocsChanged |= LiveIn->ID != *ValueNum;
LiveIn->ID = *ValueNum;
DbgOpID ValueID = DbgOpStore.insert(*ValueNum);
InLocsChanged |= LiveIn->getDbgOpID(0) != ValueID;
LiveIn->setDbgOpIDs(ValueID);
}
}
@ -2878,8 +2923,7 @@ void InstrRefBasedLDV::buildVLocValueMap(
DbgValue *BlockLiveIn = LiveInIdx[MBB];
if (BlockLiveIn->Kind == DbgValue::NoVal)
continue;
if (BlockLiveIn->Kind == DbgValue::VPHI &&
BlockLiveIn->ID == ValueIDNum::EmptyValue)
if (BlockLiveIn->isUnjoinedPHI())
continue;
if (BlockLiveIn->Kind == DbgValue::VPHI)
BlockLiveIn->Kind = DbgValue::Def;
@ -3070,7 +3114,8 @@ bool InstrRefBasedLDV::depthFirstVLocAndEmit(
// instructions, installing transfers.
MTracker->reset();
MTracker->loadFromArray(MInLocs[BBNum], BBNum);
TTracker->loadInlocs(MBB, MInLocs[BBNum], Output[BBNum], NumLocs);
TTracker->loadInlocs(MBB, MInLocs[BBNum], DbgOpStore, Output[BBNum],
NumLocs);
CurBB = BBNum;
CurInst = 1;
@ -3368,6 +3413,7 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
OverlapFragments.clear();
SeenFragments.clear();
SeenDbgPHIs.clear();
DbgOpStore.clear();
return Changed;
}

View File

@ -30,6 +30,7 @@ class InstrRefLDVTest;
namespace LiveDebugValues {
class MLocTracker;
class DbgOpIDMap;
using namespace llvm;
@ -168,6 +169,40 @@ public:
static ValueIDNum TombstoneValue;
};
} // End namespace LiveDebugValues
namespace llvm {
using namespace LiveDebugValues;
template <> struct DenseMapInfo<LocIdx> {
static inline LocIdx getEmptyKey() { return LocIdx::MakeIllegalLoc(); }
static inline LocIdx getTombstoneKey() { return LocIdx::MakeTombstoneLoc(); }
static unsigned getHashValue(const LocIdx &Loc) { return Loc.asU64(); }
static bool isEqual(const LocIdx &A, const LocIdx &B) { return A == B; }
};
template <> struct DenseMapInfo<ValueIDNum> {
static inline ValueIDNum getEmptyKey() { return ValueIDNum::EmptyValue; }
static inline ValueIDNum getTombstoneKey() {
return ValueIDNum::TombstoneValue;
}
static unsigned getHashValue(const ValueIDNum &Val) {
return hash_value(Val.asU64());
}
static bool isEqual(const ValueIDNum &A, const ValueIDNum &B) {
return A == B;
}
};
} // end namespace llvm
namespace LiveDebugValues {
using namespace llvm;
/// Type for a table of values in a block.
using ValueTable = std::unique_ptr<ValueIDNum[]>;
@ -230,19 +265,181 @@ public:
bool IsVariadic;
};
/// Class recording the (high level) _value_ of a variable. Identifies either
/// the value of the variable as a ValueIDNum, or a constant MachineOperand.
/// TODO: Might pack better if we changed this to a Struct of Arrays, since
/// MachineOperand is width 32, making this struct width 33. We could also
/// potentially avoid storing the whole MachineOperand (sizeof=32), instead
/// choosing to store just the contents portion (sizeof=8) and a Kind enum,
/// since we already know it is some type of immediate value.
/// Stores a single debug operand, which can either be a MachineOperand for
/// directly storing immediate values, or a ValueIDNum representing some value
/// computed at some point in the program. IsConst is used as a discriminator.
struct DbgOp {
union {
ValueIDNum ID;
MachineOperand MO;
};
bool IsConst;
DbgOp() : ID(ValueIDNum::EmptyValue), IsConst(false) {}
DbgOp(ValueIDNum ID) : ID(ID), IsConst(false) {}
DbgOp(MachineOperand MO) : MO(MO), IsConst(true) {}
bool isUndef() const { return !IsConst && ID == ValueIDNum::EmptyValue; }
#ifndef NDEBUG
void dump(const MLocTracker *MTrack) const;
#endif
};
/// A DbgOp whose ID (if any) has resolved to an actual location, LocIdx. Used
/// when working with concrete debug values, i.e. when joining MLocs and VLocs
/// in the TransferTracker or emitting DBG_VALUE/DBG_VALUE_LIST instructions in
/// the MLocTracker.
struct ResolvedDbgOp {
union {
LocIdx Loc;
MachineOperand MO;
};
bool IsConst;
ResolvedDbgOp(LocIdx Loc) : Loc(Loc), IsConst(false) {}
ResolvedDbgOp(MachineOperand MO) : MO(MO), IsConst(true) {}
bool operator==(const ResolvedDbgOp &Other) const {
if (IsConst != Other.IsConst)
return false;
if (IsConst)
return MO.isIdenticalTo(Other.MO);
return Loc == Other.Loc;
}
#ifndef NDEBUG
void dump(const MLocTracker *MTrack) const;
#endif
};
/// An ID used in the DbgOpIDMap (below) to lookup a stored DbgOp. This is used
/// in place of actual DbgOps inside of a DbgValue to reduce its size, as
/// DbgValue is very frequently used and passed around, and the actual DbgOp is
/// over 8x larger than this class, due to storing a MachineOperand. This ID
/// should be equal for all equal DbgOps, and also encodes whether the mapped
/// DbgOp is a constant, meaning that for simple equality or const-ness checks
/// it is not necessary to lookup this ID.
struct DbgOpID {
union {
struct {
uint32_t IsConst : 1;
uint32_t Index : 31;
} ID;
uint32_t RawID;
};
DbgOpID() : RawID(UndefID.RawID) {
static_assert(sizeof(DbgOpID) == 4, "DbgOpID should fit within 4 bytes.");
}
DbgOpID(uint32_t RawID) : RawID(RawID) {}
DbgOpID(bool IsConst, uint32_t Index) : ID({IsConst, Index}) {}
static DbgOpID UndefID;
bool operator==(const DbgOpID &Other) const { return RawID == Other.RawID; }
bool operator!=(const DbgOpID &Other) const { return !(*this == Other); }
uint32_t asU32() const { return RawID; }
bool isUndef() const { return *this == UndefID; }
bool isConst() const { return ID.IsConst && !isUndef(); }
uint32_t getIndex() const { return ID.Index; }
#ifndef NDEBUG
void dump(const MLocTracker *MTrack, const DbgOpIDMap *OpStore) const;
#endif
};
/// Class storing the complete set of values that are observed by DbgValues
/// within the current function. Allows 2-way lookup, with `find` returning the
/// Op for a given ID and `insert` returning the ID for a given Op (creating one
/// if none exists).
class DbgOpIDMap {
SmallVector<ValueIDNum, 0> ValueOps;
SmallVector<MachineOperand, 0> ConstOps;
DenseMap<ValueIDNum, DbgOpID> ValueOpToID;
DenseMap<MachineOperand, DbgOpID> ConstOpToID;
public:
/// If \p Op does not already exist in this map, it is inserted and the
/// corresponding DbgOpID is returned. If Op already exists in this map, then
/// no change is made and the existing ID for Op is returned.
/// Calling this with the undef DbgOp will always return DbgOpID::UndefID.
DbgOpID insert(DbgOp Op) {
if (Op.isUndef())
return DbgOpID::UndefID;
if (Op.IsConst)
return insertConstOp(Op.MO);
return insertValueOp(Op.ID);
}
/// Returns the DbgOp associated with \p ID. Should only be used for IDs
/// returned from calling `insert` from this map or DbgOpID::UndefID.
DbgOp find(DbgOpID ID) const {
if (ID == DbgOpID::UndefID)
return DbgOp();
if (ID.isConst())
return DbgOp(ConstOps[ID.getIndex()]);
return DbgOp(ValueOps[ID.getIndex()]);
}
void clear() {
ValueOps.clear();
ConstOps.clear();
ValueOpToID.clear();
ConstOpToID.clear();
}
private:
DbgOpID insertConstOp(MachineOperand &MO) {
auto ExistingIt = ConstOpToID.find(MO);
if (ExistingIt != ConstOpToID.end())
return ExistingIt->second;
DbgOpID ID(true, ConstOps.size());
ConstOpToID.insert(std::make_pair(MO, ID));
ConstOps.push_back(MO);
return ID;
}
DbgOpID insertValueOp(ValueIDNum VID) {
auto ExistingIt = ValueOpToID.find(VID);
if (ExistingIt != ValueOpToID.end())
return ExistingIt->second;
DbgOpID ID(false, ValueOps.size());
ValueOpToID.insert(std::make_pair(VID, ID));
ValueOps.push_back(VID);
return ID;
}
};
// We set the maximum number of operands that we will handle to keep DbgValue
// within a reasonable size (64 bytes), as we store and pass a lot of them
// around.
#define MAX_DBG_OPS 8
/// Class recording the (high level) _value_ of a variable. Identifies the value
/// of the variable as a list of ValueIDNums and constant MachineOperands, or as
/// an empty list for undef debug values or VPHI values which we have not found
/// valid locations for.
/// This class also stores meta-information about how the value is qualified.
/// Used to reason about variable values when performing the second
/// (DebugVariable specific) dataflow analysis.
class DbgValue {
private:
/// If Kind is Def or VPHI, the set of IDs corresponding to the DbgOps that
/// are used. VPHIs set every ID to EmptyID when we have not found a valid
/// machine-value for every operand, and sets them to the corresponding
/// machine-values when we have found all of them.
DbgOpID DbgOps[MAX_DBG_OPS];
unsigned OpCount;
public:
/// If Kind is Def, the value number that this value is based on. VPHIs set
/// this field to EmptyValue if there is no machine-value for this VPHI, or
/// the corresponding machine-value if there is one.
ValueIDNum ID;
/// If Kind is Const, the MachineOperand defining this value.
Optional<MachineOperand> MO;
/// For a NoVal or VPHI DbgValue, which block it was generated in.
int BlockNo;
@ -251,8 +448,8 @@ public:
typedef enum {
Undef, // Represents a DBG_VALUE $noreg in the transfer function only.
Def, // This value is defined by an inst, or is a PHI value.
Const, // A constant value contained in the MachineOperand field.
Def, // This value is defined by some combination of constants,
// instructions, or PHI values.
VPHI, // Incoming values to BlockNo differ, those values must be joined by
// a PHI in this block.
NoVal, // Empty DbgValue indicating an unknown value. Used as initializer,
@ -261,52 +458,113 @@ public:
/// Discriminator for whether this is a constant or an in-program value.
KindT Kind;
DbgValue(const ValueIDNum &Val, const DbgValueProperties &Prop, KindT Kind)
: ID(Val), MO(None), BlockNo(0), Properties(Prop), Kind(Kind) {
assert(Kind == Def);
DbgValue(ArrayRef<DbgOpID> DbgOps, const DbgValueProperties &Prop)
: OpCount(DbgOps.size()), BlockNo(0), Properties(Prop), Kind(Def) {
static_assert(sizeof(DbgValue) <= 64,
"DbgValue should fit within 64 bytes.");
assert(DbgOps.size() == Prop.getLocationOpCount());
if (DbgOps.size() > MAX_DBG_OPS ||
any_of(DbgOps, [](DbgOpID ID) { return ID.isUndef(); })) {
Kind = Undef;
OpCount = 0;
#define DEBUG_TYPE "LiveDebugValues"
if (DbgOps.size() > MAX_DBG_OPS) {
LLVM_DEBUG(dbgs() << "Found DbgValue with more than maximum allowed "
"operands.\n");
}
#undef DEBUG_TYPE
} else {
for (unsigned Idx = 0; Idx < DbgOps.size(); ++Idx)
this->DbgOps[Idx] = DbgOps[Idx];
}
}
DbgValue(unsigned BlockNo, const DbgValueProperties &Prop, KindT Kind)
: ID(ValueIDNum::EmptyValue), MO(None), BlockNo(BlockNo),
Properties(Prop), Kind(Kind) {
: OpCount(0), BlockNo(BlockNo), Properties(Prop), Kind(Kind) {
assert(Kind == NoVal || Kind == VPHI);
}
DbgValue(const MachineOperand &MO, const DbgValueProperties &Prop, KindT Kind)
: ID(ValueIDNum::EmptyValue), MO(MO), BlockNo(0), Properties(Prop),
Kind(Kind) {
assert(Kind == Const);
}
DbgValue(const DbgValueProperties &Prop, KindT Kind)
: ID(ValueIDNum::EmptyValue), MO(None), BlockNo(0), Properties(Prop),
Kind(Kind) {
: OpCount(0), BlockNo(0), Properties(Prop), Kind(Kind) {
assert(Kind == Undef &&
"Empty DbgValue constructor must pass in Undef kind");
}
#ifndef NDEBUG
void dump(const MLocTracker *MTrack) const;
void dump(const MLocTracker *MTrack = nullptr,
const DbgOpIDMap *OpStore = nullptr) const;
#endif
bool operator==(const DbgValue &Other) const {
if (std::tie(Kind, Properties) != std::tie(Other.Kind, Other.Properties))
return false;
else if (Kind == Def && ID != Other.ID)
else if (Kind == Def && !equal(getDbgOpIDs(), Other.getDbgOpIDs()))
return false;
else if (Kind == NoVal && BlockNo != Other.BlockNo)
return false;
else if (Kind == Const)
return MO->isIdenticalTo(*Other.MO);
else if (Kind == VPHI && BlockNo != Other.BlockNo)
return false;
else if (Kind == VPHI && ID != Other.ID)
else if (Kind == VPHI && !equal(getDbgOpIDs(), Other.getDbgOpIDs()))
return false;
return true;
}
bool operator!=(const DbgValue &Other) const { return !(*this == Other); }
// Returns an array of all the machine values used to calculate this variable
// value, or an empty list for an Undef or unjoined VPHI.
ArrayRef<DbgOpID> getDbgOpIDs() const { return {DbgOps, OpCount}; }
// Returns either DbgOps[Index] if this DbgValue has Debug Operands, or
// the ID for ValueIDNum::EmptyValue otherwise (i.e. if this is an Undef,
// NoVal, or an unjoined VPHI).
DbgOpID getDbgOpID(unsigned Index) const {
if (!OpCount)
return DbgOpID::UndefID;
assert(Index < OpCount);
return DbgOps[Index];
}
// Replaces this DbgValue's existing DbgOpIDs (if any) with the contents of
// \p NewIDs. The number of DbgOpIDs passed must be equal to the number of
// arguments expected by this DbgValue's properties (the return value of
// `getLocationOpCount()`).
void setDbgOpIDs(ArrayRef<DbgOpID> NewIDs) {
// We can go from no ops to some ops, but not from some ops to no ops.
assert(NewIDs.size() == getLocationOpCount() &&
"Incorrect number of Debug Operands for this DbgValue.");
OpCount = NewIDs.size();
for (unsigned Idx = 0; Idx < NewIDs.size(); ++Idx)
DbgOps[Idx] = NewIDs[Idx];
}
// The number of debug operands expected by this DbgValue's expression.
// getDbgOpIDs() should return an array of this length, unless this is an
// Undef or an unjoined VPHI.
unsigned getLocationOpCount() const {
return Properties.getLocationOpCount();
}
// Returns true if this or Other are unjoined PHIs, which do not have defined
// Loc Ops, or if the `n`th Loc Op for this has a different constness to the
// `n`th Loc Op for Other.
bool hasJoinableLocOps(const DbgValue &Other) const {
if (isUnjoinedPHI() || Other.isUnjoinedPHI())
return true;
for (unsigned Idx = 0; Idx < getLocationOpCount(); ++Idx) {
if (getDbgOpID(Idx).isConst() != Other.getDbgOpID(Idx).isConst())
return false;
}
return true;
}
bool isUnjoinedPHI() const { return Kind == VPHI && OpCount == 0; }
bool hasIdenticalValidLocOps(const DbgValue &Other) const {
if (!OpCount)
return false;
return equal(getDbgOpIDs(), Other.getDbgOpIDs());
}
};
class LocIdxToIndexFunctor {
@ -716,29 +974,14 @@ public:
: OverlappingFragments(O), EmptyProperties(EmptyExpr, false, false) {}
void defVar(const MachineInstr &MI, const DbgValueProperties &Properties,
Optional<ValueIDNum> ID) {
const SmallVectorImpl<DbgOpID> &DebugOps) {
assert(MI.isDebugValue() || MI.isDebugRef());
assert(DebugOps.size() <= 1);
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt());
DbgValue Rec = (ID) ? DbgValue(*ID, Properties, DbgValue::Def)
: DbgValue(Properties, DbgValue::Undef);
// Attempt insertion; overwrite if it's already mapped.
auto Result = Vars.insert(std::make_pair(Var, Rec));
if (!Result.second)
Result.first->second = Rec;
Scopes[Var] = MI.getDebugLoc().get();
considerOverlaps(Var, MI.getDebugLoc().get());
}
void defVar(const MachineInstr &MI, const MachineOperand &MO) {
// Only DBG_VALUEs can define constant-valued variables.
assert(MI.isDebugValue());
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt());
DbgValueProperties Properties(MI);
DbgValue Rec = DbgValue(MO, Properties, DbgValue::Const);
DbgValue Rec = (DebugOps.size() > 0)
? DbgValue(DebugOps, Properties)
: DbgValue(Properties, DbgValue::Undef);
// Attempt insertion; overwrite if it's already mapped.
auto Result = Vars.insert(std::make_pair(Var, Rec));
@ -907,6 +1150,8 @@ private:
/// the result.
DenseMap<MachineInstr *, Optional<ValueIDNum>> SeenDbgPHIs;
DbgOpIDMap DbgOpStore;
/// True if we need to examine call instructions for stack clobbers. We
/// normally assume that they don't clobber SP, but stack probes on Windows
/// do.
@ -1166,33 +1411,4 @@ public:
} // namespace LiveDebugValues
namespace llvm {
using namespace LiveDebugValues;
template <> struct DenseMapInfo<LocIdx> {
static inline LocIdx getEmptyKey() { return LocIdx::MakeIllegalLoc(); }
static inline LocIdx getTombstoneKey() { return LocIdx::MakeTombstoneLoc(); }
static unsigned getHashValue(const LocIdx &Loc) { return Loc.asU64(); }
static bool isEqual(const LocIdx &A, const LocIdx &B) { return A == B; }
};
template <> struct DenseMapInfo<ValueIDNum> {
static inline ValueIDNum getEmptyKey() { return ValueIDNum::EmptyValue; }
static inline ValueIDNum getTombstoneKey() {
return ValueIDNum::TombstoneValue;
}
static unsigned getHashValue(const ValueIDNum &Val) {
return hash_value(Val.asU64());
}
static bool isEqual(const ValueIDNum &A, const ValueIDNum &B) {
return A == B;
}
};
} // end namespace llvm
#endif /* LLVM_LIB_CODEGEN_LIVEDEBUGVALUES_INSTRREFBASEDLDV_H */

File diff suppressed because it is too large Load Diff