mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-13 08:54:59 +00:00
[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:
parent
948b602c7f
commit
afaad946a7
@ -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
|
||||
|
@ -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";
|
||||
});
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user