diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/CodeGen/AsmPrinter | |
parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) |
Notes
Diffstat (limited to 'lib/CodeGen/AsmPrinter')
42 files changed, 1984 insertions, 1226 deletions
diff --git a/lib/CodeGen/AsmPrinter/ARMException.cpp b/lib/CodeGen/AsmPrinter/ARMException.cpp index 9011f025f595..f6ef85a5b78f 100644 --- a/lib/CodeGen/AsmPrinter/ARMException.cpp +++ b/lib/CodeGen/AsmPrinter/ARMException.cpp @@ -1,9 +1,8 @@ //===-- CodeGen/AsmPrinter/ARMException.cpp - ARM EHABI Exception Impl ----===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/AccelTable.cpp b/lib/CodeGen/AsmPrinter/AccelTable.cpp index 95875ccb8a0b..b1b7921ea976 100644 --- a/lib/CodeGen/AsmPrinter/AccelTable.cpp +++ b/lib/CodeGen/AsmPrinter/AccelTable.cpp @@ -1,9 +1,8 @@ //===- 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. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -56,10 +55,10 @@ 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; - }); + llvm::stable_sort(E.second.Values, + [](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()); @@ -82,10 +81,9 @@ void AccelTableBase::finalize(AsmPrinter *Asm, StringRef 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; - }); + llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) { + return LHS->HashValue < RHS->HashValue; + }); } namespace { @@ -557,8 +555,8 @@ void llvm::emitDWARF5AccelTable( SmallVector<unsigned, 1> CUIndex(CUs.size()); int Count = 0; for (const auto &CU : enumerate(CUs)) { - if (CU.value()->getCUNode()->getNameTableKind() == - DICompileUnit::DebugNameTableKind::None) + if (CU.value()->getCUNode()->getNameTableKind() != + DICompileUnit::DebugNameTableKind::Default) continue; CUIndex[CU.index()] = Count++; assert(CU.index() == CU.value()->getUniqueID()); @@ -616,30 +614,10 @@ void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const { 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 { diff --git a/lib/CodeGen/AsmPrinter/AddressPool.cpp b/lib/CodeGen/AsmPrinter/AddressPool.cpp index 042243b79259..f11c7de5ed8a 100644 --- a/lib/CodeGen/AsmPrinter/AddressPool.cpp +++ b/lib/CodeGen/AsmPrinter/AddressPool.cpp @@ -1,9 +1,8 @@ //===- llvm/CodeGen/AddressPool.cpp - Dwarf Debug Framework ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -24,21 +23,24 @@ unsigned AddressPool::getIndex(const MCSymbol *Sym, bool TLS) { return IterBool.first->second.Number; } - -void AddressPool::emitHeader(AsmPrinter &Asm, MCSection *Section) { +MCSymbol *AddressPool::emitHeader(AsmPrinter &Asm, MCSection *Section) { static const uint8_t AddrSize = Asm.getDataLayout().getPointerSize(); - uint64_t Length = sizeof(uint16_t) // version - + sizeof(uint8_t) // address_size - + sizeof(uint8_t) // segment_selector_size - + AddrSize * Pool.size(); // entries + StringRef Prefix = "debug_addr_"; + MCSymbol *BeginLabel = Asm.createTempSymbol(Prefix + "start"); + MCSymbol *EndLabel = Asm.createTempSymbol(Prefix + "end"); + Asm.OutStreamer->AddComment("Length of contribution"); - Asm.emitInt32(Length); // TODO: Support DWARF64 format. + Asm.EmitLabelDifference(EndLabel, BeginLabel, + 4); // TODO: Support DWARF64 format. + Asm.OutStreamer->EmitLabel(BeginLabel); Asm.OutStreamer->AddComment("DWARF version number"); Asm.emitInt16(Asm.getDwarfVersion()); Asm.OutStreamer->AddComment("Address size"); Asm.emitInt8(AddrSize); Asm.OutStreamer->AddComment("Segment selector size"); Asm.emitInt8(0); // TODO: Support non-zero segment_selector_size. + + return EndLabel; } // Emit addresses into the section given. @@ -49,8 +51,10 @@ void AddressPool::emit(AsmPrinter &Asm, MCSection *AddrSection) { // Start the dwarf addr section. Asm.OutStreamer->SwitchSection(AddrSection); + MCSymbol *EndLabel = nullptr; + if (Asm.getDwarfVersion() >= 5) - emitHeader(Asm, AddrSection); + EndLabel = emitHeader(Asm, AddrSection); // Define the symbol that marks the start of the contribution. // It is referenced via DW_AT_addr_base. @@ -67,4 +71,7 @@ void AddressPool::emit(AsmPrinter &Asm, MCSection *AddrSection) { for (const MCExpr *Entry : Entries) Asm.OutStreamer->EmitValue(Entry, Asm.getDataLayout().getPointerSize()); + + if (EndLabel) + Asm.OutStreamer->EmitLabel(EndLabel); } diff --git a/lib/CodeGen/AsmPrinter/AddressPool.h b/lib/CodeGen/AsmPrinter/AddressPool.h index 2209c7eb50ed..f92cf72093ca 100644 --- a/lib/CodeGen/AsmPrinter/AddressPool.h +++ b/lib/CodeGen/AsmPrinter/AddressPool.h @@ -1,9 +1,8 @@ //===- llvm/CodeGen/AddressPool.h - Dwarf Debug Framework -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -55,7 +54,7 @@ public: void setLabel(MCSymbol *Sym) { AddressTableBaseSym = Sym; } private: - void emitHeader(AsmPrinter &Asm, MCSection *Section); + MCSymbol *emitHeader(AsmPrinter &Asm, MCSection *Section); /// Symbol designates the start of the contribution to the address table. MCSymbol *AddressTableBaseSym = nullptr; diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 7070451e3330..54f6cc2d5571 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1,9 +1,8 @@ //===- AsmPrinter.cpp - Common AsmPrinter code ----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -35,7 +34,6 @@ #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/ELF.h" -#include "llvm/CodeGen/AsmPrinterHandler.h" #include "llvm/CodeGen/GCMetadata.h" #include "llvm/CodeGen/GCMetadataPrinter.h" #include "llvm/CodeGen/GCStrategy.h" @@ -60,7 +58,6 @@ #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/CodeGen/TargetRegisterInfo.h" -#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/Constant.h" @@ -80,6 +77,7 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/MC/MCAsmInfo.h" @@ -101,6 +99,9 @@ #include "llvm/MC/MCValue.h" #include "llvm/MC/SectionKind.h" #include "llvm/Pass.h" +#include "llvm/Remarks/Remark.h" +#include "llvm/Remarks/RemarkFormat.h" +#include "llvm/Remarks/RemarkStringTable.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -143,9 +144,10 @@ static const char *const CodeViewLineTablesGroupDescription = STATISTIC(EmittedInsts, "Number of machine instrs printed"); -static cl::opt<bool> - PrintSchedule("print-schedule", cl::Hidden, cl::init(false), - cl::desc("Print 'sched: [latency:throughput]' in .s output")); +static cl::opt<bool> EnableRemarksSection( + "remarks-section", + cl::desc("Emit a section containing remark diagnostics metadata"), + cl::init(false)); char AsmPrinter::ID = 0; @@ -232,6 +234,12 @@ void AsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { S.EmitInstruction(Inst, getSubtargetInfo()); } +void AsmPrinter::emitInitialRawDwarfLocDirective(const MachineFunction &MF) { + assert(DD && "Dwarf debug file is not defined."); + assert(OutStreamer->hasRawTextSupport() && "Expected assembly output mode."); + (void)DD->emitInitialLocDirective(MF, /*CUID=*/0); +} + /// getCurrentSection() - Return the current section we are emitting to. const MCSection *AsmPrinter::getCurrentSection() const { return OutStreamer->getCurrentSectionOnly(); @@ -252,6 +260,9 @@ bool AsmPrinter::doInitialization(Module &M) { const_cast<TargetLoweringObjectFile&>(getObjFileLowering()) .Initialize(OutContext, TM); + const_cast<TargetLoweringObjectFile &>(getObjFileLowering()) + .getModuleMetadata(M); + OutStreamer->InitSections(false); // Emit the version-min deployment target directive if needed. @@ -300,16 +311,17 @@ bool AsmPrinter::doInitialization(Module &M) { if (MAI->doesSupportDebugInformation()) { bool EmitCodeView = MMI->getModule()->getCodeViewFlag(); if (EmitCodeView && TM.getTargetTriple().isOSWindows()) { - Handlers.push_back(HandlerInfo(new CodeViewDebug(this), - DbgTimerName, DbgTimerDescription, - CodeViewLineTablesGroupName, - CodeViewLineTablesGroupDescription)); + Handlers.emplace_back(llvm::make_unique<CodeViewDebug>(this), + DbgTimerName, DbgTimerDescription, + CodeViewLineTablesGroupName, + CodeViewLineTablesGroupDescription); } if (!EmitCodeView || MMI->getModule()->getDwarfVersion()) { DD = new DwarfDebug(this, &M); DD->beginModule(); - Handlers.push_back(HandlerInfo(DD, DbgTimerName, DbgTimerDescription, - DWARFGroupName, DWARFGroupDescription)); + Handlers.emplace_back(std::unique_ptr<DwarfDebug>(DD), DbgTimerName, + DbgTimerDescription, DWARFGroupName, + DWARFGroupDescription); } } @@ -362,14 +374,15 @@ bool AsmPrinter::doInitialization(Module &M) { break; } if (ES) - Handlers.push_back(HandlerInfo(ES, EHTimerName, EHTimerDescription, - DWARFGroupName, DWARFGroupDescription)); + Handlers.emplace_back(std::unique_ptr<EHStreamer>(ES), EHTimerName, + EHTimerDescription, DWARFGroupName, + DWARFGroupDescription); if (mdconst::extract_or_null<ConstantInt>( MMI->getModule()->getModuleFlag("cfguardtable"))) - Handlers.push_back(HandlerInfo(new WinCFGuard(this), CFGuardName, - CFGuardDescription, DWARFGroupName, - DWARFGroupDescription)); + Handlers.emplace_back(llvm::make_unique<WinCFGuard>(this), CFGuardName, + CFGuardDescription, DWARFGroupName, + DWARFGroupDescription); return false; } @@ -483,7 +496,7 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM); const DataLayout &DL = GV->getParent()->getDataLayout(); - uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); + uint64_t Size = DL.getTypeAllocSize(GV->getValueType()); // If the alignment is specified, we *must* obey it. Overaligning a global // with a specified alignment is a prompt way to break globals emitted to @@ -658,6 +671,9 @@ void AsmPrinter::EmitFunctionHeader() { if (MAI->hasDotTypeDotSizeDirective()) OutStreamer->EmitSymbolAttribute(CurrentFnSym, MCSA_ELF_TypeFunction); + if (F.hasFnAttribute(Attribute::Cold)) + OutStreamer->EmitSymbolAttribute(CurrentFnSym, MCSA_Cold); + if (isVerbose()) { F.printAsOperand(OutStreamer->GetCommentOS(), /*PrintType=*/false, F.getParent()); @@ -738,74 +754,30 @@ void AsmPrinter::EmitFunctionEntryLabel() { } /// emitComments - Pretty-print comments for instructions. -/// It returns true iff the sched comment was emitted. -/// Otherwise it returns false. -static bool emitComments(const MachineInstr &MI, raw_ostream &CommentOS, - AsmPrinter *AP) { +static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) { const MachineFunction *MF = MI.getMF(); const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); // Check for spills and reloads - int FI; - - const MachineFrameInfo &MFI = MF->getFrameInfo(); - bool Commented = false; - - auto getSize = - [&MFI](const SmallVectorImpl<const MachineMemOperand *> &Accesses) { - unsigned Size = 0; - for (auto A : Accesses) - if (MFI.isSpillSlotObjectIndex( - cast<FixedStackPseudoSourceValue>(A->getPseudoValue()) - ->getFrameIndex())) - Size += A->getSize(); - return Size; - }; // We assume a single instruction only has a spill or reload, not // both. - const MachineMemOperand *MMO; - SmallVector<const MachineMemOperand *, 2> Accesses; - if (TII->isLoadFromStackSlotPostFE(MI, FI)) { - if (MFI.isSpillSlotObjectIndex(FI)) { - MMO = *MI.memoperands_begin(); - CommentOS << MMO->getSize() << "-byte Reload"; - Commented = true; - } - } else if (TII->hasLoadFromStackSlot(MI, Accesses)) { - if (auto Size = getSize(Accesses)) { - CommentOS << Size << "-byte Folded Reload"; - Commented = true; - } - } else if (TII->isStoreToStackSlotPostFE(MI, FI)) { - if (MFI.isSpillSlotObjectIndex(FI)) { - MMO = *MI.memoperands_begin(); - CommentOS << MMO->getSize() << "-byte Spill"; - Commented = true; - } - } else if (TII->hasStoreToStackSlot(MI, Accesses)) { - if (auto Size = getSize(Accesses)) { - CommentOS << Size << "-byte Folded Spill"; - Commented = true; - } + Optional<unsigned> Size; + if ((Size = MI.getRestoreSize(TII))) { + CommentOS << *Size << "-byte Reload\n"; + } else if ((Size = MI.getFoldedRestoreSize(TII))) { + if (*Size) + CommentOS << *Size << "-byte Folded Reload\n"; + } else if ((Size = MI.getSpillSize(TII))) { + CommentOS << *Size << "-byte Spill\n"; + } else if ((Size = MI.getFoldedSpillSize(TII))) { + if (*Size) + CommentOS << *Size << "-byte Folded Spill\n"; } // Check for spill-induced copies - if (MI.getAsmPrinterFlag(MachineInstr::ReloadReuse)) { - Commented = true; - CommentOS << " Reload Reuse"; - } - - if (Commented) { - if (AP->EnablePrintSchedInfo) { - // If any comment was added above and we need sched info comment then add - // this new comment just after the above comment w/o "\n" between them. - CommentOS << " " << MF->getSubtarget().getSchedInfoStr(MI) << "\n"; - return true; - } - CommentOS << "\n"; - } - return false; + if (MI.getAsmPrinterFlag(MachineInstr::ReloadReuse)) + CommentOS << " Reload Reuse\n"; } /// emitImplicitDef - This method emits the specified machine instruction @@ -1093,10 +1065,8 @@ void AsmPrinter::EmitFunctionBody() { } } - if (isVerbose() && emitComments(MI, OutStreamer->GetCommentOS(), this)) { - MachineInstr *MIP = const_cast<MachineInstr *>(&MI); - MIP->setAsmPrinterFlag(MachineInstr::NoSchedComment); - } + if (isVerbose()) + emitComments(MI, OutStreamer->GetCommentOS()); switch (MI.getOpcode()) { case TargetOpcode::CFI_INSTRUCTION: @@ -1105,11 +1075,13 @@ void AsmPrinter::EmitFunctionBody() { case TargetOpcode::LOCAL_ESCAPE: emitFrameAlloc(MI); break; + case TargetOpcode::ANNOTATION_LABEL: case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: OutStreamer->EmitLabel(MI.getOperand(0).getMCSymbol()); break; case TargetOpcode::INLINEASM: + case TargetOpcode::INLINEASM_BR: EmitInlineAsm(&MI); break; case TargetOpcode::DBG_VALUE: @@ -1266,7 +1238,7 @@ static bool isGOTEquivalentCandidate(const GlobalVariable *GV, // GlobalVariable or Function, i.e., as GlobalValue. if (!GV->hasGlobalUnnamedAddr() || !GV->hasInitializer() || !GV->isConstant() || !GV->isDiscardableIfUnused() || - !dyn_cast<GlobalValue>(GV->getOperand(0))) + !isa<GlobalValue>(GV->getOperand(0))) return false; // To be a got equivalent, at least one of its users need to be a constant @@ -1329,9 +1301,19 @@ void AsmPrinter::emitGlobalIndirectSymbol(Module &M, else assert(GIS.hasLocalLinkage() && "Invalid alias or ifunc linkage"); + bool IsFunction = GIS.getValueType()->isFunctionTy(); + + // Treat bitcasts of functions as functions also. This is important at least + // on WebAssembly where object and function addresses can't alias each other. + if (!IsFunction) + if (auto *CE = dyn_cast<ConstantExpr>(GIS.getIndirectSymbol())) + if (CE->getOpcode() == Instruction::BitCast) + IsFunction = + CE->getOperand(0)->getType()->getPointerElementType()->isFunctionTy(); + // Set the symbol type to function if the alias has a function type. // This affects codegen when the aliasee is not a function. - if (GIS.getType()->getPointerElementType()->isFunctionTy()) { + if (IsFunction) { OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction); if (isa<GlobalIFunc>(GIS)) OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction); @@ -1363,6 +1345,66 @@ void AsmPrinter::emitGlobalIndirectSymbol(Module &M, } } +void AsmPrinter::emitRemarksSection(Module &M) { + RemarkStreamer *RS = M.getContext().getRemarkStreamer(); + if (!RS) + return; + const remarks::Serializer &Serializer = RS->getSerializer(); + + // Switch to the right section: .remarks/__remarks. + MCSection *RemarksSection = + OutContext.getObjectFileInfo()->getRemarksSection(); + OutStreamer->SwitchSection(RemarksSection); + + // Emit the magic number. + OutStreamer->EmitBytes(remarks::Magic); + // Explicitly emit a '\0'. + OutStreamer->EmitIntValue(/*Value=*/0, /*Size=*/1); + + // Emit the version number: little-endian uint64_t. + // The version number is located at the offset 0x0 in the section. + std::array<char, 8> Version; + support::endian::write64le(Version.data(), remarks::Version); + OutStreamer->EmitBinaryData(StringRef(Version.data(), Version.size())); + + // Emit the string table in the section. + // Note: we need to use the streamer here to emit it in the section. We can't + // just use the serialize function with a raw_ostream because of the way + // MCStreamers work. + uint64_t StrTabSize = + Serializer.StrTab ? Serializer.StrTab->SerializedSize : 0; + // Emit the total size of the string table (the size itself excluded): + // little-endian uint64_t. + // The total size is located after the version number. + // Note: even if no string table is used, emit 0. + std::array<char, 8> StrTabSizeBuf; + support::endian::write64le(StrTabSizeBuf.data(), StrTabSize); + OutStreamer->EmitBinaryData( + StringRef(StrTabSizeBuf.data(), StrTabSizeBuf.size())); + + if (const Optional<remarks::StringTable> &StrTab = Serializer.StrTab) { + std::vector<StringRef> StrTabStrings = StrTab->serialize(); + // Emit a list of null-terminated strings. + // Note: the order is important here: the ID used in the remarks corresponds + // to the position of the string in the section. + for (StringRef Str : StrTabStrings) { + OutStreamer->EmitBytes(Str); + // Explicitly emit a '\0'. + OutStreamer->EmitIntValue(/*Value=*/0, /*Size=*/1); + } + } + + // Emit the null-terminated absolute path to the remark file. + // The path is located at the offset 0x4 in the section. + StringRef FilenameRef = RS->getFilename(); + SmallString<128> Filename = FilenameRef; + sys::fs::make_absolute(Filename); + assert(!Filename.empty() && "The filename can't be empty."); + OutStreamer->EmitBytes(Filename); + // Explicitly emit a '\0'. + OutStreamer->EmitIntValue(/*Value=*/0, /*Size=*/1); +} + bool AsmPrinter::doFinalization(Module &M) { // Set the MachineFunction to nullptr so that we can catch attempted // accesses to MF specific features at the module level and so that @@ -1394,6 +1436,12 @@ bool AsmPrinter::doFinalization(Module &M) { EmitVisibility(Name, V, false); } + // Emit the remarks section contents. + // FIXME: Figure out when is the safest time to emit this section. It should + // not come after debug info. + if (EnableRemarksSection) + emitRemarksSection(M); + const TargetLoweringObjectFile &TLOF = getObjFileLowering(); TLOF.emitModuleMetadata(*OutStreamer, M); @@ -1448,7 +1496,6 @@ bool AsmPrinter::doFinalization(Module &M) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->endModule(); - delete HI.Handler; } Handlers.clear(); DD = nullptr; @@ -1592,6 +1639,24 @@ bool AsmPrinter::doFinalization(Module &M) { OutStreamer->EmitAddrsigSym(getSymbol(&GV)); } + // Emit symbol partition specifications (ELF only). + if (TM.getTargetTriple().isOSBinFormatELF()) { + unsigned UniqueID = 0; + for (const GlobalValue &GV : M.global_values()) { + if (!GV.hasPartition() || GV.isDeclarationForLinker() || + GV.getVisibility() != GlobalValue::DefaultVisibility) + continue; + + OutStreamer->SwitchSection(OutContext.getELFSection( + ".llvm_sympart", ELF::SHT_LLVM_SYMPART, 0, 0, "", ++UniqueID)); + OutStreamer->EmitBytes(GV.getPartition()); + OutStreamer->EmitZeros(1); + OutStreamer->EmitValue( + MCSymbolRefExpr::create(getSymbol(&GV), OutContext), + MAI->getCodePointerSize()); + } + } + // Allow the target to emit any magic that it wants at the end of the file, // after everything else has gone out. EmitEndOfAsmFile(M); @@ -1628,11 +1693,6 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { } ORE = &getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE(); - - const TargetSubtargetInfo &STI = MF.getSubtarget(); - EnablePrintSchedInfo = PrintSchedule.getNumOccurrences() - ? PrintSchedule - : STI.supportPrintSchedInfo(); } namespace { @@ -1905,8 +1965,7 @@ bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) { } /// EmitLLVMUsedList - For targets that define a MAI::UsedDirective, mark each -/// global in the specified llvm.used list for which emitUsedDirectiveFor -/// is true, as being used with this directive. +/// global in the specified llvm.used list. void AsmPrinter::EmitLLVMUsedList(const ConstantArray *InitList) { // Should be an array of 'i8*'. for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { @@ -1933,7 +1992,7 @@ struct Structor { /// priority. void AsmPrinter::EmitXXStructorList(const DataLayout &DL, const Constant *List, bool isCtor) { - // Should be an array of '{ int, void ()* }' structs. The first value is the + // Should be an array of '{ i32, void ()*, i8* }' structs. The first value is the // init priority. if (!isa<ConstantArray>(List)) return; @@ -1941,12 +2000,10 @@ void AsmPrinter::EmitXXStructorList(const DataLayout &DL, const Constant *List, const ConstantArray *InitList = dyn_cast<ConstantArray>(List); if (!InitList) return; // Not an array! StructType *ETy = dyn_cast<StructType>(InitList->getType()->getElementType()); - // FIXME: Only allow the 3-field form in LLVM 4.0. - if (!ETy || ETy->getNumElements() < 2 || ETy->getNumElements() > 3) - return; // Not an array of two or three elements! - if (!isa<IntegerType>(ETy->getTypeAtIndex(0U)) || - !isa<PointerType>(ETy->getTypeAtIndex(1U))) return; // Not (int, ptr). - if (ETy->getNumElements() == 3 && !isa<PointerType>(ETy->getTypeAtIndex(2U))) + if (!ETy || ETy->getNumElements() != 3 || + !isa<IntegerType>(ETy->getTypeAtIndex(0U)) || + !isa<PointerType>(ETy->getTypeAtIndex(1U)) || + !isa<PointerType>(ETy->getTypeAtIndex(2U))) return; // Not (int, ptr, ptr). // Gather the structors in a form that's convenient for sorting by priority. @@ -1962,16 +2019,16 @@ void AsmPrinter::EmitXXStructorList(const DataLayout &DL, const Constant *List, Structor &S = Structors.back(); S.Priority = Priority->getLimitedValue(65535); S.Func = CS->getOperand(1); - if (ETy->getNumElements() == 3 && !CS->getOperand(2)->isNullValue()) + if (!CS->getOperand(2)->isNullValue()) S.ComdatKey = dyn_cast<GlobalValue>(CS->getOperand(2)->stripPointerCasts()); } // Emit the function pointers in the target-specific order unsigned Align = Log2_32(DL.getPointerPrefAlignment()); - std::stable_sort(Structors.begin(), Structors.end(), - [](const Structor &L, - const Structor &R) { return L.Priority < R.Priority; }); + llvm::stable_sort(Structors, [](const Structor &L, const Structor &R) { + return L.Priority < R.Priority; + }); for (Structor &S : Structors) { const TargetLoweringObjectFile &Obj = getObjFileLowering(); const MCSymbol *KeySym = nullptr; @@ -2199,7 +2256,10 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { // We can emit the pointer value into this slot if the slot is an // integer slot equal to the size of the pointer. - if (DL.getTypeAllocSize(Ty) == DL.getTypeAllocSize(Op->getType())) + // + // If the pointer is larger than the resultant integer, then + // as with Trunc just depend on the assembler to truncate it. + if (DL.getTypeAllocSize(Ty) <= DL.getTypeAllocSize(Op->getType())) return OpExpr; // Otherwise the pointer is smaller than the resultant integer, mask off @@ -2740,7 +2800,7 @@ 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()) { + if (getSubtargetInfo().getTargetTriple().isWindowsMSVCEnvironment()) { const MachineConstantPoolEntry &CPE = MF->getConstantPool()->getConstants()[CPID]; if (!CPE.isMachineConstantPoolEntry()) { @@ -2858,7 +2918,7 @@ void AsmPrinter::setupCodePaddingContext(const MachineBasicBlock &MBB, MCCodePaddingContext &Context) const { assert(MF != nullptr && "Machine function must be valid"); Context.IsPaddingActive = !MF->hasInlineAsm() && - !MF->getFunction().optForSize() && + !MF->getFunction().hasOptSize() && TM.getOptLevel() != CodeGenOpt::None; Context.IsBasicBlockReachableViaFallthrough = std::find(MBB.pred_begin(), MBB.pred_end(), MBB.getPrevNode()) != @@ -2918,13 +2978,16 @@ void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const { // Print the main label for the block. if (MBB.pred_empty() || - (isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry())) { + (isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry() && + !MBB.hasLabelMustBeEmitted())) { if (isVerbose()) { // NOTE: Want this comment at start of line, don't emit with AddComment. OutStreamer->emitRawComment(" %bb." + Twine(MBB.getNumber()) + ":", false); } } else { + if (isVerbose() && MBB.hasLabelMustBeEmitted()) + OutStreamer->AddComment("Label of block must be emitted"); OutStreamer->EmitLabel(MBB.getSymbol()); } } diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index afce3ad3133b..992e44d95306 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -1,9 +1,8 @@ //===-- AsmPrinterDwarf.cpp - AsmPrinter Dwarf Support --------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -19,6 +18,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" @@ -43,11 +43,11 @@ void AsmPrinter::EmitSLEB128(int64_t Value, const char *Desc) const { OutStreamer->EmitSLEB128IntValue(Value); } -void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc) const { +void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc, unsigned PadTo) const { if (isVerbose() && Desc) OutStreamer->AddComment(Desc); - OutStreamer->EmitULEB128IntValue(Value); + OutStreamer->EmitULEB128IntValue(Value, PadTo); } /// Emit something like ".uleb128 Hi-Lo". @@ -183,6 +183,25 @@ void AsmPrinter::EmitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const { EmitLabelPlusOffset(Label, Offset, MAI->getCodePointerSize()); } +void AsmPrinter::EmitCallSiteOffset(const MCSymbol *Hi, + const MCSymbol *Lo, + unsigned Encoding) const { + // The least significant 3 bits specify the width of the encoding + if ((Encoding & 0x7) == dwarf::DW_EH_PE_uleb128) + EmitLabelDifferenceAsULEB128(Hi, Lo); + else + EmitLabelDifference(Hi, Lo, GetSizeOfEncodedValue(Encoding)); +} + +void AsmPrinter::EmitCallSiteValue(uint64_t Value, + unsigned Encoding) const { + // The least significant 3 bits specify the width of the encoding + if ((Encoding & 0x7) == dwarf::DW_EH_PE_uleb128) + EmitULEB128(Value); + else + OutStreamer->EmitIntValue(Value, GetSizeOfEncodedValue(Encoding)); +} + //===----------------------------------------------------------------------===// // Dwarf Lowering Routines //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 62103e3107c0..7721e996aca5 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -1,9 +1,8 @@ //===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -19,7 +18,6 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h" -#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" @@ -155,15 +153,10 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, " we don't have an asm parser for this target\n"); Parser->setAssemblerDialect(Dialect); Parser->setTargetParser(*TAP.get()); - Parser->setEnablePrintSchedInfo(EnablePrintSchedInfo); // Enable lexing Masm binary and hex integer literals in intel inline // assembly. if (Dialect == InlineAsm::AD_Intel) Parser->getLexer().setLexMasmIntegers(true); - if (MF) { - const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); - TAP->SetFrameRegister(TRI->getFrameRegister(*MF)); - } emitInlineAsmStart(); // Don't implicitly switch to the text section before the asm. @@ -176,9 +169,8 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, } static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, - MachineModuleInfo *MMI, int InlineAsmVariant, - AsmPrinter *AP, unsigned LocCookie, - raw_ostream &OS) { + MachineModuleInfo *MMI, AsmPrinter *AP, + unsigned LocCookie, raw_ostream &OS) { // Switch to the inline assembly variant. OS << "\t.intel_syntax\n\t"; @@ -270,11 +262,9 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, ++OpNo; // Skip over the ID number. if (InlineAsm::isMemKind(OpFlags)) { - Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant, - /*Modifier*/ nullptr, OS); + Error = AP->PrintAsmMemoryOperand(MI, OpNo, /*Modifier*/ nullptr, OS); } else { - Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, - /*Modifier*/ nullptr, OS); + Error = AP->PrintAsmOperand(MI, OpNo, /*Modifier*/ nullptr, OS); } } if (Error) { @@ -291,9 +281,9 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, } static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, - MachineModuleInfo *MMI, int InlineAsmVariant, - int AsmPrinterVariant, AsmPrinter *AP, - unsigned LocCookie, raw_ostream &OS) { + MachineModuleInfo *MMI, int AsmPrinterVariant, + AsmPrinter *AP, unsigned LocCookie, + raw_ostream &OS) { int CurVariant = -1; // The number of the {.|.|.} region we are in. const char *LastEmitted = AsmStr; // One past the last character emitted. unsigned NumOperands = MI->getNumOperands(); @@ -435,17 +425,25 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, unsigned OpFlags = MI->getOperand(OpNo).getImm(); ++OpNo; // Skip over the ID number. + // FIXME: Shouldn't arch-independent output template handling go into + // PrintAsmOperand? if (Modifier[0] == 'l') { // Labels are target independent. - // FIXME: What if the operand isn't an MBB, report error? - const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol(); - Sym->print(OS, AP->MAI); + if (MI->getOperand(OpNo).isBlockAddress()) { + const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress(); + MCSymbol *Sym = AP->GetBlockAddressSymbol(BA); + Sym->print(OS, AP->MAI); + } else if (MI->getOperand(OpNo).isMBB()) { + const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol(); + Sym->print(OS, AP->MAI); + } else { + Error = true; + } } else { if (InlineAsm::isMemKind(OpFlags)) { - Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant, - Modifier[0] ? Modifier : nullptr, - OS); + Error = AP->PrintAsmMemoryOperand( + MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); } else { - Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, + Error = AP->PrintAsmOperand(MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); } } @@ -515,18 +513,11 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { // The variant of the current asmprinter. int AsmPrinterVariant = MAI->getAssemblerDialect(); - InlineAsm::AsmDialect InlineAsmVariant = MI->getInlineAsmDialect(); AsmPrinter *AP = const_cast<AsmPrinter*>(this); - if (InlineAsmVariant == InlineAsm::AD_ATT) - EmitGCCInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AsmPrinterVariant, - AP, LocCookie, OS); + if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT) + EmitGCCInlineAsmStr(AsmStr, MI, MMI, AsmPrinterVariant, AP, LocCookie, OS); else - EmitMSInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AP, LocCookie, OS); - - // Reset SanitizeAddress based on the function's attribute. - MCTargetOptions MCOptions = TM.Options.MCOptions; - MCOptions.SanitizeAddress = - MF->getFunction().hasFnAttribute(Attribute::SanitizeAddress); + EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS); // Emit warnings if we use reserved registers on the clobber list, as // that might give surprising results. @@ -566,7 +557,7 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, Note); } - EmitInlineAsm(OS.str(), getSubtargetInfo(), MCOptions, LocMD, + EmitInlineAsm(OS.str(), getSubtargetInfo(), TM.Options.MCOptions, LocMD, MI->getInlineAsmDialect()); // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't @@ -608,32 +599,50 @@ void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, } } +void AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS) { + assert(MO.isGlobal() && "caller should check MO.isGlobal"); + getSymbol(MO.getGlobal())->print(OS, MAI); + printOffset(MO.getOffset(), OS); +} + /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM /// instruction, using the specified assembler variant. Targets should -/// override this to format as appropriate. +/// override this to format as appropriate for machine specific ExtraCodes +/// or when the arch-independent handling would be too complex otherwise. bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) { + const char *ExtraCode, raw_ostream &O) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. + // https://gcc.gnu.org/onlinedocs/gccint/Output-Template.html const MachineOperand &MO = MI->getOperand(OpNo); switch (ExtraCode[0]) { default: return true; // Unknown modifier. + case 'a': // Print as memory address. + if (MO.isReg()) { + PrintAsmMemoryOperand(MI, OpNo, nullptr, O); + return false; + } + LLVM_FALLTHROUGH; // GCC allows '%a' to behave like '%c' with immediates. case 'c': // Substitute immediate value without immediate syntax - if (MO.getType() != MachineOperand::MO_Immediate) - return true; - O << MO.getImm(); - return false; + if (MO.isImm()) { + O << MO.getImm(); + return false; + } + if (MO.isGlobal()) { + PrintSymbolOperand(MO, O); + return false; + } + return true; case 'n': // Negate the immediate constant. - if (MO.getType() != MachineOperand::MO_Immediate) + if (!MO.isImm()) return true; O << -MO.getImm(); return false; case 's': // The GCC deprecated s modifier - if (MO.getType() != MachineOperand::MO_Immediate) + if (!MO.isImm()) return true; O << ((32 - MO.getImm()) & 31); return false; @@ -643,7 +652,6 @@ bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, } bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) { // Target doesn't support this yet! return true; diff --git a/lib/CodeGen/AsmPrinter/ByteStreamer.h b/lib/CodeGen/AsmPrinter/ByteStreamer.h index 2163cc7e3e11..db2ff458eb2e 100644 --- a/lib/CodeGen/AsmPrinter/ByteStreamer.h +++ b/lib/CodeGen/AsmPrinter/ByteStreamer.h @@ -1,9 +1,8 @@ //===-- llvm/CodeGen/ByteStreamer.h - ByteStreamer class --------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -32,7 +31,7 @@ class ByteStreamer { // For now we're just handling the calls we need for dwarf emission/hashing. virtual void EmitInt8(uint8_t Byte, const Twine &Comment = "") = 0; virtual void EmitSLEB128(uint64_t DWord, const Twine &Comment = "") = 0; - virtual void EmitULEB128(uint64_t DWord, const Twine &Comment = "") = 0; + virtual void EmitULEB128(uint64_t DWord, const Twine &Comment = "", unsigned PadTo = 0) = 0; }; class APByteStreamer final : public ByteStreamer { @@ -49,7 +48,7 @@ public: AP.OutStreamer->AddComment(Comment); AP.EmitSLEB128(DWord); } - void EmitULEB128(uint64_t DWord, const Twine &Comment) override { + void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override { AP.OutStreamer->AddComment(Comment); AP.EmitULEB128(DWord); } @@ -66,7 +65,7 @@ class HashingByteStreamer final : public ByteStreamer { void EmitSLEB128(uint64_t DWord, const Twine &Comment) override { Hash.addSLEB128(DWord); } - void EmitULEB128(uint64_t DWord, const Twine &Comment) override { + void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override { Hash.addULEB128(DWord); } }; @@ -103,9 +102,9 @@ public: } } - void EmitULEB128(uint64_t DWord, const Twine &Comment) override { + void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override { raw_svector_ostream OSE(Buffer); - unsigned Length = encodeULEB128(DWord, OSE); + unsigned Length = encodeULEB128(DWord, OSE, PadTo); if (GenerateComments) { Comments.push_back(Comment.str()); // Add some empty comments to keep the Buffer and Comments vectors aligned diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 8cabad4ad312..932959c311fa 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1,9 +1,8 @@ //===- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp ----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -42,6 +41,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" @@ -51,6 +51,7 @@ #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeTableCollection.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfoMetadata.h" @@ -67,6 +68,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -93,6 +95,26 @@ using namespace llvm; using namespace llvm::codeview; +namespace { +class CVMCAdapter : public CodeViewRecordStreamer { +public: + CVMCAdapter(MCStreamer &OS) : OS(&OS) {} + + void EmitBytes(StringRef Data) { OS->EmitBytes(Data); } + + void EmitIntValue(uint64_t Value, unsigned Size) { + OS->EmitIntValueInHex(Value, Size); + } + + void EmitBinaryData(StringRef Data) { OS->EmitBinaryData(Data); } + + void AddComment(const Twine &T) { OS->AddComment(T); } + +private: + MCStreamer *OS = nullptr; +}; +} // namespace + static CPUType mapArchToCVCPUType(Triple::ArchType Type) { switch (Type) { case Triple::ArchType::x86: @@ -273,7 +295,7 @@ static const DISubprogram *getQualifiedNameComponents( StringRef ScopeName = getPrettyScopeName(Scope); if (!ScopeName.empty()) QualifiedNameComponents.push_back(ScopeName); - Scope = Scope->getScope().resolve(); + Scope = Scope->getScope(); } return ClosestSubprogram; } @@ -309,7 +331,7 @@ struct CodeViewDebug::TypeLoweringScope { }; static std::string getFullyQualifiedName(const DIScope *Ty) { - const DIScope *Scope = Ty->getScope().resolve(); + const DIScope *Scope = Ty->getScope(); return getFullyQualifiedName(Scope, getPrettyScopeName(Ty)); } @@ -344,7 +366,7 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) { // MSVC. StringRef DisplayName = SP->getName().split('<').first; - const DIScope *Scope = SP->getScope().resolve(); + const DIScope *Scope = SP->getScope(); TypeIndex TI; if (const auto *Class = dyn_cast_or_null<DICompositeType>(Scope)) { // If the scope is a DICompositeType, then this must be a method. Member @@ -364,8 +386,8 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) { return recordTypeIndexForDINode(SP, TI); } -static bool isTrivial(const DICompositeType *DCTy) { - return ((DCTy->getFlags() & DINode::FlagTrivial) == DINode::FlagTrivial); +static bool isNonTrivial(const DICompositeType *DCTy) { + return ((DCTy->getFlags() & DINode::FlagNonTrivial) == DINode::FlagNonTrivial); } static FunctionOptions @@ -376,16 +398,16 @@ getFunctionOptions(const DISubroutineType *Ty, const DIType *ReturnTy = nullptr; if (auto TypeArray = Ty->getTypeArray()) { if (TypeArray.size()) - ReturnTy = TypeArray[0].resolve(); + ReturnTy = TypeArray[0]; } if (auto *ReturnDCTy = dyn_cast_or_null<DICompositeType>(ReturnTy)) { - if (!isTrivial(ReturnDCTy)) + if (isNonTrivial(ReturnDCTy)) FO |= FunctionOptions::CxxReturnUdt; } // DISubroutineType is unnamed. Use DISubprogram's i.e. SPName in comparison. - if (ClassTy && !isTrivial(ClassTy) && SPName == ClassTy->getName()) { + if (ClassTy && isNonTrivial(ClassTy) && SPName == ClassTy->getName()) { FO |= FunctionOptions::Constructor; // TODO: put the FunctionOptions::ConstructorWithVirtualBases flag. @@ -582,8 +604,9 @@ void CodeViewDebug::endModule() { clear(); } -static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S, - unsigned MaxFixedRecordLength = 0xF00) { +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 @@ -594,6 +617,13 @@ static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S, OS.EmitBytes(NullTerminatedString); } +static StringRef getTypeLeafName(TypeLeafKind TypeKind) { + for (const EnumEntry<TypeLeafKind> &EE : getTypeLeafNames()) + if (EE.Value == TypeKind) + return EE.Name; + return ""; +} + void CodeViewDebug::emitTypeInformation() { if (TypeTable.empty()) return; @@ -610,31 +640,55 @@ void CodeViewDebug::emitTypeInformation() { } TypeTableCollection Table(TypeTable.records()); + SmallString<512> CommentBlock; + raw_svector_ostream CommentOS(CommentBlock); + std::unique_ptr<ScopedPrinter> SP; + std::unique_ptr<TypeDumpVisitor> TDV; + TypeVisitorCallbackPipeline Pipeline; + + if (OS.isVerboseAsm()) { + // To construct block comment describing the type record for readability. + SP = llvm::make_unique<ScopedPrinter>(CommentOS); + SP->setPrefix(CommentPrefix); + TDV = llvm::make_unique<TypeDumpVisitor>(Table, SP.get(), false); + Pipeline.addCallbackToPipeline(*TDV); + } + + // To emit type record using Codeview MCStreamer adapter + CVMCAdapter CVMCOS(OS); + TypeRecordMapping typeMapping(CVMCOS); + Pipeline.addCallbackToPipeline(typeMapping); + Optional<TypeIndex> B = Table.getFirst(); while (B) { // This will fail if the record data is invalid. CVType Record = Table.getType(*B); + CommentBlock.clear(); + + auto RecordLen = Record.length(); + auto RecordKind = Record.kind(); + if (OS.isVerboseAsm()) + CVMCOS.AddComment("Record length"); + CVMCOS.EmitIntValue(RecordLen - 2, 2); + if (OS.isVerboseAsm()) + CVMCOS.AddComment("Record kind: " + getTypeLeafName(RecordKind)); + CVMCOS.EmitIntValue(RecordKind, sizeof(RecordKind)); + + Error E = codeview::visitTypeRecord(Record, *B, Pipeline); + + if (E) { + logAllUnhandledErrors(std::move(E), errs(), "error: "); + llvm_unreachable("produced malformed type record"); + } + if (OS.isVerboseAsm()) { - // Emit a block comment describing the type record for readability. - SmallString<512> CommentBlock; - raw_svector_ostream CommentOS(CommentBlock); - ScopedPrinter SP(CommentOS); - SP.setPrefix(CommentPrefix); - TypeDumpVisitor TDV(Table, &SP, false); - - Error E = codeview::visitTypeRecord(Record, *B, TDV); - if (E) { - logAllUnhandledErrors(std::move(E), errs(), "error: "); - llvm_unreachable("produced malformed type record"); - } // emitRawComment will insert its own tab and comment string before // the first line, so strip off our first one. It also prints its own // newline. OS.emitRawComment( CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim()); } - OS.EmitBinaryData(Record.str_data()); B = Table.getNext(*B); } } @@ -700,6 +754,8 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) { return SourceLanguage::Java; case dwarf::DW_LANG_D: return SourceLanguage::D; + case dwarf::DW_LANG_Swift: + return SourceLanguage::Swift; default: // There's no CodeView representation for this language, and CV doesn't // have an "unknown" option for the language field, so we'll use MASM, @@ -973,8 +1029,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, // If we have a display name, build the fully qualified name by walking the // chain of scopes. if (!SP->getName().empty()) - FuncName = - getFullyQualifiedName(SP->getScope().resolve(), SP->getName()); + FuncName = getFullyQualifiedName(SP->getScope(), SP->getName()); // If our DISubprogram name is empty, use the mangled name. if (FuncName.empty()) @@ -1071,6 +1126,28 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, endSymbolRecord(AnnotEnd); } + for (auto HeapAllocSite : FI.HeapAllocSites) { + MCSymbol *BeginLabel = std::get<0>(HeapAllocSite); + MCSymbol *EndLabel = std::get<1>(HeapAllocSite); + + // The labels might not be defined if the instruction was replaced + // somewhere in the codegen pipeline. + if (!BeginLabel->isDefined() || !EndLabel->isDefined()) + continue; + + DIType *DITy = std::get<2>(HeapAllocSite); + MCSymbol *HeapAllocEnd = beginSymbolRecord(SymbolKind::S_HEAPALLOCSITE); + OS.AddComment("Call site offset"); + OS.EmitCOFFSecRel32(BeginLabel, /*Offset=*/0); + OS.AddComment("Call site section index"); + OS.EmitCOFFSectionIndex(BeginLabel); + OS.AddComment("Call instruction length"); + OS.emitAbsoluteSymbolDiff(EndLabel, BeginLabel, 2); + OS.AddComment("Type index"); + OS.EmitIntValue(getCompleteTypeIndex(DITy).getIndex(), 4); + endSymbolRecord(HeapAllocEnd); + } + if (SP != nullptr) emitDebugInfoForUDTs(LocalUDTs); @@ -1118,9 +1195,15 @@ void CodeViewDebug::collectVariableInfoFromMFTable( // If the variable has an attached offset expression, extract it. // FIXME: Try to handle DW_OP_deref as well. int64_t ExprOffset = 0; - if (VI.Expr) - if (!VI.Expr->extractIfOffset(ExprOffset)) + bool Deref = false; + if (VI.Expr) { + // If there is one DW_OP_deref element, use offset of 0 and keep going. + if (VI.Expr->getNumElements() == 1 && + VI.Expr->getElement(0) == llvm::dwarf::DW_OP_deref) + Deref = true; + else if (!VI.Expr->extractIfOffset(ExprOffset)) continue; + } // Get the frame register used and the offset. unsigned FrameReg = 0; @@ -1130,6 +1213,7 @@ void CodeViewDebug::collectVariableInfoFromMFTable( // Calculate the label ranges. LocalVarDefRange DefRange = createDefRangeMem(CVReg, FrameOffset + ExprOffset); + for (const InsnRange &Range : Scope->getRanges()) { const MCSymbol *Begin = getLabelBeforeInsn(Range.first); const MCSymbol *End = getLabelAfterInsn(Range.second); @@ -1140,6 +1224,9 @@ void CodeViewDebug::collectVariableInfoFromMFTable( LocalVariable Var; Var.DIVar = VI.Var; Var.DefRanges.emplace_back(std::move(DefRange)); + if (Deref) + Var.UseReferenceType = true; + recordLocalVariable(std::move(Var), Scope); } } @@ -1153,13 +1240,15 @@ static bool needsReferenceType(const DbgVariableLocation &Loc) { } void CodeViewDebug::calculateRanges( - LocalVariable &Var, const DbgValueHistoryMap::InstrRanges &Ranges) { + LocalVariable &Var, const DbgValueHistoryMap::Entries &Entries) { const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo(); // Calculate the definition ranges. - for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - const InsnRange &Range = *I; - const MachineInstr *DVInst = Range.first; + for (auto I = Entries.begin(), E = Entries.end(); I != E; ++I) { + const auto &Entry = *I; + if (!Entry.isDbgValue()) + continue; + const MachineInstr *DVInst = Entry.getInstr(); assert(DVInst->isDebugValue() && "Invalid History entry"); // FIXME: Find a way to represent constant variables, since they are // relatively common. @@ -1186,7 +1275,7 @@ void CodeViewDebug::calculateRanges( // Start over using that. Var.UseReferenceType = true; Var.DefRanges.clear(); - calculateRanges(Var, Ranges); + calculateRanges(Var, Entries); return; } @@ -1214,21 +1303,15 @@ void CodeViewDebug::calculateRanges( } // Compute the label range. - const MCSymbol *Begin = getLabelBeforeInsn(Range.first); - const MCSymbol *End = getLabelAfterInsn(Range.second); - if (!End) { - // This range is valid until the next overlapping bitpiece. In the - // common case, ranges will not be bitpieces, so they will overlap. - auto J = std::next(I); - const DIExpression *DIExpr = DVInst->getDebugExpression(); - while (J != E && - !DIExpr->fragmentsOverlap(J->first->getDebugExpression())) - ++J; - if (J != E) - End = getLabelBeforeInsn(J->first); - else - End = Asm->getFunctionEnd(); - } + const MCSymbol *Begin = getLabelBeforeInsn(Entry.getInstr()); + const MCSymbol *End; + if (Entry.getEndIndex() != DbgValueHistoryMap::NoEntry) { + auto &EndingEntry = Entries[Entry.getEndIndex()]; + End = EndingEntry.isDbgValue() + ? getLabelBeforeInsn(EndingEntry.getInstr()) + : getLabelAfterInsn(EndingEntry.getInstr()); + } else + End = Asm->getFunctionEnd(); // If the last range end is our begin, just extend the last range. // Otherwise make a new range. @@ -1256,7 +1339,7 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { const DILocation *InlinedAt = IV.second; // Instruction ranges, specifying where IV is accessible. - const auto &Ranges = I.second; + const auto &Entries = I.second; LexicalScope *Scope = nullptr; if (InlinedAt) @@ -1270,7 +1353,7 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { LocalVariable Var; Var.DIVar = DIVar; - calculateRanges(Var, Ranges); + calculateRanges(Var, Entries); recordLocalVariable(std::move(Var), Scope); } } @@ -1340,8 +1423,8 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { FPO |= FrameProcedureOptions::SecurityChecks; FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedLocalFramePtrReg) << 14U); FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedParamFramePtrReg) << 16U); - if (Asm->TM.getOptLevel() != CodeGenOpt::None && !GV.optForSize() && - !GV.hasFnAttribute(Attribute::OptimizeNone)) + if (Asm->TM.getOptLevel() != CodeGenOpt::None && + !GV.hasOptSize() && !GV.hasOptNone()) FPO |= FrameProcedureOptions::OptimizedForSpeed; // FIXME: Set GuardCfg when it is implemented. CurFn->FrameProcOpts = FPO; @@ -1379,7 +1462,7 @@ static bool shouldEmitUdt(const DIType *T) { // MSVC does not emit UDTs for typedefs that are scoped to classes. if (T->getTag() == dwarf::DW_TAG_typedef) { - if (DIScope *Scope = T->getScope().resolve()) { + if (DIScope *Scope = T->getScope()) { switch (Scope->getTag()) { case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_class_type: @@ -1396,7 +1479,7 @@ static bool shouldEmitUdt(const DIType *T) { const DIDerivedType *DT = dyn_cast<DIDerivedType>(T); if (!DT) return true; - T = DT->getBaseType().resolve(); + T = DT->getBaseType(); } return true; } @@ -1409,8 +1492,8 @@ void CodeViewDebug::addToUDTs(const DIType *Ty) { return; SmallVector<StringRef, 5> QualifiedNameComponents; - const DISubprogram *ClosestSubprogram = getQualifiedNameComponents( - Ty->getScope().resolve(), QualifiedNameComponents); + const DISubprogram *ClosestSubprogram = + getQualifiedNameComponents(Ty->getScope(), QualifiedNameComponents); std::string FullyQualifiedName = getQualifiedName(QualifiedNameComponents, getPrettyScopeName(Ty)); @@ -1479,8 +1562,7 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) { } TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) { - DITypeRef UnderlyingTypeRef = Ty->getBaseType(); - TypeIndex UnderlyingTypeIndex = getTypeIndex(UnderlyingTypeRef); + TypeIndex UnderlyingTypeIndex = getTypeIndex(Ty->getBaseType()); StringRef TypeName = Ty->getName(); addToUDTs(Ty); @@ -1496,14 +1578,14 @@ TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) { } TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { - DITypeRef ElementTypeRef = Ty->getBaseType(); - TypeIndex ElementTypeIndex = getTypeIndex(ElementTypeRef); + const DIType *ElementType = Ty->getBaseType(); + TypeIndex ElementTypeIndex = getTypeIndex(ElementType); // IndexType is size_t, which depends on the bitness of the target. TypeIndex IndexType = getPointerSizeInBytes() == 8 ? TypeIndex(SimpleTypeKind::UInt64Quad) : TypeIndex(SimpleTypeKind::UInt32Long); - uint64_t ElementSize = getBaseTypeSize(ElementTypeRef) / 8; + uint64_t ElementSize = getBaseTypeSize(ElementType) / 8; // Add subranges to array type. DINodeArray Elements = Ty->getElements(); @@ -1764,7 +1846,7 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) { break; } if (IsModifier) - BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType().resolve(); + BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType(); } // Check if the inner type will use an LF_POINTER record. If so, the @@ -1797,8 +1879,8 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) { TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) { SmallVector<TypeIndex, 8> ReturnAndArgTypeIndices; - for (DITypeRef ArgTypeRef : Ty->getTypeArray()) - ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef)); + for (const DIType *ArgType : Ty->getTypeArray()) + ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgType)); // MSVC uses type none for variadic argument. if (ReturnAndArgTypeIndices.size() > 1 && @@ -1836,7 +1918,10 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, unsigned Index = 0; SmallVector<TypeIndex, 8> ArgTypeIndices; - TypeIndex ReturnTypeIndex = getTypeIndex(ReturnAndArgs[Index++]); + TypeIndex ReturnTypeIndex = TypeIndex::Void(); + if (ReturnAndArgs.size() > Index) { + ReturnTypeIndex = getTypeIndex(ReturnAndArgs[Index++]); + } // If the first argument is a pointer type and this isn't a static method, // treat it as the special 'this' parameter, which is encoded separately from @@ -1844,7 +1929,7 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, TypeIndex ThisTypeIndex; if (!IsStaticMethod && ReturnAndArgs.size() > Index) { if (const DIDerivedType *PtrTy = - dyn_cast_or_null<DIDerivedType>(ReturnAndArgs[Index].resolve())) { + dyn_cast_or_null<DIDerivedType>(ReturnAndArgs[Index])) { if (PtrTy->getTag() == dwarf::DW_TAG_pointer_type) { ThisTypeIndex = getTypeIndexForThisPtr(PtrTy, Ty); Index++; @@ -1942,7 +2027,7 @@ static ClassOptions getCommonClassOptions(const DICompositeType *Ty) { // Put the Nested flag on a type if it appears immediately inside a tag type. // Do not walk the scope chain. Do not attempt to compute ContainsNestedClass // here. That flag is only set on definitions, and not forward declarations. - const DIScope *ImmediateScope = Ty->getScope().resolve(); + const DIScope *ImmediateScope = Ty->getScope(); if (ImmediateScope && isa<DICompositeType>(ImmediateScope)) CO |= ClassOptions::Nested; @@ -1955,7 +2040,7 @@ static ClassOptions getCommonClassOptions(const DICompositeType *Ty) { CO |= ClassOptions::Scoped; } else { for (const DIScope *Scope = ImmediateScope; Scope != nullptr; - Scope = Scope->getScope().resolve()) { + Scope = Scope->getScope()) { if (isa<DISubprogram>(Scope)) { CO |= ClassOptions::Scoped; break; @@ -2075,7 +2160,7 @@ void CodeViewDebug::collectMemberInfo(ClassInfo &Info, // 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 DIType *Ty = DDTy->getBaseType(); bool FullyResolved = false; while (!FullyResolved) { switch (Ty->getTag()) { @@ -2083,7 +2168,7 @@ void CodeViewDebug::collectMemberInfo(ClassInfo &Info, 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(); + Ty = cast<DIDerivedType>(Ty)->getBaseType(); break; default: FullyResolved = true; @@ -2184,6 +2269,14 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) { if (ContainsNestedClass) CO |= ClassOptions::ContainsNestedClass; + // MSVC appears to set this flag by searching any destructor or method with + // FunctionOptions::Constructor among the emitted members. Clang AST has all + // the members, however special member functions are not yet emitted into + // debug information. For now checking a class's non-triviality seems enough. + // FIXME: not true for a nested unnamed struct. + if (isNonTrivial(Ty)) + CO |= ClassOptions::HasConstructorOrDestructor; + std::string FullName = getFullyQualifiedName(Ty); uint64_t SizeInBytes = Ty->getSizeInBits() / 8; @@ -2358,7 +2451,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { // Create nested classes. for (const DIType *Nested : Info.NestedTypes) { - NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName()); + NestedTypeRecord R(getTypeIndex(Nested), Nested->getName()); ContinuationBuilder.writeMemberType(R); MemberCount++; } @@ -2385,10 +2478,7 @@ TypeIndex CodeViewDebug::getVBPTypeIndex() { return VBPType; } -TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef) { - const DIType *Ty = TypeRef.resolve(); - const DIType *ClassTy = ClassTyRef.resolve(); - +TypeIndex CodeViewDebug::getTypeIndex(const DIType *Ty, const DIType *ClassTy) { // The null DIType is the void type. Don't try to hash it. if (!Ty) return TypeIndex::Void(); @@ -2431,8 +2521,7 @@ CodeViewDebug::getTypeIndexForThisPtr(const DIDerivedType *PtrTy, return recordTypeIndexForDINode(PtrTy, TI, SubroutineTy); } -TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(DITypeRef TypeRef) { - DIType *Ty = TypeRef.resolve(); +TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(const DIType *Ty) { PointerRecord PR(getTypeIndex(Ty), getPointerSizeInBytes() == 8 ? PointerKind::Near64 : PointerKind::Near32, @@ -2441,9 +2530,7 @@ TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(DITypeRef TypeRef) { return TypeTable.writeLeafType(PR); } -TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { - const DIType *Ty = TypeRef.resolve(); - +TypeIndex CodeViewDebug::getCompleteTypeIndex(const DIType *Ty) { // The null DIType is the void type. Don't try to hash it. if (!Ty) return TypeIndex::Void(); @@ -2454,7 +2541,7 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { if (Ty->getTag() == dwarf::DW_TAG_typedef) (void)getTypeIndex(Ty); while (Ty->getTag() == dwarf::DW_TAG_typedef) - Ty = cast<DIDerivedType>(Ty)->getBaseType().resolve(); + Ty = cast<DIDerivedType>(Ty)->getBaseType(); // If this is a non-record type, the complete type index is the same as the // normal type index. Just call getTypeIndex. @@ -2467,11 +2554,7 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { return getTypeIndex(Ty); } - // 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) - return InsertResult.first->second; TypeLoweringScope S(*this); @@ -2489,6 +2572,13 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { return FwdDeclTI; } + // Check if we've already translated the complete record type. + // Insert the type with a null TypeIndex to signify that the type is currently + // being lowered. + auto InsertResult = CompleteTypeIndices.insert({CTy, TypeIndex()}); + if (!InsertResult.second) + return InsertResult.first->second; + TypeIndex TI; switch (CTy->getTag()) { case dwarf::DW_TAG_class_type: @@ -2799,6 +2889,7 @@ void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) { } CurFn->Annotations = MF->getCodeViewAnnotations(); + CurFn->HeapAllocSites = MF->getCodeViewHeapAllocSites(); CurFn->End = Asm->getFunctionEnd(); @@ -2914,10 +3005,19 @@ void CodeViewDebug::collectGlobalVariableInfo() { for (const MDNode *Node : CUs->operands()) { const auto *CU = cast<DICompileUnit>(Node); for (const auto *GVE : CU->getGlobalVariables()) { + const DIGlobalVariable *DIGV = GVE->getVariable(); + const DIExpression *DIE = GVE->getExpression(); + + // Emit constant global variables in a global symbol section. + if (GlobalMap.count(GVE) == 0 && DIE->isConstant()) { + CVGlobalVariable CVGV = {DIGV, DIE}; + GlobalVariables.emplace_back(std::move(CVGV)); + } + const auto *GV = GlobalMap.lookup(GVE); if (!GV || GV->isDeclarationForLinker()) continue; - const DIGlobalVariable *DIGV = GVE->getVariable(); + DIScope *Scope = DIGV->getScope(); SmallVector<CVGlobalVariable, 1> *VariableList; if (Scope && isa<DILocalScope>(Scope)) { @@ -2932,7 +3032,7 @@ void CodeViewDebug::collectGlobalVariableInfo() { // Emit this global variable into a COMDAT section. VariableList = &ComdatVariables; else - // Emit this globla variable in a single global symbol section. + // Emit this global variable in a single global symbol section. VariableList = &GlobalVariables; CVGlobalVariable CVGV = {DIGV, GV}; VariableList->emplace_back(std::move(CVGV)); @@ -2955,13 +3055,14 @@ void CodeViewDebug::emitDebugInfoForGlobals() { // Second, emit each global that is in a comdat into its own .debug$S // section along with its own symbol substream. for (const CVGlobalVariable &CVGV : ComdatVariables) { - MCSymbol *GVSym = Asm->getSymbol(CVGV.GV); + const GlobalVariable *GV = CVGV.GVInfo.get<const GlobalVariable *>(); + MCSymbol *GVSym = Asm->getSymbol(GV); OS.AddComment("Symbol subsection for " + - Twine(GlobalValue::dropLLVMManglingEscape(CVGV.GV->getName()))); + Twine(GlobalValue::dropLLVMManglingEscape(GV->getName()))); switchToDebugSectionForSymbol(GVSym); MCSymbol *EndLabel = beginCVSubsection(DebugSubsectionKind::Symbols); // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions. - emitDebugInfoForGlobal(CVGV.DIGV, CVGV.GV, GVSym); + emitDebugInfoForGlobal(CVGV); endCVSubsection(EndLabel); } } @@ -2981,31 +3082,63 @@ void CodeViewDebug::emitDebugInfoForRetainedTypes() { // Emit each global variable in the specified array. void CodeViewDebug::emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals) { for (const CVGlobalVariable &CVGV : Globals) { - MCSymbol *GVSym = Asm->getSymbol(CVGV.GV); // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions. - emitDebugInfoForGlobal(CVGV.DIGV, CVGV.GV, GVSym); - } -} - -void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, - const GlobalVariable *GV, - MCSymbol *GVSym) { - // DataSym record, see SymbolRecord.h for more info. Thread local data - // happens to have the same format as global data. - SymbolKind DataSym = GV->isThreadLocal() - ? (DIGV->isLocalToUnit() ? SymbolKind::S_LTHREAD32 - : SymbolKind::S_GTHREAD32) - : (DIGV->isLocalToUnit() ? SymbolKind::S_LDATA32 - : SymbolKind::S_GDATA32); - MCSymbol *DataEnd = beginSymbolRecord(DataSym); - OS.AddComment("Type"); - OS.EmitIntValue(getCompleteTypeIndex(DIGV->getType()).getIndex(), 4); - OS.AddComment("DataOffset"); - OS.EmitCOFFSecRel32(GVSym, /*Offset=*/0); - OS.AddComment("Segment"); - OS.EmitCOFFSectionIndex(GVSym); - OS.AddComment("Name"); - const unsigned LengthOfDataRecord = 12; - emitNullTerminatedSymbolName(OS, DIGV->getName(), LengthOfDataRecord); - endSymbolRecord(DataEnd); + emitDebugInfoForGlobal(CVGV); + } +} + +void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) { + const DIGlobalVariable *DIGV = CVGV.DIGV; + if (const GlobalVariable *GV = + CVGV.GVInfo.dyn_cast<const GlobalVariable *>()) { + // DataSym record, see SymbolRecord.h for more info. Thread local data + // happens to have the same format as global data. + MCSymbol *GVSym = Asm->getSymbol(GV); + SymbolKind DataSym = GV->isThreadLocal() + ? (DIGV->isLocalToUnit() ? SymbolKind::S_LTHREAD32 + : SymbolKind::S_GTHREAD32) + : (DIGV->isLocalToUnit() ? SymbolKind::S_LDATA32 + : SymbolKind::S_GDATA32); + MCSymbol *DataEnd = beginSymbolRecord(DataSym); + OS.AddComment("Type"); + OS.EmitIntValue(getCompleteTypeIndex(DIGV->getType()).getIndex(), 4); + OS.AddComment("DataOffset"); + OS.EmitCOFFSecRel32(GVSym, /*Offset=*/0); + OS.AddComment("Segment"); + OS.EmitCOFFSectionIndex(GVSym); + OS.AddComment("Name"); + const unsigned LengthOfDataRecord = 12; + emitNullTerminatedSymbolName(OS, DIGV->getName(), LengthOfDataRecord); + endSymbolRecord(DataEnd); + } else { + // FIXME: Currently this only emits the global variables in the IR metadata. + // This should also emit enums and static data members. + const DIExpression *DIE = CVGV.GVInfo.get<const DIExpression *>(); + assert(DIE->isConstant() && + "Global constant variables must contain a constant expression."); + uint64_t Val = DIE->getElement(1); + + MCSymbol *SConstantEnd = beginSymbolRecord(SymbolKind::S_CONSTANT); + OS.AddComment("Type"); + OS.EmitIntValue(getTypeIndex(DIGV->getType()).getIndex(), 4); + OS.AddComment("Value"); + + // Encoded integers shouldn't need more than 10 bytes. + uint8_t data[10]; + BinaryStreamWriter Writer(data, llvm::support::endianness::little); + CodeViewRecordIO IO(Writer); + cantFail(IO.mapEncodedInteger(Val)); + StringRef SRef((char *)data, Writer.getOffset()); + OS.EmitBinaryData(SRef); + + OS.AddComment("Name"); + const DIScope *Scope = DIGV->getScope(); + // For static data members, get the scope from the declaration. + if (const auto *MemberDecl = dyn_cast_or_null<DIDerivedType>( + DIGV->getRawStaticDataMemberDeclaration())) + Scope = MemberDecl->getScope(); + emitNullTerminatedSymbolName(OS, + getFullyQualifiedName(Scope, DIGV->getName())); + endSymbolRecord(SConstantEnd); + } } diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/lib/CodeGen/AsmPrinter/CodeViewDebug.h index 21557ed1be35..ce57b789d7fa 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -1,9 +1,8 @@ //===- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h --------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -18,6 +17,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/DbgEntityHistoryCalculator.h" @@ -101,7 +101,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { struct CVGlobalVariable { const DIGlobalVariable *DIGV; - const GlobalVariable *GV; + PointerUnion<const GlobalVariable *, const DIExpression *> GVInfo; }; struct InlineSite { @@ -148,6 +148,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { SmallVector<LexicalBlock *, 1> ChildBlocks; std::vector<std::pair<MCSymbol *, MDNode *>> Annotations; + std::vector<std::tuple<MCSymbol *, MCSymbol *, DIType *>> HeapAllocSites; const MCSymbol *Begin = nullptr; const MCSymbol *End = nullptr; @@ -223,7 +224,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { codeview::TypeIndex getFuncIdForSubprogram(const DISubprogram *SP); void calculateRanges(LocalVariable &Var, - const DbgValueHistoryMap::InstrRanges &Ranges); + const DbgValueHistoryMap::Entries &Entries); static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children, const FunctionInfo &FI, @@ -313,8 +314,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void emitDebugInfoForGlobals(); void emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals); - void emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, - const GlobalVariable *GV, MCSymbol *GVSym); + void emitDebugInfoForGlobal(const CVGlobalVariable &CVGV); /// Opens a subsection of the given kind in a .debug$S codeview section. /// Returns an end label for use with endCVSubsection when the subsection is @@ -373,14 +373,14 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { /// Translates the DIType to codeview if necessary and returns a type index /// for it. - codeview::TypeIndex getTypeIndex(DITypeRef TypeRef, - DITypeRef ClassTyRef = DITypeRef()); + codeview::TypeIndex getTypeIndex(const DIType *Ty, + const DIType *ClassTy = nullptr); codeview::TypeIndex getTypeIndexForThisPtr(const DIDerivedType *PtrTy, const DISubroutineType *SubroutineTy); - codeview::TypeIndex getTypeIndexForReferenceTo(DITypeRef TypeRef); + codeview::TypeIndex getTypeIndexForReferenceTo(const DIType *Ty); codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP, const DICompositeType *Class); @@ -419,7 +419,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { /// use this entry point when generating symbol records. The complete and /// incomplete type indices only differ for record types. All other types use /// the same index. - codeview::TypeIndex getCompleteTypeIndex(DITypeRef TypeRef); + codeview::TypeIndex getCompleteTypeIndex(const DIType *Ty); codeview::TypeIndex lowerCompleteTypeClass(const DICompositeType *Ty); codeview::TypeIndex lowerCompleteTypeUnion(const DICompositeType *Ty); diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp index e27659494f08..f4134da48caa 100644 --- a/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/lib/CodeGen/AsmPrinter/DIE.cpp @@ -1,9 +1,8 @@ //===--- lib/CodeGen/DIE.cpp - DWARF Info Entries -------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -212,7 +211,7 @@ const DIE *DIE::getUnitDie() const { return nullptr; } -const DIEUnit *DIE::getUnit() const { +DIEUnit *DIE::getUnit() const { const DIE *UnitDie = getUnitDie(); if (UnitDie) return UnitDie->Owner.dyn_cast<DIEUnit*>(); @@ -507,6 +506,23 @@ LLVM_DUMP_METHOD void DIELabel::print(raw_ostream &O) const { O << "Lbl: " << Label->getName(); } //===----------------------------------------------------------------------===// +// DIEBaseTypeRef Implementation +//===----------------------------------------------------------------------===// + +void DIEBaseTypeRef::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { + uint64_t Offset = CU->ExprRefedBaseTypes[Index].Die->getOffset(); + assert(Offset < (1ULL << (ULEB128PadSize * 7)) && "Offset wont fit"); + AP->EmitULEB128(Offset, nullptr, ULEB128PadSize); +} + +unsigned DIEBaseTypeRef::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { + return ULEB128PadSize; +} + +LLVM_DUMP_METHOD +void DIEBaseTypeRef::print(raw_ostream &O) const { O << "BaseTypeRef: " << Index; } + +//===----------------------------------------------------------------------===// // DIEDelta Implementation //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/DIEHash.cpp b/lib/CodeGen/AsmPrinter/DIEHash.cpp index b8f1202494d7..bfac8850a2a6 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -1,9 +1,8 @@ //===-- llvm/CodeGen/DIEHash.cpp - Dwarf Hashing Framework ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -226,7 +225,7 @@ void DIEHash::hashLocList(const DIELocList &LocList) { DwarfDebug &DD = *AP->getDwarfDebug(); const DebugLocStream &Locs = DD.getDebugLocs(); for (const auto &Entry : Locs.getEntries(Locs.getList(LocList.getValue()))) - DD.emitDebugLocEntry(Streamer, Entry); + DD.emitDebugLocEntry(Streamer, Entry, nullptr); } // Hash an individual attribute \param Attr based on the type of attribute and @@ -310,6 +309,7 @@ void DIEHash::hashAttribute(const DIEValue &Value, dwarf::Tag Tag) { // FIXME: It's uncertain whether or not we should handle this at the moment. case DIEValue::isExpr: case DIEValue::isLabel: + case DIEValue::isBaseTypeRef: case DIEValue::isDelta: llvm_unreachable("Add support for additional value types."); } diff --git a/lib/CodeGen/AsmPrinter/DIEHash.h b/lib/CodeGen/AsmPrinter/DIEHash.h index dae517ab2c29..2e49514c98be 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.h +++ b/lib/CodeGen/AsmPrinter/DIEHash.h @@ -1,9 +1,8 @@ //===-- llvm/CodeGen/DIEHash.h - Dwarf Hashing Framework -------*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp b/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp index 09867822c30a..ddd60575b6c0 100644 --- a/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ b/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -1,15 +1,15 @@ //===- llvm/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/DbgEntityHistoryCalculator.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" @@ -31,51 +31,62 @@ using namespace llvm; #define DEBUG_TYPE "dwarfdebug" +namespace { +using EntryIndex = DbgValueHistoryMap::EntryIndex; +} + // 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) { +static Register isDescribedByReg(const MachineInstr &MI) { assert(MI.isDebugValue()); assert(MI.getNumOperands() == 4); + // If the location of variable is an entry value (DW_OP_entry_value) + // do not consider it as a register location. + if (MI.getDebugExpression()->isEntryValue()) + return 0; // If location of variable is described using a register (directly or // indirectly), this register is always a first operand. - return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; + return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : Register(); } -void DbgValueHistoryMap::startInstrRange(InlinedEntity Var, - const MachineInstr &MI) { +bool DbgValueHistoryMap::startDbgValue(InlinedEntity Var, + const MachineInstr &MI, + EntryIndex &NewIndex) { // Instruction range should start with a DBG_VALUE instruction for the // variable. assert(MI.isDebugValue() && "not a DBG_VALUE"); - auto &Ranges = VarInstrRanges[Var]; - if (!Ranges.empty() && Ranges.back().second == nullptr && - Ranges.back().first->isIdenticalTo(MI)) { + auto &Entries = VarEntries[Var]; + if (!Entries.empty() && Entries.back().isDbgValue() && + !Entries.back().isClosed() && + Entries.back().getInstr()->isIdenticalTo(MI)) { LLVM_DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" - << "\t" << Ranges.back().first << "\t" << MI << "\n"); - return; + << "\t" << Entries.back().getInstr() << "\t" << MI + << "\n"); + return false; } - Ranges.push_back(std::make_pair(&MI, nullptr)); + Entries.emplace_back(&MI, Entry::DbgValue); + NewIndex = Entries.size() - 1; + return true; } -void DbgValueHistoryMap::endInstrRange(InlinedEntity Var, - const MachineInstr &MI) { - auto &Ranges = VarInstrRanges[Var]; - // Verify that the current instruction range is not yet closed. - assert(!Ranges.empty() && Ranges.back().second == nullptr); - // For now, instruction ranges are not allowed to cross basic block - // boundaries. - assert(Ranges.back().first->getParent() == MI.getParent()); - Ranges.back().second = &MI; +EntryIndex DbgValueHistoryMap::startClobber(InlinedEntity Var, + const MachineInstr &MI) { + auto &Entries = VarEntries[Var]; + // If an instruction clobbers multiple registers that the variable is + // described by, then we may have already created a clobbering instruction. + if (Entries.back().isClobber() && Entries.back().getInstr() == &MI) + return Entries.size() - 1; + Entries.emplace_back(&MI, Entry::Clobber); + return Entries.size() - 1; } -unsigned DbgValueHistoryMap::getRegisterForVar(InlinedEntity Var) const { - const auto &I = VarInstrRanges.find(Var); - if (I == VarInstrRanges.end()) - return 0; - const auto &Ranges = I->second; - if (Ranges.empty() || Ranges.back().second != nullptr) - return 0; - return isDescribedByReg(*Ranges.back().first); +void DbgValueHistoryMap::Entry::endEntry(EntryIndex Index) { + // For now, instruction ranges are not allowed to cross basic block + // boundaries. + assert(isDbgValue() && "Setting end index for non-debug value"); + assert(!isClosed() && "End index has already been set"); + EndIndex = Index; } void DbgLabelInstrMap::addInstr(InlinedEntity Label, const MachineInstr &MI) { @@ -89,6 +100,12 @@ namespace { using InlinedEntity = DbgValueHistoryMap::InlinedEntity; using RegDescribedVarsMap = std::map<unsigned, SmallVector<InlinedEntity, 1>>; +// Keeps track of the debug value entries that are currently live for each +// inlined entity. As the history map entries are stored in a SmallVector, they +// may be moved at insertion of new entries, so store indices rather than +// pointers. +using DbgValueEntriesMap = std::map<InlinedEntity, SmallSet<EntryIndex, 1>>; + } // end anonymous namespace // Claim that @Var is not described by @RegNo anymore. @@ -114,16 +131,88 @@ static void addRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, VarSet.push_back(Var); } +/// Create a clobbering entry and end all open debug value entries +/// for \p Var that are described by \p RegNo using that entry. +static void clobberRegEntries(InlinedEntity Var, unsigned RegNo, + const MachineInstr &ClobberingInstr, + DbgValueEntriesMap &LiveEntries, + DbgValueHistoryMap &HistMap) { + EntryIndex ClobberIndex = HistMap.startClobber(Var, ClobberingInstr); + + // Close all entries whose values are described by the register. + SmallVector<EntryIndex, 4> IndicesToErase; + for (auto Index : LiveEntries[Var]) { + auto &Entry = HistMap.getEntry(Var, Index); + assert(Entry.isDbgValue() && "Not a DBG_VALUE in LiveEntries"); + if (isDescribedByReg(*Entry.getInstr()) == RegNo) { + IndicesToErase.push_back(Index); + Entry.endEntry(ClobberIndex); + } + } + + // Drop all entries that have ended. + for (auto Index : IndicesToErase) + LiveEntries[Var].erase(Index); +} + +/// Add a new debug value for \p Var. Closes all overlapping debug values. +static void handleNewDebugValue(InlinedEntity Var, const MachineInstr &DV, + RegDescribedVarsMap &RegVars, + DbgValueEntriesMap &LiveEntries, + DbgValueHistoryMap &HistMap) { + EntryIndex NewIndex; + if (HistMap.startDbgValue(Var, DV, NewIndex)) { + SmallDenseMap<unsigned, bool, 4> TrackedRegs; + + // If we have created a new debug value entry, close all preceding + // live entries that overlap. + SmallVector<EntryIndex, 4> IndicesToErase; + const DIExpression *DIExpr = DV.getDebugExpression(); + for (auto Index : LiveEntries[Var]) { + auto &Entry = HistMap.getEntry(Var, Index); + assert(Entry.isDbgValue() && "Not a DBG_VALUE in LiveEntries"); + const MachineInstr &DV = *Entry.getInstr(); + bool Overlaps = DIExpr->fragmentsOverlap(DV.getDebugExpression()); + if (Overlaps) { + IndicesToErase.push_back(Index); + Entry.endEntry(NewIndex); + } + if (unsigned Reg = isDescribedByReg(DV)) + TrackedRegs[Reg] |= !Overlaps; + } + + // If the new debug value is described by a register, add tracking of + // that register if it is not already tracked. + if (unsigned NewReg = isDescribedByReg(DV)) { + if (!TrackedRegs.count(NewReg)) + addRegDescribedVar(RegVars, NewReg, Var); + LiveEntries[Var].insert(NewIndex); + TrackedRegs[NewReg] = true; + } + + // Drop tracking of registers that are no longer used. + for (auto I : TrackedRegs) + if (!I.second) + dropRegDescribedVar(RegVars, I.first, Var); + + // Drop all entries that have ended, and mark the new entry as live. + for (auto Index : IndicesToErase) + LiveEntries[Var].erase(Index); + LiveEntries[Var].insert(NewIndex); + } +} + // 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, DbgValueHistoryMap &HistMap, + DbgValueEntriesMap &LiveEntries, const MachineInstr &ClobberingInstr) { // Iterate over all variables described by this register and add this // instruction to their history, clobbering it. for (const auto &Var : I->second) - HistMap.endInstrRange(Var, ClobberingInstr); + clobberRegEntries(Var, I->first, ClobberingInstr, LiveEntries, HistMap); RegVars.erase(I); } @@ -131,115 +220,25 @@ static void clobberRegisterUses(RegDescribedVarsMap &RegVars, // @RegNo by inserting @ClobberingInstr to their history. static void clobberRegisterUses(RegDescribedVarsMap &RegVars, unsigned RegNo, DbgValueHistoryMap &HistMap, + DbgValueEntriesMap &LiveEntries, const MachineInstr &ClobberingInstr) { const auto &I = RegVars.find(RegNo); if (I == RegVars.end()) return; - clobberRegisterUses(RegVars, I, HistMap, ClobberingInstr); -} - -// 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(); - if (LastMI == MBB.end() || !LastMI->isReturn()) - return nullptr; - // Assume that epilogue starts with instruction having the same debug location - // as the return instruction. - DebugLoc LastLoc = LastMI->getDebugLoc(); - auto Res = LastMI; - for (MachineBasicBlock::const_reverse_iterator I = LastMI.getReverse(), - E = MBB.rend(); - I != E; ++I) { - if (I->getDebugLoc() != LastLoc) - return &*Res; - Res = &*I; - } - // If all instructions have the same debug location, assume whole MBB is - // an epilogue. - return &*MBB.begin(); -} - -// 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, - BitVector &Regs) { - for (const auto &MBB : *MF) { - auto FirstEpilogueInst = getFirstEpilogueInst(MBB); - - for (const auto &MI : MBB) { - // Avoid looking at prologue or epilogue instructions. - if (&MI == FirstEpilogueInst) - break; - if (MI.getFlag(MachineInstr::FrameSetup)) - continue; - - // Look for register defs and register masks. Register masks are - // typically on calls and they clobber everything not in the mask. - for (const MachineOperand &MO : MI.operands()) { - // Skip virtual registers since they are handled by the parent. - if (MO.isReg() && MO.isDef() && MO.getReg() && - !TRI->isVirtualRegister(MO.getReg())) { - for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); - ++AI) - Regs.set(*AI); - } else if (MO.isRegMask()) { - Regs.setBitsNotInMask(MO.getRegMask()); - } - } - } - } + clobberRegisterUses(RegVars, I, HistMap, LiveEntries, ClobberingInstr); } void llvm::calculateDbgEntityHistory(const MachineFunction *MF, const TargetRegisterInfo *TRI, DbgValueHistoryMap &DbgValues, DbgLabelInstrMap &DbgLabels) { - BitVector ChangingRegs(TRI->getNumRegs()); - collectChangingRegs(MF, TRI, ChangingRegs); - const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); + unsigned FrameReg = TRI->getFrameRegister(*MF); RegDescribedVarsMap RegVars; + DbgValueEntriesMap LiveEntries; for (const auto &MBB : *MF) { for (const auto &MI : MBB) { - if (!MI.isDebugInstr()) { - // Not a DBG_VALUE instruction. It may clobber registers which describe - // some variables. - for (const MachineOperand &MO : MI.operands()) { - if (MO.isReg() && MO.isDef() && MO.getReg()) { - // Ignore call instructions that claim to clobber SP. The AArch64 - // backend does this for aggregate function arguments. - if (MI.isCall() && MO.getReg() == SP) - continue; - // If this is a virtual register, only clobber it since it doesn't - // have aliases. - if (TRI->isVirtualRegister(MO.getReg())) - clobberRegisterUses(RegVars, MO.getReg(), DbgValues, MI); - // If this is a register def operand, it may end a debug value - // range. - else { - for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); - ++AI) - if (ChangingRegs.test(*AI)) - clobberRegisterUses(RegVars, *AI, DbgValues, MI); - } - } else if (MO.isRegMask()) { - // If this is a register mask operand, clobber all debug values in - // non-CSRs. - for (unsigned I : ChangingRegs.set_bits()) { - // Don't consider SP to be clobbered by register masks. - if (unsigned(I) != SP && TRI->isPhysicalRegister(I) && - MO.clobbersPhysReg(I)) { - clobberRegisterUses(RegVars, I, DbgValues, MI); - } - } - } - } - continue; - } - if (MI.isDebugValue()) { assert(MI.getNumOperands() > 1 && "Invalid DBG_VALUE instruction!"); // Use the base variable (without any DW_OP_piece expressions) @@ -250,13 +249,7 @@ void llvm::calculateDbgEntityHistory(const MachineFunction *MF, "Expected inlined-at fields to agree"); InlinedEntity Var(RawVar, MI.getDebugLoc()->getInlinedAt()); - if (unsigned PrevReg = DbgValues.getRegisterForVar(Var)) - dropRegDescribedVar(RegVars, PrevReg, Var); - - DbgValues.startInstrRange(Var, MI); - - if (unsigned NewReg = isDescribedByReg(MI)) - addRegDescribedVar(RegVars, NewReg, Var); + handleNewDebugValue(Var, MI, RegVars, LiveEntries, DbgValues); } else if (MI.isDebugLabel()) { assert(MI.getNumOperands() == 1 && "Invalid DBG_LABEL instruction!"); const DILabel *RawLabel = MI.getDebugLabel(); @@ -268,18 +261,75 @@ void llvm::calculateDbgEntityHistory(const MachineFunction *MF, InlinedEntity L(RawLabel, MI.getDebugLoc()->getInlinedAt()); DbgLabels.addInstr(L, MI); } - } - // Make sure locations for register-described variables are valid only - // until the end of the basic block (unless it's the last basic block, in - // which case let their liveness run off to the end of the function). + if (MI.isDebugInstr()) + continue; + + // Not a DBG_VALUE instruction. It may clobber registers which describe + // some variables. + for (const MachineOperand &MO : MI.operands()) { + if (MO.isReg() && MO.isDef() && MO.getReg()) { + // Ignore call instructions that claim to clobber SP. The AArch64 + // backend does this for aggregate function arguments. + if (MI.isCall() && MO.getReg() == SP) + continue; + // If this is a virtual register, only clobber it since it doesn't + // have aliases. + if (TRI->isVirtualRegister(MO.getReg())) + clobberRegisterUses(RegVars, MO.getReg(), DbgValues, LiveEntries, + MI); + // If this is a register def operand, it may end a debug value + // range. Ignore frame-register defs in the epilogue and prologue, + // we expect debuggers to understand that stack-locations are + // invalid outside of the function body. + else if (MO.getReg() != FrameReg || + (!MI.getFlag(MachineInstr::FrameDestroy) && + !MI.getFlag(MachineInstr::FrameSetup))) { + for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); + ++AI) + clobberRegisterUses(RegVars, *AI, DbgValues, LiveEntries, MI); + } + } else if (MO.isRegMask()) { + // If this is a register mask operand, clobber all debug values in + // non-CSRs. + SmallVector<unsigned, 32> RegsToClobber; + // Don't consider SP to be clobbered by register masks. + for (auto It : RegVars) { + unsigned int Reg = It.first; + if (Reg != SP && TRI->isPhysicalRegister(Reg) && + MO.clobbersPhysReg(Reg)) + RegsToClobber.push_back(Reg); + } + + for (unsigned Reg : RegsToClobber) { + clobberRegisterUses(RegVars, Reg, DbgValues, LiveEntries, MI); + } + } + } // End MO loop. + } // End instr loop. + + // Make sure locations for all variables are valid only until the end of + // the basic block (unless it's the last basic block, in which case let + // their liveness run off to the end of the function). if (!MBB.empty() && &MBB != &MF->back()) { - for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) { - auto CurElem = I++; // CurElem can be erased below. - if (TRI->isVirtualRegister(CurElem->first) || - ChangingRegs.test(CurElem->first)) - clobberRegisterUses(RegVars, CurElem, DbgValues, MBB.back()); + // Iterate over all variables that have open debug values. + for (auto &Pair : LiveEntries) { + if (Pair.second.empty()) + continue; + + // Create a clobbering entry. + EntryIndex ClobIdx = DbgValues.startClobber(Pair.first, MBB.back()); + + // End all entries. + for (EntryIndex Idx : Pair.second) { + DbgValueHistoryMap::Entry &Ent = DbgValues.getEntry(Pair.first, Idx); + assert(Ent.isDbgValue() && !Ent.isClosed()); + Ent.endEntry(ClobIdx); + } } + + LiveEntries.clear(); + RegVars.clear(); } } } @@ -289,7 +339,7 @@ LLVM_DUMP_METHOD void DbgValueHistoryMap::dump() const { dbgs() << "DbgValueHistoryMap:\n"; for (const auto &VarRangePair : *this) { const InlinedEntity &Var = VarRangePair.first; - const InstrRanges &Ranges = VarRangePair.second; + const Entries &Entries = VarRangePair.second; const DILocalVariable *LocalVar = cast<DILocalVariable>(Var.first); const DILocation *Location = Var.second; @@ -304,10 +354,20 @@ LLVM_DUMP_METHOD void DbgValueHistoryMap::dump() const { dbgs() << " --\n"; - for (const InstrRange &Range : Ranges) { - dbgs() << " Begin: " << *Range.first; - if (Range.second) - dbgs() << " End : " << *Range.second; + for (const auto &E : enumerate(Entries)) { + const auto &Entry = E.value(); + dbgs() << " Entry[" << E.index() << "]: "; + if (Entry.isDbgValue()) + dbgs() << "Debug value\n"; + else + dbgs() << "Clobber\n"; + dbgs() << " Instr: " << *Entry.getInstr(); + if (Entry.isDbgValue()) { + if (Entry.getEndIndex() == NoEntry) + dbgs() << " - Valid until end of function\n"; + else + dbgs() << " - Closed by Entry[" << Entry.getEndIndex() << "]\n"; + } dbgs() << "\n"; } } diff --git a/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp b/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp index 551cd36d1984..22f458e4b03e 100644 --- a/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ b/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -1,9 +1,8 @@ //===-- llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp -------*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -141,10 +140,9 @@ DebugHandlerBase::getFunctionLocalOffsetAfterInsn(const MachineInstr *MI) { } /// 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(); +uint64_t DebugHandlerBase::getBaseTypeSize(const DIType *Ty) { assert(Ty); - DIDerivedType *DDTy = dyn_cast<DIDerivedType>(Ty); + const DIDerivedType *DDTy = dyn_cast<DIDerivedType>(Ty); if (!DDTy) return Ty->getSizeInBits(); @@ -155,7 +153,7 @@ uint64_t DebugHandlerBase::getBaseTypeSize(const DITypeRef TyRef) { Tag != dwarf::DW_TAG_restrict_type && Tag != dwarf::DW_TAG_atomic_type) return DDTy->getSizeInBits(); - DIType *BaseType = DDTy->getBaseType().resolve(); + DIType *BaseType = DDTy->getBaseType(); if (!BaseType) return 0; @@ -212,36 +210,58 @@ void DebugHandlerBase::beginFunction(const MachineFunction *MF) { // Request labels for the full history. for (const auto &I : DbgValues) { - const auto &Ranges = I.second; - if (Ranges.empty()) + const auto &Entries = I.second; + if (Entries.empty()) continue; - // The first mention of a function argument gets the CurrentFnBegin - // label, so arguments are visible when breaking at function entry. - const DILocalVariable *DIVar = Ranges.front().first->getDebugVariable(); + auto IsDescribedByReg = [](const MachineInstr *MI) { + return MI->getOperand(0).isReg() && MI->getOperand(0).getReg(); + }; + + // The first mention of a function argument gets the CurrentFnBegin label, + // so arguments are visible when breaking at function entry. + // + // We do not change the label for values that are described by registers, + // as that could place them above their defining instructions. We should + // ideally not change the labels for constant debug values either, since + // doing that violates the ranges that are calculated in the history map. + // However, we currently do not emit debug values for constant arguments + // directly at the start of the function, so this code is still useful. + const DILocalVariable *DIVar = + Entries.front().getInstr()->getDebugVariable(); if (DIVar->isParameter() && getDISubprogram(DIVar->getScope())->describes(&MF->getFunction())) { - LabelsBeforeInsn[Ranges.front().first] = Asm->getFunctionBegin(); - if (Ranges.front().first->getDebugExpression()->isFragment()) { + if (!IsDescribedByReg(Entries.front().getInstr())) + LabelsBeforeInsn[Entries.front().getInstr()] = Asm->getFunctionBegin(); + if (Entries.front().getInstr()->getDebugExpression()->isFragment()) { // Mark all non-overlapping initial fragments. - for (auto I = Ranges.begin(); I != Ranges.end(); ++I) { - const DIExpression *Fragment = I->first->getDebugExpression(); - if (std::all_of(Ranges.begin(), I, - [&](DbgValueHistoryMap::InstrRange Pred) { - return !Fragment->fragmentsOverlap( - Pred.first->getDebugExpression()); + for (auto I = Entries.begin(); I != Entries.end(); ++I) { + if (!I->isDbgValue()) + continue; + const DIExpression *Fragment = I->getInstr()->getDebugExpression(); + if (std::any_of(Entries.begin(), I, + [&](DbgValueHistoryMap::Entry Pred) { + return Pred.isDbgValue() && + Fragment->fragmentsOverlap( + Pred.getInstr()->getDebugExpression()); })) - LabelsBeforeInsn[I->first] = Asm->getFunctionBegin(); - else break; + // The code that generates location lists for DWARF assumes that the + // entries' start labels are monotonically increasing, and since we + // don't change the label for fragments that are described by + // registers, we must bail out when encountering such a fragment. + if (IsDescribedByReg(I->getInstr())) + break; + LabelsBeforeInsn[I->getInstr()] = Asm->getFunctionBegin(); } } } - for (const auto &Range : Ranges) { - requestLabelBeforeInsn(Range.first); - if (Range.second) - requestLabelAfterInsn(Range.second); + for (const auto &Entry : Entries) { + if (Entry.isDbgValue()) + requestLabelBeforeInsn(Entry.getInstr()); + else + requestLabelAfterInsn(Entry.getInstr()); } } diff --git a/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/lib/CodeGen/AsmPrinter/DebugLocEntry.h index befa4b941c8d..17e39b3d3268 100644 --- a/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ b/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -1,9 +1,8 @@ //===-- llvm/CodeGen/DebugLocEntry.h - Entry in debug_loc list -*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -21,6 +20,73 @@ namespace llvm { class AsmPrinter; +/// A single location or constant. +class DbgValueLoc { + /// Any complex address location expression for this DbgValueLoc. + const DIExpression *Expression; + + /// Type of entry that this represents. + enum EntryType { E_Location, E_Integer, E_ConstantFP, E_ConstantInt }; + enum EntryType EntryKind; + + /// Either a constant, + union { + int64_t Int; + const ConstantFP *CFP; + const ConstantInt *CIP; + } Constant; + + /// Or a location in the machine frame. + MachineLocation Loc; + +public: + DbgValueLoc(const DIExpression *Expr, int64_t i) + : Expression(Expr), EntryKind(E_Integer) { + Constant.Int = i; + } + DbgValueLoc(const DIExpression *Expr, const ConstantFP *CFP) + : Expression(Expr), EntryKind(E_ConstantFP) { + Constant.CFP = CFP; + } + DbgValueLoc(const DIExpression *Expr, const ConstantInt *CIP) + : Expression(Expr), EntryKind(E_ConstantInt) { + Constant.CIP = CIP; + } + DbgValueLoc(const DIExpression *Expr, MachineLocation Loc) + : Expression(Expr), EntryKind(E_Location), Loc(Loc) { + assert(cast<DIExpression>(Expr)->isValid()); + } + + bool isLocation() const { return EntryKind == E_Location; } + bool isInt() const { return EntryKind == E_Integer; } + bool isConstantFP() const { return EntryKind == E_ConstantFP; } + bool isConstantInt() const { return EntryKind == E_ConstantInt; } + int64_t getInt() const { return Constant.Int; } + const ConstantFP *getConstantFP() const { return Constant.CFP; } + const ConstantInt *getConstantInt() const { return Constant.CIP; } + MachineLocation getLoc() const { return Loc; } + bool isFragment() const { return getExpression()->isFragment(); } + bool isEntryVal() const { return getExpression()->isEntryValue(); } + const DIExpression *getExpression() const { return Expression; } + friend bool operator==(const DbgValueLoc &, const DbgValueLoc &); + friend bool operator<(const DbgValueLoc &, const DbgValueLoc &); +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { + if (isLocation()) { + llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " "; + if (Loc.isIndirect()) + llvm::dbgs() << "+0"; + llvm::dbgs() << "} "; + } else if (isConstantInt()) + Constant.CIP->dump(); + else if (isConstantFP()) + Constant.CFP->dump(); + if (Expression) + Expression->dump(); + } +#endif +}; + /// This struct describes location entries emitted in the .debug_loc /// section. class DebugLocEntry { @@ -28,90 +94,20 @@ class DebugLocEntry { const MCSymbol *Begin; const MCSymbol *End; -public: - /// A single location or constant. - struct Value { - Value(const DIExpression *Expr, int64_t i) - : Expression(Expr), EntryKind(E_Integer) { - Constant.Int = i; - } - Value(const DIExpression *Expr, const ConstantFP *CFP) - : Expression(Expr), EntryKind(E_ConstantFP) { - Constant.CFP = CFP; - } - Value(const DIExpression *Expr, const ConstantInt *CIP) - : Expression(Expr), EntryKind(E_ConstantInt) { - Constant.CIP = CIP; - } - Value(const DIExpression *Expr, MachineLocation Loc) - : Expression(Expr), EntryKind(E_Location), Loc(Loc) { - assert(cast<DIExpression>(Expr)->isValid()); - } - - /// Any complex address location expression for this Value. - const DIExpression *Expression; - - /// Type of entry that this represents. - enum EntryType { E_Location, E_Integer, E_ConstantFP, E_ConstantInt }; - enum EntryType EntryKind; - - /// Either a constant, - union { - int64_t Int; - const ConstantFP *CFP; - const ConstantInt *CIP; - } Constant; - - // Or a location in the machine frame. - MachineLocation Loc; - - bool isLocation() const { return EntryKind == E_Location; } - bool isInt() const { return EntryKind == E_Integer; } - bool isConstantFP() const { return EntryKind == E_ConstantFP; } - bool isConstantInt() const { return EntryKind == E_ConstantInt; } - int64_t getInt() const { return Constant.Int; } - const ConstantFP *getConstantFP() const { return Constant.CFP; } - const ConstantInt *getConstantInt() const { return Constant.CIP; } - MachineLocation getLoc() const { return Loc; } - bool isFragment() const { return getExpression()->isFragment(); } - const DIExpression *getExpression() const { return Expression; } - friend bool operator==(const Value &, const Value &); - friend bool operator<(const Value &, const Value &); -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - LLVM_DUMP_METHOD void dump() const { - if (isLocation()) { - llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " "; - if (Loc.isIndirect()) - llvm::dbgs() << "+0"; - llvm::dbgs() << "} "; - } - else if (isConstantInt()) - Constant.CIP->dump(); - else if (isConstantFP()) - Constant.CFP->dump(); - if (Expression) - Expression->dump(); - } -#endif - }; - -private: /// A nonempty list of locations/constants belonging to this entry, /// sorted by offset. - SmallVector<Value, 1> Values; + SmallVector<DbgValueLoc, 1> Values; public: - DebugLocEntry(const MCSymbol *B, const MCSymbol *E, Value Val) - : Begin(B), End(E) { - Values.push_back(std::move(Val)); + /// Create a location list entry for the range [\p Begin, \p End). + /// + /// \param Vals One or more values describing (parts of) the variable. + DebugLocEntry(const MCSymbol *Begin, const MCSymbol *End, + ArrayRef<DbgValueLoc> Vals) + : Begin(Begin), End(End) { + addValues(Vals); } - /// 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); - /// 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 @@ -127,35 +123,36 @@ public: const MCSymbol *getBeginSym() const { return Begin; } const MCSymbol *getEndSym() const { return End; } - ArrayRef<Value> getValues() const { return Values; } - void addValues(ArrayRef<DebugLocEntry::Value> Vals) { + ArrayRef<DbgValueLoc> getValues() const { return Values; } + void addValues(ArrayRef<DbgValueLoc> Vals) { Values.append(Vals.begin(), Vals.end()); sortUniqueValues(); - assert(all_of(Values, [](DebugLocEntry::Value V) { - return V.isFragment(); - }) && "value must be a piece"); + assert((Values.size() == 1 || all_of(Values, [](DbgValueLoc V) { + return V.isFragment(); + })) && "must either have a single value or multiple pieces"); } // Sort the pieces by offset. // Remove any duplicate entries by dropping all but the first. void sortUniqueValues() { llvm::sort(Values); - Values.erase( - std::unique( - Values.begin(), Values.end(), [](const Value &A, const Value &B) { - return A.getExpression() == B.getExpression(); - }), - Values.end()); + Values.erase(std::unique(Values.begin(), Values.end(), + [](const DbgValueLoc &A, const DbgValueLoc &B) { + return A.getExpression() == B.getExpression(); + }), + Values.end()); } /// Lower this entry into a DWARF expression. - void finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List, - const DIBasicType *BT); + void finalize(const AsmPrinter &AP, + DebugLocStream::ListBuilder &List, + const DIBasicType *BT, + DwarfCompileUnit &TheCU); }; -/// Compare two Values for equality. -inline bool operator==(const DebugLocEntry::Value &A, - const DebugLocEntry::Value &B) { +/// Compare two DbgValueLocs for equality. +inline bool operator==(const DbgValueLoc &A, + const DbgValueLoc &B) { if (A.EntryKind != B.EntryKind) return false; @@ -163,21 +160,21 @@ inline bool operator==(const DebugLocEntry::Value &A, return false; switch (A.EntryKind) { - case DebugLocEntry::Value::E_Location: + case DbgValueLoc::E_Location: return A.Loc == B.Loc; - case DebugLocEntry::Value::E_Integer: + case DbgValueLoc::E_Integer: return A.Constant.Int == B.Constant.Int; - case DebugLocEntry::Value::E_ConstantFP: + case DbgValueLoc::E_ConstantFP: return A.Constant.CFP == B.Constant.CFP; - case DebugLocEntry::Value::E_ConstantInt: + case DbgValueLoc::E_ConstantInt: return A.Constant.CIP == B.Constant.CIP; } llvm_unreachable("unhandled EntryKind"); } /// Compare two fragments based on their offset. -inline bool operator<(const DebugLocEntry::Value &A, - const DebugLocEntry::Value &B) { +inline bool operator<(const DbgValueLoc &A, + const DbgValueLoc &B) { return A.getExpression()->getFragmentInfo()->OffsetInBits < B.getExpression()->getFragmentInfo()->OffsetInBits; } diff --git a/lib/CodeGen/AsmPrinter/DebugLocStream.cpp b/lib/CodeGen/AsmPrinter/DebugLocStream.cpp index 7e8ed7104af3..f483d532ff07 100644 --- a/lib/CodeGen/AsmPrinter/DebugLocStream.cpp +++ b/lib/CodeGen/AsmPrinter/DebugLocStream.cpp @@ -1,9 +1,8 @@ //===- DebugLocStream.cpp - DWARF debug_loc stream --------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/DebugLocStream.h b/lib/CodeGen/AsmPrinter/DebugLocStream.h index 8dcf5cbc1889..789291771b5a 100644 --- a/lib/CodeGen/AsmPrinter/DebugLocStream.h +++ b/lib/CodeGen/AsmPrinter/DebugLocStream.h @@ -1,9 +1,8 @@ //===--- lib/CodeGen/DebugLocStream.h - DWARF debug_loc stream --*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp index 1990456cc555..207a7284dafa 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -1,9 +1,8 @@ //===-- CodeGen/AsmPrinter/DwarfException.cpp - Dwarf Exception Impl ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 1dca3f0fce5b..9548ad9918c1 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfCompileUnit.cpp - Dwarf Compile Units ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -18,6 +17,7 @@ #include "DwarfUnit.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -104,7 +104,7 @@ unsigned DwarfCompileUnit::getOrCreateSourceID(const DIFile *File) { // 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, "", "", None, None, CUID); return Asm->OutStreamer->EmitDwarfFileDirective( 0, File->getDirectory(), File->getFilename(), getMD5AsBytes(File), File->getSource(), CUID); @@ -119,17 +119,19 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( assert(GV); auto *GVContext = GV->getScope(); - auto *GTy = DD->resolve(GV->getType()); + const DIType *GTy = GV->getType(); // Construct the context before querying for the existence of the DIE in // case such construction creates the DIE. - DIE *ContextDIE = getOrCreateContextDIE(GVContext); + auto *CB = GVContext ? dyn_cast<DICommonBlock>(GVContext) : nullptr; + DIE *ContextDIE = CB ? getOrCreateCommonBlock(CB, GlobalExprs) + : getOrCreateContextDIE(GVContext); // Add to map. DIE *VariableDIE = &createAndAddDIE(GV->getTag(), *ContextDIE, GV); DIScope *DeclContext; if (auto *SDMDecl = GV->getStaticDataMemberDeclaration()) { - DeclContext = resolve(SDMDecl->getScope()); + DeclContext = SDMDecl->getScope(); assert(SDMDecl->isStaticMember() && "Expected static member decl"); assert(GV->isDefinition()); // We need the declaration DIE that is in the static member's class. @@ -137,7 +139,7 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( addDIEEntry(*VariableDIE, dwarf::DW_AT_specification, *VariableSpecDIE); // If the global variable's type is different from the one in the class // member type, assume that it's more specific and also emit it. - if (GTy != DD->resolve(SDMDecl->getBaseType())) + if (GTy != SDMDecl->getBaseType()) addType(*VariableDIE, GTy); } else { DeclContext = GV->getScope(); @@ -166,8 +168,16 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( addTemplateParams(*VariableDIE, DINodeArray(TP)); // Add location. + addLocationAttribute(VariableDIE, GV, GlobalExprs); + + return VariableDIE; +} + +void DwarfCompileUnit::addLocationAttribute( + DIE *VariableDIE, const DIGlobalVariable *GV, ArrayRef<GlobalExpr> GlobalExprs) { bool addToAccelTable = false; DIELoc *Loc = nullptr; + Optional<unsigned> NVPTXAddressSpace; std::unique_ptr<DIEDwarfExpression> DwarfExpr; for (const auto &GE : GlobalExprs) { const GlobalVariable *Global = GE.Var; @@ -201,8 +211,24 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( DwarfExpr = llvm::make_unique<DIEDwarfExpression>(*Asm, *this, *Loc); } - if (Expr) + if (Expr) { + // According to + // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf + // cuda-gdb requires DW_AT_address_class for all variables to be able to + // correctly interpret address space of the variable address. + // Decode DW_OP_constu <DWARF Address Space> DW_OP_swap DW_OP_xderef + // sequence for the NVPTX + gdb target. + unsigned LocalNVPTXAddressSpace; + if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { + const DIExpression *NewExpr = + DIExpression::extractAddressClass(Expr, LocalNVPTXAddressSpace); + if (NewExpr != Expr) { + Expr = NewExpr; + NVPTXAddressSpace = LocalNVPTXAddressSpace; + } + } DwarfExpr->addFragmentOffset(Expr); + } if (Global) { const MCSymbol *Sym = Asm->getSymbol(Global); @@ -247,6 +273,15 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( DwarfExpr->setMemoryLocationKind(); DwarfExpr->addExpression(Expr); } + if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { + // According to + // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf + // cuda-gdb requires DW_AT_address_class for all variables to be able to + // correctly interpret address space of the variable address. + const unsigned NVPTX_ADDR_global_space = 5; + addUInt(*VariableDIE, dwarf::DW_AT_address_class, dwarf::DW_FORM_data1, + NVPTXAddressSpace ? *NVPTXAddressSpace : NVPTX_ADDR_global_space); + } if (Loc) addBlock(*VariableDIE, dwarf::DW_AT_location, DwarfExpr->finalize()); @@ -262,8 +297,25 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( DD->useAllLinkageNames()) DD->addAccelName(*CUNode, GV->getLinkageName(), *VariableDIE); } +} - return VariableDIE; +DIE *DwarfCompileUnit::getOrCreateCommonBlock( + const DICommonBlock *CB, ArrayRef<GlobalExpr> GlobalExprs) { + // Construct the context before querying for the existence of the DIE in case + // such construction creates the DIE. + DIE *ContextDIE = getOrCreateContextDIE(CB->getScope()); + + if (DIE *NDie = getDIE(CB)) + return NDie; + DIE &NDie = createAndAddDIE(dwarf::DW_TAG_common_block, *ContextDIE, CB); + StringRef Name = CB->getName().empty() ? "_BLNK_" : CB->getName(); + addString(NDie, dwarf::DW_AT_name, Name); + addGlobalName(Name, NDie, CB->getScope()); + if (CB->getFile()) + addSourceLine(NDie, CB->getLineNo(), CB->getFile()); + if (DIGlobalVariable *V = CB->getDecl()) + getCU().addLocationAttribute(&NDie, V, GlobalExprs); + return &NDie; } void DwarfCompileUnit::addRange(RangeSpan Range) { @@ -491,6 +543,8 @@ DIE *DwarfCompileUnit::constructInlinedScopeDIE(LexicalScope *Scope) { addUInt(*ScopeDIE, dwarf::DW_AT_call_file, None, getOrCreateSourceID(IA->getFile())); addUInt(*ScopeDIE, dwarf::DW_AT_call_line, None, IA->getLine()); + if (IA->getColumn()) + addUInt(*ScopeDIE, dwarf::DW_AT_call_column, None, IA->getColumn()); if (IA->getDiscriminator() && DD->getDwarfVersion() >= 4) addUInt(*ScopeDIE, dwarf::DW_AT_GNU_discriminator, None, IA->getDiscriminator()); @@ -555,36 +609,27 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, return VariableDie; } - // Check if variable is described by a DBG_VALUE instruction. - if (const MachineInstr *DVInsn = DV.getMInsn()) { - assert(DVInsn->getNumOperands() == 4); - if (DVInsn->getOperand(0).isReg()) { - auto RegOp = DVInsn->getOperand(0); - auto Op1 = DVInsn->getOperand(1); - // If the second operand is an immediate, this is an indirect value. - assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); - MachineLocation Location(RegOp.getReg(), Op1.isImm()); - addVariableAddress(DV, *VariableDie, Location); - } else if (DVInsn->getOperand(0).isImm()) { - // This variable is described by a single constant. - // Check whether it has a DIExpression. + // Check if variable has a single location description. + if (auto *DVal = DV.getValueLoc()) { + if (DVal->isLocation()) + addVariableAddress(DV, *VariableDie, DVal->getLoc()); + else if (DVal->isInt()) { auto *Expr = DV.getSingleExpression(); if (Expr && Expr->getNumElements()) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); // If there is an expression, emit raw unsigned bytes. DwarfExpr.addFragmentOffset(Expr); - DwarfExpr.addUnsignedConstant(DVInsn->getOperand(0).getImm()); + DwarfExpr.addUnsignedConstant(DVal->getInt()); DwarfExpr.addExpression(Expr); addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); } else - addConstantValue(*VariableDie, DVInsn->getOperand(0), DV.getType()); - } else if (DVInsn->getOperand(0).isFPImm()) - addConstantFPValue(*VariableDie, DVInsn->getOperand(0)); - else if (DVInsn->getOperand(0).isCImm()) - addConstantValue(*VariableDie, DVInsn->getOperand(0).getCImm(), - DV.getType()); - + addConstantValue(*VariableDie, DVal->getInt(), DV.getType()); + } else if (DVal->isConstantFP()) { + addConstantFPValue(*VariableDie, DVal->getConstantFP()); + } else if (DVal->isConstantInt()) { + addConstantValue(*VariableDie, DVal->getConstantInt(), DV.getType()); + } return VariableDie; } @@ -592,6 +637,7 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, if (!DV.hasFrameIndexExprs()) return VariableDie; + Optional<unsigned> NVPTXAddressSpace; DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); for (auto &Fragment : DV.getFrameIndexExprs()) { @@ -603,7 +649,23 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, SmallVector<uint64_t, 8> Ops; Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(Offset); - Ops.append(Expr->elements_begin(), Expr->elements_end()); + // According to + // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf + // cuda-gdb requires DW_AT_address_class for all variables to be able to + // correctly interpret address space of the variable address. + // Decode DW_OP_constu <DWARF Address Space> DW_OP_swap DW_OP_xderef + // sequence for the NVPTX + gdb target. + unsigned LocalNVPTXAddressSpace; + if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { + const DIExpression *NewExpr = + DIExpression::extractAddressClass(Expr, LocalNVPTXAddressSpace); + if (NewExpr != Expr) { + Expr = NewExpr; + NVPTXAddressSpace = LocalNVPTXAddressSpace; + } + } + if (Expr) + Ops.append(Expr->elements_begin(), Expr->elements_end()); DIExpressionCursor Cursor(Ops); DwarfExpr.setMemoryLocationKind(); if (const MCSymbol *FrameSymbol = Asm->getFunctionFrameSymbol()) @@ -613,7 +675,19 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, FrameReg); DwarfExpr.addExpression(std::move(Cursor)); } + if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { + // According to + // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf + // cuda-gdb requires DW_AT_address_class for all variables to be able to + // correctly interpret address space of the variable address. + const unsigned NVPTX_ADDR_local_space = 6; + addUInt(*VariableDie, dwarf::DW_AT_address_class, dwarf::DW_FORM_data1, + NVPTXAddressSpace ? *NVPTXAddressSpace : NVPTX_ADDR_local_space); + } addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); + if (DwarfExpr.TagOffset) + addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, dwarf::DW_FORM_data1, + *DwarfExpr.TagOffset); return VariableDie; } @@ -800,7 +874,7 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE( ContextDIE = &getUnitDie(); getOrCreateSubprogramDIE(SPDecl); } else { - ContextDIE = getOrCreateContextDIE(resolve(SP->getScope())); + ContextDIE = getOrCreateContextDIE(SP->getScope()); // The scope may be shared with a subprogram that has already been // constructed in another CU, in which case we need to construct this // subprogram in the same CU. @@ -849,7 +923,7 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE( DIE *IMDie = DIE::get(DIEValueAllocator, (dwarf::Tag)Module->getTag()); insertDIE(Module, IMDie); DIE *EntityDie; - auto *Entity = resolve(Module->getEntity()); + auto *Entity = Module->getEntity(); if (auto *NS = dyn_cast<DINamespace>(Entity)) EntityDie = getOrCreateNameSpace(NS); else if (auto *M = dyn_cast<DIModule>(Entity)) @@ -958,7 +1032,9 @@ bool DwarfCompileUnit::hasDwarfPubSections() const { return true; case DICompileUnit::DebugNameTableKind::Default: return DD->tuneForGDB() && !includeMinimalInlineScopes() && - !CUNode->isDebugDirectivesOnly(); + !CUNode->isDebugDirectivesOnly() && + DD->getAccelTableKind() != AccelTableKind::Apple && + DD->getDwarfVersion() < 5; } llvm_unreachable("Unhandled DICompileUnit::DebugNameTableKind enum"); } @@ -1054,6 +1130,12 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die, DwarfExpr.setMemoryLocationKind(); DIExpressionCursor Cursor(DIExpr); + + if (DIExpr->isEntryValue()) { + DwarfExpr.setEntryValueFlag(); + DwarfExpr.addEntryValueExpression(Cursor); + } + const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg())) return; @@ -1112,7 +1194,7 @@ void DwarfCompileUnit::addAddressExpr(DIE &Die, dwarf::Attribute Attribute, void DwarfCompileUnit::applySubprogramAttributesToDefinition( const DISubprogram *SP, DIE &SPDie) { auto *SPDecl = SP->getDeclaration(); - auto *Context = resolve(SPDecl ? SPDecl->getScope() : SP->getScope()); + auto *Context = SPDecl ? SPDecl->getScope() : SP->getScope(); applySubprogramAttributes(SP, SPDie, includeMinimalInlineScopes()); addGlobalName(SP->getName(), SPDie, Context); } @@ -1121,6 +1203,10 @@ bool DwarfCompileUnit::isDwoUnit() const { return DD->useSplitDwarf() && Skeleton; } +void DwarfCompileUnit::finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) { + constructTypeDIE(D, CTy); +} + bool DwarfCompileUnit::includeMinimalInlineScopes() const { return getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly || (DD->useSplitDwarf() && !Skeleton); @@ -1134,3 +1220,27 @@ void DwarfCompileUnit::addAddrTableBase() { : dwarf::DW_AT_GNU_addr_base, Label, TLOF.getDwarfAddrSection()->getBeginSymbol()); } + +void DwarfCompileUnit::addBaseTypeRef(DIEValueList &Die, int64_t Idx) { + Die.addValue(DIEValueAllocator, (dwarf::Attribute)0, dwarf::DW_FORM_udata, + new (DIEValueAllocator) DIEBaseTypeRef(this, Idx)); +} + +void DwarfCompileUnit::createBaseTypeDIEs() { + // Insert the base_type DIEs directly after the CU so that their offsets will + // fit in the fixed size ULEB128 used inside the location expressions. + // Maintain order by iterating backwards and inserting to the front of CU + // child list. + for (auto &Btr : reverse(ExprRefedBaseTypes)) { + DIE &Die = getUnitDie().addChildFront( + DIE::get(DIEValueAllocator, dwarf::DW_TAG_base_type)); + SmallString<32> Str; + addString(Die, dwarf::DW_AT_name, + Twine(dwarf::AttributeEncodingString(Btr.Encoding) + + "_" + Twine(Btr.BitSize)).toStringRef(Str)); + addUInt(Die, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, Btr.Encoding); + addUInt(Die, dwarf::DW_AT_byte_size, None, Btr.BitSize / 8); + + Btr.Die = &Die; + } +} diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 9ec22f68c12f..ea980dfda17e 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfCompileUnit.h - Dwarf Compile Unit -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -101,6 +100,8 @@ class DwarfCompileUnit final : public DwarfUnit { return DU->getAbstractEntities(); } + void finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) override; + public: DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU); @@ -125,11 +126,27 @@ public: const DIExpression *Expr; }; + struct BaseTypeRef { + BaseTypeRef(unsigned BitSize, dwarf::TypeKind Encoding) : + BitSize(BitSize), Encoding(Encoding) {} + unsigned BitSize; + dwarf::TypeKind Encoding; + DIE *Die = nullptr; + }; + + std::vector<BaseTypeRef> ExprRefedBaseTypes; + /// Get or create global variable DIE. DIE * getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV, ArrayRef<GlobalExpr> GlobalExprs); + DIE *getOrCreateCommonBlock(const DICommonBlock *CB, + ArrayRef<GlobalExpr> GlobalExprs); + + void addLocationAttribute(DIE *ToDIE, const DIGlobalVariable *GV, + ArrayRef<GlobalExpr> GlobalExprs); + /// addLabelAddress - Add a dwarf label attribute data and value using /// either DW_FORM_addr or DW_FORM_GNU_addr_index. void addLabelAddress(DIE &Die, dwarf::Attribute Attribute, @@ -200,6 +217,8 @@ public: SmallVectorImpl<DIE *> &Children, bool *HasNonScopeChildren = nullptr); + void createBaseTypeDIEs(); + /// Construct a DIE for this subprogram scope. DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope); @@ -314,6 +333,8 @@ public: void setDWOId(uint64_t DwoId) { DWOId = DwoId; } bool hasDwarfPubSections() const; + + void addBaseTypeRef(DIEValueList &Die, int64_t Idx); }; } // end namespace llvm diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 1de2ffb6cfa1..71bb2b0858cc 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfDebug.cpp - Dwarf Debug Framework ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -42,6 +41,8 @@ #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" @@ -162,6 +163,7 @@ static const char *const DWARFGroupName = "dwarf"; static const char *const DWARFGroupDescription = "DWARF Emission"; static const char *const DbgTimerName = "writer"; static const char *const DbgTimerDescription = "DWARF Debug Writer"; +static constexpr unsigned ULEB128PadSize = 4; void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) { BS.EmitInt8( @@ -177,6 +179,15 @@ void DebugLocDwarfExpression::emitUnsigned(uint64_t Value) { BS.EmitULEB128(Value, Twine(Value)); } +void DebugLocDwarfExpression::emitData1(uint8_t Value) { + BS.EmitInt8(Value, Twine(Value)); +} + +void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) { + assert(Idx < (1ULL << (ULEB128PadSize * 7)) && "Idx wont fit"); + BS.EmitULEB128(Idx, Twine(Idx), ULEB128PadSize); +} + bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) { // This information is not available while emitting .debug_loc entries. @@ -185,11 +196,11 @@ bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, bool DbgVariable::isBlockByrefVariable() const { assert(getVariable() && "Invalid complex DbgVariable!"); - return getVariable()->getType().resolve()->isBlockByrefStruct(); + return getVariable()->getType()->isBlockByrefStruct(); } const DIType *DbgVariable::getType() const { - DIType *Ty = getVariable()->getType().resolve(); + DIType *Ty = getVariable()->getType(); // FIXME: isBlockByrefVariable should be reformulated in terms of complex // addresses instead. if (Ty->isBlockByrefStruct()) { @@ -221,18 +232,55 @@ const DIType *DbgVariable::getType() const { uint16_t tag = Ty->getTag(); if (tag == dwarf::DW_TAG_pointer_type) - subType = resolve(cast<DIDerivedType>(Ty)->getBaseType()); + subType = cast<DIDerivedType>(Ty)->getBaseType(); auto Elements = cast<DICompositeType>(subType)->getElements(); for (unsigned i = 0, N = Elements.size(); i < N; ++i) { auto *DT = cast<DIDerivedType>(Elements[i]); if (getName() == DT->getName()) - return resolve(DT->getBaseType()); + return DT->getBaseType(); } } return Ty; } +/// Get .debug_loc entry for the instruction range starting at MI. +static DbgValueLoc getDebugLocValue(const MachineInstr *MI) { + const DIExpression *Expr = MI->getDebugExpression(); + assert(MI->getNumOperands() == 4); + if (MI->getOperand(0).isReg()) { + auto RegOp = MI->getOperand(0); + auto Op1 = MI->getOperand(1); + // If the second operand is an immediate, this is a + // register-indirect address. + assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); + MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); + return DbgValueLoc(Expr, MLoc); + } + if (MI->getOperand(0).isImm()) + return DbgValueLoc(Expr, MI->getOperand(0).getImm()); + if (MI->getOperand(0).isFPImm()) + return DbgValueLoc(Expr, MI->getOperand(0).getFPImm()); + if (MI->getOperand(0).isCImm()) + return DbgValueLoc(Expr, MI->getOperand(0).getCImm()); + + llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); +} + +void DbgVariable::initializeDbgValue(const MachineInstr *DbgValue) { + assert(FrameIndexExprs.empty() && "Already initialized?"); + assert(!ValueLoc.get() && "Already initialized?"); + + assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); + assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && + "Wrong inlined-at"); + + ValueLoc = llvm::make_unique<DbgValueLoc>(getDebugLocValue(DbgValue)); + if (auto *E = DbgValue->getDebugExpression()) + if (E->getNumElements()) + FrameIndexExprs.push_back({0, E}); +} + ArrayRef<DbgVariable::FrameIndexExpr> DbgVariable::getFrameIndexExprs() const { if (FrameIndexExprs.size() == 1) return FrameIndexExprs; @@ -252,8 +300,8 @@ ArrayRef<DbgVariable::FrameIndexExpr> DbgVariable::getFrameIndexExprs() const { } void DbgVariable::addMMIEntry(const DbgVariable &V) { - assert(DebugLocListIndex == ~0U && !MInsn && "not an MMI entry"); - assert(V.DebugLocListIndex == ~0U && !V.MInsn && "not an MMI entry"); + assert(DebugLocListIndex == ~0U && !ValueLoc.get() && "not an MMI entry"); + assert(V.DebugLocListIndex == ~0U && !V.ValueLoc.get() && "not an MMI entry"); assert(V.getVariable() == getVariable() && "conflicting variable"); assert(V.getInlinedAt() == getInlinedAt() && "conflicting inlined-at location"); @@ -315,7 +363,7 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) IsDarwin(A->TM.getTargetTriple().isOSDarwin()) { const Triple &TT = Asm->TM.getTargetTriple(); - // Make sure we know our "debugger tuning." The target option takes + // Make sure we know our "debugger tuning". The target option takes // precedence; fall back to triple-based defaults. if (Asm->TM.Options.DebuggerTuning != DebuggerKind::Default) DebuggerTuning = Asm->TM.Options.DebuggerTuning; @@ -658,6 +706,11 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) { NewCU.setSection(Asm->getObjFileLowering().getDwarfInfoSection()); } + // Create DIEs for function declarations used for call site debug info. + for (auto Scope : DIUnit->getRetainedTypes()) + if (auto *SP = dyn_cast_or_null<DISubprogram>(Scope)) + NewCU.getOrCreateSubprogramDIE(SP); + CUMap.insert({DIUnit, &NewCU}); CUDieMap.insert({&NewCU.getUnitDie(), &NewCU}); return NewCU; @@ -890,13 +943,6 @@ void DwarfDebug::finalizeModuleInfo() { // ranges for all subprogram DIEs for mach-o. DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; - // We don't keep track of which addresses are used in which CU so this - // is a bit pessimistic under LTO. - if (!AddrPool.isEmpty() && - (getDwarfVersion() >= 5 || - (SkCU && !empty(TheCU.getUnitDie().children())))) - U.addAddrTableBase(); - if (unsigned NumRanges = TheCU.getRanges().size()) { if (NumRanges > 1 && useRangesSection()) // A DW_AT_low_pc attribute may also be specified in combination with @@ -909,6 +955,13 @@ void DwarfDebug::finalizeModuleInfo() { U.attachRangesOrLowHighPC(U.getUnitDie(), TheCU.takeRanges()); } + // We don't keep track of which addresses are used in which CU so this + // is a bit pessimistic under LTO. + if (!AddrPool.isEmpty() && + (getDwarfVersion() >= 5 || + (SkCU && !empty(TheCU.getUnitDie().children())))) + U.addAddrTableBase(); + if (getDwarfVersion() >= 5) { if (U.hasRangeLists()) U.addRnglistsBase(); @@ -941,6 +994,11 @@ void DwarfDebug::endModule() { assert(CurFn == nullptr); assert(CurMI == nullptr); + for (const auto &P : CUMap) { + auto &CU = *P.second; + CU.createBaseTypeDIEs(); + } + // If we aren't actually generating debug info (check beginModule - // conditionalized on !DisableDebugInfoPrinting and the presence of the // llvm.dbg.cu metadata node) @@ -1059,161 +1117,177 @@ void DwarfDebug::collectVariableInfoFromMFTable( } } -// Get .debug_loc entry for the instruction range starting at MI. -static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { - const DIExpression *Expr = MI->getDebugExpression(); - assert(MI->getNumOperands() == 4); - if (MI->getOperand(0).isReg()) { - auto RegOp = MI->getOperand(0); - auto Op1 = MI->getOperand(1); - // If the second operand is an immediate, this is a - // register-indirect address. - assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); - MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); - return DebugLocEntry::Value(Expr, MLoc); - } - if (MI->getOperand(0).isImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getImm()); - if (MI->getOperand(0).isFPImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getFPImm()); - if (MI->getOperand(0).isCImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getCImm()); - - llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); -} +/// Determine whether a *singular* DBG_VALUE is valid for the entirety of its +/// enclosing lexical scope. The check ensures there are no other instructions +/// in the same lexical scope preceding the DBG_VALUE and that its range is +/// either open or otherwise rolls off the end of the scope. +static bool validThroughout(LexicalScopes &LScopes, + const MachineInstr *DbgValue, + const MachineInstr *RangeEnd) { + assert(DbgValue->getDebugLoc() && "DBG_VALUE without a debug location"); + auto MBB = DbgValue->getParent(); + auto DL = DbgValue->getDebugLoc(); + auto *LScope = LScopes.findLexicalScope(DL); + // Scope doesn't exist; this is a dead DBG_VALUE. + if (!LScope) + return false; + auto &LSRange = LScope->getRanges(); + if (LSRange.size() == 0) + return false; -/// 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. -bool DebugLocEntry::MergeValues(const DebugLocEntry &Next) { - if (Begin == Next.Begin) { - auto *FirstExpr = cast<DIExpression>(Values[0].Expression); - auto *FirstNextExpr = cast<DIExpression>(Next.Values[0].Expression); - if (!FirstExpr->isFragment() || !FirstNextExpr->isFragment()) + // Determine if the DBG_VALUE is valid at the beginning of its lexical block. + const MachineInstr *LScopeBegin = LSRange.front().first; + // Early exit if the lexical scope begins outside of the current block. + if (LScopeBegin->getParent() != MBB) + return false; + MachineBasicBlock::const_reverse_iterator Pred(DbgValue); + for (++Pred; Pred != MBB->rend(); ++Pred) { + if (Pred->getFlag(MachineInstr::FrameSetup)) + break; + auto PredDL = Pred->getDebugLoc(); + if (!PredDL || Pred->isMetaInstruction()) + continue; + // Check whether the instruction preceding the DBG_VALUE is in the same + // (sub)scope as the DBG_VALUE. + if (DL->getScope() == PredDL->getScope()) + return false; + auto *PredScope = LScopes.findLexicalScope(PredDL); + if (!PredScope || LScope->dominates(PredScope)) return false; + } - // We can only merge entries if none of the fragments overlap any others. - // In doing so, we can take advantage of the fact that both lists are - // sorted. - for (unsigned i = 0, j = 0; i < Values.size(); ++i) { - for (; j < Next.Values.size(); ++j) { - 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; - // Values[i] is entirely before Next.Values[j], - // so go back to the next entry of Values. - else if (res == -1) - break; - // Next.Values[j] is entirely before Values[i], so go on to the - // next entry of Next.Values. - } - } + // If the range of the DBG_VALUE is open-ended, report success. + if (!RangeEnd) + return true; - addValues(Next.Values); - End = Next.End; + // Fail if there are instructions belonging to our scope in another block. + const MachineInstr *LScopeEnd = LSRange.back().second; + if (LScopeEnd->getParent() != MBB) + return false; + + // Single, constant DBG_VALUEs in the prologue are promoted to be live + // throughout the function. This is a hack, presumably for DWARF v2 and not + // necessarily correct. It would be much better to use a dbg.declare instead + // if we know the constant is live throughout the scope. + if (DbgValue->getOperand(0).isImm() && MBB->pred_empty()) return true; - } + return false; } /// Build the location list for all DBG_VALUEs in the function that -/// describe the same variable. If the ranges of several independent -/// fragments of the same variable overlap partially, split them up and -/// combine the ranges. The resulting DebugLocEntries are will have +/// describe the same variable. The resulting DebugLocEntries will have /// strict monotonically increasing begin addresses and will never -/// overlap. +/// overlap. If the resulting list has only one entry that is valid +/// throughout variable's scope return true. +// +// See the definition of DbgValueHistoryMap::Entry for an explanation of the +// different kinds of history map entries. One thing to be aware of is that if +// a debug value is ended by another entry (rather than being valid until the +// end of the function), that entry's instruction may or may not be included in +// the range, depending on if the entry is a clobbering entry (it has an +// instruction that clobbers one or more preceding locations), or if it is an +// (overlapping) debug value entry. This distinction can be seen in the example +// below. The first debug value is ended by the clobbering entry 2, and the +// second and third debug values are ended by the overlapping debug value entry +// 4. // // Input: // -// Ranges History [var, loc, fragment ofs size] -// 0 | [x, (reg0, fragment 0, 32)] -// 1 | | [x, (reg1, fragment 32, 32)] <- IsFragmentOfPrevEntry -// 2 | | ... -// 3 | [clobber reg0] -// 4 [x, (mem, fragment 0, 64)] <- overlapping with both previous fragments of -// x. +// History map entries [type, end index, mi] // -// Output: +// 0 | [DbgValue, 2, DBG_VALUE $reg0, [...] (fragment 0, 32)] +// 1 | | [DbgValue, 4, DBG_VALUE $reg1, [...] (fragment 32, 32)] +// 2 | | [Clobber, $reg0 = [...], -, -] +// 3 | | [DbgValue, 4, DBG_VALUE 123, [...] (fragment 64, 32)] +// 4 [DbgValue, ~0, DBG_VALUE @g, [...] (fragment 0, 96)] // -// [0-1] [x, (reg0, fragment 0, 32)] -// [1-3] [x, (reg0, fragment 0, 32), (reg1, fragment 32, 32)] -// [3-4] [x, (reg1, fragment 32, 32)] -// [4- ] [x, (mem, fragment 0, 64)] -void -DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, - const DbgValueHistoryMap::InstrRanges &Ranges) { - SmallVector<DebugLocEntry::Value, 4> OpenRanges; - - for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - const MachineInstr *Begin = I->first; - const MachineInstr *End = I->second; - assert(Begin->isDebugValue() && "Invalid History entry"); - - // Check if a variable is inaccessible in this range. - if (Begin->getNumOperands() > 1 && - Begin->getOperand(0).isReg() && !Begin->getOperand(0).getReg()) { - OpenRanges.clear(); - continue; - } - - // If this fragment overlaps with any open ranges, truncate them. - const DIExpression *DIExpr = Begin->getDebugExpression(); - auto Last = remove_if(OpenRanges, [&](DebugLocEntry::Value R) { - return DIExpr->fragmentsOverlap(R.getExpression()); - }); +// Output [start, end) [Value...]: +// +// [0-1) [(reg0, fragment 0, 32)] +// [1-3) [(reg0, fragment 0, 32), (reg1, fragment 32, 32)] +// [3-4) [(reg1, fragment 32, 32), (123, fragment 64, 32)] +// [4-) [(@g, fragment 0, 96)] +bool DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, + const DbgValueHistoryMap::Entries &Entries) { + using OpenRange = + std::pair<DbgValueHistoryMap::EntryIndex, DbgValueLoc>; + SmallVector<OpenRange, 4> OpenRanges; + bool isSafeForSingleLocation = true; + const MachineInstr *StartDebugMI = nullptr; + const MachineInstr *EndMI = nullptr; + + for (auto EB = Entries.begin(), EI = EB, EE = Entries.end(); EI != EE; ++EI) { + const MachineInstr *Instr = EI->getInstr(); + + // Remove all values that are no longer live. + size_t Index = std::distance(EB, EI); + auto Last = + remove_if(OpenRanges, [&](OpenRange &R) { return R.first <= Index; }); OpenRanges.erase(Last, OpenRanges.end()); - const MCSymbol *StartLabel = getLabelBeforeInsn(Begin); - assert(StartLabel && "Forgot label before DBG_VALUE starting a range!"); + // If we are dealing with a clobbering entry, this iteration will result in + // a location list entry starting after the clobbering instruction. + const MCSymbol *StartLabel = + EI->isClobber() ? getLabelAfterInsn(Instr) : getLabelBeforeInsn(Instr); + assert(StartLabel && + "Forgot label before/after instruction starting a range!"); const MCSymbol *EndLabel; - if (End != nullptr) - EndLabel = getLabelAfterInsn(End); - else if (std::next(I) == Ranges.end()) + if (std::next(EI) == Entries.end()) { EndLabel = Asm->getFunctionEnd(); + if (EI->isClobber()) + EndMI = EI->getInstr(); + } + else if (std::next(EI)->isClobber()) + EndLabel = getLabelAfterInsn(std::next(EI)->getInstr()); else - EndLabel = getLabelBeforeInsn(std::next(I)->first); + EndLabel = getLabelBeforeInsn(std::next(EI)->getInstr()); assert(EndLabel && "Forgot label after instruction ending a range!"); - LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n"); + if (EI->isDbgValue()) + LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Instr << "\n"); + + // If this history map entry has a debug value, add that to the list of + // open ranges and check if its location is valid for a single value + // location. + if (EI->isDbgValue()) { + // Do not add undef debug values, as they are redundant information in + // the location list entries. An undef debug results in an empty location + // description. If there are any non-undef fragments then padding pieces + // with empty location descriptions will automatically be inserted, and if + // all fragments are undef then the whole location list entry is + // redundant. + if (!Instr->isUndefDebugValue()) { + auto Value = getDebugLocValue(Instr); + OpenRanges.emplace_back(EI->getEndIndex(), Value); + + // TODO: Add support for single value fragment locations. + if (Instr->getDebugExpression()->isFragment()) + isSafeForSingleLocation = false; + + if (!StartDebugMI) + StartDebugMI = Instr; + } else { + isSafeForSingleLocation = false; + } + } - auto Value = getDebugLocValue(Begin); + // Location list entries with empty location descriptions are redundant + // information in DWARF, so do not emit those. + if (OpenRanges.empty()) + continue; // Omit entries with empty ranges as they do not have any effect in DWARF. if (StartLabel == EndLabel) { - // If this is a fragment, we must still add the value to the list of - // open ranges, since it may describe non-overlapping parts of the - // variable. - if (DIExpr->isFragment()) - OpenRanges.push_back(Value); LLVM_DEBUG(dbgs() << "Omitting location list entry with empty range.\n"); continue; } - DebugLocEntry Loc(StartLabel, EndLabel, Value); - bool couldMerge = false; - - // If this is a fragment, it may belong to the current DebugLocEntry. - if (DIExpr->isFragment()) { - // Add this value to the list of open ranges. - OpenRanges.push_back(Value); - - // Attempt to add the fragment to the last entry. - if (!DebugLoc.empty()) - if (DebugLoc.back().MergeValues(Loc)) - couldMerge = true; - } - - if (!couldMerge) { - // Need to add a new DebugLocEntry. Add all values from still - // valid non-overlapping fragments. - if (OpenRanges.size()) - Loc.addValues(OpenRanges); - - DebugLoc.push_back(std::move(Loc)); - } + SmallVector<DbgValueLoc, 4> Values; + for (auto &R : OpenRanges) + Values.push_back(R.second); + DebugLoc.emplace_back(StartLabel, EndLabel, Values); // Attempt to coalesce the ranges of two otherwise identical // DebugLocEntries. @@ -1229,6 +1303,9 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, if (PrevEntry != DebugLoc.rend() && PrevEntry->MergeRanges(*CurEntry)) DebugLoc.pop_back(); } + + return DebugLoc.size() == 1 && isSafeForSingleLocation && + validThroughout(LScopes, StartDebugMI, EndMI); } DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU, @@ -1253,64 +1330,6 @@ DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU, return ConcreteEntities.back().get(); } -/// Determine whether a *singular* DBG_VALUE is valid for the entirety of its -/// enclosing lexical scope. The check ensures there are no other instructions -/// in the same lexical scope preceding the DBG_VALUE and that its range is -/// either open or otherwise rolls off the end of the scope. -static bool validThroughout(LexicalScopes &LScopes, - const MachineInstr *DbgValue, - const MachineInstr *RangeEnd) { - assert(DbgValue->getDebugLoc() && "DBG_VALUE without a debug location"); - auto MBB = DbgValue->getParent(); - auto DL = DbgValue->getDebugLoc(); - auto *LScope = LScopes.findLexicalScope(DL); - // Scope doesn't exist; this is a dead DBG_VALUE. - if (!LScope) - return false; - auto &LSRange = LScope->getRanges(); - if (LSRange.size() == 0) - return false; - - // Determine if the DBG_VALUE is valid at the beginning of its lexical block. - const MachineInstr *LScopeBegin = LSRange.front().first; - // Early exit if the lexical scope begins outside of the current block. - if (LScopeBegin->getParent() != MBB) - return false; - MachineBasicBlock::const_reverse_iterator Pred(DbgValue); - for (++Pred; Pred != MBB->rend(); ++Pred) { - if (Pred->getFlag(MachineInstr::FrameSetup)) - break; - auto PredDL = Pred->getDebugLoc(); - if (!PredDL || Pred->isMetaInstruction()) - continue; - // Check whether the instruction preceding the DBG_VALUE is in the same - // (sub)scope as the DBG_VALUE. - if (DL->getScope() == PredDL->getScope()) - return false; - auto *PredScope = LScopes.findLexicalScope(PredDL); - if (!PredScope || LScope->dominates(PredScope)) - return false; - } - - // If the range of the DBG_VALUE is open-ended, report success. - if (!RangeEnd) - return true; - - // Fail if there are instructions belonging to our scope in another block. - const MachineInstr *LScopeEnd = LSRange.back().second; - if (LScopeEnd->getParent() != MBB) - return false; - - // Single, constant DBG_VALUEs in the prologue are promoted to be live - // throughout the function. This is a hack, presumably for DWARF v2 and not - // necessarily correct. It would be much better to use a dbg.declare instead - // if we know the constant is live throughout the scope. - if (DbgValue->getOperand(0).isImm() && MBB->pred_empty()) - return true; - - return false; -} - // Find variables for each lexical scope. void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, @@ -1324,8 +1343,8 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, continue; // Instruction ranges, specifying where IV is accessible. - const auto &Ranges = I.second; - if (Ranges.empty()) + const auto &HistoryMapEntries = I.second; + if (HistoryMapEntries.empty()) continue; LexicalScope *Scope = nullptr; @@ -1342,15 +1361,24 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, DbgVariable *RegVar = cast<DbgVariable>(createConcreteEntity(TheCU, *Scope, LocalVar, IV.second)); - const MachineInstr *MInsn = Ranges.front().first; + const MachineInstr *MInsn = HistoryMapEntries.front().getInstr(); assert(MInsn->isDebugValue() && "History must begin with debug value"); // Check if there is a single DBG_VALUE, valid throughout the var's scope. - if (Ranges.size() == 1 && - validThroughout(LScopes, MInsn, Ranges.front().second)) { - RegVar->initializeDbgValue(MInsn); - continue; + // If the history map contains a single debug value, there may be an + // additional entry which clobbers the debug value. + size_t HistSize = HistoryMapEntries.size(); + bool SingleValueWithClobber = + HistSize == 2 && HistoryMapEntries[1].isClobber(); + if (HistSize == 1 || SingleValueWithClobber) { + const auto *End = + SingleValueWithClobber ? HistoryMapEntries[1].getInstr() : nullptr; + if (validThroughout(LScopes, MInsn, End)) { + RegVar->initializeDbgValue(MInsn); + continue; + } } + // Do not emit location lists if .debug_loc secton is disabled. if (!useLocSection()) continue; @@ -1360,7 +1388,15 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, // Build the location list for this variable. SmallVector<DebugLocEntry, 8> Entries; - buildLocationList(Entries, Ranges); + bool isValidSingleLocation = buildLocationList(Entries, HistoryMapEntries); + + // Check whether buildLocationList managed to merge all locations to one + // that is valid throughout the variable's scope. If so, produce single + // value location. + if (isValidSingleLocation) { + RegVar->initializeDbgValue(Entries[0].getValues()[0]); + continue; + } // If the variable has a DIBasicType, extract it. Basic types cannot have // unique identifiers, so don't bother resolving the type with the @@ -1370,7 +1406,7 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, // Finalize the entry by lowering it into a DWARF bytestream. for (auto &Entry : Entries) - Entry.finalize(*Asm, List, BT); + Entry.finalize(*Asm, List, BT, TheCU); } // For each InlinedEntity collected from DBG_LABEL instructions, convert to @@ -1489,7 +1525,7 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { // We have an explicit location, different from the previous location. // Don't repeat a line-0 record, but otherwise emit the new location. // (The new location might be an explicit line 0, which we do emit.) - if (PrevInstLoc && DL.getLine() == 0 && LastAsmLine == 0) + if (DL.getLine() == 0 && LastAsmLine == 0) return; unsigned Flags = 0; if (DL == PrologEndLoc) { @@ -1521,6 +1557,46 @@ static DebugLoc findPrologueEndLoc(const MachineFunction *MF) { return DebugLoc(); } +/// Register a source line with debug info. Returns the unique label that was +/// emitted and which provides correspondence to the source line list. +static void recordSourceLine(AsmPrinter &Asm, unsigned Line, unsigned Col, + const MDNode *S, unsigned Flags, unsigned CUID, + uint16_t DwarfVersion, + ArrayRef<std::unique_ptr<DwarfCompileUnit>> DCUs) { + StringRef Fn; + unsigned FileNo = 1; + unsigned Discriminator = 0; + if (auto *Scope = cast_or_null<DIScope>(S)) { + Fn = Scope->getFilename(); + if (Line != 0 && DwarfVersion >= 4) + if (auto *LBF = dyn_cast<DILexicalBlockFile>(Scope)) + Discriminator = LBF->getDiscriminator(); + + FileNo = static_cast<DwarfCompileUnit &>(*DCUs[CUID]) + .getOrCreateSourceID(Scope->getFile()); + } + Asm.OutStreamer->EmitDwarfLocDirective(FileNo, Line, Col, Flags, 0, + Discriminator, Fn); +} + +DebugLoc DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, + unsigned CUID) { + // Get beginning of function. + if (DebugLoc PrologEndLoc = findPrologueEndLoc(&MF)) { + // Ensure the compile unit is created if the function is called before + // beginFunction(). + (void)getOrCreateDwarfCompileUnit( + MF.getFunction().getSubprogram()->getUnit()); + // We'd like to list the prologue as "not statements" but GDB behaves + // poorly if we do that. Revisit this with caution/GDB (7.5+) testing. + const DISubprogram *SP = PrologEndLoc->getInlinedAtScope()->getSubprogram(); + ::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT, + CUID, getDwarfVersion(), getUnits()); + return PrologEndLoc; + } + return DebugLoc(); +} + // Gather pre-function debug information. Assumes being called immediately // after the function entry point has been emitted. void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) { @@ -1543,13 +1619,8 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) { Asm->OutStreamer->getContext().setDwarfCompileUnitID(CU.getUniqueID()); // Record beginning of function. - PrologEndLoc = findPrologueEndLoc(MF); - if (PrologEndLoc) { - // We'd like to list the prologue as "not statements" but GDB behaves - // poorly if we do that. Revisit this with caution/GDB (7.5+) testing. - auto *SP = PrologEndLoc->getInlinedAtScope()->getSubprogram(); - recordSourceLine(SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT); - } + PrologEndLoc = emitInitialLocDirective( + *MF, Asm->OutStreamer->getContext().getDwarfCompileUnitID()); } void DwarfDebug::skippedNonDebugFunction() { @@ -1647,21 +1718,9 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) { // emitted and which provides correspondence to the source line list. void DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, const MDNode *S, unsigned Flags) { - StringRef Fn; - unsigned FileNo = 1; - unsigned Discriminator = 0; - if (auto *Scope = cast_or_null<DIScope>(S)) { - Fn = Scope->getFilename(); - if (Line != 0 && getDwarfVersion() >= 4) - if (auto *LBF = dyn_cast<DILexicalBlockFile>(Scope)) - Discriminator = LBF->getDiscriminator(); - - unsigned CUID = Asm->OutStreamer->getContext().getDwarfCompileUnitID(); - FileNo = static_cast<DwarfCompileUnit &>(*InfoHolder.getUnits()[CUID]) - .getOrCreateSourceID(Scope->getFile()); - } - Asm->OutStreamer->EmitDwarfLocDirective(FileNo, Line, Col, Flags, 0, - Discriminator, Fn); + ::recordSourceLine(*Asm, Line, Col, S, Flags, + Asm->OutStreamer->getContext().getDwarfCompileUnitID(), + getDwarfVersion(), getUnits()); } //===----------------------------------------------------------------------===// @@ -1890,17 +1949,59 @@ void DwarfDebug::emitDebugStr() { } void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, - const DebugLocStream::Entry &Entry) { + const DebugLocStream::Entry &Entry, + const DwarfCompileUnit *CU) { auto &&Comments = DebugLocs.getComments(Entry); auto Comment = Comments.begin(); auto End = Comments.end(); - for (uint8_t Byte : DebugLocs.getBytes(Entry)) - Streamer.EmitInt8(Byte, Comment != End ? *(Comment++) : ""); + + // The expressions are inserted into a byte stream rather early (see + // DwarfExpression::addExpression) so for those ops (e.g. DW_OP_convert) that + // need to reference a base_type DIE the offset of that DIE is not yet known. + // To deal with this we instead insert a placeholder early and then extract + // it here and replace it with the real reference. + unsigned PtrSize = Asm->MAI->getCodePointerSize(); + DWARFDataExtractor Data(StringRef(DebugLocs.getBytes(Entry).data(), + DebugLocs.getBytes(Entry).size()), + Asm->getDataLayout().isLittleEndian(), PtrSize); + DWARFExpression Expr(Data, getDwarfVersion(), PtrSize); + + using Encoding = DWARFExpression::Operation::Encoding; + uint32_t Offset = 0; + for (auto &Op : Expr) { + assert(Op.getCode() != dwarf::DW_OP_const_type && + "3 operand ops not yet supported"); + Streamer.EmitInt8(Op.getCode(), Comment != End ? *(Comment++) : ""); + Offset++; + for (unsigned I = 0; I < 2; ++I) { + if (Op.getDescription().Op[I] == Encoding::SizeNA) + continue; + if (Op.getDescription().Op[I] == Encoding::BaseTypeRef) { + if (CU) { + uint64_t Offset = CU->ExprRefedBaseTypes[Op.getRawOperand(I)].Die->getOffset(); + assert(Offset < (1ULL << (ULEB128PadSize * 7)) && "Offset wont fit"); + Asm->EmitULEB128(Offset, nullptr, ULEB128PadSize); + } else { + // Emit a reference to the 'generic type'. + Asm->EmitULEB128(0, nullptr, ULEB128PadSize); + } + // Make sure comments stay aligned. + for (unsigned J = 0; J < ULEB128PadSize; ++J) + if (Comment != End) + Comment++; + } else { + for (uint32_t J = Offset; J < Op.getOperandEndOffset(I); ++J) + Streamer.EmitInt8(Data.getData()[J], Comment != End ? *(Comment++) : ""); + } + Offset = Op.getOperandEndOffset(I); + } + assert(Offset == Op.getEndOffset()); + } } -static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, - const DebugLocEntry::Value &Value, - DwarfExpression &DwarfExpr) { +void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, + const DbgValueLoc &Value, + DwarfExpression &DwarfExpr) { auto *DIExpr = Value.getExpression(); DIExpressionCursor ExprCursor(DIExpr); DwarfExpr.addFragmentOffset(DIExpr); @@ -1916,6 +2017,12 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, if (Location.isIndirect()) DwarfExpr.setMemoryLocationKind(); DIExpressionCursor Cursor(DIExpr); + + if (DIExpr->isEntryValue()) { + DwarfExpr.setEntryValueFlag(); + DwarfExpr.addEntryValueExpression(Cursor); + } + const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo(); if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg())) return; @@ -1929,38 +2036,50 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, void DebugLocEntry::finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List, - const DIBasicType *BT) { + const DIBasicType *BT, + DwarfCompileUnit &TheCU) { + assert(!Values.empty() && + "location list entries without values are redundant"); assert(Begin != End && "unexpected location list entry with empty range"); DebugLocStream::EntryBuilder Entry(List, Begin, End); BufferByteStreamer Streamer = Entry.getStreamer(); - DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer); - const DebugLocEntry::Value &Value = Values[0]; + DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer, TheCU); + const DbgValueLoc &Value = Values[0]; if (Value.isFragment()) { // Emit all fragments that belong to the same variable and range. - assert(llvm::all_of(Values, [](DebugLocEntry::Value P) { + assert(llvm::all_of(Values, [](DbgValueLoc P) { return P.isFragment(); }) && "all values are expected to be fragments"); assert(std::is_sorted(Values.begin(), Values.end()) && "fragments are expected to be sorted"); for (auto Fragment : Values) - emitDebugLocValue(AP, BT, Fragment, DwarfExpr); + DwarfDebug::emitDebugLocValue(AP, BT, Fragment, DwarfExpr); } else { assert(Values.size() == 1 && "only fragments may have >1 value"); - emitDebugLocValue(AP, BT, Value, DwarfExpr); + DwarfDebug::emitDebugLocValue(AP, BT, Value, DwarfExpr); } DwarfExpr.finalize(); } -void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) { +void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry, + const DwarfCompileUnit *CU) { // Emit the size. Asm->OutStreamer->AddComment("Loc expr size"); - Asm->emitInt16(DebugLocs.getBytes(Entry).size()); - + if (getDwarfVersion() >= 5) + Asm->EmitULEB128(DebugLocs.getBytes(Entry).size()); + else if (DebugLocs.getBytes(Entry).size() <= std::numeric_limits<uint16_t>::max()) + Asm->emitInt16(DebugLocs.getBytes(Entry).size()); + else { + // The entry is too big to fit into 16 bit, drop it as there is nothing we + // can do. + Asm->emitInt16(0); + return; + } // Emit the entry. APByteStreamer Streamer(*Asm); - emitDebugLocEntry(Streamer, Entry); + emitDebugLocEntry(Streamer, Entry, CU); } // Emit the common part of the DWARF 5 range/locations list tables header. @@ -2060,7 +2179,7 @@ void DwarfDebug::emitDebugLoc() { Asm->EmitLabelDifference(Entry.EndSym, Base, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(Entry, CU); continue; } @@ -2081,7 +2200,7 @@ void DwarfDebug::emitDebugLoc() { Asm->OutStreamer->EmitSymbolValue(Entry.EndSym, Size); } - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(Entry, CU); } if (IsLocLists) { @@ -2100,9 +2219,9 @@ void DwarfDebug::emitDebugLoc() { } void DwarfDebug::emitDebugLocDWO() { - Asm->OutStreamer->SwitchSection( - Asm->getObjFileLowering().getDwarfLocDWOSection()); for (const auto &List : DebugLocs.getLists()) { + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfLocDWOSection()); Asm->OutStreamer->EmitLabel(List.Label); for (const auto &Entry : DebugLocs.getEntries(List)) { // GDB only supports startx_length in pre-standard split-DWARF. @@ -2117,7 +2236,7 @@ void DwarfDebug::emitDebugLocDWO() { Asm->EmitULEB128(idx); Asm->EmitLabelDifference(Entry.EndSym, Entry.BeginSym, 4); - emitDebugLocEntryLocation(Entry); + emitDebugLocEntryLocation(Entry, List.CU); } Asm->emitInt8(dwarf::DW_LLE_end_of_list); } @@ -2170,19 +2289,18 @@ void DwarfDebug::emitDebugARanges() { } // Sort the symbols by offset within the section. - 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; - - // Symbols with no order assigned should be placed at the end. - // (e.g. section end labels) - if (IA == 0) - return false; - if (IB == 0) - return true; - return IA < IB; - }); + llvm::stable_sort(List, [&](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; + + // Symbols with no order assigned should be placed at the end. + // (e.g. section end labels) + if (IA == 0) + return false; + if (IB == 0) + return true; + return IA < IB; + }); // Insert a final terminator. List.push_back(SymbolCU(nullptr, Asm->OutStreamer->endSection(Section))); @@ -2687,6 +2805,22 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, CU.addDIETypeSignature(RefDie, Signature); } +DwarfDebug::NonTypeUnitContext::NonTypeUnitContext(DwarfDebug *DD) + : DD(DD), + TypeUnitsUnderConstruction(std::move(DD->TypeUnitsUnderConstruction)) { + DD->TypeUnitsUnderConstruction.clear(); + assert(TypeUnitsUnderConstruction.empty() || !DD->AddrPool.hasBeenUsed()); +} + +DwarfDebug::NonTypeUnitContext::~NonTypeUnitContext() { + DD->TypeUnitsUnderConstruction = std::move(TypeUnitsUnderConstruction); + DD->AddrPool.resetUsedFlag(); +} + +DwarfDebug::NonTypeUnitContext DwarfDebug::enterNonTypeUnitContext() { + return NonTypeUnitContext(this); +} + // 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 @@ -2699,7 +2833,7 @@ void DwarfDebug::addAccelNameImpl(const DICompileUnit &CU, return; if (getAccelTableKind() != AccelTableKind::Apple && - CU.getNameTableKind() == DICompileUnit::DebugNameTableKind::None) + CU.getNameTableKind() != DICompileUnit::DebugNameTableKind::Default) return; DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 8a31e989b289..3ac474e2bdda 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfDebug.h - Dwarf Debug Framework --------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -16,6 +15,7 @@ #include "AddressPool.h" #include "DebugLocStream.h" +#include "DebugLocEntry.h" #include "DwarfFile.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -52,6 +52,7 @@ class ByteStreamer; class DebugLocEntry; class DIE; class DwarfCompileUnit; +class DwarfExpression; class DwarfTypeUnit; class DwarfUnit; class LexicalScope; @@ -111,12 +112,14 @@ public: /// /// Variables can be created from \c DBG_VALUE instructions. Those whose /// location changes over time use \a DebugLocListIndex, while those with a -/// single instruction use \a MInsn and (optionally) a single entry of \a Expr. +/// single location use \a ValueLoc and (optionally) a single entry of \a Expr. /// /// Variables that have been optimized out use none of these fields. class DbgVariable : public DbgEntity { - unsigned DebugLocListIndex = ~0u; /// Offset in DebugLocs. - const MachineInstr *MInsn = nullptr; /// DBG_VALUE instruction. + /// Offset in DebugLocs. + unsigned DebugLocListIndex = ~0u; + /// Single value location description. + std::unique_ptr<DbgValueLoc> ValueLoc = nullptr; struct FrameIndexExpr { int FI; @@ -136,7 +139,7 @@ public: /// Initialize from the MMI table. void initializeMMI(const DIExpression *E, int FI) { assert(FrameIndexExprs.empty() && "Already initialized?"); - assert(!MInsn && "Already initialized?"); + assert(!ValueLoc.get() && "Already initialized?"); assert((!E || E->isValid()) && "Expected valid expression"); assert(FI != std::numeric_limits<int>::max() && "Expected valid index"); @@ -144,35 +147,35 @@ public: FrameIndexExprs.push_back({FI, E}); } - /// Initialize from a DBG_VALUE instruction. - void initializeDbgValue(const MachineInstr *DbgValue) { + // Initialize variable's location. + void initializeDbgValue(DbgValueLoc Value) { assert(FrameIndexExprs.empty() && "Already initialized?"); - assert(!MInsn && "Already initialized?"); + assert(!ValueLoc && "Already initialized?"); + assert(!Value.getExpression()->isFragment() && "Fragments not supported."); - assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); - assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && - "Wrong inlined-at"); - - MInsn = DbgValue; - if (auto *E = DbgValue->getDebugExpression()) + ValueLoc = llvm::make_unique<DbgValueLoc>(Value); + if (auto *E = ValueLoc->getExpression()) if (E->getNumElements()) FrameIndexExprs.push_back({0, E}); } + /// Initialize from a DBG_VALUE instruction. + void initializeDbgValue(const MachineInstr *DbgValue); + // Accessors. const DILocalVariable *getVariable() const { return cast<DILocalVariable>(getEntity()); } const DIExpression *getSingleExpression() const { - assert(MInsn && FrameIndexExprs.size() <= 1); + assert(ValueLoc.get() && FrameIndexExprs.size() <= 1); return FrameIndexExprs.size() ? FrameIndexExprs[0].Expr : nullptr; } void setDebugLocListIndex(unsigned O) { DebugLocListIndex = O; } unsigned getDebugLocListIndex() const { return DebugLocListIndex; } StringRef getName() const { return getVariable()->getName(); } - const MachineInstr *getMInsn() const { return MInsn; } + const DbgValueLoc *getValueLoc() const { return ValueLoc.get(); } /// Get the FI entries, sorted by fragment offset. ArrayRef<FrameIndexExpr> getFrameIndexExprs() const; bool hasFrameIndexExprs() const { return !FrameIndexExprs.empty(); } @@ -205,7 +208,7 @@ public: } bool hasComplexAddress() const { - assert(MInsn && "Expected DBG_VALUE, not MMI variable"); + assert(ValueLoc.get() && "Expected DBG_VALUE, not MMI variable"); assert((FrameIndexExprs.empty() || (FrameIndexExprs.size() == 1 && FrameIndexExprs[0].Expr->getNumElements())) && @@ -219,11 +222,6 @@ public: static bool classof(const DbgEntity *N) { return N->getDbgEntityID() == DbgVariableKind; } - -private: - template <typename T> T *resolve(TypedDINodeRef<T> Ref) const { - return Ref.resolve(); - } }; //===----------------------------------------------------------------------===// @@ -254,11 +252,6 @@ public: static bool classof(const DbgEntity *N) { return N->getDbgEntityID() == DbgLabelKind; } - -private: - template <typename T> T *resolve(TypedDINodeRef<T> Ref) const { - return Ref.resolve(); - } }; /// Helper used to pair up a symbol and its DWARF compile unit. @@ -558,9 +551,11 @@ class DwarfDebug : public DebugHandlerBase { DenseSet<InlinedEntity> &ProcessedVars); /// Build the location list for all DBG_VALUEs in the - /// function that describe the same variable. - void buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, - const DbgValueHistoryMap::InstrRanges &Ranges); + /// function that describe the same variable. If the resulting + /// list has only one entry that is valid for entire variable's + /// scope return true. + bool buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, + const DbgValueHistoryMap::Entries &Entries); /// Collect variable information from the side table maintained by MF. void collectVariableInfoFromMFTable(DwarfCompileUnit &TheCU, @@ -593,6 +588,9 @@ public: /// Emit all Dwarf sections that should come after the content. void endModule() override; + /// Emits inital debug location directive. + DebugLoc emitInitialLocDirective(const MachineFunction &MF, unsigned CUID); + /// Process beginning of an instruction. void beginInstruction(const MachineInstr *MI) override; @@ -604,6 +602,19 @@ public: void addDwarfTypeUnitType(DwarfCompileUnit &CU, StringRef Identifier, DIE &Die, const DICompositeType *CTy); + friend class NonTypeUnitContext; + class NonTypeUnitContext { + DwarfDebug *DD; + decltype(DwarfDebug::TypeUnitsUnderConstruction) TypeUnitsUnderConstruction; + friend class DwarfDebug; + NonTypeUnitContext(DwarfDebug *DD); + public: + NonTypeUnitContext(NonTypeUnitContext&&) = default; + ~NonTypeUnitContext(); + }; + + NonTypeUnitContext enterNonTypeUnitContext(); + /// Add a label so that arange data can be generated for it. void addArangeLabel(SymbolCU SCU) { ArangeLabels.push_back(SCU); } @@ -680,15 +691,12 @@ public: /// Emit an entry for the debug loc section. This can be used to /// handle an entry that's going to be emitted into the debug loc section. void emitDebugLocEntry(ByteStreamer &Streamer, - const DebugLocStream::Entry &Entry); + const DebugLocStream::Entry &Entry, + const DwarfCompileUnit *CU); /// Emit the location for a debug loc entry, including the size header. - void emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry); - - /// Find the MDNode for the given reference. - template <typename T> T *resolve(TypedDINodeRef<T> Ref) const { - return Ref.resolve(); - } + void emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry, + const DwarfCompileUnit *CU); void addSubprogramNames(const DICompileUnit &CU, const DISubprogram *SP, DIE &Die); @@ -728,6 +736,10 @@ public: void addSectionLabel(const MCSymbol *Sym); const MCSymbol *getSectionLabel(const MCSection *S); + + static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, + const DbgValueLoc &Value, + DwarfExpression &DwarfExpr); }; } // end namespace llvm diff --git a/lib/CodeGen/AsmPrinter/DwarfException.h b/lib/CodeGen/AsmPrinter/DwarfException.h index b57ea8fc6322..24bbf58b91ec 100644 --- a/lib/CodeGen/AsmPrinter/DwarfException.h +++ b/lib/CodeGen/AsmPrinter/DwarfException.h @@ -1,9 +1,8 @@ //===-- DwarfException.h - Dwarf Exception Framework -----------*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index 19c350afbf17..2858afaa1cf1 100644 --- a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfExpression.cpp - Dwarf Debug Framework -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -12,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "DwarfExpression.h" +#include "DwarfCompileUnit.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -40,7 +40,7 @@ void DwarfExpression::emitConstu(uint64_t Value) { void DwarfExpression::addReg(int DwarfReg, const char *Comment) { assert(DwarfReg >= 0 && "invalid negative dwarf register number"); - assert((LocationKind == Unknown || LocationKind == Register) && + assert((isUnknownLocation() || isRegisterLocation()) && "location description already locked down"); LocationKind = Register; if (DwarfReg < 32) { @@ -53,7 +53,7 @@ void DwarfExpression::addReg(int DwarfReg, const char *Comment) { void DwarfExpression::addBReg(int DwarfReg, int Offset) { assert(DwarfReg >= 0 && "invalid negative dwarf register number"); - assert(LocationKind != Register && "location description already locked down"); + assert(!isRegisterLocation() && "location description already locked down"); if (DwarfReg < 32) { emitOp(dwarf::DW_OP_breg0 + DwarfReg); } else { @@ -184,20 +184,20 @@ void DwarfExpression::addStackValue() { } void DwarfExpression::addSignedConstant(int64_t Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); + assert(isImplicitLocation() || isUnknownLocation()); LocationKind = Implicit; emitOp(dwarf::DW_OP_consts); emitSigned(Value); } void DwarfExpression::addUnsignedConstant(uint64_t Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); + assert(isImplicitLocation() || isUnknownLocation()); LocationKind = Implicit; emitConstu(Value); } void DwarfExpression::addUnsignedConstant(const APInt &Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); + assert(isImplicitLocation() || isUnknownLocation()); LocationKind = Implicit; unsigned Size = Value.getBitWidth(); @@ -242,12 +242,16 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI, } // Handle simple register locations. - if (LocationKind != Memory && !HasComplexExpression) { + if (!isMemoryLocation() && !HasComplexExpression) { for (auto &Reg : DwarfRegs) { if (Reg.DwarfRegNo >= 0) addReg(Reg.DwarfRegNo, Reg.Comment); addOpPiece(Reg.Size); } + + if (isEntryValue() && DwarfVersion >= 4) + emitOp(dwarf::DW_OP_stack_value); + DwarfRegs.clear(); return true; } @@ -296,6 +300,19 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI, return true; } +void DwarfExpression::addEntryValueExpression(DIExpressionCursor &ExprCursor) { + auto Op = ExprCursor.take(); + assert(Op && Op->getOp() == dwarf::DW_OP_entry_value); + assert(!isMemoryLocation() && + "We don't support entry values of memory locations yet"); + + if (DwarfVersion >= 5) + emitOp(dwarf::DW_OP_entry_value); + else + emitOp(dwarf::DW_OP_GNU_entry_value); + emitUnsigned(Op->getArg(0)); +} + /// Assuming a well-formed expression, match "DW_OP_deref* DW_OP_LLVM_fragment?". static bool isMemoryLocation(DIExpressionCursor ExprCursor) { while (ExprCursor) { @@ -319,6 +336,8 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, if (SubRegisterSizeInBits && N && (N->getOp() != dwarf::DW_OP_LLVM_fragment)) maskSubRegister(); + Optional<DIExpression::ExprOperand> PrevConvertOp = None; + while (ExprCursor) { auto Op = ExprCursor.take(); switch (Op->getOp()) { @@ -341,7 +360,7 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, SizeInBits = std::min<unsigned>(SizeInBits, SubRegisterSizeInBits); // Emit a DW_OP_stack_value for implicit location descriptions. - if (LocationKind == Implicit) + if (isImplicitLocation()) addStackValue(); // Emit the DW_OP_piece. @@ -352,7 +371,7 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, return; } case dwarf::DW_OP_plus_uconst: - assert(LocationKind != Register); + assert(!isRegisterLocation()); emitOp(dwarf::DW_OP_plus_uconst); emitUnsigned(Op->getArg(0)); break; @@ -373,8 +392,8 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, emitOp(Op->getOp()); break; case dwarf::DW_OP_deref: - assert(LocationKind != Register); - if (LocationKind != Memory && ::isMemoryLocation(ExprCursor)) + assert(!isRegisterLocation()); + if (!isMemoryLocation() && ::isMemoryLocation(ExprCursor)) // Turning this into a memory location description makes the deref // implicit. LocationKind = Memory; @@ -382,26 +401,69 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, emitOp(dwarf::DW_OP_deref); break; case dwarf::DW_OP_constu: - assert(LocationKind != Register); + assert(!isRegisterLocation()); emitConstu(Op->getArg(0)); break; + case dwarf::DW_OP_LLVM_convert: { + unsigned BitSize = Op->getArg(0); + dwarf::TypeKind Encoding = static_cast<dwarf::TypeKind>(Op->getArg(1)); + if (DwarfVersion >= 5) { + emitOp(dwarf::DW_OP_convert); + // Reuse the base_type if we already have one in this CU otherwise we + // create a new one. + unsigned I = 0, E = CU.ExprRefedBaseTypes.size(); + for (; I != E; ++I) + if (CU.ExprRefedBaseTypes[I].BitSize == BitSize && + CU.ExprRefedBaseTypes[I].Encoding == Encoding) + break; + + if (I == E) + CU.ExprRefedBaseTypes.emplace_back(BitSize, Encoding); + + // If targeting a location-list; simply emit the index into the raw + // byte stream as ULEB128, DwarfDebug::emitDebugLocEntry has been + // fitted with means to extract it later. + // If targeting a inlined DW_AT_location; insert a DIEBaseTypeRef + // (containing the index and a resolve mechanism during emit) into the + // DIE value list. + emitBaseTypeRef(I); + } else { + if (PrevConvertOp && PrevConvertOp->getArg(0) < BitSize) { + if (Encoding == dwarf::DW_ATE_signed) + emitLegacySExt(PrevConvertOp->getArg(0)); + else if (Encoding == dwarf::DW_ATE_unsigned) + emitLegacyZExt(PrevConvertOp->getArg(0)); + PrevConvertOp = None; + } else { + PrevConvertOp = Op; + } + } + break; + } case dwarf::DW_OP_stack_value: LocationKind = Implicit; break; case dwarf::DW_OP_swap: - assert(LocationKind != Register); + assert(!isRegisterLocation()); emitOp(dwarf::DW_OP_swap); break; case dwarf::DW_OP_xderef: - assert(LocationKind != Register); + assert(!isRegisterLocation()); emitOp(dwarf::DW_OP_xderef); break; + case dwarf::DW_OP_deref_size: + emitOp(dwarf::DW_OP_deref_size); + emitData1(Op->getArg(0)); + break; + case dwarf::DW_OP_LLVM_tag_offset: + TagOffset = Op->getArg(0); + break; default: llvm_unreachable("unhandled opcode found in expression"); } } - if (LocationKind == Implicit) + if (isImplicitLocation()) // Turn this into an implicit location description. addStackValue(); } @@ -437,3 +499,25 @@ void DwarfExpression::addFragmentOffset(const DIExpression *Expr) { addOpPiece(FragmentOffset - OffsetInBits); OffsetInBits = FragmentOffset; } + +void DwarfExpression::emitLegacySExt(unsigned FromBits) { + // (((X >> (FromBits - 1)) * (~0)) << FromBits) | X + emitOp(dwarf::DW_OP_dup); + emitOp(dwarf::DW_OP_constu); + emitUnsigned(FromBits - 1); + emitOp(dwarf::DW_OP_shr); + emitOp(dwarf::DW_OP_lit0); + emitOp(dwarf::DW_OP_not); + emitOp(dwarf::DW_OP_mul); + emitOp(dwarf::DW_OP_constu); + emitUnsigned(FromBits); + emitOp(dwarf::DW_OP_shl); + emitOp(dwarf::DW_OP_or); +} + +void DwarfExpression::emitLegacyZExt(unsigned FromBits) { + // (X & (1 << FromBits - 1)) + emitOp(dwarf::DW_OP_constu); + emitUnsigned((1ULL << FromBits) - 1); + emitOp(dwarf::DW_OP_and); +} diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.h b/lib/CodeGen/AsmPrinter/DwarfExpression.h index 91568ba6d107..ec2ef6e575f7 100644 --- a/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfExpression.h - Dwarf Compile Unit ------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -28,7 +27,7 @@ namespace llvm { class AsmPrinter; class APInt; class ByteStreamer; -class DwarfUnit; +class DwarfCompileUnit; class DIELoc; class TargetRegisterInfo; @@ -105,23 +104,56 @@ protected: const char *Comment; }; + DwarfCompileUnit &CU; + /// The register location, if any. SmallVector<Register, 2> DwarfRegs; /// Current Fragment Offset in Bits. uint64_t OffsetInBits = 0; - unsigned DwarfVersion; /// Sometimes we need to add a DW_OP_bit_piece to describe a subregister. - unsigned SubRegisterSizeInBits = 0; - unsigned SubRegisterOffsetInBits = 0; + unsigned SubRegisterSizeInBits : 16; + unsigned SubRegisterOffsetInBits : 16; /// The kind of location description being produced. - enum { Unknown = 0, Register, Memory, Implicit } LocationKind = Unknown; + enum { Unknown = 0, Register, Memory, Implicit }; + + /// The flags of location description being produced. + enum { EntryValue = 1 }; + + unsigned LocationKind : 3; + unsigned LocationFlags : 2; + unsigned DwarfVersion : 4; + +public: + bool isUnknownLocation() const { + return LocationKind == Unknown; + } + + bool isMemoryLocation() const { + return LocationKind == Memory; + } + + bool isRegisterLocation() const { + return LocationKind == Register; + } + + bool isImplicitLocation() const { + return LocationKind == Implicit; + } + + bool isEntryValue() const { + return LocationFlags & EntryValue; + } + Optional<uint8_t> TagOffset; + +protected: /// Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed /// to represent a subregister. void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits) { + assert(SizeInBits < 65536 && OffsetInBits < 65536); SubRegisterSizeInBits = SizeInBits; SubRegisterOffsetInBits = OffsetInBits; } @@ -138,6 +170,10 @@ protected: /// Emit a raw unsigned value. virtual void emitUnsigned(uint64_t Value) = 0; + virtual void emitData1(uint8_t Value) = 0; + + virtual void emitBaseTypeRef(uint64_t Idx) = 0; + /// Emit a normalized unsigned constant. void emitConstu(uint64_t Value); @@ -200,7 +236,10 @@ protected: ~DwarfExpression() = default; public: - DwarfExpression(unsigned DwarfVersion) : DwarfVersion(DwarfVersion) {} + DwarfExpression(unsigned DwarfVersion, DwarfCompileUnit &CU) + : CU(CU), SubRegisterSizeInBits(0), SubRegisterOffsetInBits(0), + LocationKind(Unknown), LocationFlags(Unknown), + DwarfVersion(DwarfVersion) {} /// This needs to be called last to commit any pending changes. void finalize(); @@ -214,15 +253,17 @@ 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); + assert(isUnknownLocation()); LocationKind = Memory; } + /// Lock this down to become an entry value location. + void setEntryValueFlag() { + LocationFlags |= EntryValue; + } + /// Emit a machine register location. As an optimization this may also consume /// the prefix of a DwarfExpression if a more efficient representation for /// combining the register location and the first operation exists. @@ -237,6 +278,9 @@ public: DIExpressionCursor &Expr, unsigned MachineReg, unsigned FragmentOffsetInBits = 0); + /// Emit entry value dwarf operation. + void addEntryValueExpression(DIExpressionCursor &ExprCursor); + /// Emit all remaining operations in the DIExpressionCursor. /// /// \param FragmentOffsetInBits If this is one fragment out of multiple @@ -248,6 +292,9 @@ public: /// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to /// the fragment described by \c Expr. void addFragmentOffset(const DIExpression *Expr); + + void emitLegacySExt(unsigned FromBits); + void emitLegacyZExt(unsigned FromBits); }; /// DwarfExpression implementation for .debug_loc entries. @@ -257,27 +304,30 @@ class DebugLocDwarfExpression final : public DwarfExpression { void emitOp(uint8_t Op, const char *Comment = nullptr) override; void emitSigned(int64_t Value) override; void emitUnsigned(uint64_t Value) override; + void emitData1(uint8_t Value) override; + void emitBaseTypeRef(uint64_t Idx) override; bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) override; public: - DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS) - : DwarfExpression(DwarfVersion), BS(BS) {} + DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS, DwarfCompileUnit &CU) + : DwarfExpression(DwarfVersion, CU), BS(BS) {} }; /// DwarfExpression implementation for singular DW_AT_location. class DIEDwarfExpression final : public DwarfExpression { const AsmPrinter &AP; - DwarfUnit &DU; DIELoc &DIE; void emitOp(uint8_t Op, const char *Comment = nullptr) override; void emitSigned(int64_t Value) override; void emitUnsigned(uint64_t Value) override; + void emitData1(uint8_t Value) override; + void emitBaseTypeRef(uint64_t Idx) override; bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) override; public: - DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU, DIELoc &DIE); + DIEDwarfExpression(const AsmPrinter &AP, DwarfCompileUnit &CU, DIELoc &DIE); DIELoc *finalize() { DwarfExpression::finalize(); diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/lib/CodeGen/AsmPrinter/DwarfFile.cpp index 78ccad481411..e3c9095d1343 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfFile.cpp - Dwarf Debug Framework -----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -44,6 +43,11 @@ void DwarfFile::emitUnit(DwarfUnit *TheU, bool UseOffsets) { if (!S) return; + // Skip CUs that ended up not being needed (split CUs that were abandoned + // because they added no information beyond the non-split CU) + if (llvm::empty(TheU->getUnitDie().values())) + return; + Asm->OutStreamer->SwitchSection(S); TheU->emitHeader(UseOffsets); Asm->emitDwarfDIE(TheU->getUnitDie()); @@ -63,6 +67,11 @@ void DwarfFile::computeSizeAndOffsets() { if (TheU->getCUNode()->isDebugDirectivesOnly()) continue; + // Skip CUs that ended up not being needed (split CUs that were abandoned + // because they added no information beyond the non-split CU) + if (llvm::empty(TheU->getUnitDie().values())) + return; + TheU->setDebugSectionOffset(SecOffset); SecOffset += computeSizeAndOffsetsForUnit(TheU.get()); } diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.h b/lib/CodeGen/AsmPrinter/DwarfFile.h index 51acca8c1e53..244678ce9dc1 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfFile.h - Dwarf Debug Framework ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -59,7 +58,6 @@ public: MCSymbol *getSym() const { return RangeSym; } const DwarfCompileUnit &getCU() const { return *CU; } const SmallVectorImpl<RangeSpan> &getRanges() const { return Ranges; } - void addRange(RangeSpan Range) { Ranges.push_back(Range); } }; class DwarfFile { @@ -148,7 +146,7 @@ public: void emitUnits(bool UseOffsets); /// Emit the given unit to its section. - void emitUnit(DwarfUnit *U, bool UseOffsets); + void emitUnit(DwarfUnit *TheU, bool UseOffsets); /// Emit a set of abbreviations to the specific section. void emitAbbrevs(MCSection *); diff --git a/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp b/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp index 02016534a774..2a76dcb1b082 100644 --- a/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfStringPool.cpp - Dwarf Debug Framework -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/DwarfStringPool.h b/lib/CodeGen/AsmPrinter/DwarfStringPool.h index f484540d8d37..c5f5637fdae3 100644 --- a/lib/CodeGen/AsmPrinter/DwarfStringPool.h +++ b/lib/CodeGen/AsmPrinter/DwarfStringPool.h @@ -1,9 +1,8 @@ //===- llvm/CodeGen/DwarfStringPool.h - Dwarf Debug Framework ---*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 80b365f1aa43..991ab94b50ab 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1,9 +1,8 @@ //===-- llvm/CodeGen/DwarfUnit.cpp - Dwarf Type and Compile Units ---------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -47,21 +46,30 @@ using namespace llvm; #define DEBUG_TYPE "dwarfdebug" -DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU, +DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP, + DwarfCompileUnit &CU, DIELoc &DIE) - : DwarfExpression(AP.getDwarfVersion()), AP(AP), DU(DU), + : DwarfExpression(AP.getDwarfVersion(), CU), AP(AP), DIE(DIE) {} void DIEDwarfExpression::emitOp(uint8_t Op, const char* Comment) { - DU.addUInt(DIE, dwarf::DW_FORM_data1, Op); + CU.addUInt(DIE, dwarf::DW_FORM_data1, Op); } void DIEDwarfExpression::emitSigned(int64_t Value) { - DU.addSInt(DIE, dwarf::DW_FORM_sdata, Value); + CU.addSInt(DIE, dwarf::DW_FORM_sdata, Value); } void DIEDwarfExpression::emitUnsigned(uint64_t Value) { - DU.addUInt(DIE, dwarf::DW_FORM_udata, Value); + CU.addUInt(DIE, dwarf::DW_FORM_udata, Value); +} + +void DIEDwarfExpression::emitData1(uint8_t Value) { + CU.addUInt(DIE, dwarf::DW_FORM_data1, Value); +} + +void DIEDwarfExpression::emitBaseTypeRef(uint64_t Idx) { + CU.addBaseTypeRef(DIE, Idx); } bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, @@ -285,21 +293,21 @@ void DwarfUnit::addSectionOffset(DIE &Die, dwarf::Attribute Attribute, addUInt(Die, Attribute, dwarf::DW_FORM_data4, Integer); } -MD5::MD5Result *DwarfUnit::getMD5AsBytes(const DIFile *File) const { +Optional<MD5::MD5Result> DwarfUnit::getMD5AsBytes(const DIFile *File) const { assert(File); if (DD->getDwarfVersion() < 5) - return nullptr; + return None; Optional<DIFile::ChecksumInfo<StringRef>> Checksum = File->getChecksum(); if (!Checksum || Checksum->Kind != DIFile::CSK_MD5) - return nullptr; + return None; // 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); + MD5::MD5Result CKMem; + std::copy(ChecksumString.begin(), ChecksumString.end(), CKMem.Bytes.data()); + return CKMem; } unsigned DwarfTypeUnit::getOrCreateSourceID(const DIFile *File) { @@ -311,7 +319,9 @@ unsigned DwarfTypeUnit::getOrCreateSourceID(const DIFile *File) { addSectionOffset(getUnitDie(), dwarf::DW_AT_stmt_list, 0); } return SplitLineTable->getFile(File->getDirectory(), File->getFilename(), - getMD5AsBytes(File), File->getSource()); + getMD5AsBytes(File), + Asm->OutContext.getDwarfVersion(), + File->getSource()); } void DwarfUnit::addOpAddress(DIELoc &Die, const MCSymbol *Sym) { @@ -393,7 +403,6 @@ void DwarfUnit::addSourceLine(DIE &Die, unsigned Line, const DIFile *File) { return; 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); } @@ -462,9 +471,8 @@ static bool isUnsignedDIType(DwarfDebug *DD, const DIType *Ty) { assert(T == dwarf::DW_TAG_typedef || T == dwarf::DW_TAG_const_type || T == dwarf::DW_TAG_volatile_type || T == dwarf::DW_TAG_restrict_type || T == dwarf::DW_TAG_atomic_type); - DITypeRef Deriv = DTy->getBaseType(); - assert(Deriv && "Expected valid base type"); - return isUnsignedDIType(DD, DD->resolve(Deriv)); + assert(DTy->getBaseType() && "Expected valid base type"); + return isUnsignedDIType(DD, DTy->getBaseType()); } auto *BTy = cast<DIBasicType>(Ty); @@ -523,6 +531,10 @@ void DwarfUnit::addConstantValue(DIE &Die, const MachineOperand &MO, addConstantValue(Die, isUnsignedDIType(DD, Ty), MO.getImm()); } +void DwarfUnit::addConstantValue(DIE &Die, uint64_t Val, const DIType *Ty) { + addConstantValue(Die, isUnsignedDIType(DD, Ty), Val); +} + void DwarfUnit::addConstantValue(DIE &Die, bool Unsigned, uint64_t Val) { // FIXME: This is a bit conservative/simple - it emits negative values always // sign extended to 64 bits rather than minimizing the number of bytes. @@ -603,8 +615,8 @@ DIE *DwarfUnit::getOrCreateContextDIE(const DIScope *Context) { return getDIE(Context); } -DIE *DwarfTypeUnit::createTypeDIE(const DICompositeType *Ty) { - auto *Context = resolve(Ty->getScope()); +DIE *DwarfUnit::createTypeDIE(const DICompositeType *Ty) { + auto *Context = Ty->getScope(); DIE *ContextDIE = getOrCreateContextDIE(Context); if (DIE *TyDIE = getDIE(Ty)) @@ -619,6 +631,37 @@ DIE *DwarfTypeUnit::createTypeDIE(const DICompositeType *Ty) { return &TyDIE; } +DIE *DwarfUnit::createTypeDIE(const DIScope *Context, DIE &ContextDIE, + const DIType *Ty) { + // Create new type. + DIE &TyDIE = createAndAddDIE(Ty->getTag(), ContextDIE, Ty); + + updateAcceleratorTables(Context, Ty, TyDIE); + + if (auto *BT = dyn_cast<DIBasicType>(Ty)) + constructTypeDIE(TyDIE, BT); + else if (auto *STy = dyn_cast<DISubroutineType>(Ty)) + constructTypeDIE(TyDIE, STy); + else if (auto *CTy = dyn_cast<DICompositeType>(Ty)) { + if (DD->generateTypeUnits() && !Ty->isForwardDecl() && + (Ty->getRawName() || CTy->getRawIdentifier())) { + // Skip updating the accelerator tables since this is not the full type. + if (MDString *TypeId = CTy->getRawIdentifier()) + DD->addDwarfTypeUnitType(getCU(), TypeId->getString(), TyDIE, CTy); + else { + auto X = DD->enterNonTypeUnitContext(); + finishNonUnitTypeDIE(TyDIE, CTy); + } + return &TyDIE; + } + constructTypeDIE(TyDIE, CTy); + } else { + constructTypeDIE(TyDIE, cast<DIDerivedType>(Ty)); + } + + return &TyDIE; +} + DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) { if (!TyNode) return nullptr; @@ -627,43 +670,23 @@ DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) { // DW_TAG_restrict_type is not supported in DWARF2 if (Ty->getTag() == dwarf::DW_TAG_restrict_type && DD->getDwarfVersion() <= 2) - return getOrCreateTypeDIE(resolve(cast<DIDerivedType>(Ty)->getBaseType())); + return getOrCreateTypeDIE(cast<DIDerivedType>(Ty)->getBaseType()); // DW_TAG_atomic_type is not supported in DWARF < 5 if (Ty->getTag() == dwarf::DW_TAG_atomic_type && DD->getDwarfVersion() < 5) - return getOrCreateTypeDIE(resolve(cast<DIDerivedType>(Ty)->getBaseType())); + return getOrCreateTypeDIE(cast<DIDerivedType>(Ty)->getBaseType()); // Construct the context before querying for the existence of the DIE in case // such construction creates the DIE. - auto *Context = resolve(Ty->getScope()); + auto *Context = Ty->getScope(); DIE *ContextDIE = getOrCreateContextDIE(Context); assert(ContextDIE); if (DIE *TyDIE = getDIE(Ty)) return TyDIE; - // Create new type. - DIE &TyDIE = createAndAddDIE(Ty->getTag(), *ContextDIE, Ty); - - updateAcceleratorTables(Context, Ty, TyDIE); - - if (auto *BT = dyn_cast<DIBasicType>(Ty)) - constructTypeDIE(TyDIE, BT); - else if (auto *STy = dyn_cast<DISubroutineType>(Ty)) - constructTypeDIE(TyDIE, STy); - else if (auto *CTy = dyn_cast<DICompositeType>(Ty)) { - 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. - return &TyDIE; - } - constructTypeDIE(TyDIE, CTy); - } else { - constructTypeDIE(TyDIE, cast<DIDerivedType>(Ty)); - } - - return &TyDIE; + return static_cast<DwarfUnit *>(ContextDIE->getUnit()) + ->createTypeDIE(Context, *ContextDIE, Ty); } void DwarfUnit::updateAcceleratorTables(const DIScope *Context, @@ -679,7 +702,7 @@ void DwarfUnit::updateAcceleratorTables(const DIScope *Context, DD->addAccelType(*CUNode, Ty->getName(), TyDIE, Flags); if (!Context || isa<DICompileUnit>(Context) || isa<DIFile>(Context) || - isa<DINamespace>(Context)) + isa<DINamespace>(Context) || isa<DICommonBlock>(Context)) addGlobalType(Ty, TyDIE, Context); } } @@ -702,8 +725,8 @@ std::string DwarfUnit::getParentContextString(const DIScope *Context) const { SmallVector<const DIScope *, 1> Parents; while (!isa<DICompileUnit>(Context)) { Parents.push_back(Context); - if (Context->getScope()) - Context = resolve(Context->getScope()); + if (const DIScope *S = Context->getScope()) + Context = S; else // Structure, etc types will have a NULL context if they're at the top // level. @@ -754,7 +777,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) { uint16_t Tag = Buffer.getTag(); // Map to main type, void will not have a type. - const DIType *FromTy = resolve(DTy->getBaseType()); + const DIType *FromTy = DTy->getBaseType(); if (FromTy) addType(Buffer, FromTy); @@ -770,24 +793,23 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) { addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size); if (Tag == dwarf::DW_TAG_ptr_to_member_type) - addDIEEntry( - Buffer, dwarf::DW_AT_containing_type, - *getOrCreateTypeDIE(resolve(cast<DIDerivedType>(DTy)->getClassType()))); + addDIEEntry(Buffer, dwarf::DW_AT_containing_type, + *getOrCreateTypeDIE(cast<DIDerivedType>(DTy)->getClassType())); // Add source line info if available and TyDesc is not a forward declaration. if (!DTy->isForwardDecl()) addSourceLine(Buffer, DTy); - // If DWARF address space value is other than None, add it for pointer and - // reference types as DW_AT_address_class. - if (DTy->getDWARFAddressSpace() && (Tag == dwarf::DW_TAG_pointer_type || - Tag == dwarf::DW_TAG_reference_type)) + // If DWARF address space value is other than None, add it. The IR + // verifier checks that DWARF address space only exists for pointer + // or reference types. + if (DTy->getDWARFAddressSpace()) addUInt(Buffer, dwarf::DW_AT_address_class, dwarf::DW_FORM_data4, DTy->getDWARFAddressSpace().getValue()); } void DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) { for (unsigned i = 1, N = Args.size(); i < N; ++i) { - const DIType *Ty = resolve(Args[i]); + const DIType *Ty = Args[i]; if (!Ty) { assert(i == N-1 && "Unspecified parameter must be the last argument"); createAndAddDIE(dwarf::DW_TAG_unspecified_parameters, Buffer); @@ -804,7 +826,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy) { // Add return type. A void return won't have a type. auto Elements = cast<DISubroutineType>(CTy)->getTypeArray(); if (Elements.size()) - if (auto RTy = resolve(Elements[0])) + if (auto RTy = Elements[0]) addType(Buffer, RTy); bool isPrototyped = true; @@ -875,7 +897,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { else if (auto *DDTy = dyn_cast<DIDerivedType>(Element)) { if (DDTy->getTag() == dwarf::DW_TAG_friend) { DIE &ElemDie = createAndAddDIE(dwarf::DW_TAG_friend, Buffer); - addType(ElemDie, resolve(DDTy->getBaseType()), dwarf::DW_AT_friend); + addType(ElemDie, DDTy->getBaseType(), dwarf::DW_AT_friend); } else if (DDTy->isStaticMember()) { getOrCreateStaticMemberDIE(DDTy); } else if (Tag == dwarf::DW_TAG_variant_part) { @@ -884,7 +906,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { 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()))) + if (isUnsignedDIType(DD, Discriminator->getBaseType())) addUInt(Variant, dwarf::DW_AT_discr_value, None, CI->getZExtValue()); else addSInt(Variant, dwarf::DW_AT_discr_value, None, CI->getSExtValue()); @@ -898,7 +920,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { StringRef PropertyName = Property->getName(); addString(ElemDie, dwarf::DW_AT_APPLE_property_name, PropertyName); if (Property->getType()) - addType(ElemDie, resolve(Property->getType())); + addType(ElemDie, Property->getType()); addSourceLine(ElemDie, Property); StringRef GetterName = Property->getGetterName(); if (!GetterName.empty()) @@ -924,7 +946,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { // inside C++ composite types to point to the base class with the vtable. // Rust uses DW_AT_containing_type to link a vtable to the type // for which it was created. - if (auto *ContainingType = resolve(CTy->getVTableHolder())) + if (auto *ContainingType = CTy->getVTableHolder()) addDIEEntry(Buffer, dwarf::DW_AT_containing_type, *getOrCreateTypeDIE(ContainingType)); @@ -994,7 +1016,7 @@ void DwarfUnit::constructTemplateTypeParameterDIE( createAndAddDIE(dwarf::DW_TAG_template_type_parameter, Buffer); // Add the type if it exists, it could be void and therefore no type. if (TP->getType()) - addType(ParamDIE, resolve(TP->getType())); + addType(ParamDIE, TP->getType()); if (!TP->getName().empty()) addString(ParamDIE, dwarf::DW_AT_name, TP->getName()); } @@ -1006,12 +1028,12 @@ void DwarfUnit::constructTemplateValueParameterDIE( // Add the type if there is one, template template and template parameter // packs will not have a type. if (VP->getTag() == dwarf::DW_TAG_template_value_parameter) - addType(ParamDIE, resolve(VP->getType())); + addType(ParamDIE, VP->getType()); if (!VP->getName().empty()) addString(ParamDIE, dwarf::DW_AT_name, VP->getName()); if (Metadata *Val = VP->getValue()) { if (ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Val)) - addConstantValue(ParamDIE, CI, resolve(VP->getType())); + addConstantValue(ParamDIE, CI, VP->getType()); else if (GlobalValue *GV = mdconst::dyn_extract<GlobalValue>(Val)) { // We cannot describe the location of dllimport'd entities: the // computation of their address requires loads from the IAT. @@ -1085,7 +1107,7 @@ DIE *DwarfUnit::getOrCreateSubprogramDIE(const DISubprogram *SP, bool Minimal) { // such construction creates the DIE (as is the case for member function // declarations). DIE *ContextDIE = - Minimal ? &getUnitDie() : getOrCreateContextDIE(resolve(SP->getScope())); + Minimal ? &getUnitDie() : getOrCreateContextDIE(SP->getScope()); if (DIE *SPDie = getDIE(SP)) return SPDie; @@ -1107,7 +1129,8 @@ DIE *DwarfUnit::getOrCreateSubprogramDIE(const DISubprogram *SP, bool Minimal) { if (SP->isDefinition()) return &SPDie; - applySubprogramAttributes(SP, SPDie); + static_cast<DwarfUnit *>(SPDie.getUnit()) + ->applySubprogramAttributes(SP, SPDie); return &SPDie; } @@ -1197,7 +1220,7 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, // Add a return type. If this is a type like a C/C++ void type we don't add a // return type. if (Args.size()) - if (auto Ty = resolve(Args[0])) + if (auto Ty = Args[0]) addType(SPDie, Ty); unsigned VK = SP->getVirtuality(); @@ -1209,8 +1232,7 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, addUInt(*Block, dwarf::DW_FORM_udata, SP->getVirtualIndex()); addBlock(SPDie, dwarf::DW_AT_vtable_elem_location, Block); } - ContainingTypeMap.insert( - std::make_pair(&SPDie, resolve(SP->getContainingType()))); + ContainingTypeMap.insert(std::make_pair(&SPDie, SP->getContainingType())); } if (!SP->isDefinition()) { @@ -1261,6 +1283,12 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, if (SP->isMainSubprogram()) addFlag(SPDie, dwarf::DW_AT_main_subprogram); + if (SP->isPure()) + addFlag(SPDie, dwarf::DW_AT_pure); + if (SP->isElemental()) + addFlag(SPDie, dwarf::DW_AT_elemental); + if (SP->isRecursive()) + addFlag(SPDie, dwarf::DW_AT_recursive); } void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, @@ -1310,7 +1338,7 @@ static bool hasVectorBeenPadded(const DICompositeType *CTy) { const uint64_t ActualSize = CTy->getSizeInBits(); // Obtain the size of each element in the vector. - DIType *BaseTy = CTy->getBaseType().resolve(); + DIType *BaseTy = CTy->getBaseType(); assert(BaseTy && "Unknown vector element type."); const uint64_t ElementSize = BaseTy->getSizeInBits(); @@ -1338,7 +1366,7 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { } // Emit the element type. - addType(Buffer, resolve(CTy->getBaseType())); + addType(Buffer, CTy->getBaseType()); // Get an anonymous type for index type. // FIXME: This type should be passed down from the front end @@ -1356,7 +1384,7 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { } void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) { - const DIType *DTy = resolve(CTy->getBaseType()); + const DIType *DTy = CTy->getBaseType(); bool IsUnsigned = DTy && isUnsignedDIType(DD, DTy); if (DTy) { if (DD->getDwarfVersion() >= 3) @@ -1365,6 +1393,9 @@ void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) { addFlag(Buffer, dwarf::DW_AT_enum_class); } + auto *Context = CTy->getScope(); + bool IndexEnumerators = !Context || isa<DICompileUnit>(Context) || isa<DIFile>(Context) || + isa<DINamespace>(Context) || isa<DICommonBlock>(Context); DINodeArray Elements = CTy->getElements(); // Add enumerators to enumeration type. @@ -1376,6 +1407,8 @@ void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) { addString(Enumerator, dwarf::DW_AT_name, Name); auto Value = static_cast<uint64_t>(Enum->getValue()); addConstantValue(Enumerator, IsUnsigned, Value); + if (IndexEnumerators) + addGlobalName(Name, Enumerator, Context); } } } @@ -1400,7 +1433,7 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { if (!Name.empty()) addString(MemberDie, dwarf::DW_AT_name, Name); - if (DIType *Resolved = resolve(DT->getBaseType())) + if (DIType *Resolved = DT->getBaseType()) addType(MemberDie, Resolved); addSourceLine(MemberDie, DT); @@ -1509,7 +1542,7 @@ DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) { // Construct the context before querying for the existence of the DIE in case // such construction creates the DIE. - DIE *ContextDIE = getOrCreateContextDIE(resolve(DT->getScope())); + DIE *ContextDIE = getOrCreateContextDIE(DT->getScope()); assert(dwarf::isType(ContextDIE->getTag()) && "Static member should belong to a type."); @@ -1518,7 +1551,7 @@ DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) { DIE &StaticMemberDIE = createAndAddDIE(DT->getTag(), *ContextDIE, DT); - const DIType *Ty = resolve(DT->getBaseType()); + const DIType *Ty = DT->getBaseType(); addString(StaticMemberDIE, dwarf::DW_AT_name, DT->getName()); addType(StaticMemberDIE, Ty); @@ -1671,3 +1704,11 @@ void DwarfUnit::addLoclistsBase() { DU->getLoclistsTableBaseSym(), TLOF.getDwarfLoclistsSection()->getBeginSymbol()); } + +void DwarfTypeUnit::finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) { + addFlag(D, dwarf::DW_AT_declaration); + StringRef Name = CTy->getName(); + if (!Name.empty()) + addString(D, dwarf::DW_AT_name, Name); + getCU().createTypeDIE(CTy); +} diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.h b/lib/CodeGen/AsmPrinter/DwarfUnit.h index a59ebb7c1465..56c934a35ae8 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -1,9 +1,8 @@ //===-- llvm/CodeGen/DwarfUnit.h - Dwarf Compile Unit ---*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -199,6 +198,7 @@ public: void addConstantValue(DIE &Die, const ConstantInt *CI, const DIType *Ty); void addConstantValue(DIE &Die, const APInt &Val, const DIType *Ty); void addConstantValue(DIE &Die, const APInt &Val, bool Unsigned); + void addConstantValue(DIE &Die, uint64_t Val, const DIType *Ty); void addConstantValue(DIE &Die, bool Unsigned, uint64_t Val); /// Add constant value entry in variable DIE. @@ -237,6 +237,9 @@ public: void applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, bool SkipSPAttributes = false); + /// Creates type DIE with specific context. + DIE *createTypeDIE(const DIScope *Context, DIE &ContextDIE, const DIType *Ty); + /// Find existing DIE or create new DIE for the given type. DIE *getOrCreateTypeDIE(const MDNode *TyNode); @@ -294,7 +297,10 @@ public: /// If the \p File has an MD5 checksum, return it as an MD5Result /// allocated in the MCContext. - MD5::MD5Result *getMD5AsBytes(const DIFile *File) const; + Optional<MD5::MD5Result> getMD5AsBytes(const DIFile *File) const; + + /// Get context owner's DIE. + DIE *createTypeDIE(const DICompositeType *Ty); protected: ~DwarfUnit(); @@ -306,17 +312,6 @@ protected: /// 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. - template <typename T> T *resolve(TypedDINodeRef<T> Ref) const { - return Ref.resolve(); - } - - /// If this is a named finished type then include it in the list of types for - /// the accelerator tables. - void updateAcceleratorTables(const DIScope *Context, const DIType *Ty, - const DIE &TyDIE); - /// Emit the common part of the header for this unit. void emitCommonHeader(bool UseOffsets, dwarf::UnitType UT); @@ -344,6 +339,13 @@ private: /// Set D as anonymous type for index which can be reused later. void setIndexTyDie(DIE *D) { IndexTyDie = D; } + virtual void finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) = 0; + + /// If this is a named finished type then include it in the list of types for + /// the accelerator tables. + void updateAcceleratorTables(const DIScope *Context, const DIType *Ty, + const DIE &TyDIE); + virtual bool isDwoUnit() const = 0; const MCSymbol *getCrossSectionRelativeBaseAddress() const override; }; @@ -356,6 +358,7 @@ class DwarfTypeUnit final : public DwarfUnit { bool UsedLineTable = false; unsigned getOrCreateSourceID(const DIFile *File) override; + void finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) override; bool isDwoUnit() const override; public: @@ -365,9 +368,6 @@ public: void setTypeSignature(uint64_t Signature) { TypeSignature = Signature; } void setType(const DIE *Ty) { this->Ty = Ty; } - /// Get context owner's DIE. - DIE *createTypeDIE(const DICompositeType *Ty); - /// Emit the header for this unit, not including the initial length field. void emitHeader(bool UseOffsets) override; unsigned getHeaderSize() const override { diff --git a/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/lib/CodeGen/AsmPrinter/EHStreamer.cpp index 7599121de2b0..99e3687b36b8 100644 --- a/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -1,9 +1,8 @@ //===- CodeGen/AsmPrinter/EHStreamer.cpp - Exception Directive Streamer ---===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -379,7 +378,8 @@ MCSymbol *EHStreamer::emitExceptionTable() { bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm; unsigned CallSiteEncoding = - IsSJLJ ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_uleb128; + IsSJLJ ? static_cast<unsigned>(dwarf::DW_EH_PE_udata4) : + Asm->getObjFileLowering().getCallSiteEncoding(); bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty(); // Type infos. @@ -524,24 +524,24 @@ MCSymbol *EHStreamer::emitExceptionTable() { // Offset of the call site relative to the start of the procedure. if (VerboseAsm) Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + " <<"); - Asm->EmitLabelDifferenceAsULEB128(BeginLabel, EHFuncBeginSym); + Asm->EmitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); if (VerboseAsm) Asm->OutStreamer->AddComment(Twine(" Call between ") + BeginLabel->getName() + " and " + EndLabel->getName()); - Asm->EmitLabelDifferenceAsULEB128(EndLabel, BeginLabel); + Asm->EmitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding); // 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->EmitULEB128(0); + Asm->EmitCallSiteValue(0, CallSiteEncoding); } else { if (VerboseAsm) Asm->OutStreamer->AddComment(Twine(" jumps to ") + S.LPad->LandingPadLabel->getName()); - Asm->EmitLabelDifferenceAsULEB128(S.LPad->LandingPadLabel, - EHFuncBeginSym); + Asm->EmitCallSiteOffset(S.LPad->LandingPadLabel, EHFuncBeginSym, + CallSiteEncoding); } // Offset of the first associated action record, relative to the start of diff --git a/lib/CodeGen/AsmPrinter/EHStreamer.h b/lib/CodeGen/AsmPrinter/EHStreamer.h index ce912d032c6d..e62cf17a05d4 100644 --- a/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -1,9 +1,8 @@ //===- EHStreamer.h - Exception Handling Directive Streamer -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp b/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp index 34677ecc9e69..39392b79e960 100644 --- a/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp @@ -1,9 +1,8 @@ //===- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp index 3479a00def23..3145cc90dc73 100644 --- a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp @@ -1,9 +1,8 @@ //===- OcamlGCPrinter.cpp - Ocaml frametable emitter ----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/WasmException.cpp b/lib/CodeGen/AsmPrinter/WasmException.cpp index 527e5ae50146..444b0ed17b6d 100644 --- a/lib/CodeGen/AsmPrinter/WasmException.cpp +++ b/lib/CodeGen/AsmPrinter/WasmException.cpp @@ -1,9 +1,8 @@ //===-- CodeGen/AsmPrinter/WasmException.cpp - Wasm Exception Impl --------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -19,10 +18,10 @@ using namespace llvm; void WasmException::endModule() { - // This is the symbol used in 'throw' and 'if_except' instruction to denote + // This is the symbol used in 'throw' and 'br_on_exn' instruction to denote // this is a C++ exception. This symbol has to be emitted somewhere once in // the module. Check if the symbol has already been created, i.e., we have at - // least one 'throw' or 'if_except' instruction in the module, and emit the + // least one 'throw' or 'br_on_exn' instruction in the module, and emit the // symbol only if so. SmallString<60> NameStr; Mangler::getNameWithPrefix(NameStr, "__cpp_exception", Asm->getDataLayout()); diff --git a/lib/CodeGen/AsmPrinter/WasmException.h b/lib/CodeGen/AsmPrinter/WasmException.h index cbdb42457cf8..1893b6b2df43 100644 --- a/lib/CodeGen/AsmPrinter/WasmException.h +++ b/lib/CodeGen/AsmPrinter/WasmException.h @@ -1,9 +1,8 @@ //===-- WasmException.h - Wasm Exception Framework -------------*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/WinCFGuard.cpp b/lib/CodeGen/AsmPrinter/WinCFGuard.cpp index 18d37caf57ee..290be81c6baa 100644 --- a/lib/CodeGen/AsmPrinter/WinCFGuard.cpp +++ b/lib/CodeGen/AsmPrinter/WinCFGuard.cpp @@ -1,9 +1,8 @@ //===-- 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. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/WinCFGuard.h b/lib/CodeGen/AsmPrinter/WinCFGuard.h index 28f119e35966..def0a59ab007 100644 --- a/lib/CodeGen/AsmPrinter/WinCFGuard.h +++ b/lib/CodeGen/AsmPrinter/WinCFGuard.h @@ -1,9 +1,8 @@ //===-- 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. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/CodeGen/AsmPrinter/WinException.cpp b/lib/CodeGen/AsmPrinter/WinException.cpp index cf8e8c69bc2a..155e91ce61a1 100644 --- a/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/lib/CodeGen/AsmPrinter/WinException.cpp @@ -1,9 +1,8 @@ //===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -110,6 +109,12 @@ void WinException::beginFunction(const MachineFunction *MF) { beginFunclet(MF->front(), Asm->CurrentFnSym); } +void WinException::markFunctionEnd() { + if (isAArch64 && CurrentFuncletEntry && + (shouldEmitMoves || shouldEmitPersonality)) + Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd(); +} + /// endFunction - Gather and emit post-function exception information. /// void WinException::endFunction(const MachineFunction *MF) { @@ -129,7 +134,7 @@ void WinException::endFunction(const MachineFunction *MF) { NonConstMF->tidyLandingPads(); } - endFunclet(); + endFuncletImpl(); // endFunclet will emit the necessary .xdata tables for x64 SEH. if (Per == EHPersonality::MSVC_Win64SEH && MF->hasEHFunclets()) @@ -232,6 +237,15 @@ void WinException::beginFunclet(const MachineBasicBlock &MBB, } void WinException::endFunclet() { + if (isAArch64 && CurrentFuncletEntry && + (shouldEmitMoves || shouldEmitPersonality)) { + Asm->OutStreamer->SwitchSection(CurrentFuncletTextSection); + Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd(); + } + endFuncletImpl(); +} + +void WinException::endFuncletImpl() { // No funclet to process? Great, we have nothing to do. if (!CurrentFuncletEntry) return; @@ -247,8 +261,6 @@ void WinException::endFunclet() { // to EmitWinEHHandlerData below can calculate the size of the funclet or // function. if (isAArch64) { - Asm->OutStreamer->SwitchSection(CurrentFuncletTextSection); - Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd(); MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection( Asm->OutStreamer->getCurrentSectionOnly()); Asm->OutStreamer->SwitchSection(XData); @@ -545,15 +557,17 @@ void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) { OS.AddComment(Comment); }; - // Emit a label assignment with the SEH frame offset so we can use it for - // llvm.eh.recoverfp. - StringRef FLinkageName = - GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName()); - MCSymbol *ParentFrameOffset = - Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName); - const MCExpr *MCOffset = - MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx); - Asm->OutStreamer->EmitAssignment(ParentFrameOffset, MCOffset); + if (!isAArch64) { + // Emit a label assignment with the SEH frame offset so we can use it for + // llvm.eh.recoverfp. + StringRef FLinkageName = + GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName()); + MCSymbol *ParentFrameOffset = + Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName); + const MCExpr *MCOffset = + MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx); + Asm->OutStreamer->EmitAssignment(ParentFrameOffset, MCOffset); + } // Use the assembler to compute the number of table entries through label // difference and division. @@ -936,8 +950,7 @@ void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, int FI = FuncInfo.EHRegNodeFrameIndex; if (FI != INT_MAX) { const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); - unsigned UnusedReg; - Offset = TFI->getFrameIndexReference(*Asm->MF, FI, UnusedReg); + Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI); } MCContext &Ctx = Asm->OutContext; diff --git a/lib/CodeGen/AsmPrinter/WinException.h b/lib/CodeGen/AsmPrinter/WinException.h index 37c796f89765..dc5036302131 100644 --- a/lib/CodeGen/AsmPrinter/WinException.h +++ b/lib/CodeGen/AsmPrinter/WinException.h @@ -1,9 +1,8 @@ //===-- WinException.h - Windows Exception Handling ----------*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -86,6 +85,7 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer { /// only), it is relative to the frame pointer. int getFrameIndexOffset(int FrameIndex, const WinEHFuncInfo &FuncInfo); + void endFuncletImpl(); public: //===--------------------------------------------------------------------===// // Main entry points. @@ -100,6 +100,8 @@ public: /// immediately after the function entry point. void beginFunction(const MachineFunction *MF) override; + void markFunctionEnd() override; + /// Gather and emit post-function exception information. void endFunction(const MachineFunction *) override; |