[DebugInfo] Make DebugVariable class available in DebugInfoMetadata

The DebugVariable class is a class declared in LiveDebugValues.cpp which
is used to uniquely identify a single variable, using its source
variable, inline location, and fragment info to do so. This patch moves
this class into DebugInfoMetadata.h, making it available in a much
broader scope.
This commit is contained in:
stozer 2019-12-03 12:24:41 +00:00
parent 948b602c7f
commit afaad946a7
4 changed files with 150 additions and 111 deletions

View File

@ -3253,6 +3253,89 @@ public:
}
};
/// Identifies a unique instance of a variable.
///
/// Storage for identifying a potentially inlined instance of a variable,
/// or a fragment thereof. This guarantees that exactly one variable instance
/// may be identified by this class, even when that variable is a fragment of
/// an aggregate variable and/or there is another inlined instance of the same
/// source code variable nearby.
/// This class does not necessarily uniquely identify that variable: it is
/// possible that a DebugVariable with different parameters may point to the
/// same variable instance, but not that one DebugVariable points to multiple
/// variable instances.
class DebugVariable {
using FragmentInfo = DIExpression::FragmentInfo;
const DILocalVariable *Variable;
Optional<FragmentInfo> Fragment;
const DILocation *InlinedAt;
/// Fragment that will overlap all other fragments. Used as default when
/// caller demands a fragment.
static const FragmentInfo DefaultFragment;
public:
DebugVariable(const DILocalVariable *Var, Optional<FragmentInfo> FragmentInfo,
const DILocation *InlinedAt)
: Variable(Var), Fragment(FragmentInfo), InlinedAt(InlinedAt) {}
DebugVariable(const DILocalVariable *Var, const DIExpression *DIExpr,
const DILocation *InlinedAt)
: Variable(Var),
Fragment(DIExpr ? DIExpr->getFragmentInfo() : NoneType()),
InlinedAt(InlinedAt) {}
const DILocalVariable *getVariable() const { return Variable; }
const Optional<FragmentInfo> getFragment() const { return Fragment; }
const DILocation *getInlinedAt() const { return InlinedAt; }
const FragmentInfo getFragmentOrDefault() const {
return Fragment.getValueOr(DefaultFragment);
}
static bool isDefaultFragment(const FragmentInfo F) {
return F == DefaultFragment;
}
bool operator==(const DebugVariable &Other) const {
return std::tie(Variable, Fragment, InlinedAt) ==
std::tie(Other.Variable, Other.Fragment, Other.InlinedAt);
}
bool operator<(const DebugVariable &Other) const {
return std::tie(Variable, Fragment, InlinedAt) <
std::tie(Other.Variable, Other.Fragment, Other.InlinedAt);
}
};
template <> struct DenseMapInfo<DebugVariable> {
using FragmentInfo = DIExpression::FragmentInfo;
/// Empty key: no key should be generated that has no DILocalVariable.
static inline DebugVariable getEmptyKey() {
return DebugVariable(nullptr, NoneType(), nullptr);
}
/// Difference in tombstone is that the Optional is meaningful.
static inline DebugVariable getTombstoneKey() {
return DebugVariable(nullptr, {{0, 0}}, nullptr);
}
static unsigned getHashValue(const DebugVariable &D) {
unsigned HV = 0;
const Optional<FragmentInfo> Fragment = D.getFragment();
if (Fragment)
HV = DenseMapInfo<FragmentInfo>::getHashValue(*Fragment);
return hash_combine(D.getVariable(), HV, D.getInlinedAt());
}
static bool isEqual(const DebugVariable &A, const DebugVariable &B) {
return A == B;
}
};
} // end namespace llvm
#undef DEFINE_MDNODE_GET_UNPACK_IMPL

View File

