Skip to content

[LLVM][DWARF] Add support for monolithic types in .debug_names #70515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 59 additions & 10 deletions llvm/include/llvm/CodeGen/AccelTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/DIE.h"
Expand Down Expand Up @@ -104,8 +103,9 @@
namespace llvm {

class AsmPrinter;
class DwarfCompileUnit;
class DwarfUnit;
class DwarfDebug;
class DwarfTypeUnit;
class MCSymbol;
class raw_ostream;

Expand Down Expand Up @@ -197,6 +197,9 @@ template <typename DataT> class AccelTable : public AccelTableBase {

template <typename... Types>
void addName(DwarfStringPoolEntryRef Name, Types &&... Args);
void clear() { Entries.clear(); }
void addEntries(AccelTable<DataT> &Table);
const StringEntries getEntries() const { return Entries; }
};

template <typename AccelTableDataT>
Expand Down Expand Up @@ -250,11 +253,18 @@ class AppleAccelTableData : public AccelTableData {
/// emitDWARF5AccelTable function.
class DWARF5AccelTableData : public AccelTableData {
public:
struct AttributeEncoding {
dwarf::Index Index;
dwarf::Form Form;
};

static uint32_t hash(StringRef Name) { return caseFoldingDjbHash(Name); }

DWARF5AccelTableData(const DIE &Die, const DwarfCompileUnit &CU);
DWARF5AccelTableData(uint64_t DieOffset, unsigned DieTag, unsigned CUIndex)
: OffsetVal(DieOffset), DieTag(DieTag), UnitID(CUIndex) {}
DWARF5AccelTableData(const DIE &Die, const uint32_t UnitID,
const bool IsTU = false);
DWARF5AccelTableData(const uint64_t DieOffset, const unsigned DieTag,
const unsigned UnitID, const bool IsTU = false)
: OffsetVal(DieOffset), DieTag(DieTag), UnitID(UnitID), IsTU(IsTU) {}

#ifndef NDEBUG
void print(raw_ostream &OS) const override;
Expand All @@ -267,28 +277,66 @@ class DWARF5AccelTableData : public AccelTableData {
}
unsigned getDieTag() const { return DieTag; }
unsigned getUnitID() const { return UnitID; }
bool isTU() const { return IsTU; }
void normalizeDIEToOffset() {
assert(std::holds_alternative<const DIE *>(OffsetVal) &&
"Accessing offset after normalizing.");
OffsetVal = std::get<const DIE *>(OffsetVal)->getOffset();
}
bool isNormalized() const {
return std::holds_alternative<uint64_t>(OffsetVal);
}

protected:
std::variant<const DIE *, uint64_t> OffsetVal;
unsigned DieTag;
unsigned UnitID;
uint32_t DieTag : 16;
uint32_t UnitID : 15;
uint32_t IsTU : 1;

uint64_t order() const override { return getDieOffset(); }
};

struct TypeUnitMetaInfo {
// Symbol for start of the TU section.
MCSymbol *Label;
// Unique ID of Type Unit.
unsigned UniqueID;
};
using TUVectorTy = SmallVector<TypeUnitMetaInfo, 1>;
class DWARF5AccelTable : public AccelTable<DWARF5AccelTableData> {
// Symbols to start of all the TU sections that were generated.
TUVectorTy TUSymbols;

public:
struct UnitIndexAndEncoding {
unsigned Index;
DWARF5AccelTableData::AttributeEncoding Endoding;
};
/// Returns type units that were constructed.
const TUVectorTy &getTypeUnitsSymbols() { return TUSymbols; }
/// Add a type unit start symbol.
void addTypeUnitSymbol(DwarfTypeUnit &U);
/// Convert DIE entries to explicit offset.
/// Needs to be called after DIE offsets are computed.
void convertDieToOffset() {
for (auto &Entry : Entries) {
for (AccelTableData *Value : Entry.second.Values) {
static_cast<DWARF5AccelTableData *>(Value)->normalizeDIEToOffset();
DWARF5AccelTableData *Data = static_cast<DWARF5AccelTableData *>(Value);
// For TU we normalize as each Unit is emitted.
// So when this is invoked after CU construction we will be in mixed
// state.
if (!Data->isNormalized())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could check that it's only already normalized if it's a TU? (we shouldn't expect to see any prenormalized CU entries, yeah?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I follow. This function is invoked when we write out finished type units on AccelTypeUnitsDebugNames. Which only has not-normalized TUs. It is also invoked in ::finalizeModuleInfo. At which point it will have normalized TU entries and not-normalized CU entries.

Are you saying we should expose IsTU() and check that?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about "exposed" - I think it's already accessible from Data->IsTU() here? And yeah, something like assert(!Data->isNormalized || Data->isTU())

Copy link
Contributor Author

@ayermolo ayermolo Nov 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah IC.
So when we normalize in CU it will be in mix state. The TU DIEs will be normalized because we do it as we write them out. The CU DIEs will not be. Without the check it will runtime assert in:
(without explicit assert somewhere in the std::get).

void normalizeDIEToOffset() {
    assert(std::holds_alternative<const DIE *>(OffsetVal) &&
           "Accessing offset after normalizing.");
    OffsetVal = std::get<const DIE *>(OffsetVal)->getOffset();
  }

Data->normalizeDIEToOffset();
}
}
}

void addTypeEntries(DWARF5AccelTable &Table) {
for (auto &Entry : Table.getEntries()) {
for (AccelTableData *Value : Entry.second.Values) {
DWARF5AccelTableData *Data = static_cast<DWARF5AccelTableData *>(Value);
addName(Entry.second.Name, Data->getDieOffset(), Data->getDieTag(),
Data->getUnitID(), true);
}
}
}
Expand Down Expand Up @@ -319,8 +367,9 @@ void emitDWARF5AccelTable(AsmPrinter *Asm, DWARF5AccelTable &Contents,
void emitDWARF5AccelTable(
AsmPrinter *Asm, DWARF5AccelTable &Contents,
ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
llvm::function_ref<unsigned(const DWARF5AccelTableData &)>
getCUIndexForEntry);
llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
const DWARF5AccelTableData &)>
getIndexForEntry);

/// Accelerator table data implementation for simple Apple accelerator tables
/// with just a DIE reference.
Expand Down
Loading