diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -3253,6 +3253,92 @@ } }; +/// 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; + using OptFragmentInfo = Optional; + + 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) {} + + 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(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 { + using DV = DebugVariable; + using OptFragmentInfo = Optional; + using FragmentInfo = DIExpression::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::getHashValue(*Fragment); + + return hash_combine(D.getVar(), HV, D.getInlinedAt()); + } + + static bool isEqual(const DV &A, const DV &B) { return A == B; } +}; + } // end namespace llvm #undef DEFINE_MDNODE_GET_UNPACK_IMPL diff --git a/llvm/lib/CodeGen/LiveDebugValues.cpp b/llvm/lib/CodeGen/LiveDebugValues.cpp --- a/llvm/lib/CodeGen/LiveDebugValues.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues.cpp @@ -144,60 +144,6 @@ using FragmentInfo = DIExpression::FragmentInfo; using OptFragmentInfo = Optional; - /// 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; - /// 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 @@ } 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"); @@ -559,46 +506,10 @@ } // end anonymous namespace -namespace llvm { - -template <> struct DenseMapInfo { - 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::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::max(), - std::numeric_limits::min()}; - char LiveDebugValues::ID = 0; char &llvm::LiveDebugValuesID = LiveDebugValues::ID; @@ -773,7 +684,9 @@ 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 @@ -1099,7 +1012,8 @@ void LiveDebugValues::accumulateFragmentMap(MachineInstr &MI, VarToFragments &SeenFragments, OverlapMap &OverlappingFragments) { - DebugVariable MIVar(MI); + DebugVariable MIVar(MI.getDebugVariable(), MI.getDebugExpression(), + MI.getDebugLoc()->getInlinedAt()); FragmentInfo ThisFragment = MIVar.getFragmentDefault(); // If this is the first sighting of this variable, then we are guaranteed diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -23,6 +23,9 @@ using namespace llvm; +const DIExpression::FragmentInfo DebugVariable::DefaultFragment = { + std::numeric_limits::max(), std::numeric_limits::min()}; + DILocation::DILocation(LLVMContext &C, StorageType Storage, unsigned Line, unsigned Column, ArrayRef MDs, bool ImplicitCode)