@ -144,60 +144,6 @@ private:
using FragmentInfo = DIExpression::FragmentInfo;
using OptFragmentInfo = Optional<DIExpression::FragmentInfo>;
/// Storage for identifying a potentially inlined instance of a variable,
/// or a fragment thereof.
class DebugVariable {
const DILocalVariable *Variable;
OptFragmentInfo Fragment;
const DILocation *InlinedAt;
/// Fragment that will overlap all other fragments. Used as default when
/// caller demands a fragment.
static const FragmentInfo DefaultFragment;
public:
DebugVariable(const DILocalVariable *Var, OptFragmentInfo &&FragmentInfo,
const DILocation *InlinedAt)
: Variable(Var), Fragment(FragmentInfo), InlinedAt(InlinedAt) {}
DebugVariable(const DILocalVariable *Var, OptFragmentInfo &FragmentInfo,
const DILocation *InlinedAt)
: Variable(Var), Fragment(FragmentInfo), InlinedAt(InlinedAt) {}
DebugVariable(const DILocalVariable *Var, const DIExpression *DIExpr,
const DILocation *InlinedAt)
: DebugVariable(Var, DIExpr->getFragmentInfo(), InlinedAt) {}
DebugVariable(const MachineInstr &MI)
: DebugVariable(MI.getDebugVariable(),
MI.getDebugExpression()->getFragmentInfo(),
MI.getDebugLoc()->getInlinedAt()) {}
const DILocalVariable *getVar() const { return Variable; }
const OptFragmentInfo &getFragment() const { return Fragment; }
const DILocation *getInlinedAt() const { return InlinedAt; }
const FragmentInfo getFragmentDefault() const {
return Fragment.getValueOr(DefaultFragment);
}
static bool isFragmentDefault(FragmentInfo &F) {
return F == DefaultFragment;
}
bool operator==(const DebugVariable &Other) const {
return std::tie(Variable, Fragment, InlinedAt) ==
std::tie(Other.Variable, Other.Fragment, Other.InlinedAt);
}
bool operator<(const DebugVariable &Other) const {
return std::tie(Variable, Fragment, InlinedAt) <
std::tie(Other.Variable, Other.Fragment, Other.InlinedAt);
}
};
friend struct llvm::DenseMapInfo<DebugVariable>;
/// A pair of debug variable and value location.
struct VarLoc {
// The location at which a spilled variable resides. It consists of a
@ -241,8 +187,9 @@ private:
} Loc;
VarLoc(const MachineInstr &MI, LexicalScopes &LS)
: Var(MI), Expr(MI.getDebugExpression()), MI(MI),
UVS(MI.getDebugLoc(), LS) {
: Var(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt()),
Expr(MI.getDebugExpression()), MI(MI), UVS(MI.getDebugLoc(), LS) {
static_assert((sizeof(Loc) == sizeof(uint64_t)),
"hash does not cover all members of Loc");
assert(MI.isDebugValue() && "not a DBG_VALUE");
@ -370,7 +317,8 @@ private:
llvm_unreachable("Invalid VarLoc in dump method");
}
dbgs() << ", \"" << Var.getVar()->getName() << "\", " << *Expr << ", ";
dbgs() << ", \"" << Var.getVariable()->getName() << "\", " << *Expr
<< ", ";
if (Var.getInlinedAt())
dbgs() << "!" << Var.getInlinedAt()->getMetadataID() << ")\n";
else
@ -559,46 +507,10 @@ public:
} // end anonymous namespace
namespace llvm {
template <> struct DenseMapInfo<LiveDebugValues::DebugVariable> {
using DV = LiveDebugValues::DebugVariable;
using OptFragmentInfo = LiveDebugValues::OptFragmentInfo;
using FragmentInfo = LiveDebugValues::FragmentInfo;
// Empty key: no key should be generated that has no DILocalVariable.
static inline DV getEmptyKey() {
return DV(nullptr, OptFragmentInfo(), nullptr);
}
// Difference in tombstone is that the Optional is meaningful
static inline DV getTombstoneKey() {
return DV(nullptr, OptFragmentInfo({0, 0}), nullptr);
}
static unsigned getHashValue(const DV &D) {
unsigned HV = 0;
const OptFragmentInfo &Fragment = D.getFragment();
if (Fragment)
HV = DenseMapInfo<FragmentInfo>::getHashValue(*Fragment);
return hash_combine(D.getVar(), HV, D.getInlinedAt());
}
static bool isEqual(const DV &A, const DV &B) { return A == B; }
};
} // namespace llvm
//===----------------------------------------------------------------------===//
// Implementation
//===----------------------------------------------------------------------===//
const DIExpression::FragmentInfo
LiveDebugValues::DebugVariable::DefaultFragment = {
std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint64_t>::min()};
char LiveDebugValues::ID = 0;
char &llvm::LiveDebugValuesID = LiveDebugValues::ID;
@ -636,17 +548,17 @@ void LiveDebugValues::OpenRangesSet::erase(DebugVariable Var) {
// Extract the fragment. Interpret an empty fragment as one that covers all
// possible bits.
FragmentInfo ThisFragment = Var.getFragmentDefault();
FragmentInfo ThisFragment = Var.getFragmentOrDefault();
// There may be fragments that overlap the designated fragment. Look them up
// in the pre-computed overlap map, and erase them too.
auto MapIt = OverlappingFragments.find({Var.getVar(), ThisFragment});
auto MapIt = OverlappingFragments.find({Var.getVariable(), ThisFragment});
if (MapIt != OverlappingFragments.end()) {
for (auto Fragment : MapIt->second) {
LiveDebugValues::OptFragmentInfo FragmentHolder;
if (!DebugVariable::isFragmentDefault(Fragment))
if (!DebugVariable::isDefaultFragment(Fragment))
FragmentHolder = LiveDebugValues::OptFragmentInfo(Fragment);
DoErase({Var.getVar(), FragmentHolder, Var.getInlinedAt()});
DoErase({Var.getVariable(), FragmentHolder, Var.getInlinedAt()});
}
}
}
@ -669,7 +581,7 @@ void LiveDebugValues::printVarLocInMBB(const MachineFunction &MF,
Out << "MBB: " << BB.getNumber() << ":\n";
for (unsigned VLL : L) {
const VarLoc &VL = VarLocIDs[VLL];
Out << " Var: " << VL.Var.getVar()->getName();
Out << " Var: " << VL.Var.getVariable()->getName();
Out << " MI: ";
VL.dump(TRI, Out);
}
@ -735,7 +647,7 @@ void LiveDebugValues::emitEntryValues(MachineInstr &MI,
DebugParamMap &DebugEntryVals,
SparseBitVector<> &KillSet) {
for (unsigned ID : KillSet) {
if (!VarLocIDs[ID].Var.getVar()->isParameter())
if (!VarLocIDs[ID].Var.getVariable()->isParameter())
continue;
const MachineInstr *CurrDebugInstr = &VarLocIDs[ID].MI;
@ -773,7 +685,9 @@ void LiveDebugValues::insertTransferDebugPair(
unsigned LocId = VarLocIDs.insert(VL);
// Close this variable's previous location range.
DebugVariable V(*DebugInstr);
DebugVariable V(DebugInstr->getDebugVariable(),
DebugInstr->getDebugExpression(),
DebugInstr->getDebugLoc()->getInlinedAt());
OpenRanges.erase(V);
// Record the new location as an open range, and a postponed transfer
@ -1005,12 +919,12 @@ void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI,
if (TKind == TransferKind::TransferSpill &&
VarLocIDs[ID].isDescribedByReg() == Reg) {
LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '('
<< VarLocIDs[ID].Var.getVar()->getName() << ")\n");
<< VarLocIDs[ID].Var.getVariable()->getName() << ")\n");
} else if (TKind == TransferKind::TransferRestore &&
VarLocIDs[ID].Kind == VarLoc::SpillLocKind &&
VarLocIDs[ID].Loc.SpillLocation == *Loc) {
LLVM_DEBUG(dbgs() << "Restoring Register " << printReg(Reg, TRI) << '('
<< VarLocIDs[ID].Var.getVar()->getName() << ")\n");
<< VarLocIDs[ID].Var.getVariable()->getName() << ")\n");
} else
continue;
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID, TKind,
@ -1099,26 +1013,27 @@ bool LiveDebugValues::transferTerminator(MachineBasicBlock *CurMBB,
void LiveDebugValues::accumulateFragmentMap(MachineInstr &MI,
VarToFragments &SeenFragments,
OverlapMap &OverlappingFragments) {
DebugVariable MIVar(MI);
FragmentInfo ThisFragment = MIVar.getFragmentDefault();
DebugVariable MIVar(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt());
FragmentInfo ThisFragment = MIVar.getFragmentOrDefault();
// If this is the first sighting of this variable, then we are guaranteed
// there are currently no overlapping fragments either. Initialize the set
// of seen fragments, record no overlaps for the current one, and return.
auto SeenIt = SeenFragments.find(MIVar.getVar());
auto SeenIt = SeenFragments.find(MIVar.getVariable());
if (SeenIt == SeenFragments.end()) {
SmallSet<FragmentInfo, 4> OneFragment;
OneFragment.insert(ThisFragment);
SeenFragments.insert({MIVar.getVar(), OneFragment});
SeenFragments.insert({MIVar.getVariable(), OneFragment});
OverlappingFragments.insert({{MIVar.getVar(), ThisFragment}, {}});
OverlappingFragments.insert({{MIVar.getVariable(), ThisFragment}, {}});
return;
}
// If this particular Variable/Fragment pair already exists in the overlap
// map, it has already been accounted for.
auto IsInOLapMap =
OverlappingFragments.insert({{MIVar.getVar(), ThisFragment}, {}});
OverlappingFragments.insert({{MIVar.getVariable(), ThisFragment}, {}});
if (!IsInOLapMap.second)
return;
@ -1136,7 +1051,7 @@ void LiveDebugValues::accumulateFragmentMap(MachineInstr &MI,
// Mark the previously seen fragment as being overlapped by the current
// one.
auto ASeenFragmentsOverlaps =
OverlappingFragments.find({MIVar.getVar(), ASeenFragment});
OverlappingFragments.find({MIVar.getVariable(), ASeenFragment});
assert(ASeenFragmentsOverlaps != OverlappingFragments.end() &&
"Previously seen var fragment has no vector of overlaps");
ASeenFragmentsOverlaps->second.push_back(ThisFragment);
@ -1201,7 +1116,7 @@ bool LiveDebugValues::join(
if (!InLocsT.empty()) {
for (auto ID : InLocsT)
dbgs() << " gathered candidate incoming var: "
<< VarLocIDs[ID].Var.getVar()->getName() << "\n";
<< VarLocIDs[ID].Var.getVariable()->getName() << "\n";
}
});
@ -1216,7 +1131,7 @@ bool LiveDebugValues::join(
if (!VarLocIDs[ID].dominates(MBB)) {
KillSet.set(ID);
LLVM_DEBUG({
auto Name = VarLocIDs[ID].Var.getVar()->getName();
auto Name = VarLocIDs[ID].Var.getVariable()->getName();
dbgs() << " killing " << Name << ", it doesn't dominate MBB\n";
});
}

View File

@ -23,6 +23,9 @@
using namespace llvm;
const DIExpression::FragmentInfo DebugVariable::DefaultFragment = {
std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::min()};
DILocation::DILocation(LLVMContext &C, StorageType Storage, unsigned Line,
unsigned Column, ArrayRef<Metadata *> MDs,
bool ImplicitCode)

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/Metadata.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfo.h"
@ -2897,4 +2898,41 @@ TEST_F(DistinctMDOperandPlaceholderTest, TrackingMDRefAndDistinctMDNode) {
}
#endif
typedef MetadataTest DebugVariableTest;
TEST_F(DebugVariableTest, DenseMap) {
DenseMap<DebugVariable, uint64_t> DebugVariableMap;
DILocalScope *Scope = getSubprogram();
DIFile *File = getFile();
DIType *Type = getDerivedType();
DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7);
DILocation *InlinedLoc = DILocation::get(Context, 2, 7, Scope);
DILocalVariable *VarA =
DILocalVariable::get(Context, Scope, "A", File, 5, Type, 2, Flags, 8);
DILocalVariable *VarB =
DILocalVariable::get(Context, Scope, "B", File, 7, Type, 3, Flags, 8);
DebugVariable DebugVariableA(VarA, NoneType(), nullptr);
DebugVariable DebugVariableInlineA(VarA, NoneType(), InlinedLoc);
DebugVariable DebugVariableB(VarB, NoneType(), nullptr);
DebugVariable DebugVariableFragB(VarB, {{16, 16}}, nullptr);
DebugVariableMap.insert({DebugVariableA, 2});
DebugVariableMap.insert({DebugVariableInlineA, 3});
DebugVariableMap.insert({DebugVariableB, 6});
DebugVariableMap.insert({DebugVariableFragB, 12});
EXPECT_EQ(DebugVariableMap.count(DebugVariableA), 1);
EXPECT_EQ(DebugVariableMap.count(DebugVariableInlineA), 1);
EXPECT_EQ(DebugVariableMap.count(DebugVariableB), 1);
EXPECT_EQ(DebugVariableMap.count(DebugVariableFragB), 1);
EXPECT_EQ(DebugVariableMap.find(DebugVariableA)->second, 2);
EXPECT_EQ(DebugVariableMap.find(DebugVariableInlineA)->second, 3);
EXPECT_EQ(DebugVariableMap.find(DebugVariableB)->second, 6);
EXPECT_EQ(DebugVariableMap.find(DebugVariableFragB)->second, 12);
}
} // end namespace