diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -882,12 +882,11 @@ return VariableDie; } - if (const std::optional &EntryValueVar = - DV.getEntryValue()) { + if (const std::set *EntryValues = DV.getEntryValues()) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); // Emit each expression as: EntryValue(Register) . - for (auto [Register, Expr] : EntryValueVar->getEntryValuesInfo()) { + for (auto [Register, Expr] : *EntryValues) { DwarfExpr.addFragmentOffset(&Expr); DIExpressionCursor Cursor(Expr.getElements()); DwarfExpr.beginEntryValueExpression(Cursor); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -41,6 +41,7 @@ #include #include #include +#include #include namespace llvm { @@ -100,36 +101,59 @@ } }; -/// Helper class to model a DbgVariable whose location is derived from an -/// EntryValue. -/// TODO: split the current implementation of `DbgVariable` into a class per -/// variant of location that it can represent, and make `DbgVariableEntryValue` -/// a subclass. -class DbgVariableEntryValue { - struct EntryValueInfo { - MCRegister Reg; - const DIExpression &Expr; - - /// Operator enabling sorting based on fragment offset. - bool operator<(const EntryValueInfo &Other) const { - return getFragmentOffsetInBits() < Other.getFragmentOffsetInBits(); - } +/// Proxy for one MMI entry. +struct FrameIndexExpr { + int FI; + const DIExpression *Expr; +}; - private: - uint64_t getFragmentOffsetInBits() const { - std::optional Fragment = - Expr.getFragmentInfo(); - return Fragment ? Fragment->OffsetInBits : 0; - } - }; +/// Represents an entry-value location, or a fragment of one. +struct EntryValueInfo { + MCRegister Reg; + const DIExpression &Expr; - std::set EntryValues; + /// Operator enabling sorting based on fragment offset. + bool operator<(const EntryValueInfo &Other) const { + return getFragmentOffsetInBits() < Other.getFragmentOffsetInBits(); + } -public: - DbgVariableEntryValue(MCRegister Reg, const DIExpression &Expr) { +private: + uint64_t getFragmentOffsetInBits() const { + std::optional Fragment = Expr.getFragmentInfo(); + return Fragment ? Fragment->OffsetInBits : 0; + } +}; + +// Namespace for private alternatives of a DbgVariable. +namespace { +/// Single value location description. +struct SingleLoc { + std::unique_ptr ValueLoc; + const DIExpression *Expr; + SingleLoc(DbgValueLoc ValueLoc) + : ValueLoc(std::make_unique(ValueLoc)), + Expr(ValueLoc.getExpression()) { + if (!Expr->getNumElements()) + Expr = nullptr; + } +}; +/// Multi-value location description. +struct MultiLoc { + /// Index of the entry list in DebugLocs. + unsigned DebugLocListIndex = ~0u; + /// DW_OP_LLVM_tag_offset value from DebugLocs. + std::optional DebugLocListTagOffset; +}; +/// Single location defined by (potentially multiple) MMI entries. +struct MMILoc { + mutable SmallVector FrameIndexExprs; +}; +/// Single location defined by (potentially multiple) EntryValueInfo. +struct EntryValueLoc { + std::set EntryValues; + EntryValueLoc(MCRegister Reg, const DIExpression &Expr) { addExpr(Reg, Expr); }; - // Add the pair Reg, Expr to the list of entry values describing the variable. // If multiple expressions are added, it is the callers responsibility to // ensure they are all non-overlapping fragments. @@ -140,46 +164,48 @@ EntryValues.insert({Reg, **NonVariadicExpr}); } - - /// Returns the set of EntryValueInfo. - const std::set &getEntryValuesInfo() const { - return EntryValues; - } }; +} // namespace //===----------------------------------------------------------------------===// /// This class is used to track local variable information. /// +/// Variables that have been optimized out hold the \c monostate alternative. +/// This is not distinguished from the case of a constructed \c DbgVariable +/// which has not be initialized yet. +/// /// Variables can be created from allocas, in which case they're generated from -/// the MMI table. Such variables can have multiple expressions and frame -/// indices. +/// the MMI table. Such variables hold the \c MMILoc alternative which can have +/// multiple expressions and frame indices. /// /// Variables can be created from the entry value of registers, in which case -/// they're generated from the MMI table. Such variables can have either a -/// single expression or multiple *fragment* expressions. +/// they're generated from the MMI table. Such variables hold the \c +/// EntryValueLoc alternative which can either have a single expression or +/// multiple *fragment* expressions. /// -/// Variables can be created from \c DBG_VALUE instructions. Those whose -/// location changes over time use \a DebugLocListIndex, while those with a -/// single location use \a ValueLoc and (optionally) a single entry of \a Expr. -/// -/// Variables that have been optimized out use none of these fields. -class DbgVariable : public DbgEntity { - /// Index of the entry list in DebugLocs. - unsigned DebugLocListIndex = ~0u; - /// DW_OP_LLVM_tag_offset value from DebugLocs. - std::optional DebugLocListTagOffset; - - /// Single value location description. - std::unique_ptr ValueLoc = nullptr; - - struct FrameIndexExpr { - int FI; - const DIExpression *Expr; - }; - mutable SmallVector - FrameIndexExprs; /// Frame index + expression. - - std::optional EntryValue; +/// Variables can be created from \c DBG_VALUE instructions. Those whose +/// location changes over time hold a \c MultiLoc alternative which uses \c +/// DebugLocListIndex and (optionally) \c DebugLocListTagOffset, while those +/// with a single location hold a \c SingleLoc alternative which use \c ValueLoc +/// and (optionally) a single \c Expr. +class DbgVariable : public DbgEntity, + private std::variant { + + /// Member shorthand for std::holds_alternative + template bool holds() const { + return std::holds_alternative(*this); + } + /// Asserting, noexcept member alternative to std::get + template auto &get() noexcept { + assert(holds()); + return *std::get_if(this); + } + /// Asserting, noexcept member alternative to std::get + template const auto &get() const noexcept { + assert(holds()); + return *std::get_if(this); + } public: /// Construct a DbgVariable. @@ -189,41 +215,27 @@ DbgVariable(const DILocalVariable *V, const DILocation *IA) : DbgEntity(V, IA, DbgVariableKind) {} - bool isInitialized() const { - return !FrameIndexExprs.empty() || ValueLoc || EntryValue; - } - /// Initialize from the MMI table. - void initializeMMI(const DIExpression *E, int FI) { - assert(!isInitialized() && "Already initialized?"); - - assert((!E || E->isValid()) && "Expected valid expression"); - assert(FI != std::numeric_limits::max() && "Expected valid index"); - - FrameIndexExprs.push_back({FI, E}); - } + void initializeMMI(const DIExpression *E, int FI); // Initialize variable's location. - void initializeDbgValue(DbgValueLoc Value) { - assert(!isInitialized() && "Already initialized?"); - assert(!Value.getExpression()->isFragment() && "Fragments not supported."); + void initializeDbgValue(DbgValueLoc Value); - ValueLoc = std::make_unique(Value); - if (auto *E = ValueLoc->getExpression()) - if (E->getNumElements()) - FrameIndexExprs.push_back({0, E}); - } + void initializeEntryValue(MCRegister Reg, const DIExpression &Expr); - void initializeEntryValue(MCRegister Reg, const DIExpression &Expr) { - assert(!isInitialized() && "Already initialized?"); - EntryValue = DbgVariableEntryValue(Reg, Expr); + const std::set *getEntryValues() const { + if (const auto *EV = std::get_if(this)) + return &EV->EntryValues; + return nullptr; } - - const std::optional &getEntryValue() const { - return EntryValue; + std::set *getEntryValues() { + if (auto *EV = std::get_if(this)) + return &EV->EntryValues; + return nullptr; + } + void addEntryValueExpr(MCRegister Reg, const DIExpression &Expr) { + get().addExpr(Reg, Expr); } - - std::optional &getEntryValue() { return EntryValue; } /// Initialize from a DBG_VALUE instruction. void initializeDbgValue(const MachineInstr *DbgValue); @@ -234,21 +246,38 @@ } const DIExpression *getSingleExpression() const { - assert(ValueLoc.get() && FrameIndexExprs.size() <= 1); - return FrameIndexExprs.size() ? FrameIndexExprs[0].Expr : nullptr; + return get().Expr; } - void setDebugLocListIndex(unsigned O) { DebugLocListIndex = O; } - unsigned getDebugLocListIndex() const { return DebugLocListIndex; } - void setDebugLocListTagOffset(uint8_t O) { DebugLocListTagOffset = O; } + void setDebugLocListIndex(uint8_t O) { + if (auto *M = std::get_if(this)) + M->DebugLocListIndex = O; + else + emplace().DebugLocListIndex = O; + } + unsigned getDebugLocListIndex() const { + if (auto *M = std::get_if(this)) + return M->DebugLocListIndex; + return ~0U; + } + void setDebugLocListTagOffset(uint8_t O) { + if (auto *M = std::get_if(this)) + M->DebugLocListTagOffset = O; + else + emplace().DebugLocListTagOffset = O; + } std::optional getDebugLocListTagOffset() const { - return DebugLocListTagOffset; + return get().DebugLocListTagOffset; } StringRef getName() const { return getVariable()->getName(); } - const DbgValueLoc *getValueLoc() const { return ValueLoc.get(); } + const DbgValueLoc *getValueLoc() const { + if (auto *M = std::get_if(this)) + return M->ValueLoc.get(); + return nullptr; + } /// Get the FI entries, sorted by fragment offset. ArrayRef getFrameIndexExprs() const; - bool hasFrameIndexExprs() const { return !FrameIndexExprs.empty(); } + bool hasFrameIndexExprs() const { return holds(); } void addMMIEntry(const DbgVariable &V); // Translate tag to proper Dwarf tag. @@ -277,14 +306,7 @@ return false; } - bool hasComplexAddress() const { - assert(ValueLoc.get() && "Expected DBG_VALUE, not MMI variable"); - assert((FrameIndexExprs.empty() || - (FrameIndexExprs.size() == 1 && - FrameIndexExprs[0].Expr->getNumElements())) && - "Invalid Expr for DBG_VALUE"); - return !FrameIndexExprs.empty(); - } + bool hasComplexAddress() const { return get().Expr; } const DIType *getType() const; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -257,21 +257,37 @@ return DbgValueLoc(Expr, DbgValueLocEntries, IsVariadic); } -void DbgVariable::initializeDbgValue(const MachineInstr *DbgValue) { - assert(FrameIndexExprs.empty() && "Already initialized?"); - assert(!ValueLoc.get() && "Already initialized?"); +/// Initialize from the MMI table. +void DbgVariable::initializeMMI(const DIExpression *E, int FI) { + assert(holds() && "Already initialized"); + assert((!E || E->isValid()) && "Expected valid expression"); + assert(FI != std::numeric_limits::max() && "Expected valid index"); + emplace().FrameIndexExprs.push_back({FI, E}); +} + +void DbgVariable::initializeDbgValue(DbgValueLoc Value) { + assert(holds() && "Already initialized"); + assert(!Value.getExpression()->isFragment() && "Fragments not supported"); + emplace(Value); +} +void DbgVariable::initializeDbgValue(const MachineInstr *DbgValue) { + assert(holds() && "Already initialized"); assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && "Wrong inlined-at"); + emplace(getDebugLocValue(DbgValue)); +} - ValueLoc = std::make_unique(getDebugLocValue(DbgValue)); - if (auto *E = DbgValue->getDebugExpression()) - if (E->getNumElements()) - FrameIndexExprs.push_back({0, E}); +void DbgVariable::initializeEntryValue(MCRegister Reg, + const DIExpression &Expr) { + assert(holds() && "Already initialized?"); + emplace(Reg, Expr); } -ArrayRef DbgVariable::getFrameIndexExprs() const { +ArrayRef DbgVariable::getFrameIndexExprs() const { + auto &FrameIndexExprs = get().FrameIndexExprs; + if (FrameIndexExprs.size() == 1) return FrameIndexExprs; @@ -290,13 +306,11 @@ } void DbgVariable::addMMIEntry(const DbgVariable &V) { - assert(DebugLocListIndex == ~0U && !ValueLoc.get() && "not an MMI entry"); - assert(V.DebugLocListIndex == ~0U && !V.ValueLoc.get() && "not an MMI entry"); assert(V.getVariable() == getVariable() && "conflicting variable"); assert(V.getInlinedAt() == getInlinedAt() && "conflicting inlined-at location"); - assert(!FrameIndexExprs.empty() && "Expected an MMI entry"); - assert(!V.FrameIndexExprs.empty() && "Expected an MMI entry"); + auto &FrameIndexExprs = get().FrameIndexExprs; + auto &VFrameIndexExprs = V.get().FrameIndexExprs; // FIXME: This logic should not be necessary anymore, as we now have proper // deduplication. However, without it, we currently run into the assertion @@ -308,7 +322,7 @@ return; } - for (const auto &FIE : V.FrameIndexExprs) + for (const auto &FIE : VFrameIndexExprs) // Ignore duplicate entries. if (llvm::none_of(FrameIndexExprs, [&](const FrameIndexExpr &Other) { return FIE.FI == Other.FI && FIE.Expr == Other.Expr; @@ -1573,7 +1587,7 @@ if (DbgVar->hasFrameIndexExprs()) DbgVar->addMMIEntry(*RegVar); else - DbgVar->getEntryValue()->addExpr(VI.getEntryValueRegister(), *VI.Expr); + DbgVar->addEntryValueExpr(VI.getEntryValueRegister(), *VI.Expr); } else if (InfoHolder.addScopeVariable(Scope, RegVar.get())) { MFVars.insert({Var, RegVar.get()}); ConcreteEntities.push_back(std::move(RegVar));