diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
| commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
| tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/CodeGen/AsmPrinter | |
| parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) | |
Notes
Diffstat (limited to 'lib/CodeGen/AsmPrinter')
45 files changed, 2821 insertions, 1391 deletions
diff --git a/lib/CodeGen/AsmPrinter/ARMException.cpp b/lib/CodeGen/AsmPrinter/ARMException.cpp index 15cfbd5c40ff..9011f025f595 100644 --- a/lib/CodeGen/AsmPrinter/ARMException.cpp +++ b/lib/CodeGen/AsmPrinter/ARMException.cpp @@ -91,7 +91,8 @@ void ARMException::endFunction(const MachineFunction *MF) { ATS.emitFnEnd(); } -void ARMException::emitTypeInfos(unsigned TTypeEncoding) { +void ARMException::emitTypeInfos(unsigned TTypeEncoding, + MCSymbol *TTBaseLabel) { const MachineFunction *MF = Asm->MF; const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos(); const std::vector<unsigned> &FilterIds = MF->getFilterIds(); @@ -112,6 +113,8 @@ void ARMException::emitTypeInfos(unsigned TTypeEncoding) { Asm->EmitTTypeReference(GV, TTypeEncoding); } + Asm->OutStreamer->EmitLabel(TTBaseLabel); + // Emit the Exception Specifications. if (VerboseAsm && !FilterIds.empty()) { Asm->OutStreamer->AddComment(">> Filter TypeInfos <<"); diff --git a/lib/CodeGen/AsmPrinter/AccelTable.cpp b/lib/CodeGen/AsmPrinter/AccelTable.cpp new file mode 100644 index 000000000000..20b0b8d3feab --- /dev/null +++ b/lib/CodeGen/AsmPrinter/AccelTable.cpp @@ -0,0 +1,721 @@ +//===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing accelerator tables. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/AccelTable.h" +#include "DwarfCompileUnit.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <limits> +#include <vector> + +using namespace llvm; + +void AccelTableBase::computeBucketCount() { + // First get the number of unique hashes. + std::vector<uint32_t> Uniques; + Uniques.reserve(Entries.size()); + for (const auto &E : Entries) + Uniques.push_back(E.second.HashValue); + array_pod_sort(Uniques.begin(), Uniques.end()); + std::vector<uint32_t>::iterator P = + std::unique(Uniques.begin(), Uniques.end()); + + UniqueHashCount = std::distance(Uniques.begin(), P); + + if (UniqueHashCount > 1024) + BucketCount = UniqueHashCount / 4; + else if (UniqueHashCount > 16) + BucketCount = UniqueHashCount / 2; + else + BucketCount = std::max<uint32_t>(UniqueHashCount, 1); +} + +void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) { + // Create the individual hash data outputs. + for (auto &E : Entries) { + // Unique the entries. + std::stable_sort(E.second.Values.begin(), E.second.Values.end(), + [](const AccelTableData *A, const AccelTableData *B) { + return *A < *B; + }); + E.second.Values.erase( + std::unique(E.second.Values.begin(), E.second.Values.end()), + E.second.Values.end()); + } + + // Figure out how many buckets we need, then compute the bucket contents and + // the final ordering. The hashes and offsets can be emitted by walking these + // data structures. We add temporary symbols to the data so they can be + // referenced when emitting the offsets. + computeBucketCount(); + + // Compute bucket contents and final ordering. + Buckets.resize(BucketCount); + for (auto &E : Entries) { + uint32_t Bucket = E.second.HashValue % BucketCount; + Buckets[Bucket].push_back(&E.second); + E.second.Sym = Asm->createTempSymbol(Prefix); + } + + // Sort the contents of the buckets by hash value so that hash collisions end + // up together. Stable sort makes testing easier and doesn't cost much more. + for (auto &Bucket : Buckets) + std::stable_sort(Bucket.begin(), Bucket.end(), + [](HashData *LHS, HashData *RHS) { + return LHS->HashValue < RHS->HashValue; + }); +} + +namespace { +/// Base class for writing out Accelerator tables. It holds the common +/// functionality for the two Accelerator table types. +class AccelTableWriter { +protected: + AsmPrinter *const Asm; ///< Destination. + const AccelTableBase &Contents; ///< Data to emit. + + /// Controls whether to emit duplicate hash and offset table entries for names + /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5 + /// tables do. + const bool SkipIdenticalHashes; + + void emitHashes() const; + + /// Emit offsets to lists of entries with identical names. The offsets are + /// relative to the Base argument. + void emitOffsets(const MCSymbol *Base) const; + +public: + AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, + bool SkipIdenticalHashes) + : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) { + } +}; + +class AppleAccelTableWriter : public AccelTableWriter { + using Atom = AppleAccelTableData::Atom; + + /// The fixed header of an Apple Accelerator Table. + struct Header { + uint32_t Magic = MagicHash; + uint16_t Version = 1; + uint16_t HashFunction = dwarf::DW_hash_function_djb; + uint32_t BucketCount; + uint32_t HashCount; + uint32_t HeaderDataLength; + + /// 'HASH' magic value to detect endianness. + static const uint32_t MagicHash = 0x48415348; + + Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength) + : BucketCount(BucketCount), HashCount(UniqueHashCount), + HeaderDataLength(DataLength) {} + + void emit(AsmPrinter *Asm) const; +#ifndef NDEBUG + void print(raw_ostream &OS) const; + void dump() const { print(dbgs()); } +#endif + }; + + /// The HeaderData describes the structure of an Apple accelerator table + /// through a list of Atoms. + struct HeaderData { + /// In the case of data that is referenced via DW_FORM_ref_* the offset + /// base is used to describe the offset for all forms in the list of atoms. + uint32_t DieOffsetBase; + + const SmallVector<Atom, 4> Atoms; + + HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0) + : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {} + + void emit(AsmPrinter *Asm) const; +#ifndef NDEBUG + void print(raw_ostream &OS) const; + void dump() const { print(dbgs()); } +#endif + }; + + Header Header; + HeaderData HeaderData; + const MCSymbol *SecBegin; + + void emitBuckets() const; + void emitData() const; + +public: + AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, + ArrayRef<Atom> Atoms, const MCSymbol *SecBegin) + : AccelTableWriter(Asm, Contents, true), + Header(Contents.getBucketCount(), Contents.getUniqueHashCount(), + 8 + (Atoms.size() * 4)), + HeaderData(Atoms), SecBegin(SecBegin) {} + + void emit() const; + +#ifndef NDEBUG + void print(raw_ostream &OS) const; + void dump() const { print(dbgs()); } +#endif +}; + +/// Class responsible for emitting a DWARF v5 Accelerator Table. The only +/// public function is emit(), which performs the actual emission. +/// +/// The class is templated in its data type. This allows us to emit both dyamic +/// and static data entries. A callback abstract the logic to provide a CU +/// index for a given entry, which is different per data type, but identical +/// for every entry in the same table. +template <typename DataT> +class Dwarf5AccelTableWriter : public AccelTableWriter { + struct Header { + uint32_t UnitLength = 0; + uint16_t Version = 5; + uint16_t Padding = 0; + uint32_t CompUnitCount; + uint32_t LocalTypeUnitCount = 0; + uint32_t ForeignTypeUnitCount = 0; + uint32_t BucketCount; + uint32_t NameCount; + uint32_t AbbrevTableSize = 0; + uint32_t AugmentationStringSize = sizeof(AugmentationString); + char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'}; + + Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount) + : CompUnitCount(CompUnitCount), BucketCount(BucketCount), + NameCount(NameCount) {} + + void emit(const Dwarf5AccelTableWriter &Ctx) const; + }; + struct AttributeEncoding { + dwarf::Index Index; + dwarf::Form Form; + }; + + Header Header; + DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations; + ArrayRef<MCSymbol *> CompUnits; + llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry; + MCSymbol *ContributionStart = Asm->createTempSymbol("names_start"); + MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end"); + MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start"); + MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end"); + MCSymbol *EntryPool = Asm->createTempSymbol("names_entries"); + + DenseSet<uint32_t> getUniqueTags() const; + + // Right now, we emit uniform attributes for all tags. + SmallVector<AttributeEncoding, 2> getUniformAttributes() const; + + void emitCUList() const; + void emitBuckets() const; + void emitStringOffsets() const; + void emitAbbrevs() const; + void emitEntry(const DataT &Entry) const; + void emitData() const; + +public: + Dwarf5AccelTableWriter( + AsmPrinter *Asm, const AccelTableBase &Contents, + ArrayRef<MCSymbol *> CompUnits, + llvm::function_ref<unsigned(const DataT &)> GetCUIndexForEntry); + + void emit() const; +}; +} // namespace + +void AccelTableWriter::emitHashes() const { + uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); + unsigned BucketIdx = 0; + for (auto &Bucket : Contents.getBuckets()) { + for (auto &Hash : Bucket) { + uint32_t HashValue = Hash->HashValue; + if (SkipIdenticalHashes && PrevHash == HashValue) + continue; + Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx)); + Asm->emitInt32(HashValue); + PrevHash = HashValue; + } + BucketIdx++; + } +} + +void AccelTableWriter::emitOffsets(const MCSymbol *Base) const { + const auto &Buckets = Contents.getBuckets(); + uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); + for (size_t i = 0, e = Buckets.size(); i < e; ++i) { + for (auto *Hash : Buckets[i]) { + uint32_t HashValue = Hash->HashValue; + if (SkipIdenticalHashes && PrevHash == HashValue) + continue; + PrevHash = HashValue; + Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i)); + Asm->EmitLabelDifference(Hash->Sym, Base, sizeof(uint32_t)); + } + } +} + +void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const { + Asm->OutStreamer->AddComment("Header Magic"); + Asm->emitInt32(Magic); + Asm->OutStreamer->AddComment("Header Version"); + Asm->emitInt16(Version); + Asm->OutStreamer->AddComment("Header Hash Function"); + Asm->emitInt16(HashFunction); + Asm->OutStreamer->AddComment("Header Bucket Count"); + Asm->emitInt32(BucketCount); + Asm->OutStreamer->AddComment("Header Hash Count"); + Asm->emitInt32(HashCount); + Asm->OutStreamer->AddComment("Header Data Length"); + Asm->emitInt32(HeaderDataLength); +} + +void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const { + Asm->OutStreamer->AddComment("HeaderData Die Offset Base"); + Asm->emitInt32(DieOffsetBase); + Asm->OutStreamer->AddComment("HeaderData Atom Count"); + Asm->emitInt32(Atoms.size()); + + for (const Atom &A : Atoms) { + Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type)); + Asm->emitInt16(A.Type); + Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form)); + Asm->emitInt16(A.Form); + } +} + +void AppleAccelTableWriter::emitBuckets() const { + const auto &Buckets = Contents.getBuckets(); + unsigned index = 0; + for (size_t i = 0, e = Buckets.size(); i < e; ++i) { + Asm->OutStreamer->AddComment("Bucket " + Twine(i)); + if (!Buckets[i].empty()) + Asm->emitInt32(index); + else + Asm->emitInt32(std::numeric_limits<uint32_t>::max()); + // Buckets point in the list of hashes, not to the data. Do not increment + // the index multiple times in case of hash collisions. + uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); + for (auto *HD : Buckets[i]) { + uint32_t HashValue = HD->HashValue; + if (PrevHash != HashValue) + ++index; + PrevHash = HashValue; + } + } +} + +void AppleAccelTableWriter::emitData() const { + const auto &Buckets = Contents.getBuckets(); + for (size_t i = 0, e = Buckets.size(); i < e; ++i) { + uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); + for (auto &Hash : Buckets[i]) { + // Terminate the previous entry if there is no hash collision with the + // current one. + if (PrevHash != std::numeric_limits<uint64_t>::max() && + PrevHash != Hash->HashValue) + Asm->emitInt32(0); + // Remember to emit the label for our offset. + Asm->OutStreamer->EmitLabel(Hash->Sym); + Asm->OutStreamer->AddComment(Hash->Name.getString()); + Asm->emitDwarfStringOffset(Hash->Name); + Asm->OutStreamer->AddComment("Num DIEs"); + Asm->emitInt32(Hash->Values.size()); + for (const auto *V : Hash->Values) + static_cast<const AppleAccelTableData *>(V)->emit(Asm); + PrevHash = Hash->HashValue; + } + // Emit the final end marker for the bucket. + if (!Buckets[i].empty()) + Asm->emitInt32(0); + } +} + +void AppleAccelTableWriter::emit() const { + Header.emit(Asm); + HeaderData.emit(Asm); + emitBuckets(); + emitHashes(); + emitOffsets(SecBegin); + emitData(); +} + +template <typename DataT> +void Dwarf5AccelTableWriter<DataT>::Header::emit( + const Dwarf5AccelTableWriter &Ctx) const { + assert(CompUnitCount > 0 && "Index must have at least one CU."); + + AsmPrinter *Asm = Ctx.Asm; + Asm->OutStreamer->AddComment("Header: unit length"); + Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart, + sizeof(uint32_t)); + Asm->OutStreamer->EmitLabel(Ctx.ContributionStart); + Asm->OutStreamer->AddComment("Header: version"); + Asm->emitInt16(Version); + Asm->OutStreamer->AddComment("Header: padding"); + Asm->emitInt16(Padding); + Asm->OutStreamer->AddComment("Header: compilation unit count"); + Asm->emitInt32(CompUnitCount); + Asm->OutStreamer->AddComment("Header: local type unit count"); + Asm->emitInt32(LocalTypeUnitCount); + Asm->OutStreamer->AddComment("Header: foreign type unit count"); + Asm->emitInt32(ForeignTypeUnitCount); + Asm->OutStreamer->AddComment("Header: bucket count"); + Asm->emitInt32(BucketCount); + Asm->OutStreamer->AddComment("Header: name count"); + Asm->emitInt32(NameCount); + Asm->OutStreamer->AddComment("Header: abbreviation table size"); + Asm->EmitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t)); + Asm->OutStreamer->AddComment("Header: augmentation string size"); + assert(AugmentationStringSize % 4 == 0); + Asm->emitInt32(AugmentationStringSize); + Asm->OutStreamer->AddComment("Header: augmentation string"); + Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize}); +} + +template <typename DataT> +DenseSet<uint32_t> Dwarf5AccelTableWriter<DataT>::getUniqueTags() const { + DenseSet<uint32_t> UniqueTags; + for (auto &Bucket : Contents.getBuckets()) { + for (auto *Hash : Bucket) { + for (auto *Value : Hash->Values) { + unsigned Tag = static_cast<const DataT *>(Value)->getDieTag(); + UniqueTags.insert(Tag); + } + } + } + return UniqueTags; +} + +template <typename DataT> +SmallVector<typename Dwarf5AccelTableWriter<DataT>::AttributeEncoding, 2> +Dwarf5AccelTableWriter<DataT>::getUniformAttributes() const { + SmallVector<AttributeEncoding, 2> UA; + if (CompUnits.size() > 1) { + size_t LargestCUIndex = CompUnits.size() - 1; + dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex); + UA.push_back({dwarf::DW_IDX_compile_unit, Form}); + } + UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); + return UA; +} + +template <typename DataT> +void Dwarf5AccelTableWriter<DataT>::emitCUList() const { + for (const auto &CU : enumerate(CompUnits)) { + Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index())); + Asm->emitDwarfSymbolReference(CU.value()); + } +} + +template <typename DataT> +void Dwarf5AccelTableWriter<DataT>::emitBuckets() const { + uint32_t Index = 1; + for (const auto &Bucket : enumerate(Contents.getBuckets())) { + Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index())); + Asm->emitInt32(Bucket.value().empty() ? 0 : Index); + Index += Bucket.value().size(); + } +} + +template <typename DataT> +void Dwarf5AccelTableWriter<DataT>::emitStringOffsets() const { + for (const auto &Bucket : enumerate(Contents.getBuckets())) { + for (auto *Hash : Bucket.value()) { + DwarfStringPoolEntryRef String = Hash->Name; + Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) + + ": " + String.getString()); + Asm->emitDwarfStringOffset(String); + } + } +} + +template <typename DataT> +void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const { + Asm->OutStreamer->EmitLabel(AbbrevStart); + for (const auto &Abbrev : Abbreviations) { + Asm->OutStreamer->AddComment("Abbrev code"); + assert(Abbrev.first != 0); + Asm->EmitULEB128(Abbrev.first); + Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first)); + Asm->EmitULEB128(Abbrev.first); + for (const auto &AttrEnc : Abbrev.second) { + Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data()); + Asm->EmitULEB128(AttrEnc.Form, + dwarf::FormEncodingString(AttrEnc.Form).data()); + } + Asm->EmitULEB128(0, "End of abbrev"); + Asm->EmitULEB128(0, "End of abbrev"); + } + Asm->EmitULEB128(0, "End of abbrev list"); + Asm->OutStreamer->EmitLabel(AbbrevEnd); +} + +template <typename DataT> +void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const { + auto AbbrevIt = Abbreviations.find(Entry.getDieTag()); + assert(AbbrevIt != Abbreviations.end() && + "Why wasn't this abbrev generated?"); + + Asm->EmitULEB128(AbbrevIt->first, "Abbreviation code"); + for (const auto &AttrEnc : AbbrevIt->second) { + Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index)); + switch (AttrEnc.Index) { + case dwarf::DW_IDX_compile_unit: { + DIEInteger ID(getCUIndexForEntry(Entry)); + ID.EmitValue(Asm, AttrEnc.Form); + break; + } + case dwarf::DW_IDX_die_offset: + assert(AttrEnc.Form == dwarf::DW_FORM_ref4); + Asm->emitInt32(Entry.getDieOffset()); + break; + default: + llvm_unreachable("Unexpected index attribute!"); + } + } +} + +template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const { + Asm->OutStreamer->EmitLabel(EntryPool); + for (auto &Bucket : Contents.getBuckets()) { + for (auto *Hash : Bucket) { + // Remember to emit the label for our offset. + Asm->OutStreamer->EmitLabel(Hash->Sym); + for (const auto *Value : Hash->Values) + emitEntry(*static_cast<const DataT *>(Value)); + Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); + Asm->emitInt32(0); + } + } +} + +template <typename DataT> +Dwarf5AccelTableWriter<DataT>::Dwarf5AccelTableWriter( + AsmPrinter *Asm, const AccelTableBase &Contents, + ArrayRef<MCSymbol *> CompUnits, + llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry) + : AccelTableWriter(Asm, Contents, false), + Header(CompUnits.size(), Contents.getBucketCount(), + Contents.getUniqueNameCount()), + CompUnits(CompUnits), getCUIndexForEntry(std::move(getCUIndexForEntry)) { + DenseSet<uint32_t> UniqueTags = getUniqueTags(); + SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes(); + + Abbreviations.reserve(UniqueTags.size()); + for (uint32_t Tag : UniqueTags) + Abbreviations.try_emplace(Tag, UniformAttributes); +} + +template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emit() const { + Header.emit(*this); + emitCUList(); + emitBuckets(); + emitHashes(); + emitStringOffsets(); + emitOffsets(EntryPool); + emitAbbrevs(); + emitData(); + Asm->OutStreamer->EmitValueToAlignment(4, 0); + Asm->OutStreamer->EmitLabel(ContributionEnd); +} + +void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, + StringRef Prefix, const MCSymbol *SecBegin, + ArrayRef<AppleAccelTableData::Atom> Atoms) { + Contents.finalize(Asm, Prefix); + AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit(); +} + +void llvm::emitDWARF5AccelTable( + AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents, + const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) { + std::vector<MCSymbol *> CompUnits; + for (const auto &CU : enumerate(CUs)) { + assert(CU.index() == CU.value()->getUniqueID()); + const DwarfCompileUnit *MainCU = + DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get(); + CompUnits.push_back(MainCU->getLabelBegin()); + } + + Contents.finalize(Asm, "names"); + Dwarf5AccelTableWriter<DWARF5AccelTableData>( + Asm, Contents, CompUnits, + [&DD](const DWARF5AccelTableData &Entry) { + const DIE *CUDie = Entry.getDie().getUnitDie(); + return DD.lookupCU(CUDie)->getUniqueID(); + }) + .emit(); +} + +void llvm::emitDWARF5AccelTable( + AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents, + ArrayRef<MCSymbol *> CUs, + llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)> + getCUIndexForEntry) { + Contents.finalize(Asm, "names"); + Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(Asm, Contents, CUs, + getCUIndexForEntry) + .emit(); +} + +void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { + Asm->emitInt32(Die.getDebugSectionOffset()); +} + +void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const { + Asm->emitInt32(Die.getDebugSectionOffset()); + Asm->emitInt16(Die.getTag()); + Asm->emitInt8(0); +} + +void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const { + Asm->emitInt32(Offset); +} + +void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const { + Asm->emitInt32(Offset); + Asm->emitInt16(Tag); + Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation + : 0); + Asm->emitInt32(QualifiedNameHash); +} + +#ifndef _MSC_VER +// The lines below are rejected by older versions (TBD) of MSVC. +constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[]; +constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[]; +constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[]; +constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[]; +#else +// FIXME: Erase this path once the minimum MSCV version has been bumped. +const SmallVector<AppleAccelTableData::Atom, 4> + AppleAccelTableOffsetData::Atoms = { + Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)}; +const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms = + {Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), + Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), + Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)}; +const SmallVector<AppleAccelTableData::Atom, 4> + AppleAccelTableStaticOffsetData::Atoms = { + Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)}; +const SmallVector<AppleAccelTableData::Atom, 4> + AppleAccelTableStaticTypeData::Atoms = { + Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), + Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), + Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)}; +#endif + +#ifndef NDEBUG +void AppleAccelTableWriter::Header::print(raw_ostream &OS) const { + OS << "Magic: " << format("0x%x", Magic) << "\n" + << "Version: " << Version << "\n" + << "Hash Function: " << HashFunction << "\n" + << "Bucket Count: " << BucketCount << "\n" + << "Header Data Length: " << HeaderDataLength << "\n"; +} + +void AppleAccelTableData::Atom::print(raw_ostream &OS) const { + OS << "Type: " << dwarf::AtomTypeString(Type) << "\n" + << "Form: " << dwarf::FormEncodingString(Form) << "\n"; +} + +void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const { + OS << "DIE Offset Base: " << DieOffsetBase << "\n"; + for (auto Atom : Atoms) + Atom.print(OS); +} + +void AppleAccelTableWriter::print(raw_ostream &OS) const { + Header.print(OS); + HeaderData.print(OS); + Contents.print(OS); + SecBegin->print(OS, nullptr); +} + +void AccelTableBase::HashData::print(raw_ostream &OS) const { + OS << "Name: " << Name.getString() << "\n"; + OS << " Hash Value: " << format("0x%x", HashValue) << "\n"; + OS << " Symbol: "; + if (Sym) + OS << *Sym; + else + OS << "<none>"; + OS << "\n"; + for (auto *Value : Values) + Value->print(OS); +} + +void AccelTableBase::print(raw_ostream &OS) const { + // Print Content. + OS << "Entries: \n"; + for (const auto &Entry : Entries) { + OS << "Name: " << Entry.first() << "\n"; + for (auto *V : Entry.second.Values) + V->print(OS); + } + + OS << "Buckets and Hashes: \n"; + for (auto &Bucket : Buckets) + for (auto &Hash : Bucket) + Hash->print(OS); + + OS << "Data: \n"; + for (auto &E : Entries) + E.second.print(OS); +} + +void DWARF5AccelTableData::print(raw_ostream &OS) const { + OS << " Offset: " << getDieOffset() << "\n"; + OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n"; +} + +void DWARF5AccelTableStaticData::print(raw_ostream &OS) const { + OS << " Offset: " << getDieOffset() << "\n"; + OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n"; +} + +void AppleAccelTableOffsetData::print(raw_ostream &OS) const { + OS << " Offset: " << Die.getOffset() << "\n"; +} + +void AppleAccelTableTypeData::print(raw_ostream &OS) const { + OS << " Offset: " << Die.getOffset() << "\n"; + OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n"; +} + +void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const { + OS << " Static Offset: " << Offset << "\n"; +} + +void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const { + OS << " Static Offset: " << Offset << "\n"; + OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n"; + OS << " Tag: " << dwarf::TagString(Tag) << "\n"; + OS << " ObjCClassIsImplementation: " + << (ObjCClassIsImplementation ? "true" : "false"); + OS << "\n"; +} +#endif diff --git a/lib/CodeGen/AsmPrinter/AddressPool.cpp b/lib/CodeGen/AsmPrinter/AddressPool.cpp index 59ed0324bdb0..4a226527cb5b 100644 --- a/lib/CodeGen/AsmPrinter/AddressPool.cpp +++ b/lib/CodeGen/AsmPrinter/AddressPool.cpp @@ -10,9 +10,9 @@ #include "AddressPool.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include <utility> using namespace llvm; diff --git a/lib/CodeGen/AsmPrinter/AddressPool.h b/lib/CodeGen/AsmPrinter/AddressPool.h index 990a158d87cd..5350006bf744 100644 --- a/lib/CodeGen/AsmPrinter/AddressPool.h +++ b/lib/CodeGen/AsmPrinter/AddressPool.h @@ -39,7 +39,7 @@ class AddressPool { public: AddressPool() = default; - /// \brief Returns the index into the address pool with the given + /// Returns the index into the address pool with the given /// label/symbol. unsigned getIndex(const MCSymbol *Sym, bool TLS = false); diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index d7995447592c..9bbc77b3056b 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -16,6 +16,7 @@ #include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" +#include "WinCFGuard.h" #include "WinException.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" @@ -30,7 +31,6 @@ #include "llvm/ADT/Twine.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/EHPersonalities.h" -#include "llvm/Analysis/ObjectUtils.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/ELF.h" @@ -39,6 +39,7 @@ #include "llvm/CodeGen/GCStrategy.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -54,7 +55,6 @@ #include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" @@ -87,6 +87,7 @@ #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" @@ -107,6 +108,7 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include <algorithm> @@ -130,6 +132,8 @@ static const char *const DbgTimerName = "emit"; static const char *const DbgTimerDescription = "Debug Info Emission"; static const char *const EHTimerName = "write_exception"; static const char *const EHTimerDescription = "DWARF Exception Writer"; +static const char *const CFGuardName = "Control Flow Guard"; +static const char *const CFGuardDescription = "Control Flow Guard Tables"; static const char *const CodeViewLineTablesGroupName = "linetables"; static const char *const CodeViewLineTablesGroupDescription = "CodeView Line Tables"; @@ -211,8 +215,10 @@ const DataLayout &AsmPrinter::getDataLayout() const { } // Do not use the cached DataLayout because some client use it without a Module -// (llvm-dsymutil, llvm-dwarfdump). -unsigned AsmPrinter::getPointerSize() const { return TM.getPointerSize(); } +// (dsymutil, llvm-dwarfdump). +unsigned AsmPrinter::getPointerSize() const { + return TM.getPointerSize(0); // FIXME: Default address space +} const MCSubtargetInfo &AsmPrinter::getSubtargetInfo() const { assert(MF && "getSubtargetInfo requires a valid MachineFunction!"); @@ -234,7 +240,6 @@ void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<MachineModuleInfo>(); AU.addRequired<MachineOptimizationRemarkEmitterPass>(); AU.addRequired<GCModuleInfo>(); - AU.addRequired<MachineLoopInfo>(); } bool AsmPrinter::doInitialization(Module &M) { @@ -246,7 +251,7 @@ bool AsmPrinter::doInitialization(Module &M) { OutStreamer->InitSections(false); - // Emit the version-min deplyment target directive if needed. + // Emit the version-min deployment target directive if needed. // // FIXME: If we end up with a collection of these sorts of Darwin-specific // or ELF-specific things, it may make sense to have a platform helper class @@ -291,8 +296,7 @@ bool AsmPrinter::doInitialization(Module &M) { if (MAI->doesSupportDebugInformation()) { bool EmitCodeView = MMI->getModule()->getCodeViewFlag(); - if (EmitCodeView && (TM.getTargetTriple().isKnownWindowsMSVCEnvironment() || - TM.getTargetTriple().isWindowsItaniumEnvironment())) { + if (EmitCodeView && TM.getTargetTriple().isOSWindows()) { Handlers.push_back(HandlerInfo(new CodeViewDebug(this), DbgTimerName, DbgTimerDescription, CodeViewLineTablesGroupName, @@ -350,10 +354,20 @@ bool AsmPrinter::doInitialization(Module &M) { break; } break; + case ExceptionHandling::Wasm: + // TODO to prevent warning + break; } if (ES) Handlers.push_back(HandlerInfo(ES, EHTimerName, EHTimerDescription, DWARFGroupName, DWARFGroupDescription)); + + if (mdconst::extract_or_null<ConstantInt>( + MMI->getModule()->getModuleFlag("cfguard"))) + Handlers.push_back(HandlerInfo(new WinCFGuard(this), CFGuardName, + CFGuardDescription, DWARFGroupName, + DWARFGroupDescription)); + return false; } @@ -361,7 +375,7 @@ static bool canBeHidden(const GlobalValue *GV, const MCAsmInfo &MAI) { if (!MAI.hasWeakDefCanBeHiddenDirective()) return false; - return canBeOmittedFromSymbolTable(GV); + return GV->canBeOmittedFromSymbolTable(); } void AsmPrinter::EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const { @@ -416,7 +430,7 @@ MCSymbol *AsmPrinter::getSymbol(const GlobalValue *GV) const { /// EmitGlobalVariable - Emit the specified global variable to the .s file. void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { - bool IsEmuTLSVar = TM.Options.EmulatedTLS && GV->isThreadLocal(); + bool IsEmuTLSVar = TM.useEmulatedTLS() && GV->isThreadLocal(); assert(!(IsEmuTLSVar && GV->hasCommonLinkage()) && "No emulated TLS variables in the common section"); @@ -898,6 +912,30 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { return true; } +/// This method handles the target-independent form of DBG_LABEL, returning +/// true if it was able to do so. A false return means the target will need +/// to handle MI in EmitInstruction. +static bool emitDebugLabelComment(const MachineInstr *MI, AsmPrinter &AP) { + if (MI->getNumOperands() != 1) + return false; + + SmallString<128> Str; + raw_svector_ostream OS(Str); + OS << "DEBUG_LABEL: "; + + const DILabel *V = MI->getDebugLabel(); + if (auto *SP = dyn_cast<DISubprogram>(V->getScope())) { + StringRef Name = SP->getName(); + if (!Name.empty()) + OS << Name << ":"; + } + OS << V->getName(); + + // NOTE: Want this comment at start of line, don't emit with AddComment. + AP.OutStreamer->emitRawComment(OS.str()); + return true; +} + AsmPrinter::CFIMoveType AsmPrinter::needsCFIMoves() const { if (MAI->getExceptionHandlingType() == ExceptionHandling::DwarfCFI && MF->getFunction().needsUnwindTableEntry()) @@ -952,7 +990,8 @@ void AsmPrinter::emitStackSizeSection(const MachineFunction &MF) { if (!MF.getTarget().Options.EmitStackSizeSection) return; - MCSection *StackSizeSection = getObjFileLowering().getStackSizesSection(); + MCSection *StackSizeSection = + getObjFileLowering().getStackSizesSection(*getCurrentSection()); if (!StackSizeSection) return; @@ -964,10 +1003,9 @@ void AsmPrinter::emitStackSizeSection(const MachineFunction &MF) { OutStreamer->PushSection(); OutStreamer->SwitchSection(StackSizeSection); - const MCSymbol *FunctionSymbol = getSymbol(&MF.getFunction()); + const MCSymbol *FunctionSymbol = getFunctionBegin(); uint64_t StackSize = FrameInfo.getStackSize(); - OutStreamer->EmitValue(MCSymbolRefExpr::create(FunctionSymbol, OutContext), - /* size = */ 8); + OutStreamer->EmitSymbolValue(FunctionSymbol, TM.getProgramPointerSize()); OutStreamer->EmitULEB128IntValue(StackSize); OutStreamer->PopSection(); @@ -996,6 +1034,24 @@ void AsmPrinter::EmitFunctionBody() { bool ShouldPrintDebugScopes = MMI->hasDebugInfo(); + if (isVerbose()) { + // Get MachineDominatorTree or compute it on the fly if it's unavailable + MDT = getAnalysisIfAvailable<MachineDominatorTree>(); + if (!MDT) { + OwnedMDT = make_unique<MachineDominatorTree>(); + OwnedMDT->getBase().recalculate(*MF); + MDT = OwnedMDT.get(); + } + + // Get MachineLoopInfo or compute it on the fly if it's unavailable + MLI = getAnalysisIfAvailable<MachineLoopInfo>(); + if (!MLI) { + OwnedMLI = make_unique<MachineLoopInfo>(); + OwnedMLI->getBase().analyze(MDT->getBase()); + MLI = OwnedMLI.get(); + } + } + // Print out code for the function. bool HasAnyRealCode = false; int NumInstsInFunction = 0; @@ -1005,7 +1061,7 @@ void AsmPrinter::EmitFunctionBody() { for (auto &MI : MBB) { // Print the assembly for the instruction. if (!MI.isPosition() && !MI.isImplicitDef() && !MI.isKill() && - !MI.isDebugValue()) { + !MI.isDebugInstr()) { HasAnyRealCode = true; ++NumInstsInFunction; } @@ -1044,6 +1100,12 @@ void AsmPrinter::EmitFunctionBody() { EmitInstruction(&MI); } break; + case TargetOpcode::DBG_LABEL: + if (isVerbose()) { + if (!emitDebugLabelComment(&MI, *this)) + EmitInstruction(&MI); + } + break; case TargetOpcode::IMPLICIT_DEF: if (isVerbose()) emitImplicitDef(&MI); break; @@ -1155,7 +1217,7 @@ void AsmPrinter::EmitFunctionBody() { OutStreamer->AddBlankLine(); } -/// \brief Compute the number of Global Variables that uses a Constant. +/// Compute the number of Global Variables that uses a Constant. static unsigned getNumGlobalVariableUses(const Constant *C) { if (!C) return 0; @@ -1170,7 +1232,7 @@ static unsigned getNumGlobalVariableUses(const Constant *C) { return NumUses; } -/// \brief Only consider global GOT equivalents if at least one user is a +/// Only consider global GOT equivalents if at least one user is a /// cstexpr inside an initializer of another global variables. Also, don't /// handle cstexpr inside instructions. During global variable emission, /// candidates are skipped and are emitted later in case at least one cstexpr @@ -1193,7 +1255,7 @@ static bool isGOTEquivalentCandidate(const GlobalVariable *GV, return NumGOTEquivUsers > 0; } -/// \brief Unnamed constant global variables solely contaning a pointer to +/// Unnamed constant global variables solely contaning a pointer to /// another globals variable is equivalent to a GOT table entry; it contains the /// the address of another symbol. Optimize it and replace accesses to these /// "GOT equivalents" by using the GOT entry for the final global instead. @@ -1214,7 +1276,7 @@ void AsmPrinter::computeGlobalGOTEquivs(Module &M) { } } -/// \brief Constant expressions using GOT equivalent globals may not be eligible +/// Constant expressions using GOT equivalent globals may not be eligible /// for PC relative GOT entry conversion, in such cases we need to emit such /// globals we previously omitted in EmitGlobalVariable. void AsmPrinter::emitGlobalGOTEquivs() { @@ -1312,7 +1374,7 @@ bool AsmPrinter::doFinalization(Module &M) { const TargetLoweringObjectFile &TLOF = getObjFileLowering(); - TLOF.emitModuleMetadata(*OutStreamer, M, TM); + TLOF.emitModuleMetadata(*OutStreamer, M); if (TM.getTargetTriple().isOSBinFormatELF()) { MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); @@ -1323,6 +1385,7 @@ bool AsmPrinter::doFinalization(Module &M) { OutStreamer->SwitchSection(TLOF.getDataSection()); const DataLayout &DL = M.getDataLayout(); + EmitAlignment(Log2_32(DL.getPointerSize())); for (const auto &Stub : Stubs) { OutStreamer->EmitLabel(Stub.first); OutStreamer->EmitSymbolValue(Stub.second.getPointer(), @@ -1421,6 +1484,61 @@ bool AsmPrinter::doFinalization(Module &M) { if (MCSection *S = MAI->getNonexecutableStackSection(OutContext)) OutStreamer->SwitchSection(S); + if (TM.getTargetTriple().isOSBinFormatCOFF()) { + // Emit /EXPORT: flags for each exported global as necessary. + const auto &TLOF = getObjFileLowering(); + std::string Flags; + + for (const GlobalValue &GV : M.global_values()) { + raw_string_ostream OS(Flags); + TLOF.emitLinkerFlagsForGlobal(OS, &GV); + OS.flush(); + if (!Flags.empty()) { + OutStreamer->SwitchSection(TLOF.getDrectveSection()); + OutStreamer->EmitBytes(Flags); + } + Flags.clear(); + } + + // Emit /INCLUDE: flags for each used global as necessary. + if (const auto *LU = M.getNamedGlobal("llvm.used")) { + assert(LU->hasInitializer() && + "expected llvm.used to have an initializer"); + assert(isa<ArrayType>(LU->getValueType()) && + "expected llvm.used to be an array type"); + if (const auto *A = cast<ConstantArray>(LU->getInitializer())) { + for (const Value *Op : A->operands()) { + const auto *GV = + cast<GlobalValue>(Op->stripPointerCastsNoFollowAliases()); + // Global symbols with internal or private linkage are not visible to + // the linker, and thus would cause an error when the linker tried to + // preserve the symbol due to the `/include:` directive. + if (GV->hasLocalLinkage()) + continue; + + raw_string_ostream OS(Flags); + TLOF.emitLinkerFlagsForUsed(OS, GV); + OS.flush(); + + if (!Flags.empty()) { + OutStreamer->SwitchSection(TLOF.getDrectveSection()); + OutStreamer->EmitBytes(Flags); + } + Flags.clear(); + } + } + } + } + + if (TM.Options.EmitAddrsig) { + // Emit address-significance attributes for all globals. + OutStreamer->EmitAddrsig(); + for (const GlobalValue &GV : M.global_values()) + if (!GV.isThreadLocal() && !GV.getName().startswith("llvm.") && + !GV.hasAtLeastLocalUnnamedAddr()) + OutStreamer->EmitAddrsigSym(getSymbol(&GV)); + } + // Allow the target to emit any magic that it wants at the end of the file, // after everything else has gone out. EmitEndOfAsmFile(M); @@ -1429,6 +1547,8 @@ bool AsmPrinter::doFinalization(Module &M) { OutStreamer->Finish(); OutStreamer->reset(); + OwnedMLI.reset(); + OwnedMDT.reset(); return false; } @@ -1447,14 +1567,14 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { CurrentFnBegin = nullptr; CurExceptionSym = nullptr; bool NeedsLocalForSize = MAI->needsLocalForSize(); - if (needFuncLabelsForEHOrDebugInfo(MF, MMI) || NeedsLocalForSize) { + if (needFuncLabelsForEHOrDebugInfo(MF, MMI) || NeedsLocalForSize || + MF.getTarget().Options.EmitStackSizeSection) { CurrentFnBegin = createTempSymbol("func_begin"); if (NeedsLocalForSize) CurrentFnSymForSize = CurrentFnBegin; } ORE = &getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE(); - LI = &getAnalysis<MachineLoopInfo>(); const TargetSubtargetInfo &STI = MF.getSubtarget(); EnablePrintSchedInfo = PrintSchedule.getNumOccurrences() @@ -1842,22 +1962,27 @@ void AsmPrinter::EmitModuleIdents(Module &M) { // Emission and print routines // -/// EmitInt8 - Emit a byte directive and value. +/// Emit a byte directive and value. /// -void AsmPrinter::EmitInt8(int Value) const { +void AsmPrinter::emitInt8(int Value) const { OutStreamer->EmitIntValue(Value, 1); } -/// EmitInt16 - Emit a short directive and value. -void AsmPrinter::EmitInt16(int Value) const { +/// Emit a short directive and value. +void AsmPrinter::emitInt16(int Value) const { OutStreamer->EmitIntValue(Value, 2); } -/// EmitInt32 - Emit a long directive and value. -void AsmPrinter::EmitInt32(int Value) const { +/// Emit a long directive and value. +void AsmPrinter::emitInt32(int Value) const { OutStreamer->EmitIntValue(Value, 4); } +/// Emit a long long directive and value. +void AsmPrinter::emitInt64(uint64_t Value) const { + OutStreamer->EmitIntValue(Value, 8); +} + /// Emit something like ".long Hi-Lo" where the size in bytes of the directive /// is specified by Size and Hi/Lo specify the labels. This implicitly uses /// .set if it avoids relocations. @@ -2069,6 +2194,7 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *C, uint64_t Offset = 0); static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP); +static void emitGlobalConstantFP(APFloat APF, Type *ET, AsmPrinter &AP); /// isRepeatedByteSequence - Determine whether the given value is /// composed of a repeated sequence of identical bytes and return the @@ -2146,13 +2272,15 @@ static void emitGlobalConstantDataSequential(const DataLayout &DL, ElementByteSize); } } else { + Type *ET = CDS->getElementType(); for (unsigned I = 0, E = CDS->getNumElements(); I != E; ++I) - emitGlobalConstantFP(cast<ConstantFP>(CDS->getElementAsConstant(I)), AP); + emitGlobalConstantFP(CDS->getElementAsAPFloat(I), ET, AP); } unsigned Size = DL.getTypeAllocSize(CDS->getType()); unsigned EmittedSize = DL.getTypeAllocSize(CDS->getType()->getElementType()) * CDS->getNumElements(); + assert(EmittedSize <= Size && "Size cannot be less than EmittedSize!"); if (unsigned Padding = Size - EmittedSize) AP.OutStreamer->EmitZeros(Padding); } @@ -2216,17 +2344,17 @@ static void emitGlobalConstantStruct(const DataLayout &DL, "Layout of constant struct may be incorrect!"); } -static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) { - APInt API = CFP->getValueAPF().bitcastToAPInt(); +static void emitGlobalConstantFP(APFloat APF, Type *ET, AsmPrinter &AP) { + APInt API = APF.bitcastToAPInt(); // First print a comment with what we think the original floating-point value // should have been. if (AP.isVerbose()) { SmallString<8> StrVal; - CFP->getValueAPF().toString(StrVal); + APF.toString(StrVal); - if (CFP->getType()) - CFP->getType()->print(AP.OutStreamer->GetCommentOS()); + if (ET) + ET->print(AP.OutStreamer->GetCommentOS()); else AP.OutStreamer->GetCommentOS() << "Printing <null> Type"; AP.OutStreamer->GetCommentOS() << ' ' << StrVal << '\n'; @@ -2241,7 +2369,7 @@ static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) { // PPC's long double has odd notions of endianness compared to how LLVM // handles it: p[0] goes first for *big* endian on PPC. - if (AP.getDataLayout().isBigEndian() && !CFP->getType()->isPPC_FP128Ty()) { + if (AP.getDataLayout().isBigEndian() && !ET->isPPC_FP128Ty()) { int Chunk = API.getNumWords() - 1; if (TrailingBytes) @@ -2260,8 +2388,11 @@ static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) { // Emit the tail padding for the long double. const DataLayout &DL = AP.getDataLayout(); - AP.OutStreamer->EmitZeros(DL.getTypeAllocSize(CFP->getType()) - - DL.getTypeStoreSize(CFP->getType())); + AP.OutStreamer->EmitZeros(DL.getTypeAllocSize(ET) - DL.getTypeStoreSize(ET)); +} + +static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) { + emitGlobalConstantFP(CFP->getValueAPF(), CFP->getType(), AP); } static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) { @@ -2320,7 +2451,7 @@ static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) { } } -/// \brief Transform a not absolute MCExpr containing a reference to a GOT +/// Transform a not absolute MCExpr containing a reference to a GOT /// equivalent global, by a target specific GOT pc relative access to the /// final symbol. static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME, @@ -2533,6 +2664,25 @@ MCSymbol *AsmPrinter::GetBlockAddressSymbol(const BasicBlock *BB) const { /// GetCPISymbol - Return the symbol for the specified constant pool entry. MCSymbol *AsmPrinter::GetCPISymbol(unsigned CPID) const { + if (getSubtargetInfo().getTargetTriple().isKnownWindowsMSVCEnvironment()) { + const MachineConstantPoolEntry &CPE = + MF->getConstantPool()->getConstants()[CPID]; + if (!CPE.isMachineConstantPoolEntry()) { + const DataLayout &DL = MF->getDataLayout(); + SectionKind Kind = CPE.getSectionKind(&DL); + const Constant *C = CPE.Val.ConstVal; + unsigned Align = CPE.Alignment; + if (const MCSectionCOFF *S = dyn_cast<MCSectionCOFF>( + getObjFileLowering().getSectionForConstant(DL, Kind, C, Align))) { + if (MCSymbol *Sym = S->getCOMDATSymbol()) { + if (Sym->isUndefined()) + OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global); + return Sym; + } + } + } + } + const DataLayout &DL = getDataLayout(); return OutContext.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) + "CPI" + Twine(getFunctionNumber()) + "_" + @@ -2631,13 +2781,9 @@ static void emitBasicBlockLoopComments(const MachineBasicBlock &MBB, void AsmPrinter::setupCodePaddingContext(const MachineBasicBlock &MBB, MCCodePaddingContext &Context) const { assert(MF != nullptr && "Machine function must be valid"); - assert(LI != nullptr && "Loop info must be valid"); Context.IsPaddingActive = !MF->hasInlineAsm() && !MF->getFunction().optForSize() && TM.getOptLevel() != CodeGenOpt::None; - const MachineLoop *CurrentLoop = LI->getLoopFor(&MBB); - Context.IsBasicBlockInsideInnermostLoop = - CurrentLoop != nullptr && CurrentLoop->getSubLoops().empty(); Context.IsBasicBlockReachableViaFallthrough = std::find(MBB.pred_begin(), MBB.pred_end(), MBB.getPrevNode()) != MBB.pred_end(); @@ -2689,7 +2835,9 @@ void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const { OutStreamer->GetCommentOS() << '\n'; } } - emitBasicBlockLoopComments(MBB, LI, *this); + + assert(MLI != nullptr && "MachineLoopInfo should has been computed"); + emitBasicBlockLoopComments(MBB, MLI, *this); } // Print the main label for the block. diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index 08eb14e242c5..605588470670 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -17,7 +17,6 @@ #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCRegisterInfo.h" @@ -26,6 +25,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MachineLocation.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; @@ -43,15 +43,6 @@ void AsmPrinter::EmitSLEB128(int64_t Value, const char *Desc) const { OutStreamer->EmitSLEB128IntValue(Value); } -/// EmitULEB128 - emit the specified unsigned leb128 value. -void AsmPrinter::EmitPaddedULEB128(uint64_t Value, unsigned PadTo, - const char *Desc) const { - if (isVerbose() && Desc) - OutStreamer->AddComment(Desc); - - OutStreamer->EmitPaddedULEB128IntValue(Value, PadTo); -} - void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc) const { if (isVerbose() && Desc) OutStreamer->AddComment(Desc); @@ -59,6 +50,12 @@ void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc) const { OutStreamer->EmitULEB128IntValue(Value); } +/// Emit something like ".uleb128 Hi-Lo". +void AsmPrinter::EmitLabelDifferenceAsULEB128(const MCSymbol *Hi, + const MCSymbol *Lo) const { + OutStreamer->emitAbsoluteSymbolDiffAsULEB128(Hi, Lo); +} + static const char *DecodeDWARFEncoding(unsigned Encoding) { switch (Encoding) { case dwarf::DW_EH_PE_absptr: @@ -67,6 +64,10 @@ static const char *DecodeDWARFEncoding(unsigned Encoding) { return "omit"; case dwarf::DW_EH_PE_pcrel: return "pcrel"; + case dwarf::DW_EH_PE_uleb128: + return "uleb128"; + case dwarf::DW_EH_PE_sleb128: + return "sleb128"; case dwarf::DW_EH_PE_udata4: return "udata4"; case dwarf::DW_EH_PE_udata8: @@ -167,14 +168,19 @@ void AsmPrinter::emitDwarfSymbolReference(const MCSymbol *Label, EmitLabelDifference(Label, Label->getSection().getBeginSymbol(), 4); } -void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntryRef S) const { +void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntry S) const { if (MAI->doesDwarfUseRelocationsAcrossSections()) { - emitDwarfSymbolReference(S.getSymbol()); + assert(S.Symbol && "No symbol available"); + emitDwarfSymbolReference(S.Symbol); return; } // Just emit the offset directly; no need for symbol math. - EmitInt32(S.getOffset()); + emitInt32(S.Offset); +} + +void AsmPrinter::EmitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const { + EmitLabelPlusOffset(Label, Offset, MAI->getCodePointerSize()); } //===----------------------------------------------------------------------===// @@ -252,7 +258,7 @@ void AsmPrinter::emitDwarfDIE(const DIE &Die) const { emitDwarfDIE(Child); OutStreamer->AddComment("End Of Children Mark"); - EmitInt8(0); + emitInt8(0); } } diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterHandler.h b/lib/CodeGen/AsmPrinter/AsmPrinterHandler.h index 638226e90a7a..f5ac95a20b10 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterHandler.h +++ b/lib/CodeGen/AsmPrinter/AsmPrinterHandler.h @@ -27,29 +27,29 @@ class MCSymbol; typedef MCSymbol *ExceptionSymbolProvider(AsmPrinter *Asm); -/// \brief Collects and handles AsmPrinter objects required to build debug +/// Collects and handles AsmPrinter objects required to build debug /// or EH information. class AsmPrinterHandler { public: virtual ~AsmPrinterHandler(); - /// \brief For symbols that have a size designated (e.g. common symbols), + /// For symbols that have a size designated (e.g. common symbols), /// this tracks that size. virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) = 0; - /// \brief Emit all sections that should come after the content. + /// Emit all sections that should come after the content. virtual void endModule() = 0; - /// \brief Gather pre-function debug information. + /// Gather pre-function debug information. /// Every beginFunction(MF) call should be followed by an endFunction(MF) /// call. virtual void beginFunction(const MachineFunction *MF) = 0; - // \brief Emit any of function marker (like .cfi_endproc). This is called + // Emit any of function marker (like .cfi_endproc). This is called // before endFunction and cannot switch sections. virtual void markFunctionEnd(); - /// \brief Gather post-function debug information. + /// Gather post-function debug information. /// Please note that some AsmPrinter implementations may not call /// beginFunction at all. virtual void endFunction(const MachineFunction *MF) = 0; @@ -58,15 +58,15 @@ public: ExceptionSymbolProvider ESP) {} virtual void endFragment() {} - /// \brief Emit target-specific EH funclet machinery. + /// Emit target-specific EH funclet machinery. virtual void beginFunclet(const MachineBasicBlock &MBB, MCSymbol *Sym = nullptr) {} virtual void endFunclet() {} - /// \brief Process beginning of an instruction. + /// Process beginning of an instruction. virtual void beginInstruction(const MachineInstr *MI) = 0; - /// \brief Process end of an instruction. + /// Process end of an instruction. virtual void endInstruction() = 0; }; } // End of namespace llvm diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 04a72ba3d738..4159eb19423a 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -132,6 +132,9 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, std::unique_ptr<MCAsmParser> Parser( createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum)); + // Do not use assembler-level information for parsing inline assembly. + OutStreamer->setUseAssemblerInfoForParsing(false); + // We create a new MCInstrInfo here since we might be at the module level // and not have a MachineFunction to initialize the TargetInstrInfo from and // we only need MCInstrInfo for asm parsing. We create one unconditionally diff --git a/lib/CodeGen/AsmPrinter/ByteStreamer.h b/lib/CodeGen/AsmPrinter/ByteStreamer.h index aaf6180c9404..2163cc7e3e11 100644 --- a/lib/CodeGen/AsmPrinter/ByteStreamer.h +++ b/lib/CodeGen/AsmPrinter/ByteStreamer.h @@ -43,7 +43,7 @@ public: APByteStreamer(AsmPrinter &Asm) : AP(Asm) {} void EmitInt8(uint8_t Byte, const Twine &Comment) override { AP.OutStreamer->AddComment(Comment); - AP.EmitInt8(Byte); + AP.emitInt8(Byte); } void EmitSLEB128(uint64_t DWord, const Twine &Comment) override { AP.OutStreamer->AddComment(Comment); @@ -76,7 +76,7 @@ private: SmallVectorImpl<char> &Buffer; SmallVectorImpl<std::string> &Comments; - /// \brief Only verbose textual output needs comments. This will be set to + /// Only verbose textual output needs comments. This will be set to /// true for that case, and false otherwise. If false, comments passed in to /// the emit methods will be ignored. bool GenerateComments; @@ -93,15 +93,27 @@ public: } void EmitSLEB128(uint64_t DWord, const Twine &Comment) override { raw_svector_ostream OSE(Buffer); - encodeSLEB128(DWord, OSE); - if (GenerateComments) + unsigned Length = encodeSLEB128(DWord, OSE); + if (GenerateComments) { Comments.push_back(Comment.str()); + // Add some empty comments to keep the Buffer and Comments vectors aligned + // with each other. + for (size_t i = 1; i < Length; ++i) + Comments.push_back(""); + + } } void EmitULEB128(uint64_t DWord, const Twine &Comment) override { raw_svector_ostream OSE(Buffer); - encodeULEB128(DWord, OSE); - if (GenerateComments) + unsigned Length = encodeULEB128(DWord, OSE); + if (GenerateComments) { Comments.push_back(Comment.str()); + // Add some empty comments to keep the Buffer and Comments vectors aligned + // with each other. + for (size_t i = 1; i < Length; ++i) + Comments.push_back(""); + + } } }; diff --git a/lib/CodeGen/AsmPrinter/CMakeLists.txt b/lib/CodeGen/AsmPrinter/CMakeLists.txt index 05c6a28bbcac..0f8c24158ee2 100644 --- a/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ b/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMAsmPrinter + AccelTable.cpp AddressPool.cpp ARMException.cpp AsmPrinter.cpp @@ -9,7 +10,6 @@ add_llvm_library(LLVMAsmPrinter DebugLocStream.cpp DIE.cpp DIEHash.cpp - DwarfAccelTable.cpp DwarfCFIException.cpp DwarfCompileUnit.cpp DwarfDebug.cpp @@ -20,6 +20,7 @@ add_llvm_library(LLVMAsmPrinter EHStreamer.cpp ErlangGCPrinter.cpp OcamlGCPrinter.cpp + WinCFGuard.cpp WinException.cpp CodeViewDebug.cpp diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 1d0a003dc50a..8c5c5478d01a 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -36,7 +36,6 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/TargetFrameLowering.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Config/llvm-config.h" @@ -75,6 +74,7 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/ScopedPrinter.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include <algorithm> #include <cassert> @@ -114,6 +114,16 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) { StringRef Dir = File->getDirectory(), Filename = File->getFilename(); + // If this is a Unix-style path, just use it as is. Don't try to canonicalize + // it textually because one of the path components could be a symlink. + if (!Dir.empty() && Dir[0] == '/') { + Filepath = Dir; + if (Dir.back() != '/') + Filepath += '/'; + Filepath += Filename; + return Filepath; + } + // Clang emits directory and relative filename info into the IR, but CodeView // operates on full paths. We could change Clang to emit full paths too, but // that would increase the IR size and probably not needed for other users. @@ -165,14 +175,21 @@ unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) { auto Insertion = FileIdMap.insert(std::make_pair(FullPath, NextId)); if (Insertion.second) { // We have to compute the full filepath and emit a .cv_file directive. - std::string Checksum = fromHex(F->getChecksum()); - void *CKMem = OS.getContext().allocate(Checksum.size(), 1); - memcpy(CKMem, Checksum.data(), Checksum.size()); - ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t *>(CKMem), - Checksum.size()); - DIFile::ChecksumKind ChecksumKind = F->getChecksumKind(); + ArrayRef<uint8_t> ChecksumAsBytes; + FileChecksumKind CSKind = FileChecksumKind::None; + if (F->getChecksum()) { + std::string Checksum = fromHex(F->getChecksum()->Value); + void *CKMem = OS.getContext().allocate(Checksum.size(), 1); + memcpy(CKMem, Checksum.data(), Checksum.size()); + ChecksumAsBytes = ArrayRef<uint8_t>( + reinterpret_cast<const uint8_t *>(CKMem), Checksum.size()); + switch (F->getChecksum()->Kind) { + case DIFile::CSK_MD5: CSKind = FileChecksumKind::MD5; break; + case DIFile::CSK_SHA1: CSKind = FileChecksumKind::SHA1; break; + } + } bool Success = OS.EmitCVFileDirective(NextId, FullPath, ChecksumAsBytes, - static_cast<unsigned>(ChecksumKind)); + static_cast<unsigned>(CSKind)); (void)Success; assert(Success && ".cv_file directive failed"); } @@ -358,15 +375,15 @@ unsigned CodeViewDebug::getPointerSizeInBytes() { } void CodeViewDebug::recordLocalVariable(LocalVariable &&Var, - const DILocation *InlinedAt) { - if (InlinedAt) { + const LexicalScope *LS) { + if (const DILocation *InlinedAt = LS->getInlinedAt()) { // This variable was inlined. Associate it with the InlineSite. const DISubprogram *Inlinee = Var.DIVar->getScope()->getSubprogram(); InlineSite &Site = getInlineSite(InlinedAt, Inlinee); Site.InlinedLocals.emplace_back(Var); } else { - // This variable goes in the main ProcSym. - CurFn->Locals.emplace_back(Var); + // This variable goes into the corresponding lexical scope. + ScopeVariables[LS].emplace_back(Var); } } @@ -463,7 +480,7 @@ void CodeViewDebug::endModule() { // Emit per-function debug information. for (auto &P : FnDebugInfo) if (!P.first->isDeclarationForLinker()) - emitDebugInfoForFunction(P.first, P.second); + emitDebugInfoForFunction(P.first, *P.second); // Emit global variable debug information. setCurrentSubprogram(nullptr); @@ -501,12 +518,12 @@ void CodeViewDebug::endModule() { clear(); } -static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S) { +static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S, + unsigned MaxFixedRecordLength = 0xF00) { // The maximum CV record length is 0xFF00. Most of the strings we emit appear // after a fixed length portion of the record. The fixed length portion should // always be less than 0xF00 (3840) bytes, so truncate the string so that the // overall record size is less than the maximum allowed. - unsigned MaxFixedRecordLength = 0xF00; SmallString<32> NullTerminatedString( S.take_front(MaxRecordLength - MaxFixedRecordLength - 1)); NullTerminatedString.push_back('\0'); @@ -517,7 +534,7 @@ void CodeViewDebug::emitTypeInformation() { if (TypeTable.empty()) return; - // Start the .debug$T section with 0x4. + // Start the .debug$T or .debug$P section with 0x4. OS.SwitchSection(Asm->getObjFileLowering().getCOFFDebugTypesSection()); emitCodeViewMagicVersion(); @@ -572,7 +589,7 @@ void CodeViewDebug::emitTypeGlobalHashes() { OS.AddComment("Section Version"); OS.EmitIntValue(0, 2); OS.AddComment("Hash Algorithm"); - OS.EmitIntValue(uint16_t(GlobalTypeHashAlg::SHA1), 2); + OS.EmitIntValue(uint16_t(GlobalTypeHashAlg::SHA1_8), 2); TypeIndex TI(TypeIndex::FirstNonSimpleIndex); for (const auto &GHR : TypeTable.hashes()) { @@ -585,7 +602,7 @@ void CodeViewDebug::emitTypeGlobalHashes() { OS.AddComment(Comment); ++TI; } - assert(GHR.Hash.size() % 20 == 0); + assert(GHR.Hash.size() == 8); StringRef S(reinterpret_cast<const char *>(GHR.Hash.data()), GHR.Hash.size()); OS.EmitBinaryData(S); @@ -821,10 +838,61 @@ void CodeViewDebug::switchToDebugSectionForSymbol(const MCSymbol *GVSym) { emitCodeViewMagicVersion(); } +// Emit an S_THUNK32/S_END symbol pair for a thunk routine. +// The only supported thunk ordinal is currently the standard type. +void CodeViewDebug::emitDebugInfoForThunk(const Function *GV, + FunctionInfo &FI, + const MCSymbol *Fn) { + std::string FuncName = GlobalValue::dropLLVMManglingEscape(GV->getName()); + const ThunkOrdinal ordinal = ThunkOrdinal::Standard; // Only supported kind. + + OS.AddComment("Symbol subsection for " + Twine(FuncName)); + MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols); + + // Emit S_THUNK32 + MCSymbol *ThunkRecordBegin = MMI->getContext().createTempSymbol(), + *ThunkRecordEnd = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(ThunkRecordEnd, ThunkRecordBegin, 2); + OS.EmitLabel(ThunkRecordBegin); + OS.AddComment("Record kind: S_THUNK32"); + OS.EmitIntValue(unsigned(SymbolKind::S_THUNK32), 2); + OS.AddComment("PtrParent"); + OS.EmitIntValue(0, 4); + OS.AddComment("PtrEnd"); + OS.EmitIntValue(0, 4); + OS.AddComment("PtrNext"); + OS.EmitIntValue(0, 4); + OS.AddComment("Thunk section relative address"); + OS.EmitCOFFSecRel32(Fn, /*Offset=*/0); + OS.AddComment("Thunk section index"); + OS.EmitCOFFSectionIndex(Fn); + OS.AddComment("Code size"); + OS.emitAbsoluteSymbolDiff(FI.End, Fn, 2); + OS.AddComment("Ordinal"); + OS.EmitIntValue(unsigned(ordinal), 1); + OS.AddComment("Function name"); + emitNullTerminatedSymbolName(OS, FuncName); + // Additional fields specific to the thunk ordinal would go here. + OS.EmitLabel(ThunkRecordEnd); + + // Local variables/inlined routines are purposely omitted here. The point of + // marking this as a thunk is so Visual Studio will NOT stop in this routine. + + // Emit S_PROC_ID_END + const unsigned RecordLengthForSymbolEnd = 2; + OS.AddComment("Record length"); + OS.EmitIntValue(RecordLengthForSymbolEnd, 2); + OS.AddComment("Record kind: S_PROC_ID_END"); + OS.EmitIntValue(unsigned(SymbolKind::S_PROC_ID_END), 2); + + endCVSubsection(SymbolsEnd); +} + void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI) { - // For each function there is a separate subsection - // which holds the PC to file:line table. + // For each function there is a separate subsection which holds the PC to + // file:line table. const MCSymbol *Fn = Asm->getSymbol(GV); assert(Fn); @@ -836,6 +904,11 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, assert(SP); setCurrentSubprogram(SP); + if (SP->isThunk()) { + emitDebugInfoForThunk(GV, FI, Fn); + return; + } + // If we have a display name, build the fully qualified name by walking the // chain of scopes. if (!SP->getName().empty()) @@ -898,6 +971,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, OS.EmitLabel(ProcRecordEnd); emitLocalVariableList(FI.Locals); + emitLexicalBlockList(FI.ChildBlocks, FI); // Emit inlined call site information. Only emit functions inlined directly // into the parent function. We'll emit the other sites recursively as part @@ -1018,7 +1092,7 @@ void CodeViewDebug::collectVariableInfoFromMFTable( LocalVariable Var; Var.DIVar = VI.Var; Var.DefRanges.emplace_back(std::move(DefRange)); - recordLocalVariable(std::move(Var), VI.Loc->getInlinedAt()); + recordLocalVariable(std::move(Var), Scope); } } @@ -1100,7 +1174,7 @@ void CodeViewDebug::calculateRanges( auto J = std::next(I); const DIExpression *DIExpr = DVInst->getDebugExpression(); while (J != E && - !fragmentsOverlap(DIExpr, J->first->getDebugExpression())) + !DIExpr->fragmentsOverlap(J->first->getDebugExpression())) ++J; if (J != E) End = getLabelBeforeInsn(J->first); @@ -1149,14 +1223,15 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { Var.DIVar = DIVar; calculateRanges(Var, Ranges); - recordLocalVariable(std::move(Var), InlinedAt); + recordLocalVariable(std::move(Var), Scope); } } void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { const Function &GV = MF->getFunction(); - assert(FnDebugInfo.count(&GV) == false); - CurFn = &FnDebugInfo[&GV]; + auto Insertion = FnDebugInfo.insert({&GV, llvm::make_unique<FunctionInfo>()}); + assert(Insertion.second && "function already has info"); + CurFn = Insertion.first->second.get(); CurFn->FuncId = NextFuncId++; CurFn->Begin = Asm->getFunctionBegin(); @@ -1261,6 +1336,7 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) { return lowerTypePointer(cast<DIDerivedType>(Ty)); case dwarf::DW_TAG_ptr_to_member_type: return lowerTypeMemberPointer(cast<DIDerivedType>(Ty)); + case dwarf::DW_TAG_restrict_type: case dwarf::DW_TAG_const_type: case dwarf::DW_TAG_volatile_type: // TODO: add support for DW_TAG_atomic_type here @@ -1281,6 +1357,8 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) { return lowerTypeClass(cast<DICompositeType>(Ty)); case dwarf::DW_TAG_union_type: return lowerTypeUnion(cast<DICompositeType>(Ty)); + case dwarf::DW_TAG_unspecified_type: + return TypeIndex::None(); default: // Use the null type index. return TypeIndex(); @@ -1308,7 +1386,7 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { DITypeRef ElementTypeRef = Ty->getBaseType(); TypeIndex ElementTypeIndex = getTypeIndex(ElementTypeRef); // IndexType is size_t, which depends on the bitness of the target. - TypeIndex IndexType = Asm->TM.getPointerSize() == 8 + TypeIndex IndexType = getPointerSizeInBytes() == 8 ? TypeIndex(SimpleTypeKind::UInt64Quad) : TypeIndex(SimpleTypeKind::UInt32Long); @@ -1323,7 +1401,9 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { const DISubrange *Subrange = cast<DISubrange>(Element); assert(Subrange->getLowerBound() == 0 && "codeview doesn't support subranges with lower bounds"); - int64_t Count = Subrange->getCount(); + int64_t Count = -1; + if (auto *CI = Subrange->getCount().dyn_cast<ConstantInt*>()) + Count = CI->getSExtValue(); // Forward declarations of arrays without a size and VLAs use a count of -1. // Emit a count of zero in these cases to match what MSVC does for arrays @@ -1441,12 +1521,13 @@ TypeIndex CodeViewDebug::lowerTypeBasic(const DIBasicType *Ty) { return TypeIndex(STK); } -TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) { +TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty, + PointerOptions PO) { TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType()); - // Pointers to simple types can use SimpleTypeMode, rather than having a - // dedicated pointer type record. - if (PointeeTI.isSimple() && + // Pointers to simple types without any options can use SimpleTypeMode, rather + // than having a dedicated pointer type record. + if (PointeeTI.isSimple() && PO == PointerOptions::None && PointeeTI.getSimpleMode() == SimpleTypeMode::Direct && Ty->getTag() == dwarf::DW_TAG_pointer_type) { SimpleTypeMode Mode = Ty->getSizeInBits() == 64 @@ -1470,10 +1551,7 @@ TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) { PM = PointerMode::RValueReference; break; } - // FIXME: MSVC folds qualifiers into PointerOptions in the context of a method - // 'this' pointer, but not normal contexts. Figure out what we're supposed to - // do. - PointerOptions PO = PointerOptions::None; + PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8); return TypeTable.writeLeafType(PR); } @@ -1511,16 +1589,17 @@ translatePtrToMemberRep(unsigned SizeInBytes, bool IsPMF, unsigned Flags) { llvm_unreachable("invalid ptr to member representation"); } -TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) { +TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty, + PointerOptions PO) { assert(Ty->getTag() == dwarf::DW_TAG_ptr_to_member_type); TypeIndex ClassTI = getTypeIndex(Ty->getClassType()); TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType(), Ty->getClassType()); - PointerKind PK = Asm->TM.getPointerSize() == 8 ? PointerKind::Near64 - : PointerKind::Near32; + PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64 + : PointerKind::Near32; bool IsPMF = isa<DISubroutineType>(Ty->getBaseType()); PointerMode PM = IsPMF ? PointerMode::PointerToMemberFunction : PointerMode::PointerToDataMember; - PointerOptions PO = PointerOptions::None; // FIXME + assert(Ty->getSizeInBits() / 8 <= 0xff && "pointer size too big"); uint8_t SizeInBytes = Ty->getSizeInBits() / 8; MemberPointerInfo MPI( @@ -1545,6 +1624,7 @@ static CallingConvention dwarfCCToCodeView(unsigned DwarfCC) { TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) { ModifierOptions Mods = ModifierOptions::None; + PointerOptions PO = PointerOptions::None; bool IsModifier = true; const DIType *BaseTy = Ty; while (IsModifier && BaseTy) { @@ -1552,9 +1632,16 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) { switch (BaseTy->getTag()) { case dwarf::DW_TAG_const_type: Mods |= ModifierOptions::Const; + PO |= PointerOptions::Const; break; case dwarf::DW_TAG_volatile_type: Mods |= ModifierOptions::Volatile; + PO |= PointerOptions::Volatile; + break; + case dwarf::DW_TAG_restrict_type: + // Only pointer types be marked with __restrict. There is no known flag + // for __restrict in LF_MODIFIER records. + PO |= PointerOptions::Restrict; break; default: IsModifier = false; @@ -1563,7 +1650,31 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) { if (IsModifier) BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType().resolve(); } + + // Check if the inner type will use an LF_POINTER record. If so, the + // qualifiers will go in the LF_POINTER record. This comes up for types like + // 'int *const' and 'int *__restrict', not the more common cases like 'const + // char *'. + if (BaseTy) { + switch (BaseTy->getTag()) { + case dwarf::DW_TAG_pointer_type: + case dwarf::DW_TAG_reference_type: + case dwarf::DW_TAG_rvalue_reference_type: + return lowerTypePointer(cast<DIDerivedType>(BaseTy), PO); + case dwarf::DW_TAG_ptr_to_member_type: + return lowerTypeMemberPointer(cast<DIDerivedType>(BaseTy), PO); + default: + break; + } + } + TypeIndex ModifiedTI = getTypeIndex(BaseTy); + + // Return the base type index if there aren't any modifiers. For example, the + // metadata could contain restrict wrappers around non-pointer types. + if (Mods == ModifierOptions::None) + return ModifiedTI; + ModifierRecord MR(ModifiedTI, Mods); return TypeTable.writeLeafType(MR); } @@ -1573,6 +1684,11 @@ TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) { for (DITypeRef ArgTypeRef : Ty->getTypeArray()) ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef)); + // MSVC uses type none for variadic argument. + if (ReturnAndArgTypeIndices.size() > 1 && + ReturnAndArgTypeIndices.back() == TypeIndex::Void()) { + ReturnAndArgTypeIndices.back() = TypeIndex::None(); + } TypeIndex ReturnTypeIndex = TypeIndex::Void(); ArrayRef<TypeIndex> ArgTypeIndices = None; if (!ReturnAndArgTypeIndices.empty()) { @@ -1602,6 +1718,11 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, for (DITypeRef ArgTypeRef : Ty->getTypeArray()) ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef)); + // MSVC uses type none for variadic argument. + if (ReturnAndArgTypeIndices.size() > 1 && + ReturnAndArgTypeIndices.back() == TypeIndex::Void()) { + ReturnAndArgTypeIndices.back() = TypeIndex::None(); + } TypeIndex ReturnTypeIndex = TypeIndex::Void(); ArrayRef<TypeIndex> ArgTypeIndices = None; if (!ReturnAndArgTypeIndices.empty()) { @@ -1716,6 +1837,26 @@ static ClassOptions getCommonClassOptions(const DICompositeType *Ty) { return CO; } +void CodeViewDebug::addUDTSrcLine(const DIType *Ty, TypeIndex TI) { + switch (Ty->getTag()) { + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_enumeration_type: + break; + default: + return; + } + + if (const auto *File = Ty->getFile()) { + StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(File)); + TypeIndex SIDI = TypeTable.writeLeafType(SIDR); + + UdtSourceLineRecord USLR(TI, SIDI, Ty->getLine()); + TypeTable.writeLeafType(USLR); + } +} + TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) { ClassOptions CO = getCommonClassOptions(Ty); TypeIndex FTI; @@ -1744,7 +1885,11 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) { EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(), getTypeIndex(Ty->getBaseType())); - return TypeTable.writeLeafType(ER); + TypeIndex EnumTI = TypeTable.writeLeafType(ER); + + addUDTSrcLine(Ty, EnumTI); + + return EnumTI; } //===----------------------------------------------------------------------===// @@ -1793,12 +1938,33 @@ void CodeViewDebug::collectMemberInfo(ClassInfo &Info, Info.Members.push_back({DDTy, 0}); return; } - // An unnamed member must represent a nested struct or union. Add all the - // indirect fields to the current record. + + // An unnamed member may represent a nested struct or union. Attempt to + // interpret the unnamed member as a DICompositeType possibly wrapped in + // qualifier types. Add all the indirect fields to the current record if that + // succeeds, and drop the member if that fails. assert((DDTy->getOffsetInBits() % 8) == 0 && "Unnamed bitfield member!"); uint64_t Offset = DDTy->getOffsetInBits(); const DIType *Ty = DDTy->getBaseType().resolve(); - const DICompositeType *DCTy = cast<DICompositeType>(Ty); + bool FullyResolved = false; + while (!FullyResolved) { + switch (Ty->getTag()) { + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_volatile_type: + // FIXME: we should apply the qualifier types to the indirect fields + // rather than dropping them. + Ty = cast<DIDerivedType>(Ty)->getBaseType().resolve(); + break; + default: + FullyResolved = true; + break; + } + } + + const DICompositeType *DCTy = dyn_cast<DICompositeType>(Ty); + if (!DCTy) + return; + ClassInfo NestedInfo = collectClassInfo(DCTy); for (const ClassInfo::MemberInfo &IndirectField : NestedInfo.Members) Info.Members.push_back( @@ -1838,7 +2004,28 @@ ClassInfo CodeViewDebug::collectClassInfo(const DICompositeType *Ty) { return Info; } +static bool shouldAlwaysEmitCompleteClassType(const DICompositeType *Ty) { + // This routine is used by lowerTypeClass and lowerTypeUnion to determine + // if a complete type should be emitted instead of a forward reference. + return Ty->getName().empty() && Ty->getIdentifier().empty() && + !Ty->isForwardDecl(); +} + TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) { + // Emit the complete type for unnamed structs. C++ classes with methods + // which have a circular reference back to the class type are expected to + // be named by the front-end and should not be "unnamed". C unnamed + // structs should not have circular references. + if (shouldAlwaysEmitCompleteClassType(Ty)) { + // If this unnamed complete type is already in the process of being defined + // then the description of the type is malformed and cannot be emitted + // into CodeView correctly so report a fatal error. + auto I = CompleteTypeIndices.find(Ty); + if (I != CompleteTypeIndices.end() && I->second == TypeIndex()) + report_fatal_error("cannot debug circular reference to unnamed type"); + return getCompleteTypeIndex(Ty); + } + // First, construct the forward decl. Don't look into Ty to compute the // forward decl options, since it might not be available in all TUs. TypeRecordKind Kind = getRecordKind(Ty); @@ -1875,13 +2062,7 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) { SizeInBytes, FullName, Ty->getIdentifier()); TypeIndex ClassTI = TypeTable.writeLeafType(CR); - if (const auto *File = Ty->getFile()) { - StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(File)); - TypeIndex SIDI = TypeTable.writeLeafType(SIDR); - - UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine()); - TypeTable.writeLeafType(USLR); - } + addUDTSrcLine(Ty, ClassTI); addToUDTs(Ty); @@ -1889,6 +2070,10 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) { } TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) { + // Emit the complete type for unnamed unions. + if (shouldAlwaysEmitCompleteClassType(Ty)) + return getCompleteTypeIndex(Ty); + ClassOptions CO = ClassOptions::ForwardReference | getCommonClassOptions(Ty); std::string FullName = getFullyQualifiedName(Ty); @@ -1917,11 +2102,7 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) { Ty->getIdentifier()); TypeIndex UnionTI = TypeTable.writeLeafType(UR); - StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile())); - TypeIndex SIRI = TypeTable.writeLeafType(SIR); - - UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine()); - TypeTable.writeLeafType(USLR); + addUDTSrcLine(Ty, UnionTI); addToUDTs(Ty); @@ -1943,8 +2124,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { for (const DIDerivedType *I : Info.Inheritance) { if (I->getFlags() & DINode::FlagVirtual) { // Virtual base. - // FIXME: Emit VBPtrOffset when the frontend provides it. - unsigned VBPtrOffset = 0; + unsigned VBPtrOffset = I->getVBPtrOffset(); // FIXME: Despite the accessor name, the offset is really in bytes. unsigned VBTableIndex = I->getOffsetInBits() / 4; auto RecordKind = (I->getFlags() & DINode::FlagIndirectVirtualBase) == DINode::FlagIndirectVirtualBase @@ -1956,6 +2136,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { VBTableIndex); ContinuationBuilder.writeMemberType(VBCR); + MemberCount++; } else { assert(I->getOffsetInBits() % 8 == 0 && "bases must be on byte boundaries"); @@ -1963,6 +2144,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8); ContinuationBuilder.writeMemberType(BCR); + MemberCount++; } } @@ -2121,9 +2303,7 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { return getTypeIndex(Ty); } - // Check if we've already translated the complete record type. Lowering a - // complete type should never trigger lowering another complete type, so we - // can reuse the hash table lookup result. + // Check if we've already translated the complete record type. const auto *CTy = cast<DICompositeType>(Ty); auto InsertResult = CompleteTypeIndices.insert({CTy, TypeIndex()}); if (!InsertResult.second) @@ -2134,13 +2314,16 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { // Make sure the forward declaration is emitted first. It's unclear if this // is necessary, but MSVC does it, and we should follow suit until we can show // otherwise. - TypeIndex FwdDeclTI = getTypeIndex(CTy); + // We only emit a forward declaration for named types. + if (!CTy->getName().empty() || !CTy->getIdentifier().empty()) { + TypeIndex FwdDeclTI = getTypeIndex(CTy); - // Just use the forward decl if we don't have complete type info. This might - // happen if the frontend is using modules and expects the complete definition - // to be emitted elsewhere. - if (CTy->isForwardDecl()) - return FwdDeclTI; + // Just use the forward decl if we don't have complete type info. This + // might happen if the frontend is using modules and expects the complete + // definition to be emitted elsewhere. + if (CTy->isForwardDecl()) + return FwdDeclTI; + } TypeIndex TI; switch (CTy->getTag()) { @@ -2155,7 +2338,11 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { llvm_unreachable("not a record"); } - InsertResult.first->second = TI; + // Update the type index associated with this CompositeType. This cannot + // use the 'InsertResult' iterator above because it is potentially + // invalidated by map insertions which can occur while lowering the class + // type above. + CompleteTypeIndices[CTy] = TI; return TI; } @@ -2179,10 +2366,10 @@ void CodeViewDebug::emitLocalVariableList(ArrayRef<LocalVariable> Locals) { for (const LocalVariable &L : Locals) if (L.DIVar->isParameter()) Params.push_back(&L); - std::sort(Params.begin(), Params.end(), - [](const LocalVariable *L, const LocalVariable *R) { - return L->DIVar->getArg() < R->DIVar->getArg(); - }); + llvm::sort(Params.begin(), Params.end(), + [](const LocalVariable *L, const LocalVariable *R) { + return L->DIVar->getArg() < R->DIVar->getArg(); + }); for (const LocalVariable *L : Params) emitLocalVariable(*L); @@ -2272,15 +2459,150 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { } } +void CodeViewDebug::emitLexicalBlockList(ArrayRef<LexicalBlock *> Blocks, + const FunctionInfo& FI) { + for (LexicalBlock *Block : Blocks) + emitLexicalBlock(*Block, FI); +} + +/// Emit an S_BLOCK32 and S_END record pair delimiting the contents of a +/// lexical block scope. +void CodeViewDebug::emitLexicalBlock(const LexicalBlock &Block, + const FunctionInfo& FI) { + MCSymbol *RecordBegin = MMI->getContext().createTempSymbol(), + *RecordEnd = MMI->getContext().createTempSymbol(); + + // Lexical block symbol record. + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(RecordEnd, RecordBegin, 2); // Record Length + OS.EmitLabel(RecordBegin); + OS.AddComment("Record kind: S_BLOCK32"); + OS.EmitIntValue(SymbolKind::S_BLOCK32, 2); // Record Kind + OS.AddComment("PtrParent"); + OS.EmitIntValue(0, 4); // PtrParent + OS.AddComment("PtrEnd"); + OS.EmitIntValue(0, 4); // PtrEnd + OS.AddComment("Code size"); + OS.emitAbsoluteSymbolDiff(Block.End, Block.Begin, 4); // Code Size + OS.AddComment("Function section relative address"); + OS.EmitCOFFSecRel32(Block.Begin, /*Offset=*/0); // Func Offset + OS.AddComment("Function section index"); + OS.EmitCOFFSectionIndex(FI.Begin); // Func Symbol + OS.AddComment("Lexical block name"); + emitNullTerminatedSymbolName(OS, Block.Name); // Name + OS.EmitLabel(RecordEnd); + + // Emit variables local to this lexical block. + emitLocalVariableList(Block.Locals); + + // Emit lexical blocks contained within this block. + emitLexicalBlockList(Block.Children, FI); + + // Close the lexical block scope. + OS.AddComment("Record length"); + OS.EmitIntValue(2, 2); // Record Length + OS.AddComment("Record kind: S_END"); + OS.EmitIntValue(SymbolKind::S_END, 2); // Record Kind +} + +/// Convenience routine for collecting lexical block information for a list +/// of lexical scopes. +void CodeViewDebug::collectLexicalBlockInfo( + SmallVectorImpl<LexicalScope *> &Scopes, + SmallVectorImpl<LexicalBlock *> &Blocks, + SmallVectorImpl<LocalVariable> &Locals) { + for (LexicalScope *Scope : Scopes) + collectLexicalBlockInfo(*Scope, Blocks, Locals); +} + +/// Populate the lexical blocks and local variable lists of the parent with +/// information about the specified lexical scope. +void CodeViewDebug::collectLexicalBlockInfo( + LexicalScope &Scope, + SmallVectorImpl<LexicalBlock *> &ParentBlocks, + SmallVectorImpl<LocalVariable> &ParentLocals) { + if (Scope.isAbstractScope()) + return; + + auto LocalsIter = ScopeVariables.find(&Scope); + if (LocalsIter == ScopeVariables.end()) { + // This scope does not contain variables and can be eliminated. + collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals); + return; + } + SmallVectorImpl<LocalVariable> &Locals = LocalsIter->second; + + const DILexicalBlock *DILB = dyn_cast<DILexicalBlock>(Scope.getScopeNode()); + if (!DILB) { + // This scope is not a lexical block and can be eliminated, but keep any + // local variables it contains. + ParentLocals.append(Locals.begin(), Locals.end()); + collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals); + return; + } + + const SmallVectorImpl<InsnRange> &Ranges = Scope.getRanges(); + if (Ranges.size() != 1 || !getLabelAfterInsn(Ranges.front().second)) { + // This lexical block scope has too many address ranges to represent in the + // current CodeView format or does not have a valid address range. + // Eliminate this lexical scope and promote any locals it contains to the + // parent scope. + // + // For lexical scopes with multiple address ranges you may be tempted to + // construct a single range covering every instruction where the block is + // live and everything in between. Unfortunately, Visual Studio only + // displays variables from the first matching lexical block scope. If the + // first lexical block contains exception handling code or cold code which + // is moved to the bottom of the routine creating a single range covering + // nearly the entire routine, then it will hide all other lexical blocks + // and the variables they contain. + // + ParentLocals.append(Locals.begin(), Locals.end()); + collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals); + return; + } + + // Create a new CodeView lexical block for this lexical scope. If we've + // seen this DILexicalBlock before then the scope tree is malformed and + // we can handle this gracefully by not processing it a second time. + auto BlockInsertion = CurFn->LexicalBlocks.insert({DILB, LexicalBlock()}); + if (!BlockInsertion.second) + return; + + // Create a lexical block containing the local variables and collect the + // the lexical block information for the children. + const InsnRange &Range = Ranges.front(); + assert(Range.first && Range.second); + LexicalBlock &Block = BlockInsertion.first->second; + Block.Begin = getLabelBeforeInsn(Range.first); + Block.End = getLabelAfterInsn(Range.second); + assert(Block.Begin && "missing label for scope begin"); + assert(Block.End && "missing label for scope end"); + Block.Name = DILB->getName(); + Block.Locals = std::move(Locals); + ParentBlocks.push_back(&Block); + collectLexicalBlockInfo(Scope.getChildren(), Block.Children, Block.Locals); +} + void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) { const Function &GV = MF->getFunction(); assert(FnDebugInfo.count(&GV)); - assert(CurFn == &FnDebugInfo[&GV]); + assert(CurFn == FnDebugInfo[&GV].get()); collectVariableInfo(GV.getSubprogram()); + // Build the lexical block structure to emit for this routine. + if (LexicalScope *CFS = LScopes.getCurrentFunctionScope()) + collectLexicalBlockInfo(*CFS, CurFn->ChildBlocks, CurFn->Locals); + + // Clear the scope and variable information from the map which will not be + // valid after we have finished processing this routine. This also prepares + // the map for the subsequent routine. + ScopeVariables.clear(); + // Don't emit anything if we don't have any line tables. - if (!CurFn->HaveLineInfo) { + // Thunks are compiler-generated and probably won't have source correlation. + if (!CurFn->HaveLineInfo && !GV.getSubprogram()->isThunk()) { FnDebugInfo.erase(&GV); CurFn = nullptr; return; @@ -2296,8 +2618,8 @@ void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) { void CodeViewDebug::beginInstruction(const MachineInstr *MI) { DebugHandlerBase::beginInstruction(MI); - // Ignore DBG_VALUE locations and function prologue. - if (!Asm || !CurFn || MI->isDebugValue() || + // Ignore DBG_VALUE and DBG_LABEL locations and function prologue. + if (!Asm || !CurFn || MI->isDebugInstr() || MI->getFlag(MachineInstr::FrameSetup)) return; @@ -2306,7 +2628,7 @@ void CodeViewDebug::beginInstruction(const MachineInstr *MI) { DebugLoc DL = MI->getDebugLoc(); if (!DL && MI->getParent() != PrevInstBB) { for (const auto &NextMI : *MI->getParent()) { - if (NextMI.isDebugValue()) + if (NextMI.isDebugInstr()) continue; DL = NextMI.getDebugLoc(); if (DL) @@ -2432,6 +2754,7 @@ void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, // FIXME: Thread local data, etc MCSymbol *DataBegin = MMI->getContext().createTempSymbol(), *DataEnd = MMI->getContext().createTempSymbol(); + const unsigned FixedLengthOfThisRecord = 12; OS.AddComment("Record length"); OS.emitAbsoluteSymbolDiff(DataEnd, DataBegin, 2); OS.EmitLabel(DataBegin); @@ -2459,6 +2782,6 @@ void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, OS.AddComment("Segment"); OS.EmitCOFFSectionIndex(GVSym); OS.AddComment("Name"); - emitNullTerminatedSymbolName(OS, DIGV->getName()); + emitNullTerminatedSymbolName(OS, DIGV->getName(), FixedLengthOfThisRecord); OS.EmitLabel(DataEnd); } diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/lib/CodeGen/AsmPrinter/CodeViewDebug.h index 69e93640d7ef..6a0da5f993d0 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -48,7 +48,7 @@ class MCStreamer; class MCSymbol; class MachineFunction; -/// \brief Collects and handles line tables information in a CodeView format. +/// Collects and handles line tables information in a CodeView format. class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { MCStreamer &OS; BumpPtrAllocator Allocator; @@ -107,9 +107,23 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { unsigned SiteFuncId = 0; }; + // Combines information from DILexicalBlock and LexicalScope. + struct LexicalBlock { + SmallVector<LocalVariable, 1> Locals; + SmallVector<LexicalBlock *, 1> Children; + const MCSymbol *Begin; + const MCSymbol *End; + StringRef Name; + }; + // For each function, store a vector of labels to its instructions, as well as // to the end of the function. struct FunctionInfo { + FunctionInfo() = default; + + // Uncopyable. + FunctionInfo(const FunctionInfo &FI) = delete; + /// Map from inlined call site to inlined instructions and child inlined /// call sites. Listed in program order. std::unordered_map<const DILocation *, InlineSite> InlineSites; @@ -119,6 +133,11 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { SmallVector<LocalVariable, 1> Locals; + std::unordered_map<const DILexicalBlockBase*, LexicalBlock> LexicalBlocks; + + // Lexical blocks containing local variables. + SmallVector<LexicalBlock *, 1> ChildBlocks; + std::vector<std::pair<MCSymbol *, MDNode *>> Annotations; const MCSymbol *Begin = nullptr; @@ -129,6 +148,12 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { }; FunctionInfo *CurFn = nullptr; + // Map used to seperate variables according to the lexical scope they belong + // in. This is populated by recordLocalVariable() before + // collectLexicalBlocks() separates the variables between the FunctionInfo + // and LexicalBlocks. + DenseMap<const LexicalScope *, SmallVector<LocalVariable, 1>> ScopeVariables; + /// The set of comdat .debug$S sections that we've seen so far. Each section /// must start with a magic version number that must only be emitted once. /// This set tracks which sections we've already opened. @@ -159,7 +184,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { /// Remember some debug info about each function. Keep it in a stable order to /// emit at the end of the TU. - MapVector<const Function *, FunctionInfo> FnDebugInfo; + MapVector<const Function *, std::unique_ptr<FunctionInfo>> FnDebugInfo; /// Map from full file path to .cv_file id. Full paths are built from DIFiles /// and are stored in FileToFilepathMap; @@ -200,7 +225,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { using FileToFilepathMapTy = std::map<const DIFile *, std::string>; FileToFilepathMapTy FileToFilepathMap; - StringRef getFullFilepath(const DIFile *S); + StringRef getFullFilepath(const DIFile *File); unsigned maybeRecordFile(const DIFile *F); @@ -214,7 +239,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { } /// Emit the magic version number at the start of a CodeView type or symbol - /// section. Appears at the front of every .debug$S or .debug$T section. + /// section. Appears at the front of every .debug$S or .debug$T or .debug$P + /// section. void emitCodeViewMagicVersion(); void emitTypeInformation(); @@ -225,6 +251,10 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void emitInlineeLinesSubsection(); + void emitDebugInfoForThunk(const Function *GV, + FunctionInfo &FI, + const MCSymbol *Fn); + void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI); void emitDebugInfoForGlobals(); @@ -253,9 +283,18 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void collectVariableInfoFromMFTable(DenseSet<InlinedVariable> &Processed); + // Construct the lexical block tree for a routine, pruning emptpy lexical + // scopes, and populate it with local variables. + void collectLexicalBlockInfo(SmallVectorImpl<LexicalScope *> &Scopes, + SmallVectorImpl<LexicalBlock *> &Blocks, + SmallVectorImpl<LocalVariable> &Locals); + void collectLexicalBlockInfo(LexicalScope &Scope, + SmallVectorImpl<LexicalBlock *> &ParentBlocks, + SmallVectorImpl<LocalVariable> &ParentLocals); + /// Records information about a local variable in the appropriate scope. In /// particular, locals from inlined code live inside the inlining site. - void recordLocalVariable(LocalVariable &&Var, const DILocation *Loc); + void recordLocalVariable(LocalVariable &&Var, const LexicalScope *LS); /// Emits local variables in the appropriate order. void emitLocalVariableList(ArrayRef<LocalVariable> Locals); @@ -263,6 +302,13 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { /// Emits an S_LOCAL record and its associated defined ranges. void emitLocalVariable(const LocalVariable &Var); + /// Emits a sequence of lexical block scopes and their children. + void emitLexicalBlockList(ArrayRef<LexicalBlock *> Blocks, + const FunctionInfo& FI); + + /// Emit a lexical block scope and its children. + void emitLexicalBlock(const LexicalBlock &Block, const FunctionInfo& FI); + /// Translates the DIType to codeview if necessary and returns a type index /// for it. codeview::TypeIndex getTypeIndex(DITypeRef TypeRef, @@ -279,12 +325,18 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void addToUDTs(const DIType *Ty); + void addUDTSrcLine(const DIType *Ty, codeview::TypeIndex TI); + codeview::TypeIndex lowerType(const DIType *Ty, const DIType *ClassTy); codeview::TypeIndex lowerTypeAlias(const DIDerivedType *Ty); codeview::TypeIndex lowerTypeArray(const DICompositeType *Ty); codeview::TypeIndex lowerTypeBasic(const DIBasicType *Ty); - codeview::TypeIndex lowerTypePointer(const DIDerivedType *Ty); - codeview::TypeIndex lowerTypeMemberPointer(const DIDerivedType *Ty); + codeview::TypeIndex lowerTypePointer( + const DIDerivedType *Ty, + codeview::PointerOptions PO = codeview::PointerOptions::None); + codeview::TypeIndex lowerTypeMemberPointer( + const DIDerivedType *Ty, + codeview::PointerOptions PO = codeview::PointerOptions::None); codeview::TypeIndex lowerTypeModifier(const DIDerivedType *Ty); codeview::TypeIndex lowerTypeFunction(const DISubroutineType *Ty); codeview::TypeIndex lowerTypeVFTableShape(const DIDerivedType *Ty); @@ -327,21 +379,21 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { unsigned getPointerSizeInBytes(); protected: - /// \brief Gather pre-function debug information. + /// Gather pre-function debug information. void beginFunctionImpl(const MachineFunction *MF) override; - /// \brief Gather post-function debug information. + /// Gather post-function debug information. void endFunctionImpl(const MachineFunction *) override; public: - CodeViewDebug(AsmPrinter *Asm); + CodeViewDebug(AsmPrinter *AP); void setSymbolSize(const MCSymbol *, uint64_t) override {} - /// \brief Emit the COFF section that holds the line table information. + /// Emit the COFF section that holds the line table information. void endModule() override; - /// \brief Process beginning of an instruction. + /// Process beginning of an instruction. void beginInstruction(const MachineInstr *MI) override; }; diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp index b3148db30cd6..570424a79c81 100644 --- a/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/lib/CodeGen/AsmPrinter/DIE.cpp @@ -17,6 +17,7 @@ #include "DwarfUnit.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Config/llvm-config.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" @@ -86,8 +87,9 @@ void DIEAbbrev::Emit(const AsmPrinter *AP) const { // easily, which helps track down where it came from. if (!dwarf::isValidFormForVersion(AttrData.getForm(), AP->getDwarfVersion())) { - DEBUG(dbgs() << "Invalid form " << format("0x%x", AttrData.getForm()) - << " for DWARF version " << AP->getDwarfVersion() << "\n"); + LLVM_DEBUG(dbgs() << "Invalid form " << format("0x%x", AttrData.getForm()) + << " for DWARF version " << AP->getDwarfVersion() + << "\n"); llvm_unreachable("Invalid form for specified DWARF version"); } #endif @@ -388,6 +390,7 @@ void DIEInteger::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { case dwarf::DW_FORM_data2: case dwarf::DW_FORM_strx2: case dwarf::DW_FORM_addrx2: + case dwarf::DW_FORM_strx3: case dwarf::DW_FORM_strp: case dwarf::DW_FORM_ref4: case dwarf::DW_FORM_data4: @@ -410,6 +413,7 @@ void DIEInteger::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { case dwarf::DW_FORM_GNU_str_index: case dwarf::DW_FORM_GNU_addr_index: case dwarf::DW_FORM_ref_udata: + case dwarf::DW_FORM_strx: case dwarf::DW_FORM_udata: Asm->EmitULEB128(Integer); return; @@ -423,58 +427,23 @@ void DIEInteger::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { /// SizeOf - Determine size of integer value in bytes. /// unsigned DIEInteger::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { + dwarf::FormParams Params = {0, 0, dwarf::DWARF32}; + if (AP) + Params = {AP->getDwarfVersion(), uint8_t(AP->getPointerSize()), + AP->OutStreamer->getContext().getDwarfFormat()}; + + if (Optional<uint8_t> FixedSize = dwarf::getFixedFormByteSize(Form, Params)) + return *FixedSize; + switch (Form) { - case dwarf::DW_FORM_implicit_const: - case dwarf::DW_FORM_flag_present: - return 0; - case dwarf::DW_FORM_flag: - case dwarf::DW_FORM_ref1: - case dwarf::DW_FORM_data1: - case dwarf::DW_FORM_strx1: - case dwarf::DW_FORM_addrx1: - return sizeof(int8_t); - case dwarf::DW_FORM_ref2: - case dwarf::DW_FORM_data2: - case dwarf::DW_FORM_strx2: - case dwarf::DW_FORM_addrx2: - return sizeof(int16_t); - case dwarf::DW_FORM_ref4: - case dwarf::DW_FORM_data4: - case dwarf::DW_FORM_ref_sup4: - case dwarf::DW_FORM_strx4: - case dwarf::DW_FORM_addrx4: - return sizeof(int32_t); - case dwarf::DW_FORM_ref8: - case dwarf::DW_FORM_ref_sig8: - case dwarf::DW_FORM_data8: - case dwarf::DW_FORM_ref_sup8: - return sizeof(int64_t); - case dwarf::DW_FORM_ref_addr: - if (AP->getDwarfVersion() == 2) - return AP->getPointerSize(); - LLVM_FALLTHROUGH; - case dwarf::DW_FORM_strp: - case dwarf::DW_FORM_GNU_ref_alt: - case dwarf::DW_FORM_GNU_strp_alt: - case dwarf::DW_FORM_line_strp: - case dwarf::DW_FORM_sec_offset: - case dwarf::DW_FORM_strp_sup: - switch (AP->OutStreamer->getContext().getDwarfFormat()) { - case dwarf::DWARF32: - return 4; - case dwarf::DWARF64: - return 8; - } - llvm_unreachable("Invalid DWARF format"); case dwarf::DW_FORM_GNU_str_index: case dwarf::DW_FORM_GNU_addr_index: case dwarf::DW_FORM_ref_udata: + case dwarf::DW_FORM_strx: case dwarf::DW_FORM_udata: return getULEB128Size(Integer); case dwarf::DW_FORM_sdata: return getSLEB128Size(Integer); - case dwarf::DW_FORM_addr: - return AP->getPointerSize(); default: llvm_unreachable("DIE Value form not supported yet"); } } @@ -564,44 +533,46 @@ void DIEDelta::print(raw_ostream &O) const { /// EmitValue - Emit string value. /// void DIEString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { - assert( - (Form == dwarf::DW_FORM_strp || Form == dwarf::DW_FORM_GNU_str_index) && - "Expected valid string form"); - // Index of string in symbol table. - if (Form == dwarf::DW_FORM_GNU_str_index) { + switch (Form) { + case dwarf::DW_FORM_GNU_str_index: + case dwarf::DW_FORM_strx: + case dwarf::DW_FORM_strx1: + case dwarf::DW_FORM_strx2: + case dwarf::DW_FORM_strx3: + case dwarf::DW_FORM_strx4: DIEInteger(S.getIndex()).EmitValue(AP, Form); return; - } - - // Relocatable symbol. - assert(Form == dwarf::DW_FORM_strp); - if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) { - DIELabel(S.getSymbol()).EmitValue(AP, Form); + case dwarf::DW_FORM_strp: + if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) + DIELabel(S.getSymbol()).EmitValue(AP, Form); + else + DIEInteger(S.getOffset()).EmitValue(AP, Form); return; + default: + llvm_unreachable("Expected valid string form"); } - - // Offset into symbol table. - DIEInteger(S.getOffset()).EmitValue(AP, Form); } /// SizeOf - Determine size of delta value in bytes. /// unsigned DIEString::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { - assert( - (Form == dwarf::DW_FORM_strp || Form == dwarf::DW_FORM_GNU_str_index) && - "Expected valid string form"); - // Index of string in symbol table. - if (Form == dwarf::DW_FORM_GNU_str_index) + switch (Form) { + case dwarf::DW_FORM_GNU_str_index: + case dwarf::DW_FORM_strx: + case dwarf::DW_FORM_strx1: + case dwarf::DW_FORM_strx2: + case dwarf::DW_FORM_strx3: + case dwarf::DW_FORM_strx4: return DIEInteger(S.getIndex()).SizeOf(AP, Form); - - // Relocatable symbol. - if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) - return DIELabel(S.getSymbol()).SizeOf(AP, Form); - - // Offset into symbol table. - return DIEInteger(S.getOffset()).SizeOf(AP, Form); + case dwarf::DW_FORM_strp: + if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) + return DIELabel(S.getSymbol()).SizeOf(AP, Form); + return DIEInteger(S.getOffset()).SizeOf(AP, Form); + default: + llvm_unreachable("Expected valid string form"); + } } LLVM_DUMP_METHOD @@ -615,8 +586,8 @@ void DIEString::print(raw_ostream &O) const { void DIEInlineString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { if (Form == dwarf::DW_FORM_string) { for (char ch : S) - AP->EmitInt8(ch); - AP->EmitInt8(0); + AP->emitInt8(ch); + AP->emitInt8(0); return; } llvm_unreachable("Expected valid string form"); @@ -722,9 +693,9 @@ unsigned DIELoc::ComputeSize(const AsmPrinter *AP) const { void DIELoc::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { switch (Form) { default: llvm_unreachable("Improper form for block"); - case dwarf::DW_FORM_block1: Asm->EmitInt8(Size); break; - case dwarf::DW_FORM_block2: Asm->EmitInt16(Size); break; - case dwarf::DW_FORM_block4: Asm->EmitInt32(Size); break; + case dwarf::DW_FORM_block1: Asm->emitInt8(Size); break; + case dwarf::DW_FORM_block2: Asm->emitInt16(Size); break; + case dwarf::DW_FORM_block4: Asm->emitInt32(Size); break; case dwarf::DW_FORM_block: case dwarf::DW_FORM_exprloc: Asm->EmitULEB128(Size); break; @@ -773,10 +744,11 @@ unsigned DIEBlock::ComputeSize(const AsmPrinter *AP) const { void DIEBlock::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { switch (Form) { default: llvm_unreachable("Improper form for block"); - case dwarf::DW_FORM_block1: Asm->EmitInt8(Size); break; - case dwarf::DW_FORM_block2: Asm->EmitInt16(Size); break; - case dwarf::DW_FORM_block4: Asm->EmitInt32(Size); break; + case dwarf::DW_FORM_block1: Asm->emitInt8(Size); break; + case dwarf::DW_FORM_block2: Asm->emitInt16(Size); break; + case dwarf::DW_FORM_block4: Asm->emitInt32(Size); break; case dwarf::DW_FORM_block: Asm->EmitULEB128(Size); break; + case dwarf::DW_FORM_string: break; case dwarf::DW_FORM_data16: break; } diff --git a/lib/CodeGen/AsmPrinter/DIEHash.cpp b/lib/CodeGen/AsmPrinter/DIEHash.cpp index 15ade3c96dfe..b8f1202494d7 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -28,7 +28,7 @@ using namespace llvm; #define DEBUG_TYPE "dwarfdebug" -/// \brief Grabs the string in whichever attribute is passed in and returns +/// Grabs the string in whichever attribute is passed in and returns /// a reference to it. static StringRef getDIEStringAttr(const DIE &Die, uint16_t Attr) { // Iterate through all the attributes until we find the one we're @@ -40,10 +40,10 @@ static StringRef getDIEStringAttr(const DIE &Die, uint16_t Attr) { return StringRef(""); } -/// \brief Adds the string in \p Str to the hash. This also hashes +/// Adds the string in \p Str to the hash. This also hashes /// a trailing NULL with the string. void DIEHash::addString(StringRef Str) { - DEBUG(dbgs() << "Adding string " << Str << " to hash.\n"); + LLVM_DEBUG(dbgs() << "Adding string " << Str << " to hash.\n"); Hash.update(Str); Hash.update(makeArrayRef((uint8_t)'\0')); } @@ -51,9 +51,9 @@ void DIEHash::addString(StringRef Str) { // FIXME: The LEB128 routines are copied and only slightly modified out of // LEB128.h. -/// \brief Adds the unsigned in \p Value to the hash encoded as a ULEB128. +/// Adds the unsigned in \p Value to the hash encoded as a ULEB128. void DIEHash::addULEB128(uint64_t Value) { - DEBUG(dbgs() << "Adding ULEB128 " << Value << " to hash.\n"); + LLVM_DEBUG(dbgs() << "Adding ULEB128 " << Value << " to hash.\n"); do { uint8_t Byte = Value & 0x7f; Value >>= 7; @@ -64,7 +64,7 @@ void DIEHash::addULEB128(uint64_t Value) { } void DIEHash::addSLEB128(int64_t Value) { - DEBUG(dbgs() << "Adding ULEB128 " << Value << " to hash.\n"); + LLVM_DEBUG(dbgs() << "Adding ULEB128 " << Value << " to hash.\n"); bool More; do { uint8_t Byte = Value & 0x7f; @@ -77,10 +77,10 @@ void DIEHash::addSLEB128(int64_t Value) { } while (More); } -/// \brief Including \p Parent adds the context of Parent to the hash.. +/// Including \p Parent adds the context of Parent to the hash.. void DIEHash::addParentContext(const DIE &Parent) { - DEBUG(dbgs() << "Adding parent context to hash...\n"); + LLVM_DEBUG(dbgs() << "Adding parent context to hash...\n"); // [7.27.2] For each surrounding type or namespace beginning with the // outermost such construct... @@ -108,7 +108,7 @@ void DIEHash::addParentContext(const DIE &Parent) { // ... Then the name, taken from the DW_AT_name attribute. StringRef Name = getDIEStringAttr(Die, dwarf::DW_AT_name); - DEBUG(dbgs() << "... adding context: " << Name << "\n"); + LLVM_DEBUG(dbgs() << "... adding context: " << Name << "\n"); if (!Name.empty()) addString(Name); } @@ -118,9 +118,9 @@ void DIEHash::addParentContext(const DIE &Parent) { void DIEHash::collectAttributes(const DIE &Die, DIEAttrs &Attrs) { for (const auto &V : Die.values()) { - DEBUG(dbgs() << "Attribute: " - << dwarf::AttributeString(V.getAttribute()) - << " added.\n"); + LLVM_DEBUG(dbgs() << "Attribute: " + << dwarf::AttributeString(V.getAttribute()) + << " added.\n"); switch (V.getAttribute()) { #define HANDLE_DIE_HASH_ATTR(NAME) \ case dwarf::NAME: \ diff --git a/lib/CodeGen/AsmPrinter/DIEHash.h b/lib/CodeGen/AsmPrinter/DIEHash.h index 29337ae38a99..dae517ab2c29 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.h +++ b/lib/CodeGen/AsmPrinter/DIEHash.h @@ -23,7 +23,7 @@ namespace llvm { class AsmPrinter; class CompileUnit; -/// \brief An object containing the capability of hashing and adding hash +/// An object containing the capability of hashing and adding hash /// attributes onto a DIE. class DIEHash { // Collection of all attributes used in hashing a particular DIE. @@ -35,66 +35,66 @@ class DIEHash { public: DIEHash(AsmPrinter *A = nullptr) : AP(A) {} - /// \brief Computes the CU signature. + /// Computes the CU signature. uint64_t computeCUSignature(StringRef DWOName, const DIE &Die); - /// \brief Computes the type signature. + /// Computes the type signature. uint64_t computeTypeSignature(const DIE &Die); // Helper routines to process parts of a DIE. private: - /// \brief Adds the parent context of \param Die to the hash. - void addParentContext(const DIE &Die); + /// Adds the parent context of \param Parent to the hash. + void addParentContext(const DIE &Parent); - /// \brief Adds the attributes of \param Die to the hash. + /// Adds the attributes of \param Die to the hash. void addAttributes(const DIE &Die); - /// \brief Computes the full DWARF4 7.27 hash of the DIE. + /// Computes the full DWARF4 7.27 hash of the DIE. void computeHash(const DIE &Die); // Routines that add DIEValues to the hash. public: - /// \brief Adds \param Value to the hash. + /// Adds \param Value to the hash. void update(uint8_t Value) { Hash.update(Value); } - /// \brief Encodes and adds \param Value to the hash as a ULEB128. + /// Encodes and adds \param Value to the hash as a ULEB128. void addULEB128(uint64_t Value); - /// \brief Encodes and adds \param Value to the hash as a SLEB128. + /// Encodes and adds \param Value to the hash as a SLEB128. void addSLEB128(int64_t Value); private: - /// \brief Adds \param Str to the hash and includes a NULL byte. + /// Adds \param Str to the hash and includes a NULL byte. void addString(StringRef Str); - /// \brief Collects the attributes of DIE \param Die into the \param Attrs + /// Collects the attributes of DIE \param Die into the \param Attrs /// structure. void collectAttributes(const DIE &Die, DIEAttrs &Attrs); - /// \brief Hashes the attributes in \param Attrs in order. + /// Hashes the attributes in \param Attrs in order. void hashAttributes(const DIEAttrs &Attrs, dwarf::Tag Tag); - /// \brief Hashes the data in a block like DIEValue, e.g. DW_FORM_block or + /// Hashes the data in a block like DIEValue, e.g. DW_FORM_block or /// DW_FORM_exprloc. void hashBlockData(const DIE::const_value_range &Values); - /// \brief Hashes the contents pointed to in the .debug_loc section. + /// Hashes the contents pointed to in the .debug_loc section. void hashLocList(const DIELocList &LocList); - /// \brief Hashes an individual attribute. + /// Hashes an individual attribute. void hashAttribute(const DIEValue &Value, dwarf::Tag Tag); - /// \brief Hashes an attribute that refers to another DIE. + /// Hashes an attribute that refers to another DIE. void hashDIEEntry(dwarf::Attribute Attribute, dwarf::Tag Tag, const DIE &Entry); - /// \brief Hashes a reference to a named type in such a way that is + /// Hashes a reference to a named type in such a way that is /// independent of whether that type is described by a declaration or a /// definition. void hashShallowTypeReference(dwarf::Attribute Attribute, const DIE &Entry, StringRef Name); - /// \brief Hashes a reference to a previously referenced type DIE. + /// Hashes a reference to a previously referenced type DIE. void hashRepeatedTypeReference(dwarf::Attribute Attribute, unsigned DieNumber); diff --git a/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp b/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp index 856758c8e4f6..25518a339c61 100644 --- a/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ b/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -31,7 +31,7 @@ using namespace llvm; #define DEBUG_TYPE "dwarfdebug" -// \brief If @MI is a DBG_VALUE with debug value described by a +// If @MI is a DBG_VALUE with debug value described by a // defined register, returns the number of this register. // In the other case, returns 0. static unsigned isDescribedByReg(const MachineInstr &MI) { @@ -50,8 +50,8 @@ void DbgValueHistoryMap::startInstrRange(InlinedVariable Var, auto &Ranges = VarInstrRanges[Var]; if (!Ranges.empty() && Ranges.back().second == nullptr && Ranges.back().first->isIdenticalTo(MI)) { - DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" - << "\t" << Ranges.back().first << "\t" << MI << "\n"); + LLVM_DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" + << "\t" << Ranges.back().first << "\t" << MI << "\n"); return; } Ranges.push_back(std::make_pair(&MI, nullptr)); @@ -86,7 +86,7 @@ using RegDescribedVarsMap = std::map<unsigned, SmallVector<InlinedVariable, 1>>; } // end anonymous namespace -// \brief Claim that @Var is not described by @RegNo anymore. +// Claim that @Var is not described by @RegNo anymore. static void dropRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, InlinedVariable Var) { const auto &I = RegVars.find(RegNo); @@ -100,7 +100,7 @@ static void dropRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, RegVars.erase(I); } -// \brief Claim that @Var is now described by @RegNo. +// Claim that @Var is now described by @RegNo. static void addRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, InlinedVariable Var) { assert(RegNo != 0U); @@ -109,7 +109,7 @@ static void addRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, VarSet.push_back(Var); } -// \brief Terminate the location range for variables described by register at +// Terminate the location range for variables described by register at // @I by inserting @ClobberingInstr to their history. static void clobberRegisterUses(RegDescribedVarsMap &RegVars, RegDescribedVarsMap::iterator I, @@ -122,7 +122,7 @@ static void clobberRegisterUses(RegDescribedVarsMap &RegVars, RegVars.erase(I); } -// \brief Terminate the location range for variables described by register +// Terminate the location range for variables described by register // @RegNo by inserting @ClobberingInstr to their history. static void clobberRegisterUses(RegDescribedVarsMap &RegVars, unsigned RegNo, DbgValueHistoryMap &HistMap, @@ -133,7 +133,7 @@ static void clobberRegisterUses(RegDescribedVarsMap &RegVars, unsigned RegNo, clobberRegisterUses(RegVars, I, HistMap, ClobberingInstr); } -// \brief Returns the first instruction in @MBB which corresponds to +// Returns the first instruction in @MBB which corresponds to // the function epilogue, or nullptr if @MBB doesn't contain an epilogue. static const MachineInstr *getFirstEpilogueInst(const MachineBasicBlock &MBB) { auto LastMI = MBB.getLastNonDebugInstr(); @@ -155,7 +155,7 @@ static const MachineInstr *getFirstEpilogueInst(const MachineBasicBlock &MBB) { return &*MBB.begin(); } -// \brief Collect registers that are modified in the function body (their +// Collect registers that are modified in the function body (their // contents is changed outside of the prologue and epilogue). static void collectChangingRegs(const MachineFunction *MF, const TargetRegisterInfo *TRI, @@ -198,7 +198,7 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF, RegDescribedVarsMap RegVars; for (const auto &MBB : *MF) { for (const auto &MI : MBB) { - if (!MI.isDebugValue()) { + if (!MI.isDebugInstr()) { // Not a DBG_VALUE instruction. It may clobber registers which describe // some variables. for (const MachineOperand &MO : MI.operands()) { @@ -234,6 +234,10 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF, continue; } + // Skip DBG_LABEL instructions. + if (MI.isDebugLabel()) + continue; + assert(MI.getNumOperands() > 1 && "Invalid DBG_VALUE instruction!"); // Use the base variable (without any DW_OP_piece expressions) // as index into History. The full variables including the @@ -265,3 +269,33 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF, } } } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void DbgValueHistoryMap::dump() const { + dbgs() << "DbgValueHistoryMap:\n"; + for (const auto &VarRangePair : *this) { + const InlinedVariable &Var = VarRangePair.first; + const InstrRanges &Ranges = VarRangePair.second; + + const DILocalVariable *LocalVar = Var.first; + const DILocation *Location = Var.second; + + dbgs() << " - " << LocalVar->getName() << " at "; + + if (Location) + dbgs() << Location->getFilename() << ":" << Location->getLine() << ":" + << Location->getColumn(); + else + dbgs() << "<unknown location>"; + + dbgs() << " --\n"; + + for (const InstrRange &Range : Ranges) { + dbgs() << " Begin: " << *Range.first; + if (Range.second) + dbgs() << " End : " << *Range.second; + dbgs() << "\n"; + } + } +} +#endif diff --git a/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h b/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h index a7b0562e8102..a262cb38b175 100644 --- a/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h +++ b/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h @@ -52,6 +52,10 @@ public: void clear() { VarInstrRanges.clear(); } InstrRangesMap::const_iterator begin() const { return VarInstrRanges.begin(); } InstrRangesMap::const_iterator end() const { return VarInstrRanges.end(); } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const; +#endif }; void calculateDbgValueHistory(const MachineFunction *MF, diff --git a/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp b/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp index d94b0e5c2118..82e14dc13cb1 100644 --- a/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ b/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -25,6 +25,8 @@ using namespace llvm; +#define DEBUG_TYPE "dwarfdebug" + Optional<DbgVariableLocation> DbgVariableLocation::extractFromMachineInstruction( const MachineInstr &Instruction) { @@ -123,29 +125,6 @@ MCSymbol *DebugHandlerBase::getLabelAfterInsn(const MachineInstr *MI) { return LabelsAfterInsn.lookup(MI); } -int DebugHandlerBase::fragmentCmp(const DIExpression *P1, - const DIExpression *P2) { - auto Fragment1 = *P1->getFragmentInfo(); - auto Fragment2 = *P2->getFragmentInfo(); - unsigned l1 = Fragment1.OffsetInBits; - unsigned l2 = Fragment2.OffsetInBits; - unsigned r1 = l1 + Fragment1.SizeInBits; - unsigned r2 = l2 + Fragment2.SizeInBits; - if (r1 <= l2) - return -1; - else if (r2 <= l1) - return 1; - else - return 0; -} - -bool DebugHandlerBase::fragmentsOverlap(const DIExpression *P1, - const DIExpression *P2) { - if (!P1->isFragment() || !P2->isFragment()) - return true; - return fragmentCmp(P1, P2) == 0; -} - /// If this type is derived from a base type then return base type size. uint64_t DebugHandlerBase::getBaseTypeSize(const DITypeRef TyRef) { DIType *Ty = TyRef.resolve(); @@ -163,7 +142,8 @@ uint64_t DebugHandlerBase::getBaseTypeSize(const DITypeRef TyRef) { DIType *BaseType = DDTy->getBaseType().resolve(); - assert(BaseType && "Unexpected invalid base type"); + if (!BaseType) + return 0; // If this is a derived type, go ahead and get the base type, unless it's a // reference then it's just the size of the field. Pointer types have no need @@ -212,6 +192,7 @@ void DebugHandlerBase::beginFunction(const MachineFunction *MF) { assert(DbgValues.empty() && "DbgValues map wasn't cleaned!"); calculateDbgValueHistory(MF, Asm->MF->getSubtarget().getRegisterInfo(), DbgValues); + LLVM_DEBUG(DbgValues.dump()); // Request labels for the full history. for (const auto &I : DbgValues) { @@ -231,8 +212,8 @@ void DebugHandlerBase::beginFunction(const MachineFunction *MF) { const DIExpression *Fragment = I->first->getDebugExpression(); if (std::all_of(Ranges.begin(), I, [&](DbgValueHistoryMap::InstrRange Pred) { - return !fragmentsOverlap( - Fragment, Pred.first->getDebugExpression()); + return !Fragment->fragmentsOverlap( + Pred.first->getDebugExpression()); })) LabelsBeforeInsn[I->first] = Asm->getFunctionBegin(); else diff --git a/lib/CodeGen/AsmPrinter/DebugHandlerBase.h b/lib/CodeGen/AsmPrinter/DebugHandlerBase.h index 245d70038de9..1ccefe32be75 100644 --- a/lib/CodeGen/AsmPrinter/DebugHandlerBase.h +++ b/lib/CodeGen/AsmPrinter/DebugHandlerBase.h @@ -122,14 +122,6 @@ public: /// Return Label immediately following the instruction. MCSymbol *getLabelAfterInsn(const MachineInstr *MI); - /// Determine the relative position of the fragments described by P1 and P2. - /// Returns -1 if P1 is entirely before P2, 0 if P1 and P2 overlap, 1 if P1 is - /// entirely after P2. - static int fragmentCmp(const DIExpression *P1, const DIExpression *P2); - - /// Determine whether two variable fragments overlap. - static bool fragmentsOverlap(const DIExpression *P1, const DIExpression *P2); - /// If this type is derived from a base type then return base type size. static uint64_t getBaseTypeSize(const DITypeRef TyRef); }; diff --git a/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/lib/CodeGen/AsmPrinter/DebugLocEntry.h index 3d6d8a76529c..ac49657b68fa 100644 --- a/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ b/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -11,6 +11,7 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H #include "DebugLocStream.h" +#include "llvm/Config/llvm-config.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/MC/MCSymbol.h" @@ -20,7 +21,7 @@ namespace llvm { class AsmPrinter; -/// \brief This struct describes location entries emitted in the .debug_loc +/// This struct describes location entries emitted in the .debug_loc /// section. class DebugLocEntry { /// Begin and end symbols for the address range that this location is valid. @@ -28,7 +29,7 @@ class DebugLocEntry { const MCSymbol *End; public: - /// \brief A single location or constant. + /// A single location or constant. struct Value { Value(const DIExpression *Expr, int64_t i) : Expression(Expr), EntryKind(E_Integer) { @@ -105,13 +106,13 @@ public: Values.push_back(std::move(Val)); } - /// \brief If this and Next are describing different pieces of the same + /// If this and Next are describing different pieces of the same /// variable, merge them by appending Next's values to the current /// list of values. /// Return true if the merge was successful. bool MergeValues(const DebugLocEntry &Next); - /// \brief Attempt to merge this DebugLocEntry with Next and return + /// Attempt to merge this DebugLocEntry with Next and return /// true if the merge was successful. Entries can be merged if they /// share the same Loc/Constant and if Next immediately follows this /// Entry. @@ -135,10 +136,10 @@ public: }) && "value must be a piece"); } - // \brief Sort the pieces by offset. + // Sort the pieces by offset. // Remove any duplicate entries by dropping all but the first. void sortUniqueValues() { - std::sort(Values.begin(), Values.end()); + llvm::sort(Values.begin(), Values.end()); Values.erase( std::unique( Values.begin(), Values.end(), [](const Value &A, const Value &B) { @@ -147,12 +148,12 @@ public: Values.end()); } - /// \brief Lower this entry into a DWARF expression. + /// Lower this entry into a DWARF expression. void finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List, const DIBasicType *BT); }; -/// \brief Compare two Values for equality. +/// Compare two Values for equality. inline bool operator==(const DebugLocEntry::Value &A, const DebugLocEntry::Value &B) { if (A.EntryKind != B.EntryKind) diff --git a/lib/CodeGen/AsmPrinter/DebugLocStream.h b/lib/CodeGen/AsmPrinter/DebugLocStream.h index 0c551dfff9cc..8dcf5cbc1889 100644 --- a/lib/CodeGen/AsmPrinter/DebugLocStream.h +++ b/lib/CodeGen/AsmPrinter/DebugLocStream.h @@ -22,7 +22,7 @@ class DwarfCompileUnit; class MachineInstr; class MCSymbol; -/// \brief Byte stream of .debug_loc entries. +/// Byte stream of .debug_loc entries. /// /// Stores a unified stream of .debug_loc entries. There's \a List for each /// variable/inlined-at pair, and an \a Entry for each \a DebugLocEntry. @@ -55,7 +55,7 @@ private: SmallString<256> DWARFBytes; SmallVector<std::string, 32> Comments; - /// \brief Only verbose textual output needs comments. This will be set to + /// Only verbose textual output needs comments. This will be set to /// true for that case, and false otherwise. bool GenerateComments; @@ -69,7 +69,7 @@ public: class EntryBuilder; private: - /// \brief Start a new .debug_loc entry list. + /// Start a new .debug_loc entry list. /// /// Start a new .debug_loc entry list. Return the new list's index so it can /// be retrieved later via \a getList(). @@ -89,7 +89,7 @@ private: /// \return false iff the list is deleted. bool finalizeList(AsmPrinter &Asm); - /// \brief Start a new .debug_loc entry. + /// Start a new .debug_loc entry. /// /// Until the next call, bytes added to the stream will be added to this /// entry. diff --git a/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp b/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp deleted file mode 100644 index c21b3d3451ad..000000000000 --- a/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp +++ /dev/null @@ -1,293 +0,0 @@ -//===- llvm/CodeGen/DwarfAccelTable.cpp - Dwarf Accelerator Tables --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains support for writing dwarf accelerator tables. -// -//===----------------------------------------------------------------------===// - -#include "DwarfAccelTable.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/DIE.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <iterator> -#include <limits> -#include <vector> - -using namespace llvm; - -// The length of the header data is always going to be 4 + 4 + 4*NumAtoms. -DwarfAccelTable::DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom> atomList) - : Header(8 + (atomList.size() * 4)), HeaderData(atomList), - Entries(Allocator) {} - -void DwarfAccelTable::AddName(DwarfStringPoolEntryRef Name, const DIE *die, - char Flags) { - assert(Data.empty() && "Already finalized!"); - // If the string is in the list already then add this die to the list - // otherwise add a new one. - DataArray &DIEs = Entries[Name.getString()]; - assert(!DIEs.Name || DIEs.Name == Name); - DIEs.Name = Name; - DIEs.Values.push_back(new (Allocator) HashDataContents(die, Flags)); -} - -void DwarfAccelTable::ComputeBucketCount() { - // First get the number of unique hashes. - std::vector<uint32_t> uniques(Data.size()); - for (size_t i = 0, e = Data.size(); i < e; ++i) - uniques[i] = Data[i]->HashValue; - array_pod_sort(uniques.begin(), uniques.end()); - std::vector<uint32_t>::iterator p = - std::unique(uniques.begin(), uniques.end()); - uint32_t num = std::distance(uniques.begin(), p); - - // Then compute the bucket size, minimum of 1 bucket. - if (num > 1024) - Header.bucket_count = num / 4; - else if (num > 16) - Header.bucket_count = num / 2; - else - Header.bucket_count = num > 0 ? num : 1; - - Header.hashes_count = num; -} - -// compareDIEs - comparison predicate that sorts DIEs by their offset. -static bool compareDIEs(const DwarfAccelTable::HashDataContents *A, - const DwarfAccelTable::HashDataContents *B) { - return A->Die->getOffset() < B->Die->getOffset(); -} - -void DwarfAccelTable::FinalizeTable(AsmPrinter *Asm, StringRef Prefix) { - // Create the individual hash data outputs. - Data.reserve(Entries.size()); - for (StringMap<DataArray>::iterator EI = Entries.begin(), EE = Entries.end(); - EI != EE; ++EI) { - - // Unique the entries. - std::stable_sort(EI->second.Values.begin(), EI->second.Values.end(), compareDIEs); - EI->second.Values.erase( - std::unique(EI->second.Values.begin(), EI->second.Values.end()), - EI->second.Values.end()); - - HashData *Entry = new (Allocator) HashData(EI->getKey(), EI->second); - Data.push_back(Entry); - } - - // Figure out how many buckets we need, then compute the bucket - // contents and the final ordering. We'll emit the hashes and offsets - // by doing a walk during the emission phase. We add temporary - // symbols to the data so that we can reference them during the offset - // later, we'll emit them when we emit the data. - ComputeBucketCount(); - - // Compute bucket contents and final ordering. - Buckets.resize(Header.bucket_count); - for (size_t i = 0, e = Data.size(); i < e; ++i) { - uint32_t bucket = Data[i]->HashValue % Header.bucket_count; - Buckets[bucket].push_back(Data[i]); - Data[i]->Sym = Asm->createTempSymbol(Prefix); - } - - // Sort the contents of the buckets by hash value so that hash - // collisions end up together. Stable sort makes testing easier and - // doesn't cost much more. - for (size_t i = 0; i < Buckets.size(); ++i) - std::stable_sort(Buckets[i].begin(), Buckets[i].end(), - [] (HashData *LHS, HashData *RHS) { - return LHS->HashValue < RHS->HashValue; - }); -} - -// Emits the header for the table via the AsmPrinter. -void DwarfAccelTable::EmitHeader(AsmPrinter *Asm) { - Asm->OutStreamer->AddComment("Header Magic"); - Asm->EmitInt32(Header.magic); - Asm->OutStreamer->AddComment("Header Version"); - Asm->EmitInt16(Header.version); - Asm->OutStreamer->AddComment("Header Hash Function"); - Asm->EmitInt16(Header.hash_function); - Asm->OutStreamer->AddComment("Header Bucket Count"); - Asm->EmitInt32(Header.bucket_count); - Asm->OutStreamer->AddComment("Header Hash Count"); - Asm->EmitInt32(Header.hashes_count); - Asm->OutStreamer->AddComment("Header Data Length"); - Asm->EmitInt32(Header.header_data_len); - Asm->OutStreamer->AddComment("HeaderData Die Offset Base"); - Asm->EmitInt32(HeaderData.die_offset_base); - Asm->OutStreamer->AddComment("HeaderData Atom Count"); - Asm->EmitInt32(HeaderData.Atoms.size()); - for (size_t i = 0; i < HeaderData.Atoms.size(); i++) { - Atom A = HeaderData.Atoms[i]; - Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.type)); - Asm->EmitInt16(A.type); - Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.form)); - Asm->EmitInt16(A.form); - } -} - -// Walk through and emit the buckets for the table. Each index is -// an offset into the list of hashes. -void DwarfAccelTable::EmitBuckets(AsmPrinter *Asm) { - unsigned index = 0; - for (size_t i = 0, e = Buckets.size(); i < e; ++i) { - Asm->OutStreamer->AddComment("Bucket " + Twine(i)); - if (!Buckets[i].empty()) - Asm->EmitInt32(index); - else - Asm->EmitInt32(std::numeric_limits<uint32_t>::max()); - // Buckets point in the list of hashes, not to the data. Do not - // increment the index multiple times in case of hash collisions. - uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); - for (auto *HD : Buckets[i]) { - uint32_t HashValue = HD->HashValue; - if (PrevHash != HashValue) - ++index; - PrevHash = HashValue; - } - } -} - -// Walk through the buckets and emit the individual hashes for each -// bucket. -void DwarfAccelTable::EmitHashes(AsmPrinter *Asm) { - uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); - for (size_t i = 0, e = Buckets.size(); i < e; ++i) { - for (HashList::const_iterator HI = Buckets[i].begin(), - HE = Buckets[i].end(); - HI != HE; ++HI) { - uint32_t HashValue = (*HI)->HashValue; - if (PrevHash == HashValue) - continue; - Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(i)); - Asm->EmitInt32(HashValue); - PrevHash = HashValue; - } - } -} - -// Walk through the buckets and emit the individual offsets for each -// element in each bucket. This is done via a symbol subtraction from the -// beginning of the section. The non-section symbol will be output later -// when we emit the actual data. -void DwarfAccelTable::emitOffsets(AsmPrinter *Asm, const MCSymbol *SecBegin) { - uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); - for (size_t i = 0, e = Buckets.size(); i < e; ++i) { - for (HashList::const_iterator HI = Buckets[i].begin(), - HE = Buckets[i].end(); - HI != HE; ++HI) { - uint32_t HashValue = (*HI)->HashValue; - if (PrevHash == HashValue) - continue; - PrevHash = HashValue; - Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i)); - MCContext &Context = Asm->OutStreamer->getContext(); - const MCExpr *Sub = MCBinaryExpr::createSub( - MCSymbolRefExpr::create((*HI)->Sym, Context), - MCSymbolRefExpr::create(SecBegin, Context), Context); - Asm->OutStreamer->EmitValue(Sub, sizeof(uint32_t)); - } - } -} - -// Walk through the buckets and emit the full data for each element in -// the bucket. For the string case emit the dies and the various offsets. -// Terminate each HashData bucket with 0. -void DwarfAccelTable::EmitData(AsmPrinter *Asm, DwarfDebug *D) { - for (size_t i = 0, e = Buckets.size(); i < e; ++i) { - uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); - for (HashList::const_iterator HI = Buckets[i].begin(), - HE = Buckets[i].end(); - HI != HE; ++HI) { - // Terminate the previous entry if there is no hash collision - // with the current one. - if (PrevHash != std::numeric_limits<uint64_t>::max() && - PrevHash != (*HI)->HashValue) - Asm->EmitInt32(0); - // Remember to emit the label for our offset. - Asm->OutStreamer->EmitLabel((*HI)->Sym); - Asm->OutStreamer->AddComment((*HI)->Str); - Asm->emitDwarfStringOffset((*HI)->Data.Name); - Asm->OutStreamer->AddComment("Num DIEs"); - Asm->EmitInt32((*HI)->Data.Values.size()); - for (HashDataContents *HD : (*HI)->Data.Values) { - // Emit the DIE offset - Asm->EmitInt32(HD->Die->getDebugSectionOffset()); - // If we have multiple Atoms emit that info too. - // FIXME: A bit of a hack, we either emit only one atom or all info. - if (HeaderData.Atoms.size() > 1) { - Asm->EmitInt16(HD->Die->getTag()); - Asm->EmitInt8(HD->Flags); - } - } - PrevHash = (*HI)->HashValue; - } - // Emit the final end marker for the bucket. - if (!Buckets[i].empty()) - Asm->EmitInt32(0); - } -} - -// Emit the entire data structure to the output file. -void DwarfAccelTable::emit(AsmPrinter *Asm, const MCSymbol *SecBegin, - DwarfDebug *D) { - // Emit the header. - EmitHeader(Asm); - - // Emit the buckets. - EmitBuckets(Asm); - - // Emit the hashes. - EmitHashes(Asm); - - // Emit the offsets. - emitOffsets(Asm, SecBegin); - - // Emit the hash data. - EmitData(Asm, D); -} - -#ifndef NDEBUG -void DwarfAccelTable::print(raw_ostream &OS) { - Header.print(OS); - HeaderData.print(OS); - - OS << "Entries: \n"; - for (StringMap<DataArray>::const_iterator EI = Entries.begin(), - EE = Entries.end(); - EI != EE; ++EI) { - OS << "Name: " << EI->getKeyData() << "\n"; - for (HashDataContents *HD : EI->second.Values) - HD->print(OS); - } - - OS << "Buckets and Hashes: \n"; - for (size_t i = 0, e = Buckets.size(); i < e; ++i) - for (HashList::const_iterator HI = Buckets[i].begin(), - HE = Buckets[i].end(); - HI != HE; ++HI) - (*HI)->print(OS); - - OS << "Data: \n"; - for (std::vector<HashData *>::const_iterator DI = Data.begin(), - DE = Data.end(); - DI != DE; ++DI) - (*DI)->print(OS); -} -#endif diff --git a/lib/CodeGen/AsmPrinter/DwarfAccelTable.h b/lib/CodeGen/AsmPrinter/DwarfAccelTable.h deleted file mode 100644 index f56199dc8e72..000000000000 --- a/lib/CodeGen/AsmPrinter/DwarfAccelTable.h +++ /dev/null @@ -1,261 +0,0 @@ -//==- llvm/CodeGen/DwarfAccelTable.h - Dwarf Accelerator Tables --*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains support for writing dwarf accelerator tables. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H -#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/CodeGen/DIE.h" -#include "llvm/CodeGen/DwarfStringPoolEntry.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <cstddef> -#include <cstdint> -#include <vector> - -// The dwarf accelerator tables are an indirect hash table optimized -// for null lookup rather than access to known data. They are output into -// an on-disk format that looks like this: -// -// .-------------. -// | HEADER | -// |-------------| -// | BUCKETS | -// |-------------| -// | HASHES | -// |-------------| -// | OFFSETS | -// |-------------| -// | DATA | -// `-------------' -// -// where the header contains a magic number, version, type of hash function, -// the number of buckets, total number of hashes, and room for a special -// struct of data and the length of that struct. -// -// The buckets contain an index (e.g. 6) into the hashes array. The hashes -// section contains all of the 32-bit hash values in contiguous memory, and -// the offsets contain the offset into the data area for the particular -// hash. -// -// For a lookup example, we could hash a function name and take it modulo the -// number of buckets giving us our bucket. From there we take the bucket value -// as an index into the hashes table and look at each successive hash as long -// as the hash value is still the same modulo result (bucket value) as earlier. -// If we have a match we look at that same entry in the offsets table and -// grab the offset in the data for our final match. - -namespace llvm { - -class AsmPrinter; -class DwarfDebug; - -class DwarfAccelTable { - // Helper function to compute the number of buckets needed based on - // the number of unique hashes. - void ComputeBucketCount(); - - struct TableHeader { - uint32_t magic = MagicHash; // 'HASH' magic value to allow endian detection - uint16_t version = 1; // Version number. - uint16_t hash_function = dwarf::DW_hash_function_djb; - // The hash function enumeration that was used. - uint32_t bucket_count = 0; // The number of buckets in this hash table. - uint32_t hashes_count = 0; // The total number of unique hash values - // and hash data offsets in this table. - uint32_t header_data_len; // The bytes to skip to get to the hash - // indexes (buckets) for correct alignment. - // Also written to disk is the implementation specific header data. - - static const uint32_t MagicHash = 0x48415348; - - TableHeader(uint32_t data_len) : header_data_len(data_len) {} - -#ifndef NDEBUG - void print(raw_ostream &OS) { - OS << "Magic: " << format("0x%x", magic) << "\n" - << "Version: " << version << "\n" - << "Hash Function: " << hash_function << "\n" - << "Bucket Count: " << bucket_count << "\n" - << "Header Data Length: " << header_data_len << "\n"; - } - - void dump() { print(dbgs()); } -#endif - }; - -public: - // The HeaderData describes the form of each set of data. In general this - // is as a list of atoms (atom_count) where each atom contains a type - // (AtomType type) of data, and an encoding form (form). In the case of - // data that is referenced via DW_FORM_ref_* the die_offset_base is - // used to describe the offset for all forms in the list of atoms. - // This also serves as a public interface of sorts. - // When written to disk this will have the form: - // - // uint32_t die_offset_base - // uint32_t atom_count - // atom_count Atoms - - // Make these public so that they can be used as a general interface to - // the class. - struct Atom { - uint16_t type; // enum AtomType - uint16_t form; // DWARF DW_FORM_ defines - - constexpr Atom(uint16_t type, uint16_t form) : type(type), form(form) {} - -#ifndef NDEBUG - void print(raw_ostream &OS) { - OS << "Type: " << dwarf::AtomTypeString(type) << "\n" - << "Form: " << dwarf::FormEncodingString(form) << "\n"; - } - - void dump() { print(dbgs()); } -#endif - }; - -private: - struct TableHeaderData { - uint32_t die_offset_base; - SmallVector<Atom, 3> Atoms; - - TableHeaderData(ArrayRef<Atom> AtomList, uint32_t offset = 0) - : die_offset_base(offset), Atoms(AtomList.begin(), AtomList.end()) {} - -#ifndef NDEBUG - void print(raw_ostream &OS) { - OS << "die_offset_base: " << die_offset_base << "\n"; - for (size_t i = 0; i < Atoms.size(); i++) - Atoms[i].print(OS); - } - - void dump() { print(dbgs()); } -#endif - }; - - // The data itself consists of a str_offset, a count of the DIEs in the - // hash and the offsets to the DIEs themselves. - // On disk each data section is ended with a 0 KeyType as the end of the - // hash chain. - // On output this looks like: - // uint32_t str_offset - // uint32_t hash_data_count - // HashData[hash_data_count] -public: - struct HashDataContents { - const DIE *Die; // Offsets - char Flags; // Specific flags to output - - HashDataContents(const DIE *D, char Flags) : Die(D), Flags(Flags) {} - -#ifndef NDEBUG - void print(raw_ostream &OS) const { - OS << " Offset: " << Die->getOffset() << "\n" - << " Tag: " << dwarf::TagString(Die->getTag()) << "\n" - << " Flags: " << Flags << "\n"; - } -#endif - }; - -private: - // String Data - struct DataArray { - DwarfStringPoolEntryRef Name; - std::vector<HashDataContents *> Values; - }; - - friend struct HashData; - - struct HashData { - StringRef Str; - uint32_t HashValue; - MCSymbol *Sym; - DwarfAccelTable::DataArray &Data; // offsets - - HashData(StringRef S, DwarfAccelTable::DataArray &Data) - : Str(S), Data(Data) { - HashValue = dwarf::djbHash(S); - } - -#ifndef NDEBUG - void print(raw_ostream &OS) { - OS << "Name: " << Str << "\n"; - OS << " Hash Value: " << format("0x%x", HashValue) << "\n"; - OS << " Symbol: "; - if (Sym) - OS << *Sym; - else - OS << "<none>"; - OS << "\n"; - for (HashDataContents *C : Data.Values) { - OS << " Offset: " << C->Die->getOffset() << "\n"; - OS << " Tag: " << dwarf::TagString(C->Die->getTag()) << "\n"; - OS << " Flags: " << C->Flags << "\n"; - } - } - - void dump() { print(dbgs()); } -#endif - }; - - // Internal Functions - void EmitHeader(AsmPrinter *); - void EmitBuckets(AsmPrinter *); - void EmitHashes(AsmPrinter *); - void emitOffsets(AsmPrinter *, const MCSymbol *); - void EmitData(AsmPrinter *, DwarfDebug *D); - - // Allocator for HashData and HashDataContents. - BumpPtrAllocator Allocator; - - // Output Variables - TableHeader Header; - TableHeaderData HeaderData; - std::vector<HashData *> Data; - - using StringEntries = StringMap<DataArray, BumpPtrAllocator &>; - - StringEntries Entries; - - // Buckets/Hashes/Offsets - using HashList = std::vector<HashData *>; - using BucketList = std::vector<HashList>; - BucketList Buckets; - HashList Hashes; - - // Public Implementation -public: - DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom>); - DwarfAccelTable(const DwarfAccelTable &) = delete; - DwarfAccelTable &operator=(const DwarfAccelTable &) = delete; - - void AddName(DwarfStringPoolEntryRef Name, const DIE *Die, char Flags = 0); - void FinalizeTable(AsmPrinter *, StringRef); - void emit(AsmPrinter *, const MCSymbol *, DwarfDebug *); -#ifndef NDEBUG - void print(raw_ostream &OS); - void dump() { print(dbgs()); } -#endif -}; - -} // end namespace llvm - -#endif // LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H diff --git a/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp index cbb4c48b4d88..1990456cc555 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -17,7 +17,6 @@ #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" @@ -30,6 +29,7 @@ #include "llvm/MC/MachineLocation.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index c8cd8eb8ffd3..32271a0ef24a 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -28,7 +28,6 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/TargetFrameLowering.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" @@ -40,6 +39,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MachineLocation.h" #include "llvm/Support/Casting.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include <algorithm> @@ -94,16 +94,18 @@ void DwarfCompileUnit::addLocalLabelAddress(DIE &Die, DIEInteger(0)); } -unsigned DwarfCompileUnit::getOrCreateSourceID(StringRef FileName, - StringRef DirName) { +unsigned DwarfCompileUnit::getOrCreateSourceID(const DIFile *File) { // If we print assembly, we can't separate .file entries according to // compile units. Thus all files will belong to the default compile unit. // FIXME: add a better feature test than hasRawTextSupport. Even better, // extend .file to support this. + unsigned CUID = Asm->OutStreamer->hasRawTextSupport() ? 0 : getUniqueID(); + if (!File) + return Asm->OutStreamer->EmitDwarfFileDirective(0, "", "", nullptr, None, CUID); return Asm->OutStreamer->EmitDwarfFileDirective( - 0, DirName, FileName, - Asm->OutStreamer->hasRawTextSupport() ? 0 : getUniqueID()); + 0, File->getDirectory(), File->getFilename(), getMD5AsBytes(File), + File->getSource(), CUID); } DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( @@ -190,10 +192,13 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( DwarfExpr = llvm::make_unique<DIEDwarfExpression>(*Asm, *this, *Loc); } + if (Expr) + DwarfExpr->addFragmentOffset(Expr); + if (Global) { const MCSymbol *Sym = Asm->getSymbol(Global); if (Global->isThreadLocal()) { - if (Asm->TM.Options.EmulatedTLS) { + if (Asm->TM.useEmulatedTLS()) { // TODO: add debug info for emulated thread local mode. } else { // FIXME: Make this work with -gsplit-dwarf. @@ -225,10 +230,13 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( addOpAddress(*Loc, Sym); } } - if (Expr) { - DwarfExpr->addFragmentOffset(Expr); - DwarfExpr->addExpression(Expr); - } + // Global variables attached to symbols are memory locations. + // It would be better if this were unconditional, but malformed input that + // mixes non-fragments and fragments for the same variable is too expensive + // to detect in the verifier. + if (DwarfExpr->isUnknownLocation()) + DwarfExpr->setMemoryLocationKind(); + DwarfExpr->addExpression(Expr); } if (Loc) addBlock(*VariableDIE, dwarf::DW_AT_location, DwarfExpr->finalize()); @@ -241,7 +249,8 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( // If the linkage name is different than the name, go ahead and output // that as well into the name table. - if (GV->getLinkageName() != "" && GV->getName() != GV->getLinkageName()) + if (GV->getLinkageName() != "" && GV->getName() != GV->getLinkageName() && + DD->useAllLinkageNames()) DD->addAccelName(GV->getLinkageName(), *VariableDIE); } @@ -267,15 +276,20 @@ void DwarfCompileUnit::addRange(RangeSpan Range) { void DwarfCompileUnit::initStmtList() { // Define start line table label for each Compile Unit. - MCSymbol *LineTableStartSym = - Asm->OutStreamer->getDwarfLineTableSymbol(getUniqueID()); + MCSymbol *LineTableStartSym; + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + if (DD->useSectionsAsReferences()) { + LineTableStartSym = TLOF.getDwarfLineSection()->getBeginSymbol(); + } else { + LineTableStartSym = + Asm->OutStreamer->getDwarfLineTableSymbol(getUniqueID()); + } // DW_AT_stmt_list is a offset of line number information for this // compile unit in debug_line section. For split dwarf this is // left in the skeleton CU and so not included. // The line table entries are not always emitted in assembly, so it // is not okay to use line_table_start here. - const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); StmtListValue = addSectionLabel(getUnitDie(), dwarf::DW_AT_stmt_list, LineTableStartSym, TLOF.getDwarfLineSection()->getBeginSymbol()); @@ -313,10 +327,16 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) { // Only include DW_AT_frame_base in full debug info if (!includeMinimalInlineScopes()) { - const TargetRegisterInfo *RI = Asm->MF->getSubtarget().getRegisterInfo(); - MachineLocation Location(RI->getFrameRegister(*Asm->MF)); - if (RI->isPhysicalRegister(Location.getReg())) - addAddress(*SPDie, dwarf::DW_AT_frame_base, Location); + if (Asm->MF->getTarget().getTargetTriple().isNVPTX()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_call_frame_cfa); + addBlock(*SPDie, dwarf::DW_AT_frame_base, Loc); + } else { + const TargetRegisterInfo *RI = Asm->MF->getSubtarget().getRegisterInfo(); + MachineLocation Location(RI->getFrameRegister(*Asm->MF)); + if (RI->isPhysicalRegister(Location.getReg())) + addAddress(*SPDie, dwarf::DW_AT_frame_base, Location); + } } // Add name to the name table, we do this here because we're guaranteed @@ -385,21 +405,28 @@ void DwarfCompileUnit::addScopeRangeList(DIE &ScopeDIE, SmallVector<RangeSpan, 2> Range) { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - // Emit offset in .debug_range as a relocatable label. emitDIE will handle - // emitting it appropriately. + // Emit the offset into .debug_ranges or .debug_rnglists as a relocatable + // label. emitDIE() will handle emitting it appropriately. const MCSymbol *RangeSectionSym = - TLOF.getDwarfRangesSection()->getBeginSymbol(); + DD->getDwarfVersion() >= 5 + ? TLOF.getDwarfRnglistsSection()->getBeginSymbol() + : TLOF.getDwarfRangesSection()->getBeginSymbol(); RangeSpanList List(Asm->createTempSymbol("debug_ranges"), std::move(Range)); // Under fission, ranges are specified by constant offsets relative to the // CU's DW_AT_GNU_ranges_base. - if (isDwoUnit()) - addSectionDelta(ScopeDIE, dwarf::DW_AT_ranges, List.getSym(), - RangeSectionSym); - else + // FIXME: For DWARF v5, do not generate the DW_AT_ranges attribute under + // fission until we support the forms using the .debug_addr section + // (DW_RLE_startx_endx etc.). + if (isDwoUnit()) { + if (DD->getDwarfVersion() < 5) + addSectionDelta(ScopeDIE, dwarf::DW_AT_ranges, List.getSym(), + RangeSectionSym); + } else { addSectionLabel(ScopeDIE, dwarf::DW_AT_ranges, List.getSym(), RangeSectionSym); + } // Add the range list to the set of ranges to be emitted. (Skeleton ? Skeleton : this)->CURangeLists.push_back(std::move(List)); @@ -407,9 +434,10 @@ void DwarfCompileUnit::addScopeRangeList(DIE &ScopeDIE, void DwarfCompileUnit::attachRangesOrLowHighPC( DIE &Die, SmallVector<RangeSpan, 2> Ranges) { - if (Ranges.size() == 1) { - const auto &single = Ranges.front(); - attachLowHighPC(Die, single.getStart(), single.getEnd()); + if (Ranges.size() == 1 || !DD->useRangesSection()) { + const RangeSpan &Front = Ranges.front(); + const RangeSpan &Back = Ranges.back(); + attachLowHighPC(Die, Front.getStart(), Back.getEnd()); } else addScopeRangeList(Die, std::move(Ranges)); } @@ -443,7 +471,7 @@ DIE *DwarfCompileUnit::constructInlinedScopeDIE(LexicalScope *Scope) { // Add the call site information to the DIE. const DILocation *IA = Scope->getInlinedAt(); addUInt(*ScopeDIE, dwarf::DW_AT_call_file, None, - getOrCreateSourceID(IA->getFilename(), IA->getDirectory())); + getOrCreateSourceID(IA->getFile())); addUInt(*ScopeDIE, dwarf::DW_AT_call_line, None, IA->getLine()); if (IA->getDiscriminator() && DD->getDwarfVersion() >= 4) addUInt(*ScopeDIE, dwarf::DW_AT_GNU_discriminator, None, @@ -482,6 +510,7 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, bool Abstract) { // Define variable debug information entry. auto VariableDie = DIE::get(DIEValueAllocator, DV.getTag()); + insertDIE(DV.getVariable(), VariableDie); if (Abstract) { applyVariableAttributes(DV, *VariableDie); @@ -547,8 +576,11 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, Ops.append(Expr->elements_begin(), Expr->elements_end()); DIExpressionCursor Cursor(Ops); DwarfExpr.setMemoryLocationKind(); - DwarfExpr.addMachineRegExpression( - *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, FrameReg); + if (const MCSymbol *FrameSymbol = Asm->getFunctionFrameSymbol()) + addOpAddress(*Loc, FrameSymbol); + else + DwarfExpr.addMachineRegExpression( + *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, FrameReg); DwarfExpr.addExpression(std::move(Cursor)); } addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); @@ -565,13 +597,95 @@ DIE *DwarfCompileUnit::constructVariableDIE(DbgVariable &DV, return Var; } +/// Return all DIVariables that appear in count: expressions. +static SmallVector<const DIVariable *, 2> dependencies(DbgVariable *Var) { + SmallVector<const DIVariable *, 2> Result; + auto *Array = dyn_cast<DICompositeType>(Var->getType()); + if (!Array || Array->getTag() != dwarf::DW_TAG_array_type) + return Result; + for (auto *El : Array->getElements()) { + if (auto *Subrange = dyn_cast<DISubrange>(El)) { + auto Count = Subrange->getCount(); + if (auto *Dependency = Count.dyn_cast<DIVariable *>()) + Result.push_back(Dependency); + } + } + return Result; +} + +/// Sort local variables so that variables appearing inside of helper +/// expressions come first. +static SmallVector<DbgVariable *, 8> +sortLocalVars(SmallVectorImpl<DbgVariable *> &Input) { + SmallVector<DbgVariable *, 8> Result; + SmallVector<PointerIntPair<DbgVariable *, 1>, 8> WorkList; + // Map back from a DIVariable to its containing DbgVariable. + SmallDenseMap<const DILocalVariable *, DbgVariable *> DbgVar; + // Set of DbgVariables in Result. + SmallDenseSet<DbgVariable *, 8> Visited; + // For cycle detection. + SmallDenseSet<DbgVariable *, 8> Visiting; + + // Initialize the worklist and the DIVariable lookup table. + for (auto Var : reverse(Input)) { + DbgVar.insert({Var->getVariable(), Var}); + WorkList.push_back({Var, 0}); + } + + // Perform a stable topological sort by doing a DFS. + while (!WorkList.empty()) { + auto Item = WorkList.back(); + DbgVariable *Var = Item.getPointer(); + bool visitedAllDependencies = Item.getInt(); + WorkList.pop_back(); + + // Dependency is in a different lexical scope or a global. + if (!Var) + continue; + + // Already handled. + if (Visited.count(Var)) + continue; + + // Add to Result if all dependencies are visited. + if (visitedAllDependencies) { + Visited.insert(Var); + Result.push_back(Var); + continue; + } + + // Detect cycles. + auto Res = Visiting.insert(Var); + if (!Res.second) { + assert(false && "dependency cycle in local variables"); + return Result; + } + + // Push dependencies and this node onto the worklist, so that this node is + // visited again after all of its dependencies are handled. + WorkList.push_back({Var, 1}); + for (auto *Dependency : dependencies(Var)) { + auto Dep = dyn_cast_or_null<const DILocalVariable>(Dependency); + WorkList.push_back({DbgVar[Dep], 0}); + } + } + return Result; +} + DIE *DwarfCompileUnit::createScopeChildrenDIE(LexicalScope *Scope, SmallVectorImpl<DIE *> &Children, bool *HasNonScopeChildren) { assert(Children.empty()); DIE *ObjectPointer = nullptr; - for (DbgVariable *DV : DU->getScopeVariables().lookup(Scope)) + // Emit function arguments (order is significant). + auto Vars = DU->getScopeVariables().lookup(Scope); + for (auto &DV : Vars.Args) + Children.push_back(constructVariableDIE(*DV.second, *Scope, ObjectPointer)); + + // Emit local variables. + auto Locals = sortLocalVars(Vars.Locals); + for (DbgVariable *DV : Locals) Children.push_back(constructVariableDIE(*DV, *Scope, ObjectPointer)); // Skip imported directives in gmlt-like data. @@ -687,9 +801,7 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE( else EntityDie = getDIE(Entity); assert(EntityDie); - auto *File = Module->getFile(); - addSourceLine(*IMDie, Module->getLine(), File ? File->getFilename() : "", - File ? File->getDirectory() : ""); + addSourceLine(*IMDie, Module->getLine(), Module->getFile()); addDIEEntry(*IMDie, dwarf::DW_AT_import, *EntityDie); StringRef Name = Module->getName(); if (!Name.empty()) @@ -750,7 +862,7 @@ void DwarfCompileUnit::createAbstractVariable(const DILocalVariable *Var, void DwarfCompileUnit::emitHeader(bool UseOffsets) { // Don't bother labeling the .dwo unit, as its offset isn't used. - if (!Skeleton) { + if (!Skeleton && !DD->useSectionsAsReferences()) { LabelBegin = Asm->createTempSymbol("cu_begin"); Asm->OutStreamer->EmitLabel(LabelBegin); } @@ -759,6 +871,8 @@ void DwarfCompileUnit::emitHeader(bool UseOffsets) { : DD->useSplitDwarf() ? dwarf::DW_UT_skeleton : dwarf::DW_UT_compile; DwarfUnit::emitCommonHeader(UseOffsets, UT); + if (DD->getDwarfVersion() >= 5 && UT != dwarf::DW_UT_compile) + Asm->emitInt64(getDWOId()); } bool DwarfCompileUnit::hasDwarfPubSections() const { @@ -767,7 +881,8 @@ bool DwarfCompileUnit::hasDwarfPubSections() const { if (CUNode->getGnuPubnames()) return true; - return DD->tuneForGDB() && !includeMinimalInlineScopes(); + return DD->tuneForGDB() && DD->usePubSections() && + !includeMinimalInlineScopes(); } /// addGlobalName - Add a new global name to the compile unit. diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 68482eb7e358..51e1558fe4a3 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -83,7 +83,10 @@ class DwarfCompileUnit final : public DwarfUnit { DenseMap<const MDNode *, DIE *> AbstractSPDies; DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> AbstractVariables; - /// \brief Construct a DIE for the given DbgVariable without initializing the + /// DWO ID for correlating skeleton and split units. + uint64_t DWOId = 0; + + /// Construct a DIE for the given DbgVariable without initializing the /// DbgVariable's DIE reference. DIE *constructVariableDIEImpl(const DbgVariable &DV, bool Abstract); @@ -141,7 +144,7 @@ public: DwarfCompileUnit &getCU() override { return *this; } - unsigned getOrCreateSourceID(StringRef FileName, StringRef DirName) override; + unsigned getOrCreateSourceID(const DIFile *File) override; void addImportedEntity(const DIImportedEntity* IE) { DIScope *Scope = IE->getScope(); @@ -159,7 +162,7 @@ public: void attachLowHighPC(DIE &D, const MCSymbol *Begin, const MCSymbol *End); - /// \brief Find DIE for the given subprogram and attach appropriate + /// Find DIE for the given subprogram and attach appropriate /// DW_AT_low_pc and DW_AT_high_pc attributes. If there are global /// variables in this scope then create and insert DIEs for these /// variables. @@ -168,7 +171,7 @@ public: void constructScopeDIE(LexicalScope *Scope, SmallVectorImpl<DIE *> &FinalChildren); - /// \brief A helper function to construct a RangeSpanList for a given + /// A helper function to construct a RangeSpanList for a given /// lexical scope. void addScopeRangeList(DIE &ScopeDIE, SmallVector<RangeSpan, 2> Range); @@ -177,11 +180,11 @@ public: void attachRangesOrLowHighPC(DIE &D, const SmallVectorImpl<InsnRange> &Ranges); - /// \brief This scope represents inlined body of a function. Construct + /// This scope represents inlined body of a function. Construct /// DIE to represent this concrete inlined copy of the function. DIE *constructInlinedScopeDIE(LexicalScope *Scope); - /// \brief Construct new DW_TAG_lexical_block for this scope and + /// Construct new DW_TAG_lexical_block for this scope and /// attach DW_AT_low_pc/DW_AT_high_pc labels. DIE *constructLexicalScopeDIE(LexicalScope *Scope); @@ -196,14 +199,14 @@ public: SmallVectorImpl<DIE *> &Children, bool *HasNonScopeChildren = nullptr); - /// \brief Construct a DIE for this subprogram scope. + /// Construct a DIE for this subprogram scope. void constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope); DIE *createAndAddScopeChildren(LexicalScope *Scope, DIE &ScopeDIE); void constructAbstractSubprogramScopeDIE(LexicalScope *Scope); - /// \brief Construct import_module DIE. + /// Construct import_module DIE. DIE *constructImportedEntityDIE(const DIImportedEntity *Module); void finishSubprogramDefinition(const DISubprogram *SP); @@ -214,11 +217,18 @@ public: DbgVariable *getExistingAbstractVariable(InlinedVariable IV, const DILocalVariable *&Cleansed); DbgVariable *getExistingAbstractVariable(InlinedVariable IV); - void createAbstractVariable(const DILocalVariable *DV, LexicalScope *Scope); + void createAbstractVariable(const DILocalVariable *Var, LexicalScope *Scope); /// Set the skeleton unit associated with this unit. void setSkeleton(DwarfCompileUnit &Skel) { Skeleton = &Skel; } + unsigned getHeaderSize() const override { + // DWARF v5 added the DWO ID to the header for split/skeleton units. + unsigned DWOIdSize = + DD->getDwarfVersion() >= 5 && DD->useSplitDwarf() ? sizeof(uint64_t) + : 0; + return DwarfUnit::getHeaderSize() + DWOIdSize; + } unsigned getLength() { return sizeof(uint32_t) + // Length field getHeaderSize() + getUnitDie().getSize(); @@ -290,6 +300,9 @@ public: void setBaseAddress(const MCSymbol *Base) { BaseAddress = Base; } const MCSymbol *getBaseAddress() const { return BaseAddress; } + uint64_t getDWOId() const { return DWOId; } + void setDWOId(uint64_t DwoId) { DWOId = DwoId; } + bool hasDwarfPubSections() const; }; diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 2c9c7d4f3146..8761fae9dd22 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -16,7 +16,6 @@ #include "DIEHash.h" #include "DebugLocEntry.h" #include "DebugLocStream.h" -#include "DwarfAccelTable.h" #include "DwarfCompileUnit.h" #include "DwarfExpression.h" #include "DwarfFile.h" @@ -31,6 +30,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/CodeGen/AccelTable.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" #include "llvm/CodeGen/LexicalScopes.h" @@ -39,7 +39,6 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/Constants.h" @@ -66,6 +65,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include <algorithm> @@ -94,6 +94,11 @@ static cl::opt<bool> GenerateARangeSection("generate-arange-section", cl::desc("Generate dwarf aranges"), cl::init(false)); +static cl::opt<bool> + GenerateDwarfTypeUnits("generate-type-units", cl::Hidden, + cl::desc("Generate DWARF4 type units."), + cl::init(false)); + static cl::opt<bool> SplitDwarfCrossCuReferences( "split-dwarf-cross-cu-references", cl::Hidden, cl::desc("Enable cross-cu references in DWO files"), cl::init(false)); @@ -107,14 +112,40 @@ static cl::opt<DefaultOnOff> UnknownLocations( clEnumVal(Enable, "In all cases"), clEnumVal(Disable, "Never")), cl::init(Default)); +static cl::opt<AccelTableKind> AccelTables( + "accel-tables", cl::Hidden, cl::desc("Output dwarf accelerator tables."), + cl::values(clEnumValN(AccelTableKind::Default, "Default", + "Default for platform"), + clEnumValN(AccelTableKind::None, "Disable", "Disabled."), + clEnumValN(AccelTableKind::Apple, "Apple", "Apple"), + clEnumValN(AccelTableKind::Dwarf, "Dwarf", "DWARF")), + cl::init(AccelTableKind::Default)); + static cl::opt<DefaultOnOff> -DwarfAccelTables("dwarf-accel-tables", cl::Hidden, - cl::desc("Output prototype dwarf accelerator tables."), +DwarfInlinedStrings("dwarf-inlined-strings", cl::Hidden, + cl::desc("Use inlined strings rather than string section."), cl::values(clEnumVal(Default, "Default for platform"), clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), cl::init(Default)); +static cl::opt<bool> + NoDwarfPubSections("no-dwarf-pub-sections", cl::Hidden, + cl::desc("Disable emission of DWARF pub sections."), + cl::init(false)); + +static cl::opt<bool> + NoDwarfRangesSection("no-dwarf-ranges-section", cl::Hidden, + cl::desc("Disable emission .debug_ranges section."), + cl::init(false)); + +static cl::opt<DefaultOnOff> DwarfSectionsAsReferences( + "dwarf-sections-as-references", cl::Hidden, + cl::desc("Use sections+offset as references rather than labels."), + cl::values(clEnumVal(Default, "Default for platform"), + clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), + cl::init(Default)); + enum LinkageNameOption { DefaultLinkageNames, AllLinkageNames, @@ -215,11 +246,11 @@ ArrayRef<DbgVariable::FrameIndexExpr> DbgVariable::getFrameIndexExprs() const { return A.Expr->isFragment(); }) && "multiple FI expressions without DW_OP_LLVM_fragment"); - std::sort(FrameIndexExprs.begin(), FrameIndexExprs.end(), - [](const FrameIndexExpr &A, const FrameIndexExpr &B) -> bool { - return A.Expr->getFragmentInfo()->OffsetInBits < - B.Expr->getFragmentInfo()->OffsetInBits; - }); + llvm::sort(FrameIndexExprs.begin(), FrameIndexExprs.end(), + [](const FrameIndexExpr &A, const FrameIndexExpr &B) -> bool { + return A.Expr->getFragmentInfo()->OffsetInBits < + B.Expr->getFragmentInfo()->OffsetInBits; + }); return FrameIndexExprs; } @@ -258,23 +289,34 @@ void DbgVariable::addMMIEntry(const DbgVariable &V) { "conflicting locations for variable"); } -static const DwarfAccelTable::Atom TypeAtoms[] = { - DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), - DwarfAccelTable::Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), - DwarfAccelTable::Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)}; +static AccelTableKind computeAccelTableKind(unsigned DwarfVersion, + bool GenerateTypeUnits, + DebuggerKind Tuning, + const Triple &TT) { + // Honor an explicit request. + if (AccelTables != AccelTableKind::Default) + return AccelTables; + + // Accelerator tables with type units are currently not supported. + if (GenerateTypeUnits) + return AccelTableKind::None; + + // Accelerator tables get emitted if targetting DWARF v5 or LLDB. DWARF v5 + // always implies debug_names. For lower standard versions we use apple + // accelerator tables on apple platforms and debug_names elsewhere. + if (DwarfVersion >= 5) + return AccelTableKind::Dwarf; + if (Tuning == DebuggerKind::LLDB) + return TT.isOSBinFormatMachO() ? AccelTableKind::Apple + : AccelTableKind::Dwarf; + return AccelTableKind::None; +} DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) : DebugHandlerBase(A), DebugLocs(A->OutStreamer->isVerboseAsm()), InfoHolder(A, "info_string", DIEValueAllocator), SkeletonHolder(A, "skel_string", DIEValueAllocator), - IsDarwin(A->TM.getTargetTriple().isOSDarwin()), - AccelNames(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelObjC(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelNamespace(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelTypes(TypeAtoms) { + IsDarwin(A->TM.getTargetTriple().isOSDarwin()) { const Triple &TT = Asm->TM.getTargetTriple(); // Make sure we know our "debugger tuning." The target option takes @@ -288,11 +330,12 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) else DebuggerTuning = DebuggerKind::GDB; - // Turn on accelerator tables for LLDB by default. - if (DwarfAccelTables == Default) - HasDwarfAccelTables = tuneForLLDB(); + if (DwarfInlinedStrings == Default) + UseInlineStrings = TT.isNVPTX(); else - HasDwarfAccelTables = DwarfAccelTables == Enable; + UseInlineStrings = DwarfInlinedStrings == Enable; + + UseLocSection = !TT.isNVPTX(); HasAppleExtensionAttributes = tuneForLLDB(); @@ -308,8 +351,23 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) unsigned DwarfVersionNumber = Asm->TM.Options.MCOptions.DwarfVersion; unsigned DwarfVersion = DwarfVersionNumber ? DwarfVersionNumber : MMI->getModule()->getDwarfVersion(); - // Use dwarf 4 by default if nothing is requested. - DwarfVersion = DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION; + // Use dwarf 4 by default if nothing is requested. For NVPTX, use dwarf 2. + DwarfVersion = + TT.isNVPTX() ? 2 : (DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION); + + UsePubSections = !NoDwarfPubSections && !TT.isNVPTX(); + UseRangesSection = !NoDwarfRangesSection && !TT.isNVPTX(); + + // Use sections as references. Force for NVPTX. + if (DwarfSectionsAsReferences == Default) + UseSectionsAsReferences = TT.isNVPTX(); + else + UseSectionsAsReferences = DwarfSectionsAsReferences == Enable; + + GenerateTypeUnits = GenerateDwarfTypeUnits; + + TheAccelTableKind = computeAccelTableKind( + DwarfVersion, GenerateTypeUnits, DebuggerTuning, A->TM.getTargetTriple()); // Work around a GDB bug. GDB doesn't support the standard opcode; // SCE doesn't support GNU's; LLDB prefers the standard opcode, which @@ -321,6 +379,12 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) // GDB does not fully support the DWARF 4 representation for bitfields. UseDWARF2Bitfields = (DwarfVersion < 4) || tuneForGDB(); + // The DWARF v5 string offsets table has - possibly shared - contributions + // from each compile and type unit each preceded by a header. The string + // offsets table used by the pre-DWARF v5 split-DWARF implementation uses + // a monolithic string offsets table without any header. + UseSegmentedStringOffsetsTable = DwarfVersion >= 5; + Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); } @@ -355,17 +419,18 @@ static StringRef getObjCMethodName(StringRef In) { } // Add the various names to the Dwarf accelerator table names. -// TODO: Determine whether or not we should add names for programs -// that do not have a DW_AT_name or DW_AT_linkage_name field - this -// is only slightly different than the lookup of non-standard ObjC names. void DwarfDebug::addSubprogramNames(const DISubprogram *SP, DIE &Die) { if (!SP->isDefinition()) return; - addAccelName(SP->getName(), Die); - // If the linkage name is different than the name, go ahead and output - // that as well into the name table. - if (SP->getLinkageName() != "" && SP->getName() != SP->getLinkageName()) + if (SP->getName() != "") + addAccelName(SP->getName(), Die); + + // If the linkage name is different than the name, go ahead and output that as + // well into the name table. Only do that if we are going to actually emit + // that name. + if (SP->getLinkageName() != "" && SP->getName() != SP->getLinkageName() && + (useAllLinkageNames() || InfoHolder.getAbstractSPDies().lookup(SP))) addAccelName(SP->getLinkageName(), Die); // If this is an Objective-C selector name add it to the ObjC accelerator @@ -471,8 +536,9 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) { // explicitly describe the directory of all files, never relying on the // compilation directory. if (!Asm->OutStreamer->hasRawTextSupport() || SingleCU) - Asm->OutStreamer->getContext().setMCLineTableCompilationDir( - NewCU.getUniqueID(), CompilationDir); + Asm->OutStreamer->emitDwarfFile0Directive( + CompilationDir, FN, NewCU.getMD5AsBytes(DIUnit->getFile()), + DIUnit->getSource(), NewCU.getUniqueID()); StringRef Producer = DIUnit->getProducer(); StringRef Flags = DIUnit->getFlags(); @@ -486,6 +552,10 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) { DIUnit->getSourceLanguage()); NewCU.addString(Die, dwarf::DW_AT_name, FN); + // Add DW_str_offsets_base to the unit DIE, except for split units. + if (useSegmentedStringOffsetsTable() && !useSplitDwarf()) + NewCU.addStringOffsetsStart(); + if (!useSplitDwarf()) { NewCU.initStmtList(); @@ -541,21 +611,22 @@ void DwarfDebug::constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU, /// Sort and unique GVEs by comparing their fragment offset. static SmallVectorImpl<DwarfCompileUnit::GlobalExpr> & sortGlobalExprs(SmallVectorImpl<DwarfCompileUnit::GlobalExpr> &GVEs) { - std::sort(GVEs.begin(), GVEs.end(), - [](DwarfCompileUnit::GlobalExpr A, DwarfCompileUnit::GlobalExpr B) { - // Sort order: first null exprs, then exprs without fragment - // info, then sort by fragment offset in bits. - // FIXME: Come up with a more comprehensive comparator so - // the sorting isn't non-deterministic, and so the following - // std::unique call works correctly. - if (!A.Expr || !B.Expr) - return !!B.Expr; - auto FragmentA = A.Expr->getFragmentInfo(); - auto FragmentB = B.Expr->getFragmentInfo(); - if (!FragmentA || !FragmentB) - return !!FragmentB; - return FragmentA->OffsetInBits < FragmentB->OffsetInBits; - }); + llvm::sort(GVEs.begin(), GVEs.end(), + [](DwarfCompileUnit::GlobalExpr A, + DwarfCompileUnit::GlobalExpr B) { + // Sort order: first null exprs, then exprs without fragment + // info, then sort by fragment offset in bits. + // FIXME: Come up with a more comprehensive comparator so + // the sorting isn't non-deterministic, and so the following + // std::unique call works correctly. + if (!A.Expr || !B.Expr) + return !!B.Expr; + auto FragmentA = A.Expr->getFragmentInfo(); + auto FragmentB = B.Expr->getFragmentInfo(); + if (!FragmentA || !FragmentB) + return !!FragmentB; + return FragmentA->OffsetInBits < FragmentB->OffsetInBits; + }); GVEs.erase(std::unique(GVEs.begin(), GVEs.end(), [](DwarfCompileUnit::GlobalExpr A, DwarfCompileUnit::GlobalExpr B) { @@ -590,6 +661,19 @@ void DwarfDebug::beginModule() { GVMap[GVE->getVariable()].push_back({&Global, GVE->getExpression()}); } + // Create the symbol that designates the start of the unit's contribution + // to the string offsets table. In a split DWARF scenario, only the skeleton + // unit has the DW_AT_str_offsets_base attribute (and hence needs the symbol). + if (useSegmentedStringOffsetsTable()) + (useSplitDwarf() ? SkeletonHolder : InfoHolder) + .setStringOffsetsStartSym(Asm->createTempSymbol("str_offsets_base")); + + // Create the symbol that designates the start of the DWARF v5 range list + // table. It is located past the header and before the offsets table. + if (getDwarfVersion() >= 5) + (useSplitDwarf() ? SkeletonHolder : InfoHolder) + .setRnglistsTableBaseSym(Asm->createTempSymbol("rnglists_table_base")); + for (DICompileUnit *CUNode : M->debug_compile_units()) { // FIXME: Move local imported entities into a list attached to the // subprogram, then this search won't be needed and a @@ -694,11 +778,15 @@ void DwarfDebug::finalizeModuleInfo() { // Emit a unique identifier for this CU. uint64_t ID = DIEHash(Asm).computeCUSignature(DWOName, TheCU.getUnitDie()); - TheCU.addUInt(TheCU.getUnitDie(), dwarf::DW_AT_GNU_dwo_id, - dwarf::DW_FORM_data8, ID); - SkCU->addUInt(SkCU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id, - dwarf::DW_FORM_data8, ID); - + if (getDwarfVersion() >= 5) { + TheCU.setDWOId(ID); + SkCU->setDWOId(ID); + } else { + TheCU.addUInt(TheCU.getUnitDie(), dwarf::DW_AT_GNU_dwo_id, + dwarf::DW_FORM_data8, ID); + SkCU->addUInt(SkCU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id, + dwarf::DW_FORM_data8, ID); + } // We don't keep track of which addresses are used in which CU so this // is a bit pessimistic under LTO. if (!AddrPool.isEmpty()) { @@ -706,7 +794,7 @@ void DwarfDebug::finalizeModuleInfo() { SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_addr_base, Sym, Sym); } - if (!SkCU->getRangeLists().empty()) { + if (getDwarfVersion() < 5 && !SkCU->getRangeLists().empty()) { const MCSymbol *Sym = TLOF.getDwarfRangesSection()->getBeginSymbol(); SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_ranges_base, Sym, Sym); @@ -721,7 +809,7 @@ void DwarfDebug::finalizeModuleInfo() { // ranges for all subprogram DIEs for mach-o. DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; if (unsigned NumRanges = TheCU.getRanges().size()) { - if (NumRanges > 1) + if (NumRanges > 1 && useRangesSection()) // A DW_AT_low_pc attribute may also be specified in combination with // DW_AT_ranges to specify the default base address for use in // location lists (see Section 2.6.2) and range lists (see Section @@ -732,6 +820,10 @@ void DwarfDebug::finalizeModuleInfo() { U.attachRangesOrLowHighPC(U.getUnitDie(), TheCU.takeRanges()); } + if (getDwarfVersion() >= 5 && !useSplitDwarf() && + !U.getRangeLists().empty()) + U.addRnglistsBase(); + auto *CUNode = cast<DICompileUnit>(P.first); // If compile Unit has macros, emit "DW_AT_macro_info" attribute. if (CUNode->getMacros()) @@ -799,11 +891,20 @@ void DwarfDebug::endModule() { } // Emit info into the dwarf accelerator table sections. - if (useDwarfAccelTables()) { + switch (getAccelTableKind()) { + case AccelTableKind::Apple: emitAccelNames(); emitAccelObjC(); emitAccelNamespaces(); emitAccelTypes(); + break; + case AccelTableKind::Dwarf: + emitAccelDebugNames(); + break; + case AccelTableKind::None: + break; + case AccelTableKind::Default: + llvm_unreachable("Default should have already been resolved."); } // Emit the pubnames and pubtypes sections if requested. @@ -887,7 +988,7 @@ static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); } -/// \brief If this and Next are describing different fragments of the same +/// If this and Next are describing different fragments of the same /// variable, merge them by appending Next's values to the current /// list of values. /// Return true if the merge was successful. @@ -903,8 +1004,7 @@ bool DebugLocEntry::MergeValues(const DebugLocEntry &Next) { // sorted. for (unsigned i = 0, j = 0; i < Values.size(); ++i) { for (; j < Next.Values.size(); ++j) { - int res = DebugHandlerBase::fragmentCmp( - cast<DIExpression>(Values[i].Expression), + int res = cast<DIExpression>(Values[i].Expression)->fragmentCmp( cast<DIExpression>(Next.Values[j].Expression)); if (res == 0) // The two expressions overlap, we can't merge. return false; @@ -967,7 +1067,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, // If this fragment overlaps with any open ranges, truncate them. const DIExpression *DIExpr = Begin->getDebugExpression(); auto Last = remove_if(OpenRanges, [&](DebugLocEntry::Value R) { - return fragmentsOverlap(DIExpr, R.getExpression()); + return DIExpr->fragmentsOverlap(R.getExpression()); }); OpenRanges.erase(Last, OpenRanges.end()); @@ -983,7 +1083,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, EndLabel = getLabelBeforeInsn(std::next(I)->first); assert(EndLabel && "Forgot label after instruction ending a range!"); - DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n"); + LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n"); auto Value = getDebugLocValue(Begin); DebugLocEntry Loc(StartLabel, EndLabel, Value); @@ -1012,7 +1112,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, // Attempt to coalesce the ranges of two otherwise identical // DebugLocEntries. auto CurEntry = DebugLoc.rbegin(); - DEBUG({ + LLVM_DEBUG({ dbgs() << CurEntry->getValues().size() << " Values:\n"; for (auto &Value : CurEntry->getValues()) Value.dump(); @@ -1131,6 +1231,9 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, RegVar->initializeDbgValue(MInsn); continue; } + // Do not emit location lists if .debug_loc secton is disabled. + if (!useLocSection()) + continue; // Handle multiple DBG_VALUE instructions describing one variable. DebugLocStream::ListBuilder List(DebugLocs, TheCU, *Asm, *RegVar, *MInsn); @@ -1151,10 +1254,12 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, } // Collect info for variables that were optimized out. - for (const DILocalVariable *DV : SP->getVariables()) { - if (Processed.insert(InlinedVariable(DV, nullptr)).second) - if (LexicalScope *Scope = LScopes.findLexicalScope(DV->getScope())) - createConcreteVariable(TheCU, *Scope, InlinedVariable(DV, nullptr)); + for (const DINode *DN : SP->getRetainedNodes()) { + if (auto *DV = dyn_cast<DILocalVariable>(DN)) { + if (Processed.insert(InlinedVariable(DV, nullptr)).second) + if (LexicalScope *Scope = LScopes.findLexicalScope(DV->getScope())) + createConcreteVariable(TheCU, *Scope, InlinedVariable(DV, nullptr)); + } } } @@ -1168,7 +1273,9 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { return; // Check if source location changes, but ignore DBG_VALUE and CFI locations. - if (MI->isMetaInstruction()) + // If the instruction is part of the function frame setup code, do not emit + // any line record, as there is no correspondence with any user code. + if (MI->isMetaInstruction() || MI->getFlag(MachineInstr::FrameSetup)) return; const DebugLoc &DL = MI->getDebugLoc(); // When we emit a line-0 record, we don't update PrevInstLoc; so look at @@ -1333,14 +1440,16 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) { // Construct abstract scopes. for (LexicalScope *AScope : LScopes.getAbstractScopesList()) { auto *SP = cast<DISubprogram>(AScope->getScopeNode()); - // Collect info for variables that were optimized out. - for (const DILocalVariable *DV : SP->getVariables()) { - if (!ProcessedVars.insert(InlinedVariable(DV, nullptr)).second) - continue; - ensureAbstractVariableIsCreated(TheCU, InlinedVariable(DV, nullptr), - DV->getScope()); - assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes - && "ensureAbstractVariableIsCreated inserted abstract scopes"); + for (const DINode *DN : SP->getRetainedNodes()) { + if (auto *DV = dyn_cast<DILocalVariable>(DN)) { + // Collect info for variables that were optimized out. + if (!ProcessedVars.insert(InlinedVariable(DV, nullptr)).second) + continue; + ensureAbstractVariableIsCreated(TheCU, InlinedVariable(DV, nullptr), + DV->getScope()); + assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes + && "ensureAbstractVariableIsCreated inserted abstract scopes"); + } } constructAbstractSubprogramScopeDIE(TheCU, AScope); } @@ -1366,21 +1475,19 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) { void DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, const MDNode *S, unsigned Flags) { StringRef Fn; - StringRef Dir; - unsigned Src = 1; + unsigned FileNo = 1; unsigned Discriminator = 0; if (auto *Scope = cast_or_null<DIScope>(S)) { Fn = Scope->getFilename(); - Dir = Scope->getDirectory(); if (Line != 0 && getDwarfVersion() >= 4) if (auto *LBF = dyn_cast<DILexicalBlockFile>(Scope)) Discriminator = LBF->getDiscriminator(); unsigned CUID = Asm->OutStreamer->getContext().getDwarfCompileUnitID(); - Src = static_cast<DwarfCompileUnit &>(*InfoHolder.getUnits()[CUID]) - .getOrCreateSourceID(Fn, Dir); + FileNo = static_cast<DwarfCompileUnit &>(*InfoHolder.getUnits()[CUID]) + .getOrCreateSourceID(Scope->getFile()); } - Asm->OutStreamer->EmitDwarfLocDirective(Src, Line, Col, Flags, 0, + Asm->OutStreamer->EmitDwarfLocDirective(FileNo, Line, Col, Flags, 0, Discriminator, Fn); } @@ -1401,13 +1508,30 @@ void DwarfDebug::emitAbbreviations() { Holder.emitAbbrevs(Asm->getObjFileLowering().getDwarfAbbrevSection()); } -void DwarfDebug::emitAccel(DwarfAccelTable &Accel, MCSection *Section, +void DwarfDebug::emitStringOffsetsTableHeader() { + DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; + Holder.getStringPool().emitStringOffsetsTableHeader( + *Asm, Asm->getObjFileLowering().getDwarfStrOffSection(), + Holder.getStringOffsetsStartSym()); +} + +template <typename AccelTableT> +void DwarfDebug::emitAccel(AccelTableT &Accel, MCSection *Section, StringRef TableName) { - Accel.FinalizeTable(Asm, TableName); Asm->OutStreamer->SwitchSection(Section); // Emit the full data. - Accel.emit(Asm, Section->getBeginSymbol(), this); + emitAppleAccelTable(Asm, Accel, TableName, Section->getBeginSymbol()); +} + +void DwarfDebug::emitAccelDebugNames() { + // Don't emit anything if we have no compilation units to index. + if (getUnits().empty()) + return; + + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfDebugNamesSection()); + emitDWARF5AccelTable(Asm, AccelDebugNames, *this, getUnits()); } // Emit visible names into a hashed accelerator table section. @@ -1525,6 +1649,14 @@ void DwarfDebug::emitDebugPubSections() { } } +void DwarfDebug::emitSectionReference(const DwarfCompileUnit &CU) { + if (useSectionsAsReferences()) + Asm->EmitDwarfOffset(CU.getSection()->getBeginSymbol(), + CU.getDebugSectionOffset()); + else + Asm->emitDwarfSymbolReference(CU.getLabelBegin()); +} + void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, DwarfCompileUnit *TheU, const StringMap<const DIE *> &Globals) { @@ -1540,13 +1672,13 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, Asm->OutStreamer->EmitLabel(BeginLabel); Asm->OutStreamer->AddComment("DWARF Version"); - Asm->EmitInt16(dwarf::DW_PUBNAMES_VERSION); + Asm->emitInt16(dwarf::DW_PUBNAMES_VERSION); Asm->OutStreamer->AddComment("Offset of Compilation Unit Info"); - Asm->emitDwarfSymbolReference(TheU->getLabelBegin()); + emitSectionReference(*TheU); Asm->OutStreamer->AddComment("Compilation Unit Length"); - Asm->EmitInt32(TheU->getLength()); + Asm->emitInt32(TheU->getLength()); // Emit the pubnames for this compilation unit. for (const auto &GI : Globals) { @@ -1554,14 +1686,14 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, const DIE *Entity = GI.second; Asm->OutStreamer->AddComment("DIE offset"); - Asm->EmitInt32(Entity->getOffset()); + Asm->emitInt32(Entity->getOffset()); if (GnuStyle) { dwarf::PubIndexEntryDescriptor Desc = computeIndexValue(TheU, Entity); Asm->OutStreamer->AddComment( Twine("Kind: ") + dwarf::GDBIndexEntryKindString(Desc.Kind) + ", " + dwarf::GDBIndexEntryLinkageString(Desc.Linkage)); - Asm->EmitInt8(Desc.toBits()); + Asm->emitInt8(Desc.toBits()); } Asm->OutStreamer->AddComment("External Name"); @@ -1569,14 +1701,20 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, } Asm->OutStreamer->AddComment("End Mark"); - Asm->EmitInt32(0); + Asm->emitInt32(0); Asm->OutStreamer->EmitLabel(EndLabel); } /// Emit null-terminated strings into a debug str section. void DwarfDebug::emitDebugStr() { + MCSection *StringOffsetsSection = nullptr; + if (useSegmentedStringOffsetsTable()) { + emitStringOffsetsTableHeader(); + StringOffsetsSection = Asm->getObjFileLowering().getDwarfStrOffSection(); + } DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; - Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection()); + Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection(), + StringOffsetsSection, /* UseRelativeOffsets = */ true); } void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, @@ -1589,7 +1727,6 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, } static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, - ByteStreamer &Streamer, const DebugLocEntry::Value &Value, DwarfExpression &DwarfExpr) { auto *DIExpr = Value.getExpression(); @@ -1634,11 +1771,11 @@ void DebugLocEntry::finalize(const AsmPrinter &AP, "fragments are expected to be sorted"); for (auto Fragment : Values) - emitDebugLocValue(AP, BT, Streamer, Fragment, DwarfExpr); + emitDebugLocValue(AP, BT, Fragment, DwarfExpr); } else { assert(Values.size() == 1 && "only fragments may have >1 value"); - emitDebugLocValue(AP, BT, Streamer, Value, DwarfExpr); + emitDebugLocValue(AP, BT, Value, DwarfExpr); } DwarfExpr.finalize(); } @@ -1646,7 +1783,7 @@ void DebugLocEntry::finalize(const AsmPrinter &AP, void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) { // Emit the size. Asm->OutStreamer->AddComment("Loc expr size"); - Asm->EmitInt16(DebugLocs.getBytes(Entry).size()); + Asm->emitInt16(DebugLocs.getBytes(Entry).size()); // Emit the entry. APByteStreamer Streamer(*Asm); @@ -1694,14 +1831,14 @@ void DwarfDebug::emitDebugLocDWO() { // rather than two. We could get fancier and try to, say, reuse an // address we know we've emitted elsewhere (the start of the function? // The start of the CU or CU subrange that encloses this range?) - Asm->EmitInt8(dwarf::DW_LLE_startx_length); + Asm->emitInt8(dwarf::DW_LLE_startx_length); unsigned idx = AddrPool.getIndex(Entry.BeginSym); Asm->EmitULEB128(idx); Asm->EmitLabelDifference(Entry.EndSym, Entry.BeginSym, 4); emitDebugLocEntryLocation(Entry); } - Asm->EmitInt8(dwarf::DW_LLE_end_of_list); + Asm->emitInt8(dwarf::DW_LLE_end_of_list); } } @@ -1752,7 +1889,7 @@ void DwarfDebug::emitDebugARanges() { } // Sort the symbols by offset within the section. - std::sort( + std::stable_sort( List.begin(), List.end(), [&](const SymbolCU &A, const SymbolCU &B) { unsigned IA = A.Sym ? Asm->OutStreamer->GetSymbolOrder(A.Sym) : 0; unsigned IB = B.Sym ? Asm->OutStreamer->GetSymbolOrder(B.Sym) : 0; @@ -1801,10 +1938,10 @@ void DwarfDebug::emitDebugARanges() { } // Sort the CU list (again, to ensure consistent output order). - std::sort(CUs.begin(), CUs.end(), - [](const DwarfCompileUnit *A, const DwarfCompileUnit *B) { - return A->getUniqueID() < B->getUniqueID(); - }); + llvm::sort(CUs.begin(), CUs.end(), + [](const DwarfCompileUnit *A, const DwarfCompileUnit *B) { + return A->getUniqueID() < B->getUniqueID(); + }); // Emit an arange table for each CU we used. for (DwarfCompileUnit *CU : CUs) { @@ -1832,15 +1969,15 @@ void DwarfDebug::emitDebugARanges() { // For each compile unit, write the list of spans it covers. Asm->OutStreamer->AddComment("Length of ARange Set"); - Asm->EmitInt32(ContentSize); + Asm->emitInt32(ContentSize); Asm->OutStreamer->AddComment("DWARF Arange version number"); - Asm->EmitInt16(dwarf::DW_ARANGES_VERSION); + Asm->emitInt16(dwarf::DW_ARANGES_VERSION); Asm->OutStreamer->AddComment("Offset Into Debug Info Section"); - Asm->emitDwarfSymbolReference(CU->getLabelBegin()); + emitSectionReference(*CU); Asm->OutStreamer->AddComment("Address Size (in bytes)"); - Asm->EmitInt8(PtrSize); + Asm->emitInt8(PtrSize); Asm->OutStreamer->AddComment("Segment Size (in bytes)"); - Asm->EmitInt8(0); + Asm->emitInt8(0); Asm->OutStreamer->emitFill(Padding, 0xff); @@ -1867,17 +2004,151 @@ void DwarfDebug::emitDebugARanges() { } } -/// Emit address ranges into a debug ranges section. +/// Emit a single range list. We handle both DWARF v5 and earlier. +static void emitRangeList(AsmPrinter *Asm, DwarfCompileUnit *CU, + const RangeSpanList &List) { + + auto DwarfVersion = CU->getDwarfVersion(); + // Emit our symbol so we can find the beginning of the range. + Asm->OutStreamer->EmitLabel(List.getSym()); + // Gather all the ranges that apply to the same section so they can share + // a base address entry. + MapVector<const MCSection *, std::vector<const RangeSpan *>> SectionRanges; + // Size for our labels. + auto Size = Asm->MAI->getCodePointerSize(); + + for (const RangeSpan &Range : List.getRanges()) + SectionRanges[&Range.getStart()->getSection()].push_back(&Range); + + auto *CUBase = CU->getBaseAddress(); + bool BaseIsSet = false; + for (const auto &P : SectionRanges) { + // Don't bother with a base address entry if there's only one range in + // this section in this range list - for example ranges for a CU will + // usually consist of single regions from each of many sections + // (-ffunction-sections, or just C++ inline functions) except under LTO + // or optnone where there may be holes in a single CU's section + // contributions. + auto *Base = CUBase; + if (!Base && P.second.size() > 1 && + (UseDwarfRangesBaseAddressSpecifier || DwarfVersion >= 5)) { + BaseIsSet = true; + // FIXME/use care: This may not be a useful base address if it's not + // the lowest address/range in this object. + Base = P.second.front()->getStart(); + if (DwarfVersion >= 5) { + Asm->OutStreamer->AddComment("DW_RLE_base_address"); + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_base_address, 1); + } else + Asm->OutStreamer->EmitIntValue(-1, Size); + Asm->OutStreamer->AddComment(" base address"); + Asm->OutStreamer->EmitSymbolValue(Base, Size); + } else if (BaseIsSet && DwarfVersion < 5) { + BaseIsSet = false; + assert(!Base); + Asm->OutStreamer->EmitIntValue(-1, Size); + Asm->OutStreamer->EmitIntValue(0, Size); + } + + for (const auto *RS : P.second) { + const MCSymbol *Begin = RS->getStart(); + const MCSymbol *End = RS->getEnd(); + assert(Begin && "Range without a begin symbol?"); + assert(End && "Range without an end symbol?"); + if (Base) { + if (DwarfVersion >= 5) { + // Emit DW_RLE_offset_pair when we have a base. + Asm->OutStreamer->AddComment("DW_RLE_offset_pair"); + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_offset_pair, 1); + Asm->OutStreamer->AddComment(" starting offset"); + Asm->EmitLabelDifferenceAsULEB128(Begin, Base); + Asm->OutStreamer->AddComment(" ending offset"); + Asm->EmitLabelDifferenceAsULEB128(End, Base); + } else { + Asm->EmitLabelDifference(Begin, Base, Size); + Asm->EmitLabelDifference(End, Base, Size); + } + } else if (DwarfVersion >= 5) { + Asm->OutStreamer->AddComment("DW_RLE_start_length"); + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_start_length, 1); + Asm->OutStreamer->AddComment(" start"); + Asm->OutStreamer->EmitSymbolValue(Begin, Size); + Asm->OutStreamer->AddComment(" length"); + Asm->EmitLabelDifferenceAsULEB128(End, Begin); + } else { + Asm->OutStreamer->EmitSymbolValue(Begin, Size); + Asm->OutStreamer->EmitSymbolValue(End, Size); + } + } + } + if (DwarfVersion >= 5) { + Asm->OutStreamer->AddComment("DW_RLE_end_of_list"); + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_end_of_list, 1); + } else { + // Terminate the list with two 0 values. + Asm->OutStreamer->EmitIntValue(0, Size); + Asm->OutStreamer->EmitIntValue(0, Size); + } +} + +// Emit the header of a DWARF 5 range list table. Returns the symbol that +// designates the end of the table for the caller to emit when the table is +// complete. +static MCSymbol *emitRnglistsTableHeader(AsmPrinter *Asm, DwarfFile &Holder) { + // The length is described by a starting label right after the length field + // and an end label. + MCSymbol *TableStart = Asm->createTempSymbol("debug_rnglist_table_start"); + MCSymbol *TableEnd = Asm->createTempSymbol("debug_rnglist_table_end"); + // Build the range table header, which starts with the length field. + Asm->EmitLabelDifference(TableEnd, TableStart, 4); + Asm->OutStreamer->EmitLabel(TableStart); + // Version number (DWARF v5 and later). + Asm->emitInt16(Asm->OutStreamer->getContext().getDwarfVersion()); + // Address size. + Asm->emitInt8(Asm->MAI->getCodePointerSize()); + // Segment selector size. + Asm->emitInt8(0); + + MCSymbol *RnglistTableBaseSym = Holder.getRnglistsTableBaseSym(); + + // FIXME: Generate the offsets table and use DW_FORM_rnglistx with the + // DW_AT_ranges attribute. Until then set the number of offsets to 0. + Asm->emitInt32(0); + Asm->OutStreamer->EmitLabel(RnglistTableBaseSym); + return TableEnd; +} + +/// Emit address ranges into the .debug_ranges section or into the DWARF v5 +/// .debug_rnglists section. void DwarfDebug::emitDebugRanges() { if (CUMap.empty()) return; - // Start the dwarf ranges section. - Asm->OutStreamer->SwitchSection( - Asm->getObjFileLowering().getDwarfRangesSection()); + auto NoRangesPresent = [this]() { + return llvm::all_of( + CUMap, [](const decltype(CUMap)::const_iterator::value_type &Pair) { + return Pair.second->getRangeLists().empty(); + }); + }; - // Size for our labels. - unsigned char Size = Asm->MAI->getCodePointerSize(); + if (!useRangesSection()) { + assert(NoRangesPresent() && "No debug ranges expected."); + return; + } + + if (getDwarfVersion() >= 5 && NoRangesPresent()) + return; + + // Start the dwarf ranges section. + MCSymbol *TableEnd = nullptr; + if (getDwarfVersion() >= 5) { + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfRnglistsSection()); + TableEnd = emitRnglistsTableHeader(Asm, useSplitDwarf() ? SkeletonHolder + : InfoHolder); + } else + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfRangesSection()); // Grab the specific ranges for the compile units in the module. for (const auto &I : CUMap) { @@ -1887,61 +2158,12 @@ void DwarfDebug::emitDebugRanges() { TheCU = Skel; // Iterate over the misc ranges for the compile units in the module. - for (const RangeSpanList &List : TheCU->getRangeLists()) { - // Emit our symbol so we can find the beginning of the range. - Asm->OutStreamer->EmitLabel(List.getSym()); - - // Gather all the ranges that apply to the same section so they can share - // a base address entry. - MapVector<const MCSection *, std::vector<const RangeSpan *>> MV; - for (const RangeSpan &Range : List.getRanges()) { - MV[&Range.getStart()->getSection()].push_back(&Range); - } - - auto *CUBase = TheCU->getBaseAddress(); - bool BaseIsSet = false; - for (const auto &P : MV) { - // Don't bother with a base address entry if there's only one range in - // this section in this range list - for example ranges for a CU will - // usually consist of single regions from each of many sections - // (-ffunction-sections, or just C++ inline functions) except under LTO - // or optnone where there may be holes in a single CU's section - // contrubutions. - auto *Base = CUBase; - if (!Base && P.second.size() > 1 && - UseDwarfRangesBaseAddressSpecifier) { - BaseIsSet = true; - // FIXME/use care: This may not be a useful base address if it's not - // the lowest address/range in this object. - Base = P.second.front()->getStart(); - Asm->OutStreamer->EmitIntValue(-1, Size); - Asm->OutStreamer->EmitSymbolValue(Base, Size); - } else if (BaseIsSet) { - BaseIsSet = false; - Asm->OutStreamer->EmitIntValue(-1, Size); - Asm->OutStreamer->EmitIntValue(0, Size); - } - - for (const auto *RS : P.second) { - const MCSymbol *Begin = RS->getStart(); - const MCSymbol *End = RS->getEnd(); - assert(Begin && "Range without a begin symbol?"); - assert(End && "Range without an end symbol?"); - if (Base) { - Asm->EmitLabelDifference(Begin, Base, Size); - Asm->EmitLabelDifference(End, Base, Size); - } else { - Asm->OutStreamer->EmitSymbolValue(Begin, Size); - Asm->OutStreamer->EmitSymbolValue(End, Size); - } - } - } - - // And terminate the list with two 0 values. - Asm->OutStreamer->EmitIntValue(0, Size); - Asm->OutStreamer->EmitIntValue(0, Size); - } + for (const RangeSpanList &List : TheCU->getRangeLists()) + emitRangeList(Asm, TheCU, List); } + + if (TableEnd) + Asm->OutStreamer->EmitLabel(TableEnd); } void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U) { @@ -1963,20 +2185,17 @@ void DwarfDebug::emitMacro(DIMacro &M) { Asm->OutStreamer->EmitBytes(Name); if (!Value.empty()) { // There should be one space between macro name and macro value. - Asm->EmitInt8(' '); + Asm->emitInt8(' '); Asm->OutStreamer->EmitBytes(Value); } - Asm->EmitInt8('\0'); + Asm->emitInt8('\0'); } void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); Asm->EmitULEB128(dwarf::DW_MACINFO_start_file); Asm->EmitULEB128(F.getLine()); - DIFile *File = F.getFile(); - unsigned FID = - U.getOrCreateSourceID(File->getFilename(), File->getDirectory()); - Asm->EmitULEB128(FID); + Asm->EmitULEB128(U.getOrCreateSourceID(F.getFile())); handleMacroNodes(F.getElements(), U); Asm->EmitULEB128(dwarf::DW_MACINFO_end_file); } @@ -1995,11 +2214,14 @@ void DwarfDebug::emitDebugMacinfo() { auto *SkCU = TheCU.getSkeleton(); DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; auto *CUNode = cast<DICompileUnit>(P.first); - Asm->OutStreamer->EmitLabel(U.getMacroLabelBegin()); - handleMacroNodes(CUNode->getMacros(), U); + DIMacroNodeArray Macros = CUNode->getMacros(); + if (!Macros.empty()) { + Asm->OutStreamer->EmitLabel(U.getMacroLabelBegin()); + handleMacroNodes(Macros, U); + } } Asm->OutStreamer->AddComment("End Of Macro List Mark"); - Asm->EmitInt8(0); + Asm->emitInt8(0); } // DWARF5 Experimental Separate Dwarf emitters. @@ -2017,9 +2239,6 @@ void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die, SkeletonHolder.addUnit(std::move(NewU)); } -// This DIE has the following attributes: DW_AT_comp_dir, DW_AT_stmt_list, -// DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_dwo_name, DW_AT_dwo_id, -// DW_AT_addr_base, DW_AT_ranges_base. DwarfCompileUnit &DwarfDebug::constructSkeletonCU(const DwarfCompileUnit &CU) { auto OwnedUnit = llvm::make_unique<DwarfCompileUnit>( @@ -2029,6 +2248,9 @@ DwarfCompileUnit &DwarfDebug::constructSkeletonCU(const DwarfCompileUnit &CU) { NewCU.initStmtList(); + if (useSegmentedStringOffsetsTable()) + NewCU.addStringOffsetsStart(); + initSkeletonUnit(CU, NewCU.getUnitDie(), std::move(OwnedUnit)); return NewCU; @@ -2051,26 +2273,37 @@ void DwarfDebug::emitDebugAbbrevDWO() { void DwarfDebug::emitDebugLineDWO() { assert(useSplitDwarf() && "No split dwarf?"); - Asm->OutStreamer->SwitchSection( + SplitTypeUnitFileTable.Emit( + *Asm->OutStreamer, MCDwarfLineTableParams(), Asm->getObjFileLowering().getDwarfLineDWOSection()); - SplitTypeUnitFileTable.Emit(*Asm->OutStreamer, MCDwarfLineTableParams()); +} + +void DwarfDebug::emitStringOffsetsTableHeaderDWO() { + assert(useSplitDwarf() && "No split dwarf?"); + InfoHolder.getStringPool().emitStringOffsetsTableHeader( + *Asm, Asm->getObjFileLowering().getDwarfStrOffDWOSection(), + InfoHolder.getStringOffsetsStartSym()); } // Emit the .debug_str.dwo section for separated dwarf. This contains the // string section and is identical in format to traditional .debug_str // sections. void DwarfDebug::emitDebugStrDWO() { + if (useSegmentedStringOffsetsTable()) + emitStringOffsetsTableHeaderDWO(); assert(useSplitDwarf() && "No split dwarf?"); MCSection *OffSec = Asm->getObjFileLowering().getDwarfStrOffDWOSection(); InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(), - OffSec); + OffSec, /* UseRelativeOffsets = */ false); } MCDwarfDwoLineTable *DwarfDebug::getDwoLineTable(const DwarfCompileUnit &CU) { if (!useSplitDwarf()) return nullptr; - if (SingleCU) - SplitTypeUnitFileTable.setCompilationDir(CU.getCUNode()->getDirectory()); + const DICompileUnit *DIUnit = CU.getCUNode(); + SplitTypeUnitFileTable.maybeSetRootFile( + DIUnit->getDirectory(), DIUnit->getFilename(), + CU.getMD5AsBytes(DIUnit->getFile()), DIUnit->getSource()); return &SplitTypeUnitFileTable; } @@ -2119,10 +2352,16 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, if (useSplitDwarf()) NewTU.setSection(Asm->getObjFileLowering().getDwarfTypesDWOSection()); else { - CU.applyStmtList(UnitDie); NewTU.setSection(Asm->getObjFileLowering().getDwarfTypesSection(Signature)); + // Non-split type units reuse the compile unit's line table. + CU.applyStmtList(UnitDie); } + // Add DW_AT_str_offsets_base to the type unit DIE, but not for split type + // units. + if (useSegmentedStringOffsetsTable() && !useSplitDwarf()) + NewTU.addStringOffsetsStart(); + NewTU.setType(NewTU.createTypeDIE(CTy)); if (TopLevelType) { @@ -2157,32 +2396,50 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, CU.addDIETypeSignature(RefDie, Signature); } -// Accelerator table mutators - add each name along with its companion -// DIE to the proper table while ensuring that the name that we're going -// to reference is in the string table. We do this since the names we -// add may not only be identical to the names in the DIE. -void DwarfDebug::addAccelName(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) +// Add the Name along with its companion DIE to the appropriate accelerator +// table (for AccelTableKind::Dwarf it's always AccelDebugNames, for +// AccelTableKind::Apple, we use the table we got as an argument). If +// accelerator tables are disabled, this function does nothing. +template <typename DataT> +void DwarfDebug::addAccelNameImpl(AccelTable<DataT> &AppleAccel, StringRef Name, + const DIE &Die) { + if (getAccelTableKind() == AccelTableKind::None) return; - AccelNames.AddName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + + DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; + DwarfStringPoolEntryRef Ref = + Holder.getStringPool().getEntry(*Asm, Name); + + switch (getAccelTableKind()) { + case AccelTableKind::Apple: + AppleAccel.addName(Ref, Die); + break; + case AccelTableKind::Dwarf: + AccelDebugNames.addName(Ref, Die); + break; + case AccelTableKind::Default: + llvm_unreachable("Default should have already been resolved."); + case AccelTableKind::None: + llvm_unreachable("None handled above"); + } +} + +void DwarfDebug::addAccelName(StringRef Name, const DIE &Die) { + addAccelNameImpl(AccelNames, Name, Die); } void DwarfDebug::addAccelObjC(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) - return; - AccelObjC.AddName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + // ObjC names go only into the Apple accelerator tables. + if (getAccelTableKind() == AccelTableKind::Apple) + addAccelNameImpl(AccelObjC, Name, Die); } void DwarfDebug::addAccelNamespace(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) - return; - AccelNamespace.AddName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + addAccelNameImpl(AccelNamespace, Name, Die); } void DwarfDebug::addAccelType(StringRef Name, const DIE &Die, char Flags) { - if (!useDwarfAccelTables()) - return; - AccelTypes.AddName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + addAccelNameImpl(AccelTypes, Name, Die); } uint16_t DwarfDebug::getDwarfVersion() const { diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 2ae0b418a91e..0c7be5d27dfe 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -18,7 +18,6 @@ #include "DbgValueHistoryCalculator.h" #include "DebugHandlerBase.h" #include "DebugLocStream.h" -#include "DwarfAccelTable.h" #include "DwarfFile.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -31,6 +30,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/CodeGen/AccelTable.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" @@ -192,6 +192,14 @@ struct SymbolCU { DwarfCompileUnit *CU; }; +/// The kind of accelerator tables we should emit. +enum class AccelTableKind { + Default, ///< Platform default. + None, ///< None. + Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc. + Dwarf, ///< DWARF v5 .debug_names. +}; + /// Collects and handles dwarf debug information. class DwarfDebug : public DebugHandlerBase { /// All DIEValues are allocated through this allocator. @@ -255,12 +263,37 @@ class DwarfDebug : public DebugHandlerBase { /// Whether to emit all linkage names, or just abstract subprograms. bool UseAllLinkageNames; + /// Use inlined strings. + bool UseInlineStrings = false; + + /// Whether to emit DWARF pub sections or not. + bool UsePubSections = true; + + /// Allow emission of .debug_ranges section. + bool UseRangesSection = true; + + /// True if the sections itself must be used as references and don't create + /// temp symbols inside DWARF sections. + bool UseSectionsAsReferences = false; + + ///Allow emission of the .debug_loc section. + bool UseLocSection = true; + + /// Generate DWARF v4 type units. + bool GenerateTypeUnits; + /// DWARF5 Experimental Options /// @{ - bool HasDwarfAccelTables; + AccelTableKind TheAccelTableKind; bool HasAppleExtensionAttributes; bool HasSplitDwarf; + /// Whether to generate the DWARF v5 string offsets table. + /// It consists of a series of contributions, each preceded by a header. + /// The pre-DWARF v5 string offsets table for split dwarf is, in contrast, + /// a monolithic sequence of string offsets. + bool UseSegmentedStringOffsetsTable; + /// Separated Dwarf Variables /// In general these will all be for bits that are left in the /// original object file, rather than things that are meant @@ -283,10 +316,12 @@ class DwarfDebug : public DebugHandlerBase { AddressPool AddrPool; - DwarfAccelTable AccelNames; - DwarfAccelTable AccelObjC; - DwarfAccelTable AccelNamespace; - DwarfAccelTable AccelTypes; + /// Accelerator tables. + AccelTable<DWARF5AccelTableData> AccelDebugNames; + AccelTable<AppleAccelTableOffsetData> AccelNames; + AccelTable<AppleAccelTableOffsetData> AccelObjC; + AccelTable<AppleAccelTableOffsetData> AccelNamespace; + AccelTable<AppleAccelTableTypeData> AccelTypes; // Identify a debugger for "tuning" the debug info. DebuggerKind DebuggerTuning = DebuggerKind::Default; @@ -299,9 +334,9 @@ class DwarfDebug : public DebugHandlerBase { using InlinedVariable = DbgValueHistoryMap::InlinedVariable; - void ensureAbstractVariableIsCreated(DwarfCompileUnit &CU, InlinedVariable Var, + void ensureAbstractVariableIsCreated(DwarfCompileUnit &CU, InlinedVariable IV, const MDNode *Scope); - void ensureAbstractVariableIsCreatedIfScoped(DwarfCompileUnit &CU, InlinedVariable Var, + void ensureAbstractVariableIsCreatedIfScoped(DwarfCompileUnit &CU, InlinedVariable IV, const MDNode *Scope); DbgVariable *createConcreteVariable(DwarfCompileUnit &TheCU, @@ -310,6 +345,10 @@ class DwarfDebug : public DebugHandlerBase { /// Construct a DIE for this abstract scope. void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope); + template <typename DataT> + void addAccelNameImpl(AccelTable<DataT> &AppleAccel, StringRef Name, + const DIE &Die); + void finishVariableDefinitions(); void finishSubprogramDefinitions(); @@ -324,9 +363,15 @@ class DwarfDebug : public DebugHandlerBase { /// Emit the abbreviation section. void emitAbbreviations(); + /// Emit the string offsets table header. + void emitStringOffsetsTableHeader(); + /// Emit a specified accelerator table. - void emitAccel(DwarfAccelTable &Accel, MCSection *Section, - StringRef TableName); + template <typename AccelTableT> + void emitAccel(AccelTableT &Accel, MCSection *Section, StringRef TableName); + + /// Emit DWARF v5 accelerator table. + void emitAccelDebugNames(); /// Emit visible names into a hashed accelerator table section. void emitAccelNames(); @@ -363,6 +408,9 @@ class DwarfDebug : public DebugHandlerBase { /// Emit address ranges into a debug ranges section. void emitDebugRanges(); + /// Emit range lists into a DWARF v5 debug rnglists section. + void emitDebugRnglists(); + /// Emit macros into a debug macinfo section. void emitDebugMacinfo(); void emitMacro(DIMacro &M); @@ -375,8 +423,13 @@ class DwarfDebug : public DebugHandlerBase { void initSkeletonUnit(const DwarfUnit &U, DIE &Die, std::unique_ptr<DwarfCompileUnit> NewU); - /// Construct the split debug info compile unit for the debug info - /// section. + /// Construct the split debug info compile unit for the debug info section. + /// In DWARF v5, the skeleton unit DIE may have the following attributes: + /// DW_AT_addr_base, DW_AT_comp_dir, DW_AT_dwo_name, DW_AT_high_pc, + /// DW_AT_low_pc, DW_AT_ranges, DW_AT_stmt_list, and DW_AT_str_offsets_base. + /// Prior to DWARF v5 it may also have DW_AT_GNU_dwo_id. DW_AT_GNU_dwo_name + /// is used instead of DW_AT_dwo_name, Dw_AT_GNU_addr_base instead of + /// DW_AT_addr_base, and DW_AT_GNU_ranges_base instead of DW_AT_rnglists_base. DwarfCompileUnit &constructSkeletonCU(const DwarfCompileUnit &CU); /// Emit the debug info dwo section. @@ -388,6 +441,9 @@ class DwarfDebug : public DebugHandlerBase { /// Emit the debug line dwo section. void emitDebugLineDWO(); + /// Emit the dwo stringoffsets table header. + void emitStringOffsetsTableHeaderDWO(); + /// Emit the debug str dwo section. void emitDebugStrDWO(); @@ -422,6 +478,9 @@ class DwarfDebug : public DebugHandlerBase { void collectVariableInfoFromMFTable(DwarfCompileUnit &TheCU, DenseSet<InlinedVariable> &P); + /// Emit the reference to the section. + void emitSectionReference(const DwarfCompileUnit &CU); + protected: /// Gather pre-function debug information. void beginFunctionImpl(const MachineFunction *MF) override; @@ -478,11 +537,30 @@ public: /// DWARF4 format. bool useDWARF2Bitfields() const { return UseDWARF2Bitfields; } + /// Returns whether to use inline strings. + bool useInlineStrings() const { return UseInlineStrings; } + + /// Returns whether GNU pub sections should be emitted. + bool usePubSections() const { return UsePubSections; } + + /// Returns whether ranges section should be emitted. + bool useRangesSection() const { return UseRangesSection; } + + /// Returns whether to use sections as labels rather than temp symbols. + bool useSectionsAsReferences() const { + return UseSectionsAsReferences; + } + + /// Returns whether .debug_loc section should be emitted. + bool useLocSection() const { return UseLocSection; } + + /// Returns whether to generate DWARF v4 type units. + bool generateTypeUnits() const { return GenerateTypeUnits; } + // Experimental DWARF5 features. - /// Returns whether or not to emit tables that dwarf consumers can - /// use to accelerate lookup. - bool useDwarfAccelTables() const { return HasDwarfAccelTables; } + /// Returns what kind (if any) of accelerator tables to emit. + AccelTableKind getAccelTableKind() const { return TheAccelTableKind; } bool useAppleExtensionAttributes() const { return HasAppleExtensionAttributes; @@ -492,6 +570,16 @@ public: /// split dwarf proposal support. bool useSplitDwarf() const { return HasSplitDwarf; } + /// Returns whether to generate a string offsets table with (possibly shared) + /// contributions from each CU and type unit. This implies the use of + /// DW_FORM_strx* indirect references with DWARF v5 and beyond. Note that + /// DW_FORM_GNU_str_index is also an indirect reference, but it is used with + /// a pre-DWARF v5 implementation of split DWARF sections, which uses a + /// monolithic string offsets table. + bool useSegmentedStringOffsetsTable() const { + return UseSegmentedStringOffsetsTable; + } + bool shareAcrossDWOCUs() const; /// Returns the Dwarf Version. @@ -537,6 +625,9 @@ public: /// Find the matching DwarfCompileUnit for the given CU DIE. DwarfCompileUnit *lookupCU(const DIE *Die) { return CUDieMap.lookup(Die); } + const DwarfCompileUnit *lookupCU(const DIE *Die) const { + return CUDieMap.lookup(Die); + } /// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger. /// diff --git a/lib/CodeGen/AsmPrinter/DwarfException.h b/lib/CodeGen/AsmPrinter/DwarfException.h index 80d5bd208ed8..b57ea8fc6322 100644 --- a/lib/CodeGen/AsmPrinter/DwarfException.h +++ b/lib/CodeGen/AsmPrinter/DwarfException.h @@ -70,7 +70,7 @@ public: }; class LLVM_LIBRARY_VISIBILITY ARMException : public DwarfCFIExceptionBase { - void emitTypeInfos(unsigned TTypeEncoding) override; + void emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) override; ARMTargetStreamer &getTargetStreamer(); public: diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index 68d25fe37b43..d8d1a5e8f841 100644 --- a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -123,7 +123,10 @@ bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI, const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(MachineReg); unsigned RegSize = TRI.getRegSizeInBits(*RC); // Keep track of the bits in the register we already emitted, so we - // can avoid emitting redundant aliasing subregs. + // can avoid emitting redundant aliasing subregs. Because this is + // just doing a greedy scan of all subregisters, it is possible that + // this doesn't find a combination of subregisters that fully cover + // the register (even though one may exist). SmallBitVector Coverage(RegSize, false); for (MCSubRegIterator SR(MachineReg, &TRI); SR.isValid(); ++SR) { unsigned Idx = TRI.getSubRegIndex(MachineReg, *SR); @@ -143,7 +146,7 @@ bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI, if (CurSubReg.test(Coverage)) { // Emit a piece for any gap in the coverage. if (Offset > CurPos) - DwarfRegs.push_back({-1, Offset - CurPos, nullptr}); + DwarfRegs.push_back({-1, Offset - CurPos, "no DWARF register encoding"}); DwarfRegs.push_back( {Reg, std::min<unsigned>(Size, MaxSize - Offset), "sub-register"}); if (Offset >= MaxSize) @@ -154,8 +157,13 @@ bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI, CurPos = Offset + Size; } } - - return CurPos; + // Failed to find any DWARF encoding. + if (CurPos == 0) + return false; + // Found a partial or complete DWARF encoding. + if (CurPos < RegSize) + DwarfRegs.push_back({-1, RegSize - CurPos, "no DWARF register encoding"}); + return true; } void DwarfExpression::addStackValue() { @@ -341,11 +349,22 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, case dwarf::DW_OP_plus: case dwarf::DW_OP_minus: case dwarf::DW_OP_mul: + case dwarf::DW_OP_div: + case dwarf::DW_OP_mod: + case dwarf::DW_OP_or: + case dwarf::DW_OP_and: + case dwarf::DW_OP_xor: + case dwarf::DW_OP_shl: + case dwarf::DW_OP_shr: + case dwarf::DW_OP_shra: + case dwarf::DW_OP_lit0: + case dwarf::DW_OP_not: + case dwarf::DW_OP_dup: emitOp(Op->getOp()); break; case dwarf::DW_OP_deref: assert(LocationKind != Register); - if (LocationKind != Memory && isMemoryLocation(ExprCursor)) + if (LocationKind != Memory && ::isMemoryLocation(ExprCursor)) // Turning this into a memory location description makes the deref // implicit. LocationKind = Memory; diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.h b/lib/CodeGen/AsmPrinter/DwarfExpression.h index ea5cbc40ba35..952b0d99a95a 100644 --- a/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -211,6 +211,9 @@ public: /// Emit an unsigned constant. void addUnsignedConstant(const APInt &Value); + bool isMemoryLocation() const { return LocationKind == Memory; } + bool isUnknownLocation() const { return LocationKind == Unknown; } + /// Lock this down to become a memory location description. void setMemoryLocationKind() { assert(LocationKind == Unknown); diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/lib/CodeGen/AsmPrinter/DwarfFile.cpp index 3c04c969192d..c90bd568162d 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -77,42 +77,24 @@ unsigned DwarfFile::computeSizeAndOffset(DIE &Die, unsigned Offset) { void DwarfFile::emitAbbrevs(MCSection *Section) { Abbrevs.Emit(Asm, Section); } // Emit strings into a string section. -void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection) { - StrPool.emit(*Asm, StrSection, OffsetSection); +void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection, + bool UseRelativeOffsets) { + StrPool.emit(*Asm, StrSection, OffsetSection, UseRelativeOffsets); } bool DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) { - SmallVectorImpl<DbgVariable *> &Vars = ScopeVariables[LS]; + auto &ScopeVars = ScopeVariables[LS]; const DILocalVariable *DV = Var->getVariable(); - // Variables with positive arg numbers are parameters. if (unsigned ArgNum = DV->getArg()) { - // Keep all parameters in order at the start of the variable list to ensure - // function types are correct (no out-of-order parameters) - // - // This could be improved by only doing it for optimized builds (unoptimized - // builds have the right order to begin with), searching from the back (this - // would catch the unoptimized case quickly), or doing a binary search - // rather than linear search. - auto I = Vars.begin(); - while (I != Vars.end()) { - unsigned CurNum = (*I)->getVariable()->getArg(); - // A local (non-parameter) variable has been found, insert immediately - // before it. - if (CurNum == 0) - break; - // A later indexed parameter has been found, insert immediately before it. - if (CurNum > ArgNum) - break; - if (CurNum == ArgNum) { - (*I)->addMMIEntry(*Var); - return false; - } - ++I; + auto Cached = ScopeVars.Args.find(ArgNum); + if (Cached == ScopeVars.Args.end()) + ScopeVars.Args[ArgNum] = Var; + else { + Cached->second->addMMIEntry(*Var); + return false; } - Vars.insert(I, Var); - return true; - } - - Vars.push_back(Var); + } else { + ScopeVars.Locals.push_back(Var); + } return true; } diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.h b/lib/CodeGen/AsmPrinter/DwarfFile.h index 167ca13c19c1..8dfbc4e1c434 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -17,6 +17,7 @@ #include "llvm/CodeGen/DIE.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/Allocator.h" +#include <map> #include <memory> #include <utility> @@ -43,8 +44,23 @@ class DwarfFile { DwarfStringPool StrPool; - // Collection of dbg variables of a scope. - DenseMap<LexicalScope *, SmallVector<DbgVariable *, 8>> ScopeVariables; + /// DWARF v5: The symbol that designates the start of the contribution to + /// the string offsets table. The contribution is shared by all units. + MCSymbol *StringOffsetsStartSym = nullptr; + + /// DWARF v5: The symbol that designates the base of the range list table. + /// The table is shared by all units. + MCSymbol *RnglistsTableBaseSym = nullptr; + + /// The variables of a lexical scope. + struct ScopeVars { + /// We need to sort Args by ArgNo and check for duplicates. This could also + /// be implemented as a list or vector + std::lower_bound(). + std::map<unsigned, DbgVariable *> Args; + SmallVector<DbgVariable *, 8> Locals; + }; + /// Collection of DbgVariables of each lexical scope. + DenseMap<LexicalScope *, ScopeVars> ScopeVariables; // Collection of abstract subprogram DIEs. DenseMap<const MDNode *, DIE *> AbstractSPDies; @@ -62,39 +78,51 @@ public: return CUs; } - /// \brief Compute the size and offset of a DIE given an incoming Offset. + /// Compute the size and offset of a DIE given an incoming Offset. unsigned computeSizeAndOffset(DIE &Die, unsigned Offset); - /// \brief Compute the size and offset of all the DIEs. + /// Compute the size and offset of all the DIEs. void computeSizeAndOffsets(); - /// \brief Compute the size and offset of all the DIEs in the given unit. + /// Compute the size and offset of all the DIEs in the given unit. /// \returns The size of the root DIE. unsigned computeSizeAndOffsetsForUnit(DwarfUnit *TheU); - /// \brief Add a unit to the list of CUs. + /// Add a unit to the list of CUs. void addUnit(std::unique_ptr<DwarfCompileUnit> U); - /// \brief Emit all of the units to the section listed with the given + /// Emit all of the units to the section listed with the given /// abbreviation section. void emitUnits(bool UseOffsets); - /// \brief Emit the given unit to its section. + /// Emit the given unit to its section. void emitUnit(DwarfUnit *U, bool UseOffsets); - /// \brief Emit a set of abbreviations to the specific section. + /// Emit a set of abbreviations to the specific section. void emitAbbrevs(MCSection *); - /// \brief Emit all of the strings to the section given. - void emitStrings(MCSection *StrSection, MCSection *OffsetSection = nullptr); + /// Emit all of the strings to the section given. If OffsetSection is + /// non-null, emit a table of string offsets to it. If UseRelativeOffsets + /// is false, emit absolute offsets to the strings. Otherwise, emit + /// relocatable references to the strings if they are supported by the target. + void emitStrings(MCSection *StrSection, MCSection *OffsetSection = nullptr, + bool UseRelativeOffsets = false); - /// \brief Returns the string pool. + /// Returns the string pool. DwarfStringPool &getStringPool() { return StrPool; } + MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; } + + void setStringOffsetsStartSym(MCSymbol *Sym) { StringOffsetsStartSym = Sym; } + + MCSymbol *getRnglistsTableBaseSym() const { return RnglistsTableBaseSym; } + + void setRnglistsTableBaseSym(MCSymbol *Sym) { RnglistsTableBaseSym = Sym; } + /// \returns false if the variable was merged with a previous one. bool addScopeVariable(LexicalScope *LS, DbgVariable *Var); - DenseMap<LexicalScope *, SmallVector<DbgVariable *, 8>> &getScopeVariables() { + DenseMap<LexicalScope *, ScopeVars> &getScopeVariables() { return ScopeVariables; } diff --git a/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp b/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp index aa5f01e88933..a61fa83cfb03 100644 --- a/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp @@ -39,8 +39,30 @@ DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm, return EntryRef(*I.first); } +void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm, + MCSection *Section, + MCSymbol *StartSym) { + if (empty()) + return; + Asm.OutStreamer->SwitchSection(Section); + unsigned EntrySize = 4; + // FIXME: DWARF64 + // We are emitting the header for a contribution to the string offsets + // table. The header consists of an entry with the contribution's + // size (not including the size of the length field), the DWARF version and + // 2 bytes of padding. + Asm.emitInt32(size() * EntrySize + 4); + Asm.emitInt16(Asm.getDwarfVersion()); + Asm.emitInt16(0); + // Define the symbol that marks the start of the contribution. It is + // referenced by most unit headers via DW_AT_str_offsets_base. + // Split units do not use the attribute. + if (StartSym) + Asm.OutStreamer->EmitLabel(StartSym); +} + void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, - MCSection *OffsetSection) { + MCSection *OffsetSection, bool UseRelativeOffsets) { if (Pool.empty()) return; @@ -74,6 +96,9 @@ void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, Asm.OutStreamer->SwitchSection(OffsetSection); unsigned size = 4; // FIXME: DWARF64 is 8. for (const auto &Entry : Entries) - Asm.OutStreamer->EmitIntValue(Entry->getValue().Offset, size); + if (UseRelativeOffsets) + Asm.emitDwarfStringOffset(Entry->getValue()); + else + Asm.OutStreamer->EmitIntValue(Entry->getValue().Offset, size); } } diff --git a/lib/CodeGen/AsmPrinter/DwarfStringPool.h b/lib/CodeGen/AsmPrinter/DwarfStringPool.h index 1cac3b7c8432..6e6988ea4ad4 100644 --- a/lib/CodeGen/AsmPrinter/DwarfStringPool.h +++ b/lib/CodeGen/AsmPrinter/DwarfStringPool.h @@ -19,6 +19,7 @@ namespace llvm { class AsmPrinter; class MCSection; +class MCSymbol; // Collection of strings for this unit and assorted symbols. // A String->Symbol mapping of strings used by indirect @@ -36,11 +37,17 @@ public: DwarfStringPool(BumpPtrAllocator &A, AsmPrinter &Asm, StringRef Prefix); + void emitStringOffsetsTableHeader(AsmPrinter &Asm, MCSection *OffsetSection, + MCSymbol *StartSym); + void emit(AsmPrinter &Asm, MCSection *StrSection, - MCSection *OffsetSection = nullptr); + MCSection *OffsetSection = nullptr, + bool UseRelativeOffsets = false); bool empty() const { return Pool.empty(); } + unsigned size() const { return Pool.size(); } + /// Get a reference to an entry in the string pool. EntryRef getEntry(AsmPrinter &Asm, StringRef Str); }; diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 911e46235781..43b835b2c4aa 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -19,10 +19,10 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/iterator_range.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineOperand.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/Constants.h" @@ -30,12 +30,14 @@ #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Metadata.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MachineLocation.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include <cassert> #include <cstdint> #include <string> @@ -45,11 +47,6 @@ using namespace llvm; #define DEBUG_TYPE "dwarfdebug" -static cl::opt<bool> -GenerateDwarfTypeUnits("generate-type-units", cl::Hidden, - cl::desc("Generate DWARF4 type units."), - cl::init(false)); - DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU, DIELoc &DIE) : DwarfExpression(AP.getDwarfVersion()), AP(AP), DU(DU), @@ -83,8 +80,6 @@ DwarfTypeUnit::DwarfTypeUnit(DwarfCompileUnit &CU, AsmPrinter *A, MCDwarfDwoLineTable *SplitLineTable) : DwarfUnit(dwarf::DW_TAG_type_unit, CU.getCUNode(), A, DW, DWU), CU(CU), SplitLineTable(SplitLineTable) { - if (SplitLineTable) - addSectionOffset(getUnitDie(), dwarf::DW_AT_stmt_list, 0); } DwarfUnit::~DwarfUnit() { @@ -185,7 +180,7 @@ bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const { return false; return (isa<DIType>(D) || (isa<DISubprogram>(D) && !cast<DISubprogram>(D)->isDefinition())) && - !GenerateDwarfTypeUnits; + !DD->generateTypeUnits(); } DIE *DwarfUnit::getDIE(const DINode *D) const { @@ -239,9 +234,28 @@ void DwarfUnit::addSInt(DIELoc &Die, Optional<dwarf::Form> Form, void DwarfUnit::addString(DIE &Die, dwarf::Attribute Attribute, StringRef String) { - Die.addValue(DIEValueAllocator, Attribute, - isDwoUnit() ? dwarf::DW_FORM_GNU_str_index : dwarf::DW_FORM_strp, - DIEString(DU->getStringPool().getEntry(*Asm, String))); + if (DD->useInlineStrings()) { + Die.addValue(DIEValueAllocator, Attribute, dwarf::DW_FORM_string, + new (DIEValueAllocator) + DIEInlineString(String, DIEValueAllocator)); + return; + } + auto StringPoolEntry = DU->getStringPool().getEntry(*Asm, String); + dwarf::Form IxForm = + isDwoUnit() ? dwarf::DW_FORM_GNU_str_index : dwarf::DW_FORM_strp; + // For DWARF v5 and beyond, use the smallest strx? form possible. + if (useSegmentedStringOffsetsTable()) { + IxForm = dwarf::DW_FORM_strx1; + unsigned Index = StringPoolEntry.getIndex(); + if (Index > 0xffffff) + IxForm = dwarf::DW_FORM_strx4; + else if (Index > 0xffff) + IxForm = dwarf::DW_FORM_strx3; + else if (Index > 0xff) + IxForm = dwarf::DW_FORM_strx2; + } + Die.addValue(DIEValueAllocator, Attribute, IxForm, + DIEString(StringPoolEntry)); } DIEValueList::value_iterator DwarfUnit::addLabel(DIEValueList &Die, @@ -263,9 +277,33 @@ void DwarfUnit::addSectionOffset(DIE &Die, dwarf::Attribute Attribute, addUInt(Die, Attribute, dwarf::DW_FORM_data4, Integer); } -unsigned DwarfTypeUnit::getOrCreateSourceID(StringRef FileName, StringRef DirName) { - return SplitLineTable ? SplitLineTable->getFile(DirName, FileName) - : getCU().getOrCreateSourceID(FileName, DirName); +MD5::MD5Result *DwarfUnit::getMD5AsBytes(const DIFile *File) const { + assert(File); + if (DD->getDwarfVersion() < 5) + return nullptr; + Optional<DIFile::ChecksumInfo<StringRef>> Checksum = File->getChecksum(); + if (!Checksum || Checksum->Kind != DIFile::CSK_MD5) + return nullptr; + + // Convert the string checksum to an MD5Result for the streamer. + // The verifier validates the checksum so we assume it's okay. + // An MD5 checksum is 16 bytes. + std::string ChecksumString = fromHex(Checksum->Value); + void *CKMem = Asm->OutStreamer->getContext().allocate(16, 1); + memcpy(CKMem, ChecksumString.data(), 16); + return reinterpret_cast<MD5::MD5Result *>(CKMem); +} + +unsigned DwarfTypeUnit::getOrCreateSourceID(const DIFile *File) { + if (!SplitLineTable) + return getCU().getOrCreateSourceID(File); + if (!UsedLineTable) { + UsedLineTable = true; + // This is a split type unit that needs a line table. + addSectionOffset(getUnitDie(), dwarf::DW_AT_stmt_list, 0); + } + return SplitLineTable->getFile(File->getDirectory(), File->getFilename(), + getMD5AsBytes(File), File->getSource()); } void DwarfUnit::addOpAddress(DIELoc &Die, const MCSymbol *Sym) { @@ -335,12 +373,11 @@ void DwarfUnit::addBlock(DIE &Die, dwarf::Attribute Attribute, Die.addValue(DIEValueAllocator, Attribute, Block->BestForm(), Block); } -void DwarfUnit::addSourceLine(DIE &Die, unsigned Line, StringRef File, - StringRef Directory) { +void DwarfUnit::addSourceLine(DIE &Die, unsigned Line, const DIFile *File) { if (Line == 0) return; - unsigned FileID = getOrCreateSourceID(File, Directory); + unsigned FileID = getOrCreateSourceID(File); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, None, FileID); addUInt(Die, dwarf::DW_AT_decl_line, None, Line); @@ -349,32 +386,31 @@ void DwarfUnit::addSourceLine(DIE &Die, unsigned Line, StringRef File, void DwarfUnit::addSourceLine(DIE &Die, const DILocalVariable *V) { assert(V); - addSourceLine(Die, V->getLine(), V->getScope()->getFilename(), - V->getScope()->getDirectory()); + addSourceLine(Die, V->getLine(), V->getFile()); } void DwarfUnit::addSourceLine(DIE &Die, const DIGlobalVariable *G) { assert(G); - addSourceLine(Die, G->getLine(), G->getFilename(), G->getDirectory()); + addSourceLine(Die, G->getLine(), G->getFile()); } void DwarfUnit::addSourceLine(DIE &Die, const DISubprogram *SP) { assert(SP); - addSourceLine(Die, SP->getLine(), SP->getFilename(), SP->getDirectory()); + addSourceLine(Die, SP->getLine(), SP->getFile()); } void DwarfUnit::addSourceLine(DIE &Die, const DIType *Ty) { assert(Ty); - addSourceLine(Die, Ty->getLine(), Ty->getFilename(), Ty->getDirectory()); + addSourceLine(Die, Ty->getLine(), Ty->getFile()); } void DwarfUnit::addSourceLine(DIE &Die, const DIObjCProperty *Ty) { assert(Ty); - addSourceLine(Die, Ty->getLine(), Ty->getFilename(), Ty->getDirectory()); + addSourceLine(Die, Ty->getLine(), Ty->getFile()); } /* Byref variables, in Blocks, are declared by the programmer as "SomeType @@ -727,7 +763,7 @@ DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) { else if (auto *STy = dyn_cast<DISubroutineType>(Ty)) constructTypeDIE(TyDIE, STy); else if (auto *CTy = dyn_cast<DICompositeType>(Ty)) { - if (GenerateDwarfTypeUnits && !Ty->isForwardDecl()) + if (DD->generateTypeUnits() && !Ty->isForwardDecl()) if (MDString *TypeId = CTy->getRawIdentifier()) { DD->addDwarfTypeUnitType(getCU(), TypeId->getString(), TyDIE, CTy); // Skip updating the accelerator tables since this is not the full type. @@ -917,9 +953,24 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { case dwarf::DW_TAG_enumeration_type: constructEnumTypeDIE(Buffer, CTy); break; + case dwarf::DW_TAG_variant_part: case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_union_type: case dwarf::DW_TAG_class_type: { + // Emit the discriminator for a variant part. + DIDerivedType *Discriminator = nullptr; + if (Tag == dwarf::DW_TAG_variant_part) { + Discriminator = CTy->getDiscriminator(); + if (Discriminator) { + // DWARF says: + // If the variant part has a discriminant, the discriminant is + // represented by a separate debugging information entry which is + // a child of the variant part entry. + DIE &DiscMember = constructMemberDIE(Buffer, Discriminator); + addDIEEntry(Buffer, dwarf::DW_AT_discr, DiscMember); + } + } + // Add elements to structure type. DINodeArray Elements = CTy->getElements(); for (const auto *Element : Elements) { @@ -933,6 +984,18 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { addType(ElemDie, resolve(DDTy->getBaseType()), dwarf::DW_AT_friend); } else if (DDTy->isStaticMember()) { getOrCreateStaticMemberDIE(DDTy); + } else if (Tag == dwarf::DW_TAG_variant_part) { + // When emitting a variant part, wrap each member in + // DW_TAG_variant. + DIE &Variant = createAndAddDIE(dwarf::DW_TAG_variant, Buffer); + if (const ConstantInt *CI = + dyn_cast_or_null<ConstantInt>(DDTy->getDiscriminantValue())) { + if (isUnsignedDIType(DD, resolve(Discriminator->getBaseType()))) + addUInt(Variant, dwarf::DW_AT_discr_value, None, CI->getZExtValue()); + else + addSInt(Variant, dwarf::DW_AT_discr_value, None, CI->getSExtValue()); + } + constructMemberDIE(Variant, DDTy); } else { constructMemberDIE(Buffer, DDTy); } @@ -952,6 +1015,11 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { if (unsigned PropertyAttributes = Property->getAttributes()) addUInt(ElemDie, dwarf::DW_AT_APPLE_property_attribute, None, PropertyAttributes); + } else if (auto *Composite = dyn_cast<DICompositeType>(Element)) { + if (Composite->getTag() == dwarf::DW_TAG_variant_part) { + DIE &VariantPart = createAndAddDIE(Composite->getTag(), Buffer); + constructTypeDIE(VariantPart, Composite); + } } } @@ -975,6 +1043,15 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) addTemplateParams(Buffer, CTy->getTemplateParams()); + // Add the type's non-standard calling convention. + uint8_t CC = 0; + if (CTy->isTypePassByValue()) + CC = dwarf::DW_CC_pass_by_value; + else if (CTy->isTypePassByReference()) + CC = dwarf::DW_CC_pass_by_reference; + if (CC) + addUInt(Buffer, dwarf::DW_AT_calling_convention, dwarf::DW_FORM_data1, + CC); break; } default: @@ -1152,9 +1229,8 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP, // Look at the Decl's linkage name only if we emitted it. if (DD->useAllLinkageNames()) DeclLinkageName = SPDecl->getLinkageName(); - unsigned DeclID = - getOrCreateSourceID(SPDecl->getFilename(), SPDecl->getDirectory()); - unsigned DefID = getOrCreateSourceID(SP->getFilename(), SP->getDirectory()); + unsigned DeclID = getOrCreateSourceID(SPDecl->getFile()); + unsigned DefID = getOrCreateSourceID(SP->getFile()); if (DeclID != DefID) addUInt(SPDie, dwarf::DW_AT_decl_file, None, DefID); @@ -1304,14 +1380,17 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, // DW_AT_lower_bound and DW_AT_count attributes. int64_t LowerBound = SR->getLowerBound(); int64_t DefaultLowerBound = getDefaultLowerBound(); - int64_t Count = SR->getCount(); + int64_t Count = -1; + if (auto *CI = SR->getCount().dyn_cast<ConstantInt*>()) + Count = CI->getSExtValue(); if (DefaultLowerBound == -1 || LowerBound != DefaultLowerBound) addUInt(DW_Subrange, dwarf::DW_AT_lower_bound, None, LowerBound); - if (Count != -1) - // FIXME: An unbounded array should reference the expression that defines - // the array. + if (auto *CV = SR->getCount().dyn_cast<DIVariable*>()) { + if (auto *CountVarDIE = getDIE(CV)) + addDIEEntry(DW_Subrange, dwarf::DW_AT_count, *CountVarDIE); + } else if (Count != -1) addUInt(DW_Subrange, dwarf::DW_AT_count, None, Count); } @@ -1320,16 +1399,49 @@ DIE *DwarfUnit::getIndexTyDie() { return IndexTyDie; // Construct an integer type to use for indexes. IndexTyDie = &createAndAddDIE(dwarf::DW_TAG_base_type, getUnitDie()); - addString(*IndexTyDie, dwarf::DW_AT_name, "sizetype"); + StringRef Name = "__ARRAY_SIZE_TYPE__"; + addString(*IndexTyDie, dwarf::DW_AT_name, Name); addUInt(*IndexTyDie, dwarf::DW_AT_byte_size, None, sizeof(int64_t)); addUInt(*IndexTyDie, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, dwarf::DW_ATE_unsigned); + DD->addAccelType(Name, *IndexTyDie, /*Flags*/ 0); return IndexTyDie; } +/// Returns true if the vector's size differs from the sum of sizes of elements +/// the user specified. This can occur if the vector has been rounded up to +/// fit memory alignment constraints. +static bool hasVectorBeenPadded(const DICompositeType *CTy) { + assert(CTy && CTy->isVector() && "Composite type is not a vector"); + const uint64_t ActualSize = CTy->getSizeInBits(); + + // Obtain the size of each element in the vector. + DIType *BaseTy = CTy->getBaseType().resolve(); + assert(BaseTy && "Unknown vector element type."); + const uint64_t ElementSize = BaseTy->getSizeInBits(); + + // Locate the number of elements in the vector. + const DINodeArray Elements = CTy->getElements(); + assert(Elements.size() == 1 && + Elements[0]->getTag() == dwarf::DW_TAG_subrange_type && + "Invalid vector element array, expected one element of type subrange"); + const auto Subrange = cast<DISubrange>(Elements[0]); + const auto CI = Subrange->getCount().get<ConstantInt *>(); + const int32_t NumVecElements = CI->getSExtValue(); + + // Ensure we found the element count and that the actual size is wide + // enough to contain the requested size. + assert(ActualSize >= (NumVecElements * ElementSize) && "Invalid vector size"); + return ActualSize != (NumVecElements * ElementSize); +} + void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { - if (CTy->isVector()) + if (CTy->isVector()) { addFlag(Buffer, dwarf::DW_AT_GNU_vector); + if (hasVectorBeenPadded(CTy)) + addUInt(Buffer, dwarf::DW_AT_byte_size, None, + CTy->getSizeInBits() / CHAR_BIT); + } // Emit the element type. addType(Buffer, resolve(CTy->getBaseType())); @@ -1350,6 +1462,15 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { } void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) { + const DIType *DTy = resolve(CTy->getBaseType()); + bool IsUnsigned = DTy && isUnsignedDIType(DD, DTy); + if (DTy) { + if (DD->getDwarfVersion() >= 3) + addType(Buffer, DTy); + if (DD->getDwarfVersion() >= 4 && (CTy->getFlags() & DINode::FlagFixedEnum)) + addFlag(Buffer, dwarf::DW_AT_enum_class); + } + DINodeArray Elements = CTy->getElements(); // Add enumerators to enumeration type. @@ -1359,16 +1480,10 @@ void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) { DIE &Enumerator = createAndAddDIE(dwarf::DW_TAG_enumerator, Buffer); StringRef Name = Enum->getName(); addString(Enumerator, dwarf::DW_AT_name, Name); - int64_t Value = Enum->getValue(); - addSInt(Enumerator, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata, - Value); + auto Value = static_cast<uint64_t>(Enum->getValue()); + addConstantValue(Enumerator, IsUnsigned, Value); } } - const DIType *DTy = resolve(CTy->getBaseType()); - if (DTy) { - addType(Buffer, DTy); - addFlag(Buffer, dwarf::DW_AT_enum_class); - } } void DwarfUnit::constructContainingTypeDIEs() { @@ -1385,13 +1500,14 @@ void DwarfUnit::constructContainingTypeDIEs() { } } -void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { +DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { DIE &MemberDie = createAndAddDIE(DT->getTag(), Buffer); StringRef Name = DT->getName(); if (!Name.empty()) addString(MemberDie, dwarf::DW_AT_name, Name); - addType(MemberDie, resolve(DT->getBaseType())); + if (DIType *Resolved = resolve(DT->getBaseType())) + addType(MemberDie, Resolved); addSourceLine(MemberDie, DT); @@ -1489,6 +1605,8 @@ void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { if (DT->isArtificial()) addFlag(MemberDie, dwarf::DW_AT_artificial); + + return MemberDie; } DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) { @@ -1541,18 +1659,18 @@ DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) { void DwarfUnit::emitCommonHeader(bool UseOffsets, dwarf::UnitType UT) { // Emit size of content not including length itself Asm->OutStreamer->AddComment("Length of Unit"); - Asm->EmitInt32(getHeaderSize() + getUnitDie().getSize()); + Asm->emitInt32(getHeaderSize() + getUnitDie().getSize()); Asm->OutStreamer->AddComment("DWARF version number"); unsigned Version = DD->getDwarfVersion(); - Asm->EmitInt16(Version); + Asm->emitInt16(Version); // DWARF v5 reorders the address size and adds a unit type. if (Version >= 5) { Asm->OutStreamer->AddComment("DWARF Unit Type"); - Asm->EmitInt8(UT); + Asm->emitInt8(UT); Asm->OutStreamer->AddComment("Address Size (in bytes)"); - Asm->EmitInt8(Asm->MAI->getCodePointerSize()); + Asm->emitInt8(Asm->MAI->getCodePointerSize()); } // We share one abbreviations table across all units so it's always at the @@ -1561,14 +1679,14 @@ void DwarfUnit::emitCommonHeader(bool UseOffsets, dwarf::UnitType UT) { Asm->OutStreamer->AddComment("Offset Into Abbrev. Section"); const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); if (UseOffsets) - Asm->EmitInt32(0); + Asm->emitInt32(0); else Asm->emitDwarfSymbolReference( TLOF.getDwarfAbbrevSection()->getBeginSymbol(), false); if (Version <= 4) { Asm->OutStreamer->AddComment("Address Size (in bytes)"); - Asm->EmitInt8(Asm->MAI->getCodePointerSize()); + Asm->emitInt8(Asm->MAI->getCodePointerSize()); } } @@ -1627,3 +1745,19 @@ const MCSymbol *DwarfUnit::getCrossSectionRelativeBaseAddress() const { return nullptr; return getSection()->getBeginSymbol(); } + +void DwarfUnit::addStringOffsetsStart() { + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + addSectionLabel(getUnitDie(), dwarf::DW_AT_str_offsets_base, + DU->getStringOffsetsStartSym(), + TLOF.getDwarfStrOffSection()->getBeginSymbol()); +} + +void DwarfUnit::addRnglistsBase() { + assert(DD->getDwarfVersion() >= 5 && + "DW_AT_rnglists_base requires DWARF version 5 or later"); + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + addSectionLabel(getUnitDie(), dwarf::DW_AT_rnglists_base, + DU->getRnglistsTableBaseSym(), + TLOF.getDwarfRnglistsSection()->getBeginSymbol()); +} diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.h b/lib/CodeGen/AsmPrinter/DwarfUnit.h index 4cc01b3298d4..69696f626536 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -98,7 +98,7 @@ protected: /// corresponds to the MDNode mapped with the subprogram DIE. DenseMap<DIE *, const DINode *> ContainingTypeMap; - DwarfUnit(dwarf::Tag, const DICompileUnit *CU, AsmPrinter *A, DwarfDebug *DW, + DwarfUnit(dwarf::Tag, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU); bool applySubprogramDefinitionAttributes(const DISubprogram *SP, DIE &SPDie); @@ -112,6 +112,8 @@ public: uint16_t getLanguage() const { return CUNode->getSourceLanguage(); } const DICompileUnit *getCUNode() const { return CUNode; } + uint16_t getDwarfVersion() const { return DD->getDwarfVersion(); } + /// Return true if this compile unit has something to write out. bool hasContent() const { return getUnitDie().hasChildren(); } @@ -185,7 +187,7 @@ public: /// Add a dwarf op address data and value using the form given and an /// op of either DW_FORM_addr or DW_FORM_GNU_addr_index. - void addOpAddress(DIELoc &Die, const MCSymbol *Label); + void addOpAddress(DIELoc &Die, const MCSymbol *Sym); /// Add a label delta attribute data and value. void addLabelDelta(DIE &Die, dwarf::Attribute Attribute, const MCSymbol *Hi, @@ -201,14 +203,13 @@ public: void addDIETypeSignature(DIE &Die, uint64_t Signature); /// Add block data. - void addBlock(DIE &Die, dwarf::Attribute Attribute, DIELoc *Block); + void addBlock(DIE &Die, dwarf::Attribute Attribute, DIELoc *Loc); /// Add block data. void addBlock(DIE &Die, dwarf::Attribute Attribute, DIEBlock *Block); /// Add location information to specified debug information entry. - void addSourceLine(DIE &Die, unsigned Line, StringRef File, - StringRef Directory); + void addSourceLine(DIE &Die, unsigned Line, const DIFile *File); void addSourceLine(DIE &Die, const DILocalVariable *V); void addSourceLine(DIE &Die, const DIGlobalVariable *G); void addSourceLine(DIE &Die, const DISubprogram *SP); @@ -259,7 +260,7 @@ public: bool SkipSPAttributes = false); /// Find existing DIE or create new DIE for the given type. - DIE *getOrCreateTypeDIE(const MDNode *N); + DIE *getOrCreateTypeDIE(const MDNode *TyNode); /// Get context owner's DIE. DIE *getOrCreateContextDIE(const DIScope *Context); @@ -274,6 +275,10 @@ public: /// call insertDIE if MD is not null. DIE &createAndAddDIE(unsigned Tag, DIE &Parent, const DINode *N = nullptr); + bool useSegmentedStringOffsetsTable() const { + return DD->useSegmentedStringOffsetsTable(); + } + /// Compute the size of a header for this unit, not including the initial /// length field. virtual unsigned getHeaderSize() const { @@ -287,6 +292,12 @@ public: /// Emit the header for this unit, not including the initial length field. virtual void emitHeader(bool UseOffsets) = 0; + /// Add the DW_AT_str_offsets_base attribute to the unit DIE. + void addStringOffsetsStart(); + + /// Add the DW_AT_rnglists_base attribute to the unit DIE. + void addRnglistsBase(); + virtual DwarfCompileUnit &getCU() = 0; void constructTypeDIE(DIE &Buffer, const DICompositeType *CTy); @@ -300,15 +311,19 @@ public: const MCSymbol *Label, const MCSymbol *Sec); + /// If the \p File has an MD5 checksum, return it as an MD5Result + /// allocated in the MCContext. + MD5::MD5Result *getMD5AsBytes(const DIFile *File) const; + protected: ~DwarfUnit(); /// Create new static data member DIE. DIE *getOrCreateStaticMemberDIE(const DIDerivedType *DT); - /// Look up the source ID with the given directory and source file names. If - /// none currently exists, create a new ID and insert it in the line table. - virtual unsigned getOrCreateSourceID(StringRef File, StringRef Directory) = 0; + /// Look up the source ID for the given file. If none currently exists, + /// create a new ID and insert it in the line table. + virtual unsigned getOrCreateSourceID(const DIFile *File) = 0; /// Look in the DwarfDebug map for the MDNode that corresponds to the /// reference. @@ -327,11 +342,11 @@ protected: private: void constructTypeDIE(DIE &Buffer, const DIBasicType *BTy); void constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy); - void constructTypeDIE(DIE &Buffer, const DISubroutineType *DTy); + void constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy); void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy); void constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy); void constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy); - void constructMemberDIE(DIE &Buffer, const DIDerivedType *DT); + DIE &constructMemberDIE(DIE &Buffer, const DIDerivedType *DT); void constructTemplateTypeParameterDIE(DIE &Buffer, const DITemplateTypeParameter *TP); void constructTemplateValueParameterDIE(DIE &Buffer, @@ -357,8 +372,9 @@ class DwarfTypeUnit final : public DwarfUnit { const DIE *Ty; DwarfCompileUnit &CU; MCDwarfDwoLineTable *SplitLineTable; + bool UsedLineTable = false; - unsigned getOrCreateSourceID(StringRef File, StringRef Directory) override; + unsigned getOrCreateSourceID(const DIFile *File) override; bool isDwoUnit() const override; public: diff --git a/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/lib/CodeGen/AsmPrinter/EHStreamer.cpp index 3cdab57bca70..65de9d7e65a4 100644 --- a/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -20,7 +20,6 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/MC/MCAsmInfo.h" @@ -30,6 +29,7 @@ #include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/Casting.h" #include "llvm/Support/LEB128.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include <algorithm> #include <cassert> #include <cstdint> @@ -58,10 +58,10 @@ unsigned EHStreamer::sharedTypeIDs(const LandingPadInfo *L, /// Compute the actions table and gather the first action index for each landing /// pad site. -unsigned EHStreamer:: -computeActionsTable(const SmallVectorImpl<const LandingPadInfo*> &LandingPads, - SmallVectorImpl<ActionEntry> &Actions, - SmallVectorImpl<unsigned> &FirstActions) { +void EHStreamer::computeActionsTable( + const SmallVectorImpl<const LandingPadInfo *> &LandingPads, + SmallVectorImpl<ActionEntry> &Actions, + SmallVectorImpl<unsigned> &FirstActions) { // The action table follows the call-site table in the LSDA. The individual // records are of two types: // @@ -149,7 +149,7 @@ computeActionsTable(const SmallVectorImpl<const LandingPadInfo*> &LandingPads, FirstAction = SizeActions + SizeSiteActions - SizeAction + 1; } // else identical - re-use previous FirstAction - // Information used when created the call-site table. The action record + // Information used when creating the call-site table. The action record // field of the call site record is the offset of the first associated // action record, relative to the start of the actions table. This value is // biased by 1 (1 indicating the start of the actions table), and 0 @@ -161,8 +161,6 @@ computeActionsTable(const SmallVectorImpl<const LandingPadInfo*> &LandingPads, PrevLPI = LPI; } - - return SizeActions; } /// Return `true' if this is a call to a function marked `nounwind'. Return @@ -361,55 +359,33 @@ void EHStreamer::emitExceptionTable() { LandingPads.push_back(&PadInfos[i]); // Order landing pads lexicographically by type id. - std::sort(LandingPads.begin(), LandingPads.end(), - [](const LandingPadInfo *L, - const LandingPadInfo *R) { return L->TypeIds < R->TypeIds; }); + llvm::sort(LandingPads.begin(), LandingPads.end(), + [](const LandingPadInfo *L, + const LandingPadInfo *R) { return L->TypeIds < R->TypeIds; }); // Compute the actions table and gather the first action index for each // landing pad site. SmallVector<ActionEntry, 32> Actions; SmallVector<unsigned, 64> FirstActions; - unsigned SizeActions = - computeActionsTable(LandingPads, Actions, FirstActions); + computeActionsTable(LandingPads, Actions, FirstActions); // Compute the call-site table. SmallVector<CallSiteEntry, 64> CallSites; computeCallSiteTable(CallSites, LandingPads, FirstActions); - // Final tallies. - - // Call sites. bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; - bool HaveTTData = IsSJLJ ? (!TypeInfos.empty() || !FilterIds.empty()) : true; - - unsigned CallSiteTableLength; - if (IsSJLJ) - CallSiteTableLength = 0; - else { - unsigned SiteStartSize = 4; // dwarf::DW_EH_PE_udata4 - unsigned SiteLengthSize = 4; // dwarf::DW_EH_PE_udata4 - unsigned LandingPadSize = 4; // dwarf::DW_EH_PE_udata4 - CallSiteTableLength = - CallSites.size() * (SiteStartSize + SiteLengthSize + LandingPadSize); - } - - for (unsigned i = 0, e = CallSites.size(); i < e; ++i) { - CallSiteTableLength += getULEB128Size(CallSites[i].Action); - if (IsSJLJ) - CallSiteTableLength += getULEB128Size(i); - } + unsigned CallSiteEncoding = + IsSJLJ ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_uleb128; + bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty(); // Type infos. MCSection *LSDASection = Asm->getObjFileLowering().getLSDASection(); unsigned TTypeEncoding; - unsigned TypeFormatSize; if (!HaveTTData) { - // For SjLj exceptions, if there is no TypeInfo, then we just explicitly say - // that we're omitting that bit. + // If there is no TypeInfo, then we just explicitly say that we're omitting + // that bit. TTypeEncoding = dwarf::DW_EH_PE_omit; - // dwarf::DW_EH_PE_absptr - TypeFormatSize = Asm->getDataLayout().getPointerSize(); } else { // Okay, we have actual filters or typeinfos to emit. As such, we need to // pick a type encoding for them. We're about to emit a list of pointers to @@ -439,7 +415,6 @@ void EHStreamer::emitExceptionTable() { // in target-independent code. // TTypeEncoding = Asm->getObjFileLowering().getTTypeEncoding(); - TypeFormatSize = Asm->GetSizeOfEncodedValue(TTypeEncoding); } // Begin the exception table. @@ -460,64 +435,35 @@ void EHStreamer::emitExceptionTable() { Asm->EmitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); Asm->EmitEncodingByte(TTypeEncoding, "@TType"); - // The type infos need to be aligned. GCC does this by inserting padding just - // before the type infos. However, this changes the size of the exception - // table, so you need to take this into account when you output the exception - // table size. However, the size is output using a variable length encoding. - // So by increasing the size by inserting padding, you may increase the number - // of bytes used for writing the size. If it increases, say by one byte, then - // you now need to output one less byte of padding to get the type infos - // aligned. However this decreases the size of the exception table. This - // changes the value you have to output for the exception table size. Due to - // the variable length encoding, the number of bytes used for writing the - // length may decrease. If so, you then have to increase the amount of - // padding. And so on. If you look carefully at the GCC code you will see that - // it indeed does this in a loop, going on and on until the values stabilize. - // We chose another solution: don't output padding inside the table like GCC - // does, instead output it before the table. - unsigned SizeTypes = TypeInfos.size() * TypeFormatSize; - unsigned CallSiteTableLengthSize = getULEB128Size(CallSiteTableLength); - unsigned TTypeBaseOffset = - sizeof(int8_t) + // Call site format - CallSiteTableLengthSize + // Call site table length size - CallSiteTableLength + // Call site table length - SizeActions + // Actions size - SizeTypes; - unsigned TTypeBaseOffsetSize = getULEB128Size(TTypeBaseOffset); - unsigned TotalSize = - sizeof(int8_t) + // LPStart format - sizeof(int8_t) + // TType format - (HaveTTData ? TTypeBaseOffsetSize : 0) + // TType base offset size - TTypeBaseOffset; // TType base offset - unsigned PadBytes = (4 - TotalSize) & 3; - + MCSymbol *TTBaseLabel = nullptr; if (HaveTTData) { - // Account for any extra padding that will be added to the call site table - // length. - Asm->EmitPaddedULEB128(TTypeBaseOffset, TTypeBaseOffsetSize + PadBytes, - "@TType base offset"); - PadBytes = 0; + // N.B.: There is a dependency loop between the size of the TTBase uleb128 + // here and the amount of padding before the aligned type table. The + // assembler must sometimes pad this uleb128 or insert extra padding before + // the type table. See PR35809 or GNU as bug 4029. + MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); + TTBaseLabel = Asm->createTempSymbol("ttbase"); + Asm->EmitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); + Asm->OutStreamer->EmitLabel(TTBaseRefLabel); } bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); + // Emit the landing pad call site table. + MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); + MCSymbol *CstEndLabel = Asm->createTempSymbol("cst_end"); + Asm->EmitEncodingByte(CallSiteEncoding, "Call site"); + Asm->EmitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); + Asm->OutStreamer->EmitLabel(CstBeginLabel); + // SjLj Exception handling if (IsSJLJ) { - Asm->EmitEncodingByte(dwarf::DW_EH_PE_udata4, "Call site"); - - // Add extra padding if it wasn't added to the TType base offset. - Asm->EmitPaddedULEB128(CallSiteTableLength, - CallSiteTableLengthSize + PadBytes, - "Call site table length"); - - // Emit the landing pad site information. unsigned idx = 0; for (SmallVectorImpl<CallSiteEntry>::const_iterator I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) { const CallSiteEntry &S = *I; - // Offset of the landing pad, counted in 16-byte bundles relative to the - // @LPStart address. + // Index of the call site entry. if (VerboseAsm) { Asm->OutStreamer->AddComment(">> Call Site " + Twine(idx) + " <<"); Asm->OutStreamer->AddComment(" On exception at call site "+Twine(idx)); @@ -557,14 +503,6 @@ void EHStreamer::emitExceptionTable() { // A missing entry in the call-site table indicates that a call is not // supposed to throw. - // Emit the landing pad call site table. - Asm->EmitEncodingByte(dwarf::DW_EH_PE_udata4, "Call site"); - - // Add extra padding if it wasn't added to the TType base offset. - Asm->EmitPaddedULEB128(CallSiteTableLength, - CallSiteTableLengthSize + PadBytes, - "Call site table length"); - unsigned Entry = 0; for (SmallVectorImpl<CallSiteEntry>::const_iterator I = CallSites.begin(), E = CallSites.end(); I != E; ++I) { @@ -579,29 +517,27 @@ void EHStreamer::emitExceptionTable() { if (!EndLabel) EndLabel = Asm->getFunctionEnd(); - // Offset of the call site relative to the previous call site, counted in - // number of 16-byte bundles. The first call site is counted relative to - // the start of the procedure fragment. + // Offset of the call site relative to the start of the procedure. if (VerboseAsm) Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + " <<"); - Asm->EmitLabelDifference(BeginLabel, EHFuncBeginSym, 4); + Asm->EmitLabelDifferenceAsULEB128(BeginLabel, EHFuncBeginSym); if (VerboseAsm) Asm->OutStreamer->AddComment(Twine(" Call between ") + BeginLabel->getName() + " and " + EndLabel->getName()); - Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); + Asm->EmitLabelDifferenceAsULEB128(EndLabel, BeginLabel); - // Offset of the landing pad, counted in 16-byte bundles relative to the - // @LPStart address. + // Offset of the landing pad relative to the start of the procedure. if (!S.LPad) { if (VerboseAsm) Asm->OutStreamer->AddComment(" has no landing pad"); - Asm->OutStreamer->EmitIntValue(0, 4/*size*/); + Asm->EmitULEB128(0); } else { if (VerboseAsm) Asm->OutStreamer->AddComment(Twine(" jumps to ") + S.LPad->LandingPadLabel->getName()); - Asm->EmitLabelDifference(S.LPad->LandingPadLabel, EHFuncBeginSym, 4); + Asm->EmitLabelDifferenceAsULEB128(S.LPad->LandingPadLabel, + EHFuncBeginSym); } // Offset of the first associated action record, relative to the start of @@ -617,6 +553,7 @@ void EHStreamer::emitExceptionTable() { Asm->EmitULEB128(S.Action); } } + Asm->OutStreamer->EmitLabel(CstEndLabel); // Emit the Action Table. int Entry = 0; @@ -660,12 +597,15 @@ void EHStreamer::emitExceptionTable() { Asm->EmitSLEB128(Action.NextAction); } - emitTypeInfos(TTypeEncoding); + if (HaveTTData) { + Asm->EmitAlignment(2); + emitTypeInfos(TTypeEncoding, TTBaseLabel); + } Asm->EmitAlignment(2); } -void EHStreamer::emitTypeInfos(unsigned TTypeEncoding) { +void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) { const MachineFunction *MF = Asm->MF; const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos(); const std::vector<unsigned> &FilterIds = MF->getFilterIds(); @@ -687,6 +627,8 @@ void EHStreamer::emitTypeInfos(unsigned TTypeEncoding) { Asm->EmitTTypeReference(GV, TTypeEncoding); } + Asm->OutStreamer->EmitLabel(TTBaseLabel); + // Emit the Exception Specifications. if (VerboseAsm && !FilterIds.empty()) { Asm->OutStreamer->AddComment(">> Filter TypeInfos <<"); diff --git a/lib/CodeGen/AsmPrinter/EHStreamer.h b/lib/CodeGen/AsmPrinter/EHStreamer.h index 7962b761d8de..b89421a1e067 100644 --- a/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -72,9 +72,9 @@ protected: /// Compute the actions table and gather the first action index for each /// landing pad site. - unsigned computeActionsTable(const SmallVectorImpl<const LandingPadInfo*>&LPs, - SmallVectorImpl<ActionEntry> &Actions, - SmallVectorImpl<unsigned> &FirstActions); + void computeActionsTable(const SmallVectorImpl<const LandingPadInfo *> &LandingPads, + SmallVectorImpl<ActionEntry> &Actions, + SmallVectorImpl<unsigned> &FirstActions); void computePadMap(const SmallVectorImpl<const LandingPadInfo *> &LandingPads, RangeMapType &PadMap); @@ -86,7 +86,7 @@ protected: /// no entry and must not be contained in the try-range of any entry - they /// form gaps in the table. Entries must be ordered by try-range address. void computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, - const SmallVectorImpl<const LandingPadInfo *> &LPs, + const SmallVectorImpl<const LandingPadInfo *> &LandingPads, const SmallVectorImpl<unsigned> &FirstActions); /// Emit landing pads and actions. @@ -110,9 +110,9 @@ protected: /// catches in the function. This tables is reversed indexed base 1. void emitExceptionTable(); - virtual void emitTypeInfos(unsigned TTypeEncoding); + virtual void emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel); - // Helpers for for identifying what kind of clause an EH typeid or selector + // Helpers for identifying what kind of clause an EH typeid or selector // corresponds to. Negative selectors are for filter clauses, the zero // selector is for cleanups, and positive selectors are for catch clauses. static bool isFilterEHSelector(int Selector) { return Selector < 0; } diff --git a/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp b/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp index e459c02c9a6e..49cc376fcc98 100644 --- a/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp @@ -19,7 +19,6 @@ #include "llvm/CodeGen/GCMetadataPrinter.h" #include "llvm/CodeGen/GCStrategy.h" #include "llvm/CodeGen/GCs.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" @@ -27,6 +26,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/TargetLoweringObjectFile.h" using namespace llvm; @@ -77,7 +77,7 @@ void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info, // Emit PointCount. OS.AddComment("safe point count"); - AP.EmitInt16(MD.size()); + AP.emitInt16(MD.size()); // And each safe point... for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE; @@ -94,7 +94,7 @@ void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info, // Emit the stack frame size. OS.AddComment("stack frame size (in words)"); - AP.EmitInt16(MD.getFrameSize() / IntPtrSize); + AP.emitInt16(MD.getFrameSize() / IntPtrSize); // Emit stack arity, i.e. the number of stacked arguments. unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6; @@ -102,11 +102,11 @@ void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info, ? MD.getFunction().arg_size() - RegisteredArgs : 0; OS.AddComment("stack arity"); - AP.EmitInt16(StackArity); + AP.emitInt16(StackArity); // Emit the number of live roots in the function. OS.AddComment("live root count"); - AP.EmitInt16(MD.live_size(PI)); + AP.emitInt16(MD.live_size(PI)); // And for each live root... for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI), @@ -114,7 +114,7 @@ void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info, LI != LE; ++LI) { // Emit live root's offset within the stack frame. OS.AddComment("stack index (offset / wordsize)"); - AP.EmitInt16(LI->StackOffset / IntPtrSize); + AP.emitInt16(LI->StackOffset / IntPtrSize); } } } diff --git a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp index e0cc241dd23f..59a57ed30d10 100644 --- a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp @@ -18,7 +18,6 @@ #include "llvm/CodeGen/GCMetadata.h" #include "llvm/CodeGen/GCMetadataPrinter.h" #include "llvm/CodeGen/GCs.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/Mangler.h" @@ -27,6 +26,7 @@ #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include <cctype> #include <cstddef> #include <cstdint> @@ -129,7 +129,7 @@ void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, // Very rude! report_fatal_error(" Too much descriptor for ocaml GC"); } - AP.EmitInt16(NumDescriptors); + AP.emitInt16(NumDescriptors); AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), @@ -166,8 +166,8 @@ void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, } AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize); - AP.EmitInt16(FrameSize); - AP.EmitInt16(LiveCount); + AP.emitInt16(FrameSize); + AP.emitInt16(LiveCount); for (GCFunctionInfo::live_iterator K = FI.live_begin(J), KE = FI.live_end(J); @@ -178,7 +178,7 @@ void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, "GC root stack offset is outside of fixed stack frame and out " "of range for ocaml GC!"); } - AP.EmitInt16(K->StackOffset); + AP.emitInt16(K->StackOffset); } AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); diff --git a/lib/CodeGen/AsmPrinter/WinCFGuard.cpp b/lib/CodeGen/AsmPrinter/WinCFGuard.cpp new file mode 100644 index 000000000000..18d37caf57ee --- /dev/null +++ b/lib/CodeGen/AsmPrinter/WinCFGuard.cpp @@ -0,0 +1,45 @@ +//===-- CodeGen/AsmPrinter/WinCFGuard.cpp - Control Flow Guard Impl ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing Win64 exception info into asm files. +// +//===----------------------------------------------------------------------===// + +#include "WinCFGuard.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Metadata.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCStreamer.h" + +#include <vector> + +using namespace llvm; + +WinCFGuard::WinCFGuard(AsmPrinter *A) : AsmPrinterHandler(), Asm(A) {} + +WinCFGuard::~WinCFGuard() {} + +void WinCFGuard::endModule() { + const Module *M = Asm->MMI->getModule(); + std::vector<const Function *> Functions; + for (const Function &F : *M) + if (F.hasAddressTaken()) + Functions.push_back(&F); + if (Functions.empty()) + return; + auto &OS = *Asm->OutStreamer; + OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGFIDsSection()); + for (const Function *F : Functions) + OS.EmitCOFFSymbolIndex(Asm->getSymbol(F)); +} diff --git a/lib/CodeGen/AsmPrinter/WinCFGuard.h b/lib/CodeGen/AsmPrinter/WinCFGuard.h new file mode 100644 index 000000000000..124e8f04bfad --- /dev/null +++ b/lib/CodeGen/AsmPrinter/WinCFGuard.h @@ -0,0 +1,54 @@ +//===-- WinCFGuard.h - Windows Control Flow Guard Handling ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing windows exception info into asm files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_WINCFGUARD_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_WINCFGUARD_H + +#include "AsmPrinterHandler.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + +class LLVM_LIBRARY_VISIBILITY WinCFGuard : public AsmPrinterHandler { + /// Target of directive emission. + AsmPrinter *Asm; + +public: + WinCFGuard(AsmPrinter *A); + ~WinCFGuard() override; + + void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} + + /// Emit the Control Flow Guard function ID table + void endModule() override; + + /// Gather pre-function debug information. + /// Every beginFunction(MF) call should be followed by an endFunction(MF) + /// call. + void beginFunction(const MachineFunction *MF) override {} + + /// Gather post-function debug information. + /// Please note that some AsmPrinter implementations may not call + /// beginFunction at all. + void endFunction(const MachineFunction *MF) override {} + + /// Process beginning of an instruction. + void beginInstruction(const MachineInstr *MI) override {} + + /// Process end of an instruction. + void endInstruction() override {} +}; + +} // namespace llvm + +#endif diff --git a/lib/CodeGen/AsmPrinter/WinException.cpp b/lib/CodeGen/AsmPrinter/WinException.cpp index a6a8e84a949f..eff73a58d8d2 100644 --- a/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/lib/CodeGen/AsmPrinter/WinException.cpp @@ -21,7 +21,6 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/CodeGen/TargetLowering.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/DataLayout.h" @@ -35,6 +34,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; diff --git a/lib/CodeGen/AsmPrinter/WinException.h b/lib/CodeGen/AsmPrinter/WinException.h index 371061c2c2ec..eed3c4453ffc 100644 --- a/lib/CodeGen/AsmPrinter/WinException.h +++ b/lib/CodeGen/AsmPrinter/WinException.h @@ -100,7 +100,7 @@ public: /// Gather and emit post-function exception information. void endFunction(const MachineFunction *) override; - /// \brief Emit target-specific EH funclet machinery. + /// Emit target-specific EH funclet machinery. void beginFunclet(const MachineBasicBlock &MBB, MCSymbol *Sym) override; void endFunclet() override; }; |
