Index: include/llvm/CodeGen/DIE.h =================================================================== --- include/llvm/CodeGen/DIE.h +++ include/llvm/CodeGen/DIE.h @@ -18,12 +18,14 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/CodeGen/DwarfStringPoolEntry.h" #include "llvm/Support/Dwarf.h" #include namespace llvm { class AsmPrinter; +class DIEData; class MCExpr; class MCSymbol; class raw_ostream; @@ -589,7 +591,7 @@ //===--------------------------------------------------------------------===// /// DIE - A structured debug information entry. Has an abbreviation which /// describes its organization. -class DIE : IntrusiveBackListNode, public DIEValueList { +class DIE : IntrusiveBackListNode { friend class IntrusiveBackList; /// Offset - Offset in debug info section. @@ -600,19 +602,69 @@ /// unsigned Size; + // A DIE can have two possible representations. The explicit representation + // stores the DIE's attributes and children as lists of DIEValues and DIEs + // respectively, while the data representation uses the DIEData class to store + // attributes and children directly in DWARF format as a string of bytes and + // relocations. Eventually all DIEs will use the data representation and the + // DIE and DIEValue classes will be removed. + + struct DIEExplicitRepr { + /// Children DIEs. + IntrusiveBackList Children; + + /// Attribute DIEValues. + DIEValueList Attrs; + }; + + struct DIEDataRepr { + /// The data underlying this DIE. + DIEData *Data = nullptr; + + /// The DINode from which this DIE was created. + const DINode *MD = nullptr; + }; + + /// Abbreviation number. Unused in data representation DIEs. unsigned AbbrevNumber = ~0u; - /// Tag - Dwarf tag code. + /// Tag - Dwarf tag code. Data representation DIEs have this set to (dwarf::Tag)-1 + /// and the tag code is available via DIEDataRepr::MD. /// dwarf::Tag Tag = (dwarf::Tag)0; - /// Children DIEs. - IntrusiveBackList Children; + AlignedCharArrayUnion Data; + +public: + bool isDIEData() const { + return Tag == (dwarf::Tag)-1; + } + +private: + DIEExplicitRepr &getDIEExplicitRepr() { + assert(!isDIEData()); + return *reinterpret_cast(Data.buffer); + } + const DIEExplicitRepr &getDIEExplicitRepr() const { + assert(!isDIEData()); + return *reinterpret_cast(Data.buffer); + } + + DIEDataRepr &getDIEDataRepr() { + assert(isDIEData()); + return *reinterpret_cast(Data.buffer); + } + const DIEDataRepr &getDIEDataRepr() const { + assert(isDIEData()); + return *reinterpret_cast(Data.buffer); + } DIE *Parent = nullptr; DIE() = delete; - explicit DIE(dwarf::Tag Tag) : Offset(0), Size(0), Tag(Tag) {} + explicit DIE(dwarf::Tag Tag) : Offset(0), Size(0), Tag(Tag) { + new (Data.buffer) DIEExplicitRepr; + } public: static DIE *get(BumpPtrAllocator &Alloc, dwarf::Tag Tag) { @@ -620,11 +672,34 @@ } // Accessors. - unsigned getAbbrevNumber() const { return AbbrevNumber; } - dwarf::Tag getTag() const { return Tag; } + unsigned getAbbrevNumber() const { + assert(!isDIEData()); + return AbbrevNumber; + } + dwarf::Tag getTag() const { + if (isDIEData()) + return dwarf::Tag(getDIEDataRepr().MD->getTag()); + return Tag; + } + DIEData *getDIEData() const { + return getDIEDataRepr().Data; + } + const DINode *getDINode() const { + return getDIEDataRepr().MD; + } + void setDIEData(DIEData *D, const DINode *MD) { + if (!isDIEData()) { + // Switch to the data representation. + getDIEExplicitRepr().~DIEExplicitRepr(); + new (Data.buffer) DIEDataRepr; + Tag = (dwarf::Tag)-1; + } + getDIEDataRepr().Data = D; + getDIEDataRepr().MD = MD; + } unsigned getOffset() const { return Offset; } unsigned getSize() const { return Size; } - bool hasChildren() const { return !Children.empty(); } + bool hasChildren() const { return !getDIEExplicitRepr().Children.empty(); } typedef IntrusiveBackList::iterator child_iterator; typedef IntrusiveBackList::const_iterator const_child_iterator; @@ -632,10 +707,12 @@ typedef iterator_range const_child_range; child_range children() { - return llvm::make_range(Children.begin(), Children.end()); + return llvm::make_range(getDIEExplicitRepr().Children.begin(), + getDIEExplicitRepr().Children.end()); } const_child_range children() const { - return llvm::make_range(Children.begin(), Children.end()); + return llvm::make_range(getDIEExplicitRepr().Children.begin(), + getDIEExplicitRepr().Children.end()); } DIE *getParent() const { return Parent; } @@ -647,7 +724,10 @@ DIEAbbrev generateAbbrev() const; /// Set the abbreviation number for this DIE. - void setAbbrevNumber(unsigned I) { AbbrevNumber = I; } + void setAbbrevNumber(unsigned I) { + assert(!isDIEData()); + AbbrevNumber = I; + } /// Climb up the parent chain to get the compile or type unit DIE this DIE /// belongs to. @@ -662,8 +742,38 @@ DIE &addChild(DIE *Child) { assert(!Child->getParent() && "Child should be orphaned"); Child->Parent = this; - Children.push_back(*Child); - return Children.back(); + getDIEExplicitRepr().Children.push_back(*Child); + return getDIEExplicitRepr().Children.back(); + } + + // Wrap DIEValueList member functions to provide representation checking. + + operator DIEValueList&() { + return getDIEExplicitRepr().Attrs; + } + + typedef DIEValueList::value_iterator value_iterator; + typedef DIEValueList::const_value_iterator const_value_iterator; + + value_iterator addValue(BumpPtrAllocator &Alloc, DIEValue V) { + return getDIEExplicitRepr().Attrs.addValue(Alloc, V); + } + template + value_iterator addValue(BumpPtrAllocator &Alloc, dwarf::Attribute Attribute, + dwarf::Form Form, T &&Value) { + return getDIEExplicitRepr().Attrs.addValue(Alloc, Attribute, Form, + std::forward(Value)); + } + + typedef DIEValueList::value_range value_range; + typedef DIEValueList::const_value_range const_value_range; + + value_range values() { + return getDIEExplicitRepr().Attrs.values(); + } + + const_value_range values() const { + return getDIEExplicitRepr().Attrs.values(); } /// Find a value in the DIE with the attribute given. Index: include/llvm/CodeGen/DIEData.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/DIEData.h @@ -0,0 +1,174 @@ +//===--- llvm/CodeGen/DIEData.h - DWARF Info Entries ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Data structures for DWARF info entries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_DIEDATA_H +#define LLVM_CODEGEN_DIEDATA_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/LEB128.h" +#include +#include +#include +#include + +namespace llvm { + +class DIEData; +class DIEWriter; +class MCExpr; +class MCStreamer; +class MCSymbol; + +struct DIESymbolReloc { + uint8_t Size : 4; + uint64_t Offset : 60; + MCSymbol *Val; +}; + +// A block of debug information entries (DIEs). Clients add new DIEs to a +// DIEData by creating a DIEWriter, adding attributes to it and calling the +// write() function. +class DIEData { + std::vector Bytes; + std::vector SymRelocs; + +public: + /// Prepare to emit this DIEData, and compute the offset of the end of + /// the DIEData given a start offset. + uint64_t prepareToEmit(uint64_t StartOffset); + + /// Emit the DIEData to the given MCStreamer. + void emit(MCStreamer &S); + + friend class DIEWriter; +}; + +class DWARFAbbrev { + std::vector Data; + StringMap AbbrevMap; + +public: + /// Get the bytes that need to be emitted to the DWARF abbreviation + /// section. + StringRef getAbbrevData() const { return {Data.data(), Data.size()}; } + + /// Get an abbreviation number for the given attribute specification, + /// creating one if necessary. + size_t getAbbrevNo(StringRef AttrSpec); +}; + +class DIEWriter { + DWARFAbbrev *Abbrevs; + DIEData *Data; + + SmallVector AttrSpec; + SmallVector Attrs; + SmallVector SymRelocs; + + void attrSpec(dwarf::Attribute Attr, dwarf::Form Form) { + uint8_t AttrSpecULEB128[20]; + unsigned AttrSize = encodeULEB128(Attr, AttrSpecULEB128); + unsigned FormSize = encodeULEB128(Form, AttrSpecULEB128 + AttrSize); + AttrSpec.append(AttrSpecULEB128, AttrSpecULEB128 + AttrSize + FormSize); + } + +public: + DIEWriter(DWARFAbbrev &Abbrevs, DIEData &Data, dwarf::Tag Tag, + bool HasChildren) + : Abbrevs(&Abbrevs), Data(&Data) { + uint8_t AttrSpecHeader[11]; + unsigned TagSize = encodeULEB128(Tag, AttrSpecHeader); + AttrSpecHeader[TagSize] = + HasChildren ? dwarf::DW_CHILDREN_yes : dwarf::DW_CHILDREN_no; + AttrSpec.append(AttrSpecHeader, AttrSpecHeader + TagSize + 1); + } + + /// Add an attribute of pure data. + void attr(dwarf::Attribute Attr, dwarf::Form Form, ArrayRef Data) { + attrSpec(Attr, Form); + Attrs.append(Data.begin(), Data.end()); + } + + /// Add a single-byte integer attribute. + void attr1(dwarf::Attribute Attr, dwarf::Form Form, uint8_t Data) { + return attr(Attr, Form, {(char *)&Data, 1}); + } + + /// Add a 2-byte integer attribute with the given endianness. + void attr2(dwarf::Attribute Attr, dwarf::Form Form, uint16_t Data, bool BE) { + char Buf[2]; + if (BE) + support::endian::write16be(Buf, Data); + else + support::endian::write16le(Buf, Data); + attr(Attr, Form, {Buf, 2}); + } + + /// Add a 4-byte integer attribute with the given endianness. + void attr4(dwarf::Attribute Attr, dwarf::Form Form, uint32_t Data, bool BE) { + char Buf[4]; + if (BE) + support::endian::write32be(Buf, Data); + else + support::endian::write32le(Buf, Data); + attr(Attr, Form, {Buf, 4}); + } + + /// Add an 8-byte integer attribute with the given endianness. + void attr8(dwarf::Attribute Attr, dwarf::Form Form, uint64_t Data, bool BE) { + char Buf[8]; + if (BE) + support::endian::write64be(Buf, Data); + else + support::endian::write64le(Buf, Data); + attr(Attr, Form, {Buf, 8}); + } + + /// Add an integer attribute using ULEB128 encoding. + void uleb128(dwarf::Attribute Attr, dwarf::Form Form, uint64_t Data) { + uint8_t DataULEB128[10]; + unsigned Size = encodeULEB128(Data, DataULEB128); + attr(Attr, Form, {(char *)DataULEB128, Size}); + } + + /// Add an integer attribute using the most compact DW_FORM_data* form + /// possible. + void data(dwarf::Attribute Attr, uint64_t Data, bool BE) { + if (Data < (1ull << 8)) + attr1(Attr, dwarf::DW_FORM_data1, Data); + else if (Data < (1ull << 16)) + attr2(Attr, dwarf::DW_FORM_data2, Data, BE); + else if (Data < (1ull << 32)) + attr4(Attr, dwarf::DW_FORM_data4, Data, BE); + else + attr8(Attr, dwarf::DW_FORM_data8, Data, BE); + } + + /// Add an attribute that uses a symbol relocation. + void relocSym(dwarf::Attribute Attr, dwarf::Form Form, uint8_t Size, + MCSymbol *S) { + SymRelocs.push_back({Size, Attrs.size(), S}); + Attrs.append(Size, 0); + attrSpec(Attr, Form); + } + + /// Write the attribute to the DIEData passed at construction time. + void write(); +}; + +} + +#endif Index: include/llvm/Support/Allocator.h =================================================================== --- include/llvm/Support/Allocator.h +++ include/llvm/Support/Allocator.h @@ -406,6 +406,14 @@ /// \brief Allocate space for an array of objects without constructing them. T *Allocate(size_t num = 1) { return Allocator.Allocate(num); } + + /// Construct an object with the specified constructor arguments. + template + T *Construct(Args &&...args) { + T *Obj = Allocate(); + new (Obj) T(std::forward(args)...); + return Obj; + } }; } // end namespace llvm Index: lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -247,6 +247,11 @@ } void AsmPrinter::emitDwarfDIE(const DIE &Die) const { + if (Die.isDIEData()) { + Die.getDIEData()->emit(*OutStreamer); + return; + } + // Emit the code (index) for the abbreviation. if (isVerbose()) OutStreamer->AddComment("Abbrev [" + Twine(Die.getAbbrevNumber()) + "] 0x" + Index: lib/CodeGen/AsmPrinter/CMakeLists.txt =================================================================== --- lib/CodeGen/AsmPrinter/CMakeLists.txt +++ lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -8,6 +8,7 @@ DebugHandlerBase.cpp DebugLocStream.cpp DIE.cpp + DIEData.cpp DIEHash.cpp DwarfAccelTable.cpp DwarfCFIException.cpp Index: lib/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIE.cpp +++ lib/CodeGen/AsmPrinter/DIE.cpp @@ -109,7 +109,7 @@ void DIEAbbrev::dump() { print(dbgs()); } DIEAbbrev DIE::generateAbbrev() const { - DIEAbbrev Abbrev(Tag, hasChildren()); + DIEAbbrev Abbrev(getTag(), hasChildren()); for (const DIEValue &V : values()) Abbrev.AddAttribute(V.getAttribute(), V.getForm()); return Abbrev; Index: lib/CodeGen/AsmPrinter/DIEData.cpp =================================================================== --- /dev/null +++ lib/CodeGen/AsmPrinter/DIEData.cpp @@ -0,0 +1,77 @@ +//===--- lib/CodeGen/DIEData.cpp - DWARF Info Entries ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Data structures for DWARF info entries. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/DIEData.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +uint64_t DIEData::prepareToEmit(uint64_t StartOffset) { + // For now, just add the size of the Bytes array. + return StartOffset + Bytes.size(); +} + +void DIEData::emit(MCStreamer &S) { + size_t DataOffset = 0; + + for (auto &R : SymRelocs) { + // Emit bytes until the next symbol relocation, then emit the symbol + // reference. + S.EmitBytes(StringRef(Bytes.data() + DataOffset, + R.Offset - DataOffset)); + S.EmitSymbolValue(R.Val, R.Size); + DataOffset = R.Offset + R.Size; + } + + // Emit any remaining bytes. + S.EmitBytes(StringRef(Bytes.data() + DataOffset, Bytes.size() - DataOffset)); +} + +size_t DWARFAbbrev::getAbbrevNo(StringRef AttrSpec) { + // FIXME: in order that DIE abbreviations from DWARFAbbrev and from DwarfFile + // may coexist, DWARFAbbrev is made to produce even abbreviation numbers while + // DwarfFile produces odd numbers. Once DIE/DIEValue are removed, we can + // remove this hack. See DwarfFile::assignAbbrevNumber for the corresponding + // code in DwarfFile. + size_t AbbrevNo = AbbrevMap.size() * 2 + 2; + auto Ins = AbbrevMap.insert(std::make_pair(AttrSpec, AbbrevNo)); + if (Ins.second) { + uint8_t AbbrevNoULEB128[10]; + unsigned AbbrevNoSize = encodeULEB128(AbbrevNo, AbbrevNoULEB128); + + size_t Pos = Data.size(); + // Abbreviation number + abbreviation spec + 2 bytes for null terminator. + Data.insert(Data.end(), AbbrevNoSize + AttrSpec.size() + 2, 0); + memcpy(Data.data() + Pos, AbbrevNoULEB128, AbbrevNoSize); + memcpy(Data.data() + Pos + AbbrevNoSize, AttrSpec.data(), AttrSpec.size()); + } else { + AbbrevNo = Ins.first->second; + } + return AbbrevNo; +} + +void DIEWriter::write() { + size_t AbbrevNo = + Abbrevs->getAbbrevNo(StringRef(AttrSpec.data(), AttrSpec.size())); + + uint8_t AbbrevNoULEB128[10]; + unsigned AbbrevNoSize = encodeULEB128(AbbrevNo, AbbrevNoULEB128); + + size_t Pos = Data->Bytes.size(); + Data->Bytes.insert(Data->Bytes.end(), AbbrevNoSize + Attrs.size(), 0); + memcpy(Data->Bytes.data() + Pos, AbbrevNoULEB128, AbbrevNoSize); + memcpy(Data->Bytes.data() + Pos + AbbrevNoSize, Attrs.data(), Attrs.size()); + + for (auto R : SymRelocs) + Data->SymRelocs.push_back({R.Size, Pos + AbbrevNoSize + R.Offset, R.Val}); +} Index: lib/CodeGen/AsmPrinter/DIEHash.h =================================================================== --- lib/CodeGen/AsmPrinter/DIEHash.h +++ lib/CodeGen/AsmPrinter/DIEHash.h @@ -98,6 +98,15 @@ /// \brief Adds the attributes of \param Die to the hash. void addAttributes(const DIE &Die); + /// Add the given string attribute to the hash. + void addStringAttr(dwarf::Attribute Attr, StringRef Str); + + /// Add the given integer attribute to the hash. + void addIntAttr(dwarf::Attribute Attr, int64_t Value); + + /// Computes the full DWARF4 7.27 hash of the DIE from metadata. + void computeHashFromMetadata(const MDNode *MD); + /// \brief Computes the full DWARF4 7.27 hash of the DIE. void computeHash(const DIE &Die); Index: lib/CodeGen/AsmPrinter/DIEHash.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIEHash.cpp +++ lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Endian.h" @@ -237,7 +238,11 @@ // ptr_to_member_type, but it's what DWARF says, for some reason. Attribute == dwarf::DW_AT_type) { // ... has a DW_AT_name attribute, - StringRef Name = getDIEStringAttr(Entry, dwarf::DW_AT_name); + StringRef Name; + if (Entry.isDIEData()) + Name = cast(Entry.getDINode())->getName(); + else + Name = getDIEStringAttr(Entry, dwarf::DW_AT_name); if (!Name.empty()) { hashShallowTypeReference(Attribute, Entry, Name); return; @@ -300,8 +305,6 @@ hashDIEEntry(Attribute, Tag, Value.getDIEEntry().getEntry()); break; case DIEValue::isInteger: { - addULEB128('A'); - addULEB128(Attribute); switch (Value.getForm()) { case dwarf::DW_FORM_data1: case dwarf::DW_FORM_data2: @@ -309,13 +312,14 @@ case dwarf::DW_FORM_data8: case dwarf::DW_FORM_udata: case dwarf::DW_FORM_sdata: - addULEB128(dwarf::DW_FORM_sdata); - addSLEB128((int64_t)Value.getDIEInteger().getValue()); + addIntAttr(Attribute, (int64_t)Value.getDIEInteger().getValue()); break; // DW_FORM_flag_present is just flag with a value of one. We still give it a // value so just use the value. case dwarf::DW_FORM_flag_present: case dwarf::DW_FORM_flag: + addULEB128('A'); + addULEB128(Attribute); addULEB128(dwarf::DW_FORM_flag); addULEB128((int64_t)Value.getDIEInteger().getValue()); break; @@ -325,10 +329,7 @@ break; } case DIEValue::isString: - addULEB128('A'); - addULEB128(Attribute); - addULEB128(dwarf::DW_FORM_string); - addString(Value.getDIEString().getString()); + addStringAttr(Attribute, Value.getDIEString().getString()); break; case DIEValue::isBlock: case DIEValue::isLoc: @@ -438,10 +439,46 @@ addString(Name); } +void DIEHash::addStringAttr(dwarf::Attribute Attr, StringRef Str) { + addULEB128('A'); + addULEB128(Attr); + addULEB128(dwarf::DW_FORM_string); + addString(Str); +} + +void DIEHash::addIntAttr(dwarf::Attribute Attr, int64_t Value) { + addULEB128('A'); + addULEB128(Attr); + addULEB128(dwarf::DW_FORM_sdata); + addSLEB128(Value); +} + +void DIEHash::computeHashFromMetadata(const MDNode *MD) { + auto Ty = cast(MD); + + addULEB128('D'); + addULEB128(Ty->getTag()); + + if (!Ty->getName().empty()) + addStringAttr(dwarf::DW_AT_name, Ty->getName()); + + if (Ty->getTag() != dwarf::DW_TAG_unspecified_type) { + addIntAttr(dwarf::DW_AT_byte_size, Ty->getSizeInBits() >> 3); + addIntAttr(dwarf::DW_AT_encoding, Ty->getEncoding()); + } + + Hash.update(makeArrayRef((uint8_t)'\0')); +} + // Compute the hash of a DIE. This is based on the type signature computation // given in section 7.27 of the DWARF4 standard. It is the md5 hash of a // flattened description of the DIE. void DIEHash::computeHash(const DIE &Die) { + if (Die.isDIEData()) { + computeHashFromMetadata(Die.getDINode()); + return; + } + // Append the letter 'D', followed by the DWARF tag of the DIE. addULEB128('D'); addULEB128(Die.getTag()); @@ -452,10 +489,17 @@ // Then hash each of the children of the DIE. for (auto &C : Die.children()) { // 7.27 Step 7 - // If C is a nested type entry or a member function entry, ... - if (isType(C.getTag()) || C.getTag() == dwarf::DW_TAG_subprogram) { + // If C is a nested type entry or a member function entry, and has a + // DW_AT_name attribute + if (C.isDIEData()) { + auto Ty = cast(C.getDINode()); + StringRef Name = Ty->getName(); + if (!Name.empty()) { + hashNestedType(C, Name); + continue; + } + } else if (isType(C.getTag()) || C.getTag() == dwarf::DW_TAG_subprogram) { StringRef Name = getDIEStringAttr(C, dwarf::DW_AT_name); - // ... and has a DW_AT_name attribute if (!Name.empty()) { hashNestedType(C, Name); continue; Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1262,12 +1262,15 @@ // We could have a specification DIE that has our most of our knowledge, // look for that now. - if (DIEValue SpecVal = Die->findAttribute(dwarf::DW_AT_specification)) { - DIE &SpecDIE = SpecVal.getDIEEntry().getEntry(); - if (SpecDIE.findAttribute(dwarf::DW_AT_external)) + // FIXME: do something appropriate for data representation here. + if (!Die->isDIEData()) { + if (DIEValue SpecVal = Die->findAttribute(dwarf::DW_AT_specification)) { + DIE &SpecDIE = SpecVal.getDIEEntry().getEntry(); + if (SpecDIE.findAttribute(dwarf::DW_AT_external)) + Linkage = dwarf::GIEL_EXTERNAL; + } else if (Die->findAttribute(dwarf::DW_AT_external)) Linkage = dwarf::GIEL_EXTERNAL; - } else if (Die->findAttribute(dwarf::DW_AT_external)) - Linkage = dwarf::GIEL_EXTERNAL; + } switch (Die->getTag()) { case dwarf::DW_TAG_class_type: Index: lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.h +++ lib/CodeGen/AsmPrinter/DwarfFile.h @@ -16,6 +16,7 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/CodeGen/DIEData.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/Allocator.h" #include @@ -24,6 +25,7 @@ namespace llvm { class AsmPrinter; +class DWARFAbbrev; class DbgVariable; class DwarfCompileUnit; class DwarfUnit; @@ -41,10 +43,10 @@ BumpPtrAllocator AbbrevAllocator; - // Used to uniquely define abbreviations. + // Used to uniquely define abbreviations (DIE/DIEValue). FoldingSet AbbreviationsSet; - // A list of all the unique abbreviations in use. + // A list of all the unique abbreviations in use (DIE/DIEValue). std::vector Abbreviations; // A pointer to all units in the section. @@ -68,6 +70,9 @@ ~DwarfFile(); + // Abbreviations data structure (DIEData). + DWARFAbbrev Abbrevs; + const SmallVectorImpl> &getUnits() { return CUs; } Index: lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -43,8 +43,13 @@ // Move the abbreviation to the heap and assign a number. DIEAbbrev *New = new (AbbrevAllocator) DIEAbbrev(std::move(Abbrev)); Abbreviations.push_back(New); - New->setNumber(Abbreviations.size()); - Die.setAbbrevNumber(Abbreviations.size()); + // FIXME: in order that DIE abbreviations from DWARFAbbrev and from DwarfFile + // may coexist, DWARFAbbrev is made to produce even abbreviation numbers while + // DwarfFile produces odd numbers. Once DIE/DIEValue are removed, we can + // remove this hack. See DWARFAbbrev::getAbbrevNo for the corresponding code + // in DWARFAbbrev. + New->setNumber(Abbreviations.size() * 2 - 1); + Die.setAbbrevNumber(Abbreviations.size() * 2 - 1); // Store it for lookup. AbbreviationsSet.InsertNode(New, InsertPos); @@ -98,12 +103,15 @@ // Compute the size and offset of a DIE. The offset is relative to start of the // CU. It returns the offset after laying out the DIE. unsigned DwarfFile::computeSizeAndOffset(DIE &Die, unsigned Offset) { - // Record the abbreviation. - const DIEAbbrev &Abbrev = assignAbbrevNumber(Die); - // Set DIE offset Die.setOffset(Offset); + if (Die.isDIEData()) + return Die.getDIEData()->prepareToEmit(Offset); + + // Record the abbreviation. + const DIEAbbrev &Abbrev = assignAbbrevNumber(Die); + // Start the size with the size of abbreviation code. Offset += getULEB128Size(Die.getAbbrevNumber()); @@ -130,9 +138,10 @@ void DwarfFile::emitAbbrevs(MCSection *Section) { // Check to see if it is worth the effort. - if (!Abbreviations.empty()) { + if (!Abbreviations.empty() || !Abbrevs.getAbbrevData().empty()) { // Start the debug abbrev section. Asm->OutStreamer->SwitchSection(Section); + Asm->OutStreamer->EmitBytes(Abbrevs.getAbbrevData()); Asm->emitDwarfAbbrevs(Abbreviations); } } Index: lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.h +++ lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -20,6 +20,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" +#include "llvm/CodeGen/DIEData.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfo.h" #include "llvm/MC/MCDwarf.h" @@ -73,6 +74,9 @@ // All DIEValues are allocated through this allocator. BumpPtrAllocator DIEValueAllocator; + // All DIEDatas are allocated through this allocator. + SpecificBumpPtrAllocator DIEDataAlloc; + /// Unit debug information entry. DIE &UnitDie; @@ -276,6 +280,9 @@ void addType(DIE &Entity, const DIType *Ty, dwarf::Attribute Attribute = dwarf::DW_AT_type); + /// Add a string to the specified DIEWriter. + void string(DIEWriter &W, dwarf::Attribute Attr, StringRef Str); + DIE *getOrCreateNameSpace(const DINamespace *NS); DIE *getOrCreateModule(const DIModule *M); DIE *getOrCreateSubprogramDIE(const DISubprogram *SP, bool Minimal = false); @@ -331,8 +338,10 @@ return DD->resolve(Ref); } + bool isBigEndian() const { return Asm->getDataLayout().isBigEndian(); } + private: - void constructTypeDIE(DIE &Buffer, const DIBasicType *BTy); + void constructBasicType(DIEData &D, const DIBasicType *BTy); void constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy); void constructTypeDIE(DIE &Buffer, const DISubroutineType *DTy); void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy); Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -682,6 +682,17 @@ } } +void DwarfUnit::string(DIEWriter &W, dwarf::Attribute Attr, StringRef Str) { + DwarfStringPool::EntryRef Entry = DU->getStringPool().getEntry(*Asm, Str); + if (isDwoUnit()) { + W.uleb128(Attr, dwarf::DW_FORM_GNU_str_index, Entry.getIndex()); + } else if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) { + W.relocSym(Attr, dwarf::DW_FORM_strp, 4, Entry.getSymbol()); + } else { + W.attr4(Attr, dwarf::DW_FORM_strp, Entry.getOffset(), isBigEndian()); + } +} + DIE *DwarfUnit::getOrCreateContextDIE(const DIScope *Context) { if (!Context || isa(Context)) return &getUnitDie(); @@ -739,9 +750,11 @@ updateAcceleratorTables(Context, Ty, TyDIE); - if (auto *BT = dyn_cast(Ty)) - constructTypeDIE(TyDIE, BT); - else if (auto *STy = dyn_cast(Ty)) + if (auto *BT = dyn_cast(Ty)) { + DIEData *Data = DIEDataAlloc.Construct(); + constructBasicType(*Data, BT); + TyDIE.setDIEData(Data, BT); + } else if (auto *STy = dyn_cast(Ty)) constructTypeDIE(TyDIE, STy); else if (auto *CTy = dyn_cast(Ty)) { if (GenerateDwarfTypeUnits && !Ty->isForwardDecl()) @@ -816,22 +829,24 @@ return CS; } -void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) { +void DwarfUnit::constructBasicType(DIEData &D, const DIBasicType *BTy) { + DIEWriter W(DU->Abbrevs, D, dwarf::Tag(BTy->getTag()), false); + // Get core information. StringRef Name = BTy->getName(); // Add name if not anonymous or intermediate type. if (!Name.empty()) - addString(Buffer, dwarf::DW_AT_name, Name); + string(W, dwarf::DW_AT_name, Name); // An unspecified type only has a name attribute. if (BTy->getTag() == dwarf::DW_TAG_unspecified_type) - return; + return W.write(); - addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, - BTy->getEncoding()); + W.attr1(dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, BTy->getEncoding()); uint64_t Size = BTy->getSizeInBits() >> 3; - addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size); + W.data(dwarf::DW_AT_byte_size, Size, isBigEndian()); + W.write(); } void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) { Index: test/DebugInfo/X86/enum-class.ll =================================================================== --- test/DebugInfo/X86/enum-class.ll +++ test/DebugInfo/X86/enum-class.ll @@ -39,7 +39,7 @@ ; CHECK: DW_AT_enum_class [DW_FORM_flag_present] (true) ; CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[{{.*}}] = "B") -; CHECK: DW_TAG_enumeration_type [6] +; CHECK: DW_TAG_enumeration_type [{{.*}}] ; CHECK-NOT: DW_AT_enum_class ; CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[{{.*}}] = "C") !23 = !{i32 1, !"Debug Info Version", i32 3} Index: test/DebugInfo/X86/fission-cu.ll =================================================================== --- test/DebugInfo/X86/fission-cu.ll +++ test/DebugInfo/X86/fission-cu.ll @@ -32,7 +32,12 @@ ; Check that we're using the right forms. ; CHECK: .debug_abbrev.dwo contents: ; CHECK: Abbrev table for offset: 0x00000000 -; CHECK: [1] DW_TAG_compile_unit DW_CHILDREN_yes +; CHECK: [{{.*}}] DW_TAG_base_type DW_CHILDREN_no +; CHECK: DW_AT_name DW_FORM_GNU_str_index +; CHECK: DW_AT_encoding DW_FORM_data1 +; CHECK: DW_AT_byte_size DW_FORM_data1 + +; CHECK: [{{.*}}] DW_TAG_compile_unit DW_CHILDREN_yes ; CHECK: DW_AT_producer DW_FORM_GNU_str_index ; CHECK: DW_AT_language DW_FORM_data2 ; CHECK: DW_AT_name DW_FORM_GNU_str_index @@ -41,7 +46,7 @@ ; CHECK-NOT: DW_AT_comp_dir ; CHECK: DW_AT_GNU_dwo_id DW_FORM_data8 -; CHECK: [2] DW_TAG_variable DW_CHILDREN_no +; CHECK: [{{.*}}] DW_TAG_variable DW_CHILDREN_no ; CHECK: DW_AT_name DW_FORM_GNU_str_index ; CHECK: DW_AT_type DW_FORM_ref4 ; CHECK: DW_AT_external DW_FORM_flag_present @@ -49,11 +54,6 @@ ; CHECK: DW_AT_decl_line DW_FORM_data1 ; CHECK: DW_AT_location DW_FORM_exprloc -; CHECK: [3] DW_TAG_base_type DW_CHILDREN_no -; CHECK: DW_AT_name DW_FORM_GNU_str_index -; CHECK: DW_AT_encoding DW_FORM_data1 -; CHECK: DW_AT_byte_size DW_FORM_data1 - ; CHECK: .debug_info contents: ; CHECK: DW_TAG_compile_unit ; CHECK-NEXT: DW_AT_stmt_list [DW_FORM_sec_offset] (0x00000000) Index: test/DebugInfo/X86/linkage-name.ll =================================================================== --- test/DebugInfo/X86/linkage-name.ll +++ test/DebugInfo/X86/linkage-name.ll @@ -1,7 +1,10 @@ ; RUN: llc -mtriple=x86_64-macosx %s -o %t -filetype=obj ; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s -; CHECK: DW_TAG_subprogram [9] * +; CHECK: DW_TAG_class_type +; CHECK: DW_TAG_subprogram + +; CHECK: DW_TAG_subprogram ; CHECK-NOT: DW_AT_{{(MIPS_)?}}linkage_name ; CHECK: DW_AT_specification Index: test/DebugInfo/X86/low-pc-cu.ll =================================================================== --- test/DebugInfo/X86/low-pc-cu.ll +++ test/DebugInfo/X86/low-pc-cu.ll @@ -7,13 +7,13 @@ ; Check that we use DW_AT_low_pc and that it has the right encoding depending ; on dwarf version. -; CHECK: DW_TAG_compile_unit [1] +; CHECK: DW_TAG_compile_unit [ ; CHECK-NOT: DW_TAG ; CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) ; CHECK-NOT: DW_TAG ; CHECK-V3: DW_AT_high_pc [DW_FORM_addr] ; CHECK-V4: DW_AT_high_pc [DW_FORM_data4] -; CHECK: DW_TAG_subprogram [2] +; CHECK: DW_TAG_subprogram [ ; CHECK-NOT: DW_TAG ; CHECK: DW_AT_low_pc [DW_FORM_addr] ; CHECK-NOT: DW_TAG Index: test/DebugInfo/X86/pieces-2.ll =================================================================== --- test/DebugInfo/X86/pieces-2.ll +++ test/DebugInfo/X86/pieces-2.ll @@ -16,7 +16,7 @@ ; } ; ; -; CHECK: DW_TAG_variable [4] +; CHECK: DW_TAG_variable [ ; rax, piece 0x00000004 ; CHECK-NEXT: DW_AT_location [DW_FORM_block1]{{.*}}50 93 04 ; CHECK-NEXT: DW_AT_name {{.*}}"i1" Index: test/DebugInfo/X86/pieces-3.ll =================================================================== --- test/DebugInfo/X86/pieces-3.ll +++ test/DebugInfo/X86/pieces-3.ll @@ -15,7 +15,7 @@ ; return i1.a; ; } ; -; CHECK: DW_TAG_formal_parameter [3] +; CHECK: DW_TAG_formal_parameter [ ; CHECK-NEXT: DW_AT_location [DW_FORM_data4] ([[LOC:.*]]) ; CHECK-NEXT: DW_AT_name {{.*}}"outer" ; CHECK: DW_TAG_variable Index: unittests/CodeGen/CMakeLists.txt =================================================================== --- unittests/CodeGen/CMakeLists.txt +++ unittests/CodeGen/CMakeLists.txt @@ -1,9 +1,11 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} AsmPrinter Support ) set(CodeGenSources + DIEDataTest.cpp DIEHashTest.cpp ) Index: unittests/CodeGen/DIEDataTest.cpp =================================================================== --- /dev/null +++ unittests/CodeGen/DIEDataTest.cpp @@ -0,0 +1,139 @@ +//===- llvm/unittests/CodeGen/DIEDataTest.cpp -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/DIEData.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" + +using namespace llvm; + +struct TestMCContext { + const Target *TheTarget; + const char *TripleName = "x86_64-pc-linux"; + MCObjectFileInfo MOFI; + std::unique_ptr MCCtx; + std::unique_ptr MRI; + std::unique_ptr MAI; + + TestMCContext() { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllDisassemblers(); + + std::string Error; + TheTarget = TargetRegistry::lookupTarget(TripleName, Error); + if (!TheTarget) + return; + + MRI.reset(TheTarget->createMCRegInfo(TripleName)); + MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName)); + + MCCtx = llvm::make_unique(MAI.get(), MRI.get(), &MOFI); + MOFI.InitMCObjectFileInfo(Triple(TripleName), Reloc::Default, + CodeModel::Default, *MCCtx); + } +}; + +std::string dataToAsmString(TestMCContext &Ctx, DIEData *B) { + std::unique_ptr MCII(Ctx.TheTarget->createMCInstrInfo()); + MCInstPrinter *IP = Ctx.TheTarget->createMCInstPrinter( + Triple(Ctx.TripleName), 0, *Ctx.MAI, *MCII, *Ctx.MRI); + std::string Result; + raw_string_ostream OS(Result); + auto FOS = new formatted_raw_ostream(OS); + std::unique_ptr S(Ctx.TheTarget->createAsmStreamer( + *Ctx.MCCtx, std::unique_ptr(FOS), + /*asmverbose*/ true, + /*useDwarfDirectory*/ true, IP, nullptr, nullptr, false)); + S->InitSections(false); + + B->prepareToEmit(/*Offset=*/0); + B->emit(*S); + + FOS->flush(); + OS.flush(); + return Result; +} + +TEST(DIEData, Basic) { + TestMCContext Ctx; + if (!Ctx.TheTarget) + return; + + DWARFAbbrev Abbrevs; + DIEData Data; + + { + DIEWriter W(Abbrevs, Data, dwarf::DW_TAG_subprogram, false); + W.attr4(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, 1, false); + W.write(); + } + + { + DIEWriter W(Abbrevs, Data, dwarf::DW_TAG_subprogram, false); + W.attr4(dwarf::DW_AT_name, dwarf::DW_FORM_ref4, 1, false); + W.write(); + } + + EXPECT_EQ(R"( .text + .asciz "\002\001\000\000\000\004\001\000\000" +)", + dataToAsmString(Ctx, &Data)); + EXPECT_EQ( + (std::string({2, dwarf::DW_TAG_subprogram, 0, dwarf::DW_AT_type, + dwarf::DW_FORM_ref4, 0, 0, 4, dwarf::DW_TAG_subprogram, 0, + dwarf::DW_AT_name, dwarf::DW_FORM_ref4, 0, 0})), + Abbrevs.getAbbrevData()); +} + +TEST(DIEData, MCReloc) { + TestMCContext Ctx; + if (!Ctx.TheTarget) + return; + + MCSymbol *Sym1 = Ctx.MCCtx->getOrCreateSymbol("sym1"); + MCSymbol *Sym2 = Ctx.MCCtx->getOrCreateSymbol("sym2"); + + DWARFAbbrev Abbrevs; + DIEData Data; + + { + DIEWriter W(Abbrevs, Data, dwarf::DW_TAG_subprogram, false); + W.relocSym(dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, 4, Sym1); + W.write(); + } + + { + DIEWriter W(Abbrevs, Data, dwarf::DW_TAG_subprogram, false); + W.relocSym(dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, 8, Sym2); + W.write(); + } + + EXPECT_EQ(R"( .text + .byte 2 + .long sym1 + .byte 2 + .quad sym2 +)", + dataToAsmString(Ctx, &Data)); + EXPECT_EQ((std::string({2, dwarf::DW_TAG_subprogram, 0, dwarf::DW_AT_low_pc, + dwarf::DW_FORM_addr, 0, 0})), + Abbrevs.getAbbrevData()); +}