diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter')
39 files changed, 2153 insertions, 961 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AIXException.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AIXException.cpp new file mode 100644 index 000000000000..95d878e65be4 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AIXException.cpp @@ -0,0 +1,79 @@ +//===-- CodeGen/AsmPrinter/AIXException.cpp - AIX Exception Impl ----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing AIX exception info into asm files. +// +//===----------------------------------------------------------------------===// + +#include "DwarfException.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/MC/MCSectionXCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +AIXException::AIXException(AsmPrinter *A) : DwarfCFIExceptionBase(A) {} + +void AIXException::emitExceptionInfoTable(const MCSymbol *LSDA, + const MCSymbol *PerSym) { + // Generate EH Info Table. + // The EH Info Table, aka, 'compat unwind section' on AIX, have the following + // format: struct eh_info_t { + // unsigned version; /* EH info verion 0 */ + // #if defined(__64BIT__) + // char _pad[4]; /* padding */ + // #endif + // unsigned long lsda; /* Pointer to LSDA */ + // unsigned long personality; /* Pointer to the personality routine */ + // } + + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getCompactUnwindSection()); + MCSymbol *EHInfoLabel = + TargetLoweringObjectFileXCOFF::getEHInfoTableSymbol(Asm->MF); + Asm->OutStreamer->emitLabel(EHInfoLabel); + + // Version number. + Asm->emitInt32(0); + + const DataLayout &DL = MMI->getModule()->getDataLayout(); + const unsigned PointerSize = DL.getPointerSize(); + + // Add necessary paddings in 64 bit mode. + Asm->OutStreamer->emitValueToAlignment(PointerSize); + + // LSDA location. + Asm->OutStreamer->emitValue(MCSymbolRefExpr::create(LSDA, Asm->OutContext), + PointerSize); + + // Personality routine. + Asm->OutStreamer->emitValue(MCSymbolRefExpr::create(PerSym, Asm->OutContext), + PointerSize); +} + +void AIXException::endFunction(const MachineFunction *MF) { + if (!TargetLoweringObjectFileXCOFF::ShouldEmitEHBlock(MF)) + return; + + const MCSymbol *LSDALabel = emitExceptionTable(); + + const Function &F = MF->getFunction(); + assert(F.hasPersonalityFn() && + "Landingpads are presented, but no personality routine is found."); + const Function *Per = + dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts()); + const MCSymbol *PerSym = Asm->TM.getSymbol(Per); + + emitExceptionInfoTable(LSDALabel, PerSym); +} + +} // End of namespace llvm diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp index dea0227f7578..4e45a0ffc60f 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp @@ -190,7 +190,6 @@ public: template <typename DataT> class Dwarf5AccelTableWriter : public AccelTableWriter { struct Header { - uint32_t UnitLength = 0; uint16_t Version = 5; uint16_t Padding = 0; uint32_t CompUnitCount; @@ -271,7 +270,7 @@ void AccelTableWriter::emitOffsets(const MCSymbol *Base) const { continue; PrevHash = HashValue; Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i)); - Asm->emitLabelDifference(Hash->Sym, Base, sizeof(uint32_t)); + Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize()); } } } @@ -367,9 +366,8 @@ void Dwarf5AccelTableWriter<DataT>::Header::emit( assert(CompUnitCount > 0 && "Index must have at least one CU."); AsmPrinter *Asm = Ctx.Asm; - Asm->OutStreamer->AddComment("Header: unit length"); - Asm->emitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart, - sizeof(uint32_t)); + Asm->emitDwarfUnitLength(Ctx.ContributionEnd, Ctx.ContributionStart, + "Header: unit length"); Asm->OutStreamer->emitLabel(Ctx.ContributionStart); Asm->OutStreamer->AddComment("Header: version"); Asm->emitInt16(Version); @@ -506,7 +504,7 @@ template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const { for (const auto *Value : Hash->Values) emitEntry(*static_cast<const DataT *>(Value)); Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); - Asm->emitInt32(0); + Asm->emitInt8(0); } } } @@ -593,10 +591,14 @@ void llvm::emitDWARF5AccelTable( } void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { + assert(Die.getDebugSectionOffset() <= UINT32_MAX && + "The section offset exceeds the limit."); Asm->emitInt32(Die.getDebugSectionOffset()); } void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const { + assert(Die.getDebugSectionOffset() <= UINT32_MAX && + "The section offset exceeds the limit."); Asm->emitInt32(Die.getDebugSectionOffset()); Asm->emitInt16(Die.getTag()); Asm->emitInt8(0); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AddressPool.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AddressPool.cpp index 883aaf5aefc4..3df8e35accc4 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AddressPool.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AddressPool.cpp @@ -29,9 +29,7 @@ MCSymbol *AddressPool::emitHeader(AsmPrinter &Asm, MCSection *Section) { MCSymbol *BeginLabel = Asm.createTempSymbol(Prefix + "start"); MCSymbol *EndLabel = Asm.createTempSymbol(Prefix + "end"); - Asm.OutStreamer->AddComment("Length of contribution"); - Asm.emitLabelDifference(EndLabel, BeginLabel, - 4); // TODO: Support DWARF64 format. + Asm.emitDwarfUnitLength(EndLabel, BeginLabel, "Length of contribution"); Asm.OutStreamer->emitLabel(BeginLabel); Asm.OutStreamer->AddComment("DWARF version number"); Asm.emitInt16(Asm.getDwarfVersion()); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AddressPool.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AddressPool.h index f92cf72093ca..f1edc6c330d5 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AddressPool.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AddressPool.h @@ -48,7 +48,7 @@ public: bool hasBeenUsed() const { return HasBeenUsed; } - void resetUsedFlag() { HasBeenUsed = false; } + void resetUsedFlag(bool HasBeenUsed = false) { this->HasBeenUsed = HasBeenUsed; } MCSymbol *getLabel() { return AddressTableBaseSym; } void setLabel(MCSymbol *Sym) { AddressTableBaseSym = Sym; } diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index c7eb0257d71b..85754bf29d0c 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -14,6 +14,7 @@ #include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" +#include "PseudoProbePrinter.h" #include "WasmException.h" #include "WinCFGuard.h" #include "WinException.h" @@ -30,6 +31,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/EHPersonalities.h" +#include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -77,6 +79,7 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/PseudoProbe.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/MC/MCAsmInfo.h" @@ -131,17 +134,25 @@ using namespace llvm; #define DEBUG_TYPE "asm-printer" -static const char *const DWARFGroupName = "dwarf"; -static const char *const DWARFGroupDescription = "DWARF Emission"; -static const char *const DbgTimerName = "emit"; -static const char *const DbgTimerDescription = "Debug Info Emission"; -static const char *const EHTimerName = "write_exception"; -static const char *const EHTimerDescription = "DWARF Exception Writer"; -static const char *const CFGuardName = "Control Flow Guard"; -static const char *const CFGuardDescription = "Control Flow Guard"; -static const char *const CodeViewLineTablesGroupName = "linetables"; -static const char *const CodeViewLineTablesGroupDescription = - "CodeView Line Tables"; +// FIXME: this option currently only applies to DWARF, and not CodeView, tables +static cl::opt<bool> + DisableDebugInfoPrinting("disable-debug-info-print", cl::Hidden, + cl::desc("Disable debug info printing")); + +const char DWARFGroupName[] = "dwarf"; +const char DWARFGroupDescription[] = "DWARF Emission"; +const char DbgTimerName[] = "emit"; +const char DbgTimerDescription[] = "Debug Info Emission"; +const char EHTimerName[] = "write_exception"; +const char EHTimerDescription[] = "DWARF Exception Writer"; +const char CFGuardName[] = "Control Flow Guard"; +const char CFGuardDescription[] = "Control Flow Guard"; +const char CodeViewLineTablesGroupName[] = "linetables"; +const char CodeViewLineTablesGroupDescription[] = "CodeView Line Tables"; +const char PPTimerName[] = "emit"; +const char PPTimerDescription[] = "Pseudo Probe Emission"; +const char PPGroupName[] = "pseudo probe"; +const char PPGroupDescription[] = "Pseudo Probe Emission"; STATISTIC(EmittedInsts, "Number of machine instrs printed"); @@ -188,7 +199,8 @@ AsmPrinter::AsmPrinter(TargetMachine &tm, std::unique_ptr<MCStreamer> Streamer) } AsmPrinter::~AsmPrinter() { - assert(!DD && Handlers.empty() && "Debug/EH info didn't get finalized"); + assert(!DD && Handlers.size() == NumUserHandlers && + "Debug/EH info didn't get finalized"); if (GCMetadataPrinters) { gcp_map_type &GCMap = getGCMap(GCMetadataPrinters); @@ -231,9 +243,11 @@ void AsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { } 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); + if (DD) { + assert(OutStreamer->hasRawTextSupport() && + "Expected assembly output mode."); + (void)DD->emitInitialLocDirective(MF, /*CUID=*/0); + } } /// getCurrentSection() - Return the current section we are emitting to. @@ -261,6 +275,9 @@ bool AsmPrinter::doInitialization(Module &M) { OutStreamer->InitSections(false); + if (DisableDebugInfoPrinting) + MMI->setDebugInfoAvailability(false); + // Emit the version-min deployment target directive if needed. // // FIXME: If we end up with a collection of these sorts of Darwin-specific @@ -296,6 +313,7 @@ bool AsmPrinter::doInitialization(Module &M) { std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo( TM.getTargetTriple().str(), TM.getTargetCPU(), TM.getTargetFeatureString())); + assert(STI && "Unable to create subtarget info"); OutStreamer->AddComment("Start of file scope inline assembly"); OutStreamer->AddBlankLine(); emitInlineAsm(M.getModuleInlineAsm() + "\n", @@ -313,14 +331,21 @@ bool AsmPrinter::doInitialization(Module &M) { CodeViewLineTablesGroupDescription); } if (!EmitCodeView || M.getDwarfVersion()) { - DD = new DwarfDebug(this, &M); - DD->beginModule(); - Handlers.emplace_back(std::unique_ptr<DwarfDebug>(DD), DbgTimerName, - DbgTimerDescription, DWARFGroupName, - DWARFGroupDescription); + if (!DisableDebugInfoPrinting) { + DD = new DwarfDebug(this); + Handlers.emplace_back(std::unique_ptr<DwarfDebug>(DD), DbgTimerName, + DbgTimerDescription, DWARFGroupName, + DWARFGroupDescription); + } } } + if (M.getNamedMetadata(PseudoProbeDescMetadataName)) { + PP = new PseudoProbeHandler(this, &M); + Handlers.emplace_back(std::unique_ptr<PseudoProbeHandler>(PP), PPTimerName, + PPTimerDescription, PPGroupName, PPGroupDescription); + } + switch (MAI->getExceptionHandlingType()) { case ExceptionHandling::SjLj: case ExceptionHandling::DwarfCFI: @@ -368,6 +393,9 @@ bool AsmPrinter::doInitialization(Module &M) { case ExceptionHandling::Wasm: ES = new WasmException(this); break; + case ExceptionHandling::AIX: + ES = new AIXException(this); + break; } if (ES) Handlers.emplace_back(std::unique_ptr<EHStreamer>(ES), EHTimerName, @@ -379,6 +407,13 @@ bool AsmPrinter::doInitialization(Module &M) { Handlers.emplace_back(std::make_unique<WinCFGuard>(this), CFGuardName, CFGuardDescription, DWARFGroupName, DWARFGroupDescription); + + for (const HandlerInfo &HI : Handlers) { + NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, + HI.TimerGroupDescription, TimePassesIsEnabled); + HI.Handler->beginModule(&M); + } + return false; } @@ -449,10 +484,8 @@ MCSymbol *AsmPrinter::getSymbolPreferLocal(const GlobalValue &GV) const { if (TM.getTargetTriple().isOSBinFormatELF() && GV.canBenefitFromLocalAlias()) { const Module &M = *GV.getParent(); if (TM.getRelocationModel() != Reloc::Static && - M.getPIELevel() == PIELevel::Default) - if (GV.isDSOLocal() || (TM.getTargetTriple().isX86() && - GV.getParent()->noSemanticInterposition())) - return getSymbolWithGlobalValueBase(&GV, "$local"); + M.getPIELevel() == PIELevel::Default && GV.isDSOLocal()) + return getSymbolWithGlobalValueBase(&GV, "$local"); } return TM.getSymbol(&GV); } @@ -500,8 +533,8 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { GVSym->redefineIfPossible(); if (GVSym->isDefined() || GVSym->isVariable()) - report_fatal_error("symbol '" + Twine(GVSym->getName()) + - "' is already defined"); + OutContext.reportError(SMLoc(), "symbol '" + Twine(GVSym->getName()) + + "' is already defined"); if (MAI->hasDotTypeDotSizeDirective()) OutStreamer->emitSymbolAttribute(EmittedSym, MCSA_ELF_TypeObject); @@ -812,13 +845,21 @@ static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) { if ((Size = MI.getRestoreSize(TII))) { CommentOS << *Size << "-byte Reload\n"; } else if ((Size = MI.getFoldedRestoreSize(TII))) { - if (*Size) - CommentOS << *Size << "-byte Folded Reload\n"; + if (*Size) { + if (*Size == unsigned(MemoryLocation::UnknownSize)) + CommentOS << "Unknown-size Folded Reload\n"; + else + 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"; + if (*Size) { + if (*Size == unsigned(MemoryLocation::UnknownSize)) + CommentOS << "Unknown-size Folded Spill\n"; + else + CommentOS << *Size << "-byte Folded Spill\n"; + } } // Check for spill-induced copies @@ -877,7 +918,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { // The second operand is only an offset if it's an immediate. bool MemLoc = MI->isIndirectDebugValue(); - int64_t Offset = MemLoc ? MI->getOperand(1).getImm() : 0; + auto Offset = StackOffset::getFixed(MemLoc ? MI->getOperand(1).getImm() : 0); const DIExpression *Expr = MI->getDebugExpression(); if (Expr->getNumElements()) { OS << '['; @@ -916,6 +957,8 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { } else if (MI->getDebugOperand(0).isTargetIndex()) { auto Op = MI->getDebugOperand(0); OS << "!target-index(" << Op.getIndex() << "," << Op.getOffset() << ")"; + // NOTE: Want this comment at start of line, don't emit with AddComment. + AP.OutStreamer->emitRawComment(OS.str()); return true; } else { Register Reg; @@ -941,7 +984,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { } if (MemLoc) - OS << '+' << Offset << ']'; + OS << '+' << Offset.getFixed() << ']'; // NOTE: Want this comment at start of line, don't emit with AddComment. AP.OutStreamer->emitRawComment(OS.str()); @@ -1023,6 +1066,56 @@ void AsmPrinter::emitFrameAlloc(const MachineInstr &MI) { MCConstantExpr::create(FrameOffset, OutContext)); } +/// Returns the BB metadata to be emitted in the .llvm_bb_addr_map section for a +/// given basic block. This can be used to capture more precise profile +/// information. We use the last 3 bits (LSBs) to ecnode the following +/// information: +/// * (1): set if return block (ret or tail call). +/// * (2): set if ends with a tail call. +/// * (3): set if exception handling (EH) landing pad. +/// The remaining bits are zero. +static unsigned getBBAddrMapMetadata(const MachineBasicBlock &MBB) { + const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo(); + return ((unsigned)MBB.isReturnBlock()) | + ((!MBB.empty() && TII->isTailCall(MBB.back())) << 1) | + (MBB.isEHPad() << 2); +} + +void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) { + MCSection *BBAddrMapSection = + getObjFileLowering().getBBAddrMapSection(*MF.getSection()); + assert(BBAddrMapSection && ".llvm_bb_addr_map section is not initialized."); + + const MCSymbol *FunctionSymbol = getFunctionBegin(); + + OutStreamer->PushSection(); + OutStreamer->SwitchSection(BBAddrMapSection); + OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize()); + // Emit the total number of basic blocks in this function. + OutStreamer->emitULEB128IntValue(MF.size()); + // Emit BB Information for each basic block in the funciton. + for (const MachineBasicBlock &MBB : MF) { + const MCSymbol *MBBSymbol = + MBB.isEntryBlock() ? FunctionSymbol : MBB.getSymbol(); + // Emit the basic block offset. + emitLabelDifferenceAsULEB128(MBBSymbol, FunctionSymbol); + // Emit the basic block size. When BBs have alignments, their size cannot + // always be computed from their offsets. + emitLabelDifferenceAsULEB128(MBB.getEndSymbol(), MBBSymbol); + OutStreamer->emitULEB128IntValue(getBBAddrMapMetadata(MBB)); + } + OutStreamer->PopSection(); +} + +void AsmPrinter::emitPseudoProbe(const MachineInstr &MI) { + auto GUID = MI.getOperand(0).getImm(); + auto Index = MI.getOperand(1).getImm(); + auto Type = MI.getOperand(2).getImm(); + auto Attr = MI.getOperand(3).getImm(); + DILocation *DebugLoc = MI.getDebugLoc(); + PP->emitPseudoProbe(GUID, Index, Type, Attr, DebugLoc); +} + void AsmPrinter::emitStackSizeSection(const MachineFunction &MF) { if (!MF.getTarget().Options.EmitStackSizeSection) return; @@ -1069,8 +1162,6 @@ void AsmPrinter::emitFunctionBody() { // Emit target-specific gunk before the function body. emitFunctionBodyStart(); - bool ShouldPrintDebugScopes = MMI->hasDebugInfo(); - if (isVerbose()) { // Get MachineDominatorTree or compute it on the fly if it's unavailable MDT = getAnalysisIfAvailable<MachineDominatorTree>(); @@ -1093,9 +1184,11 @@ void AsmPrinter::emitFunctionBody() { bool HasAnyRealCode = false; int NumInstsInFunction = 0; + bool CanDoExtraAnalysis = ORE->allowExtraAnalysis(DEBUG_TYPE); for (auto &MBB : *MF) { // Print a label for the basic block. emitBasicBlockStart(MBB); + DenseMap<StringRef, unsigned> MnemonicCounts; for (auto &MI : MBB) { // Print the assembly for the instruction. if (!MI.isPosition() && !MI.isImplicitDef() && !MI.isKill() && @@ -1108,13 +1201,10 @@ void AsmPrinter::emitFunctionBody() { if (MCSymbol *S = MI.getPreInstrSymbol()) OutStreamer->emitLabel(S); - if (ShouldPrintDebugScopes) { - for (const HandlerInfo &HI : Handlers) { - NamedRegionTimer T(HI.TimerName, HI.TimerDescription, - HI.TimerGroupName, HI.TimerGroupDescription, - TimePassesIsEnabled); - HI.Handler->beginInstruction(&MI); - } + for (const HandlerInfo &HI : Handlers) { + NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, + HI.TimerGroupDescription, TimePassesIsEnabled); + HI.Handler->beginInstruction(&MI); } if (isVerbose()) @@ -1142,6 +1232,11 @@ void AsmPrinter::emitFunctionBody() { emitInstruction(&MI); } break; + case TargetOpcode::DBG_INSTR_REF: + // This instruction reference will have been resolved to a machine + // location, and a nearby DBG_VALUE created. We can safely ignore + // the instruction reference. + break; case TargetOpcode::DBG_LABEL: if (isVerbose()) { if (!emitDebugLabelComment(&MI, *this)) @@ -1154,8 +1249,18 @@ void AsmPrinter::emitFunctionBody() { case TargetOpcode::KILL: if (isVerbose()) emitKill(&MI, *this); break; + case TargetOpcode::PSEUDO_PROBE: + emitPseudoProbe(MI); + break; default: emitInstruction(&MI); + if (CanDoExtraAnalysis) { + MCInst MCI; + MCI.setOpcode(MI.getOpcode()); + auto Name = OutStreamer->getMnemonic(MCI); + auto I = MnemonicCounts.insert({Name, 0u}); + I.first->second++; + } break; } @@ -1163,54 +1268,69 @@ void AsmPrinter::emitFunctionBody() { if (MCSymbol *S = MI.getPostInstrSymbol()) OutStreamer->emitLabel(S); - if (ShouldPrintDebugScopes) { - for (const HandlerInfo &HI : Handlers) { - NamedRegionTimer T(HI.TimerName, HI.TimerDescription, - HI.TimerGroupName, HI.TimerGroupDescription, - TimePassesIsEnabled); - HI.Handler->endInstruction(); - } + for (const HandlerInfo &HI : Handlers) { + NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, + HI.TimerGroupDescription, TimePassesIsEnabled); + HI.Handler->endInstruction(); } } - // We need a temporary symbol for the end of this basic block, if either we - // have BBLabels enabled and we want to emit size directive for the BBs, or - // if this basic blocks marks the end of a section (except the section - // containing the entry basic block as the end symbol for that section is - // CurrentFnEnd). - MCSymbol *CurrentBBEnd = nullptr; - if ((MAI->hasDotTypeDotSizeDirective() && MF->hasBBLabels()) || - (MBB.isEndSection() && !MBB.sameSection(&MF->front()))) { - CurrentBBEnd = OutContext.createTempSymbol(); - OutStreamer->emitLabel(CurrentBBEnd); - } + // We must emit temporary symbol for the end of this basic block, if either + // we have BBLabels enabled or if this basic blocks marks the end of a + // section (except the section containing the entry basic block as the end + // symbol for that section is CurrentFnEnd). + if (MF->hasBBLabels() || + (MAI->hasDotTypeDotSizeDirective() && MBB.isEndSection() && + !MBB.sameSection(&MF->front()))) + OutStreamer->emitLabel(MBB.getEndSymbol()); - // Helper for emitting the size directive associated with a basic block - // symbol. - auto emitELFSizeDirective = [&](MCSymbol *SymForSize) { - assert(CurrentBBEnd && "Basicblock end symbol not set!"); - const MCExpr *SizeExp = MCBinaryExpr::createSub( - MCSymbolRefExpr::create(CurrentBBEnd, OutContext), - MCSymbolRefExpr::create(SymForSize, OutContext), OutContext); - OutStreamer->emitELFSize(SymForSize, SizeExp); - }; - - // Emit size directive for the size of each basic block, if BBLabels is - // enabled. - if (MAI->hasDotTypeDotSizeDirective() && MF->hasBBLabels()) - emitELFSizeDirective(MBB.getSymbol()); - - // Emit size directive for the size of each basic block section once we - // get to the end of that section. if (MBB.isEndSection()) { + // The size directive for the section containing the entry block is + // handled separately by the function section. if (!MBB.sameSection(&MF->front())) { - if (MAI->hasDotTypeDotSizeDirective()) - emitELFSizeDirective(CurrentSectionBeginSym); + if (MAI->hasDotTypeDotSizeDirective()) { + // Emit the size directive for the basic block section. + const MCExpr *SizeExp = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(MBB.getEndSymbol(), OutContext), + MCSymbolRefExpr::create(CurrentSectionBeginSym, OutContext), + OutContext); + OutStreamer->emitELFSize(CurrentSectionBeginSym, SizeExp); + } MBBSectionRanges[MBB.getSectionIDNum()] = - MBBSectionRange{CurrentSectionBeginSym, CurrentBBEnd}; + MBBSectionRange{CurrentSectionBeginSym, MBB.getEndSymbol()}; } } emitBasicBlockEnd(MBB); + + if (CanDoExtraAnalysis) { + // Skip empty blocks. + if (MBB.empty()) + continue; + + MachineOptimizationRemarkAnalysis R(DEBUG_TYPE, "InstructionMix", + MBB.begin()->getDebugLoc(), &MBB); + + // Generate instruction mix remark. First, sort counts in descending order + // by count and name. + SmallVector<std::pair<StringRef, unsigned>, 128> MnemonicVec; + for (auto &KV : MnemonicCounts) + MnemonicVec.emplace_back(KV.first, KV.second); + + sort(MnemonicVec, [](const std::pair<StringRef, unsigned> &A, + const std::pair<StringRef, unsigned> &B) { + if (A.second > B.second) + return true; + if (A.second == B.second) + return StringRef(A.first) < StringRef(B.first); + return false; + }); + R << "BasicBlock: " << ore::NV("BasicBlock", MBB.getName()) << "\n"; + for (auto &KV : MnemonicVec) { + auto Name = (Twine("INST_") + KV.first.trim()).str(); + R << KV.first << ": " << ore::NV(Name, KV.second) << "\n"; + } + ORE->emit(R); + } } EmittedInsts += NumInstsInFunction; @@ -1297,6 +1417,11 @@ void AsmPrinter::emitFunctionBody() { HI.Handler->endFunction(MF); } + // Emit section containing BB address offsets and their metadata, when + // BB labels are requested for this function. + if (MF->hasBBLabels()) + emitBBAddrMapSection(*MF); + // Emit section containing stack size metadata. emitStackSizeSection(*MF); @@ -1390,16 +1515,7 @@ void AsmPrinter::emitGlobalGOTEquivs() { void AsmPrinter::emitGlobalIndirectSymbol(Module &M, const GlobalIndirectSymbol& GIS) { MCSymbol *Name = getSymbol(&GIS); - - if (GIS.hasExternalLinkage() || !MAI->getWeakRefDirective()) - OutStreamer->emitSymbolAttribute(Name, MCSA_Global); - else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage()) - OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference); - 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) @@ -1408,6 +1524,30 @@ void AsmPrinter::emitGlobalIndirectSymbol(Module &M, IsFunction = CE->getOperand(0)->getType()->getPointerElementType()->isFunctionTy(); + // AIX's assembly directive `.set` is not usable for aliasing purpose, + // so AIX has to use the extra-label-at-definition strategy. At this + // point, all the extra label is emitted, we just have to emit linkage for + // those labels. + if (TM.getTargetTriple().isOSBinFormatXCOFF()) { + assert(!isa<GlobalIFunc>(GIS) && "IFunc is not supported on AIX."); + assert(MAI->hasVisibilityOnlyWithLinkage() && + "Visibility should be handled with emitLinkage() on AIX."); + emitLinkage(&GIS, Name); + // If it's a function, also emit linkage for aliases of function entry + // point. + if (IsFunction) + emitLinkage(&GIS, + getObjFileLowering().getFunctionEntryPointSymbol(&GIS, TM)); + return; + } + + if (GIS.hasExternalLinkage() || !MAI->getWeakRefDirective()) + OutStreamer->emitSymbolAttribute(Name, MCSA_Global); + else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage()) + OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference); + else + assert(GIS.hasLocalLinkage() && "Invalid alias or ifunc linkage"); + // Set the symbol type to function if the alias has a function type. // This affects codegen when the aliasee is not a function. if (IsFunction) @@ -1517,9 +1657,8 @@ bool AsmPrinter::doFinalization(Module &M) { // Variable `Name` is the function descriptor symbol (see above). Get the // function entry point symbol. MCSymbol *FnEntryPointSym = TLOF.getFunctionEntryPointSymbol(&F, TM); - if (cast<MCSymbolXCOFF>(FnEntryPointSym)->hasRepresentedCsectSet()) - // Emit linkage for the function entry point. - emitLinkage(&F, FnEntryPointSym); + // Emit linkage for the function entry point. + emitLinkage(&F, FnEntryPointSym); // Emit linkage for the function descriptor. emitLinkage(&F, Name); @@ -1584,7 +1723,11 @@ bool AsmPrinter::doFinalization(Module &M) { HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->endModule(); } - Handlers.clear(); + + // This deletes all the ephemeral handlers that AsmPrinter added, while + // keeping all the user-added handlers alive until the AsmPrinter is + // destroyed. + Handlers.erase(Handlers.begin() + NumUserHandlers, Handlers.end()); DD = nullptr; // If the target wants to know about weak references, print them all. @@ -1668,51 +1811,6 @@ bool AsmPrinter::doFinalization(Module &M) { if (MCSection *S = MAI->getNonexecutableStackSection(OutContext)) OutStreamer->SwitchSection(S); - if (TM.getTargetTriple().isOSBinFormatCOFF()) { - // Emit /EXPORT: flags for each exported global as necessary. - const auto &TLOF = getObjFileLowering(); - std::string Flags; - - for (const GlobalValue &GV : M.global_values()) { - raw_string_ostream OS(Flags); - TLOF.emitLinkerFlagsForGlobal(OS, &GV); - OS.flush(); - if (!Flags.empty()) { - OutStreamer->SwitchSection(TLOF.getDrectveSection()); - OutStreamer->emitBytes(Flags); - } - Flags.clear(); - } - - // Emit /INCLUDE: flags for each used global as necessary. - if (const auto *LU = M.getNamedGlobal("llvm.used")) { - assert(LU->hasInitializer() && - "expected llvm.used to have an initializer"); - assert(isa<ArrayType>(LU->getValueType()) && - "expected llvm.used to be an array type"); - if (const auto *A = cast<ConstantArray>(LU->getInitializer())) { - for (const Value *Op : A->operands()) { - const auto *GV = cast<GlobalValue>(Op->stripPointerCasts()); - // Global symbols with internal or private linkage are not visible to - // the linker, and thus would cause an error when the linker tried to - // preserve the symbol due to the `/include:` directive. - if (GV->hasLocalLinkage()) - continue; - - raw_string_ostream OS(Flags); - TLOF.emitLinkerFlagsForUsed(OS, GV); - OS.flush(); - - if (!Flags.empty()) { - OutStreamer->SwitchSection(TLOF.getDrectveSection()); - OutStreamer->emitBytes(Flags); - } - Flags.clear(); - } - } - } - } - if (TM.Options.EmitAddrsig) { // Emit address-significance attributes for all globals. OutStreamer->emitAddrsig(); @@ -1756,10 +1854,11 @@ bool AsmPrinter::doFinalization(Module &M) { return false; } -MCSymbol *AsmPrinter::getCurExceptionSym() { - if (!CurExceptionSym) - CurExceptionSym = createTempSymbol("exception"); - return CurExceptionSym; +MCSymbol *AsmPrinter::getMBBExceptionSym(const MachineBasicBlock &MBB) { + auto Res = MBBSectionExceptionSyms.try_emplace(MBB.getSectionIDNum()); + if (Res.second) + Res.first->second = createTempSymbol("exception"); + return Res.first->second; } void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { @@ -1786,13 +1885,13 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { CurrentFnBegin = nullptr; CurrentSectionBeginSym = nullptr; MBBSectionRanges.clear(); - CurExceptionSym = nullptr; + MBBSectionExceptionSyms.clear(); bool NeedsLocalForSize = MAI->needsLocalForSize(); if (F.hasFnAttribute("patchable-function-entry") || F.hasFnAttribute("function-instrument") || F.hasFnAttribute("xray-instruction-threshold") || needFuncLabelsForEHOrDebugInfo(MF) || NeedsLocalForSize || - MF.getTarget().Options.EmitStackSizeSection) { + MF.getTarget().Options.EmitStackSizeSection || MF.hasBBLabels()) { CurrentFnBegin = createTempSymbol("func_begin"); if (NeedsLocalForSize) CurrentFnSymForSize = CurrentFnBegin; @@ -1882,8 +1981,7 @@ void AsmPrinter::emitConstantPool() { unsigned NewOffset = alignTo(Offset, CPE.getAlign()); OutStreamer->emitZeros(NewOffset - Offset); - Type *Ty = CPE.getType(); - Offset = NewOffset + getDataLayout().getTypeAllocSize(Ty); + Offset = NewOffset + CPE.getSizeInBytes(getDataLayout()); OutStreamer->emitLabel(Sym); if (CPE.isMachineConstantPoolEntry()) @@ -2083,47 +2181,50 @@ void AsmPrinter::emitLLVMUsedList(const ConstantArray *InitList) { } } -namespace { - -struct Structor { - int Priority = 0; - Constant *Func = nullptr; - GlobalValue *ComdatKey = nullptr; - - Structor() = default; -}; - -} // end anonymous namespace - -/// EmitXXStructorList - Emit the ctor or dtor list taking into account the init -/// priority. -void AsmPrinter::emitXXStructorList(const DataLayout &DL, const Constant *List, - bool isCtor) { - // Should be an array of '{ i32, void ()*, i8* }' structs. The first value is the - // init priority. - if (!isa<ConstantArray>(List)) return; +void AsmPrinter::preprocessXXStructorList(const DataLayout &DL, + const Constant *List, + SmallVector<Structor, 8> &Structors) { + // Should be an array of '{ i32, void ()*, i8* }' structs. The first value is + // the init priority. + if (!isa<ConstantArray>(List)) + return; // Gather the structors in a form that's convenient for sorting by priority. - SmallVector<Structor, 8> Structors; for (Value *O : cast<ConstantArray>(List)->operands()) { auto *CS = cast<ConstantStruct>(O); if (CS->getOperand(1)->isNullValue()) - break; // Found a null terminator, skip the rest. + break; // Found a null terminator, skip the rest. ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0)); - if (!Priority) continue; // Malformed. + if (!Priority) + continue; // Malformed. Structors.push_back(Structor()); Structor &S = Structors.back(); S.Priority = Priority->getLimitedValue(65535); S.Func = CS->getOperand(1); - if (!CS->getOperand(2)->isNullValue()) + if (!CS->getOperand(2)->isNullValue()) { + if (TM.getTargetTriple().isOSAIX()) + llvm::report_fatal_error( + "associated data of XXStructor list is not yet supported on AIX"); S.ComdatKey = dyn_cast<GlobalValue>(CS->getOperand(2)->stripPointerCasts()); + } } // Emit the function pointers in the target-specific order llvm::stable_sort(Structors, [](const Structor &L, const Structor &R) { return L.Priority < R.Priority; }); +} + +/// EmitXXStructorList - Emit the ctor or dtor list taking into account the init +/// priority. +void AsmPrinter::emitXXStructorList(const DataLayout &DL, const Constant *List, + bool IsCtor) { + SmallVector<Structor, 8> Structors; + preprocessXXStructorList(DL, List, Structors); + if (Structors.empty()) + return; + const Align Align = DL.getPointerPrefAlignment(); for (Structor &S : Structors) { const TargetLoweringObjectFile &Obj = getObjFileLowering(); @@ -2139,8 +2240,9 @@ void AsmPrinter::emitXXStructorList(const DataLayout &DL, const Constant *List, KeySym = getSymbol(GV); } + MCSection *OutputSection = - (isCtor ? Obj.getStaticCtorSection(S.Priority, KeySym) + (IsCtor ? Obj.getStaticCtorSection(S.Priority, KeySym) : Obj.getStaticDtorSection(S.Priority, KeySym)); OutStreamer->SwitchSection(OutputSection); if (OutStreamer->getCurrentSection() != OutStreamer->getPreviousSection()) @@ -2274,12 +2376,25 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { if (const BlockAddress *BA = dyn_cast<BlockAddress>(CV)) return MCSymbolRefExpr::create(GetBlockAddressSymbol(BA), Ctx); + if (const auto *Equiv = dyn_cast<DSOLocalEquivalent>(CV)) + return getObjFileLowering().lowerDSOLocalEquivalent(Equiv, TM); + const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV); if (!CE) { llvm_unreachable("Unknown constant value to lower!"); } switch (CE->getOpcode()) { + case Instruction::AddrSpaceCast: { + const Constant *Op = CE->getOperand(0); + unsigned DstAS = CE->getType()->getPointerAddressSpace(); + unsigned SrcAS = Op->getType()->getPointerAddressSpace(); + if (TM.isNoopAddrSpaceCast(SrcAS, DstAS)) + return lowerConstant(Op); + + // Fallthrough to error. + LLVM_FALLTHROUGH; + } default: { // If the code isn't optimized, there may be outstanding folding // opportunities. Attempt to fold the expression using DataLayout as a @@ -2345,7 +2460,8 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { // // 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())) + if (DL.getTypeAllocSize(Ty).getFixedSize() <= + DL.getTypeAllocSize(Op->getType()).getFixedSize()) return OpExpr; // Otherwise the pointer is smaller than the resultant integer, mask off @@ -2359,18 +2475,25 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { case Instruction::Sub: { GlobalValue *LHSGV; APInt LHSOffset; + DSOLocalEquivalent *DSOEquiv; if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHSGV, LHSOffset, - getDataLayout())) { + getDataLayout(), &DSOEquiv)) { GlobalValue *RHSGV; APInt RHSOffset; if (IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset, getDataLayout())) { const MCExpr *RelocExpr = getObjFileLowering().lowerRelativeReference(LHSGV, RHSGV, TM); - if (!RelocExpr) + if (!RelocExpr) { + const MCExpr *LHSExpr = + MCSymbolRefExpr::create(getSymbol(LHSGV), Ctx); + if (DSOEquiv && + getObjFileLowering().supportDSOLocalEquivalentLowering()) + LHSExpr = + getObjFileLowering().lowerDSOLocalEquivalent(DSOEquiv, TM); RelocExpr = MCBinaryExpr::createSub( - MCSymbolRefExpr::create(getSymbol(LHSGV), Ctx), - MCSymbolRefExpr::create(getSymbol(RHSGV), Ctx), Ctx); + LHSExpr, MCSymbolRefExpr::create(getSymbol(RHSGV), Ctx), Ctx); + } int64_t Addend = (LHSOffset - RHSOffset).getSExtValue(); if (Addend != 0) RelocExpr = MCBinaryExpr::createAdd( @@ -3001,7 +3124,7 @@ static void emitBasicBlockLoopComments(const MachineBasicBlock &MBB, OS.indent(Loop->getLoopDepth()*2-2); OS << "This "; - if (Loop->empty()) + if (Loop->isInnermost()) OS << "Inner "; OS << "Loop Header: Depth=" + Twine(Loop->getLoopDepth()) << '\n'; @@ -3025,6 +3148,16 @@ void AsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) { if (Alignment != Align(1)) emitAlignment(Alignment); + // Switch to a new section if this basic block must begin a section. The + // entry block is always placed in the function section and is handled + // separately. + if (MBB.isBeginSection() && !MBB.isEntryBlock()) { + OutStreamer->SwitchSection( + getObjFileLowering().getSectionForMachineBasicBlock(MF->getFunction(), + MBB, TM)); + CurrentSectionBeginSym = MBB.getSymbol(); + } + // If the block has its address taken, emit any labels that were used to // reference the block. It is possible that there is more than one label // here, because multiple LLVM BB's may have been RAUW'd to this block after @@ -3055,33 +3188,25 @@ void AsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) { emitBasicBlockLoopComments(MBB, MLI, *this); } - if (MBB.pred_empty() || - (!MF->hasBBLabels() && isBlockOnlyReachableByFallthrough(&MBB) && - !MBB.isEHFuncletEntry() && !MBB.hasLabelMustBeEmitted())) { + // Print the main label for the block. + if (shouldEmitLabelForBasicBlock(MBB)) { + if (isVerbose() && MBB.hasLabelMustBeEmitted()) + OutStreamer->AddComment("Label of block must be emitted"); + OutStreamer->emitLabel(MBB.getSymbol()); + } else { 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"); - } - auto *BBSymbol = MBB.getSymbol(); - // Switch to a new section if this basic block must begin a section. - if (MBB.isBeginSection()) { - OutStreamer->SwitchSection( - getObjFileLowering().getSectionForMachineBasicBlock(MF->getFunction(), - MBB, TM)); - CurrentSectionBeginSym = BBSymbol; - } - OutStreamer->emitLabel(BBSymbol); - // With BB sections, each basic block must handle CFI information on its own - // if it begins a section. - if (MBB.isBeginSection()) - for (const HandlerInfo &HI : Handlers) - HI.Handler->beginBasicBlock(MBB); } + + // With BB sections, each basic block must handle CFI information on its own + // if it begins a section (Entry block is handled separately by + // AsmPrinterHandler::beginFunction). + if (MBB.isBeginSection() && !MBB.isEntryBlock()) + for (const HandlerInfo &HI : Handlers) + HI.Handler->beginBasicBlock(MBB); } void AsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) { @@ -3113,15 +3238,26 @@ void AsmPrinter::emitVisibility(MCSymbol *Sym, unsigned Visibility, OutStreamer->emitSymbolAttribute(Sym, Attr); } +bool AsmPrinter::shouldEmitLabelForBasicBlock( + const MachineBasicBlock &MBB) const { + // With `-fbasic-block-sections=`, a label is needed for every non-entry block + // in the labels mode (option `=labels`) and every section beginning in the + // sections mode (`=all` and `=list=`). + if ((MF->hasBBLabels() || MBB.isBeginSection()) && !MBB.isEntryBlock()) + return true; + // A label is needed for any block with at least one predecessor (when that + // predecessor is not the fallthrough predecessor, or if it is an EH funclet + // entry, or if a label is forced). + return !MBB.pred_empty() && + (!isBlockOnlyReachableByFallthrough(&MBB) || MBB.isEHFuncletEntry() || + MBB.hasLabelMustBeEmitted()); +} + /// isBlockOnlyReachableByFallthough - Return true if the basic block has /// exactly one predecessor and the control transfer mechanism between /// the predecessor and this block is a fall-through. bool AsmPrinter:: isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { - // With BasicBlock Sections, beginning of the section is not a fallthrough. - if (MBB->isBeginSection()) - return false; - // If this is a landing pad, it isn't a fall through. If it has no preds, // then nothing falls through to it. if (MBB->isEHPad() || MBB->pred_empty()) @@ -3232,14 +3368,10 @@ void AsmPrinter::emitXRayTable() { MCSection *InstMap = nullptr; MCSection *FnSledIndex = nullptr; const Triple &TT = TM.getTargetTriple(); - // Use PC-relative addresses on all targets except MIPS (MIPS64 cannot use - // PC-relative addresses because R_MIPS_PC64 does not exist). - bool PCRel = !TT.isMIPS(); + // Use PC-relative addresses on all targets. if (TT.isOSBinFormatELF()) { auto LinkedToSym = cast<MCSymbolELF>(CurrentFnSym); auto Flags = ELF::SHF_ALLOC | ELF::SHF_LINK_ORDER; - if (!PCRel) - Flags |= ELF::SHF_WRITE; StringRef GroupName; if (F.hasComdat()) { Flags |= ELF::SHF_GROUP; @@ -3273,25 +3405,20 @@ void AsmPrinter::emitXRayTable() { OutStreamer->SwitchSection(InstMap); OutStreamer->emitLabel(SledsStart); for (const auto &Sled : Sleds) { - if (PCRel) { - MCSymbol *Dot = Ctx.createTempSymbol(); - OutStreamer->emitLabel(Dot); - OutStreamer->emitValueImpl( - MCBinaryExpr::createSub(MCSymbolRefExpr::create(Sled.Sled, Ctx), - MCSymbolRefExpr::create(Dot, Ctx), Ctx), - WordSizeBytes); - OutStreamer->emitValueImpl( - MCBinaryExpr::createSub( - MCSymbolRefExpr::create(CurrentFnBegin, Ctx), - MCBinaryExpr::createAdd( - MCSymbolRefExpr::create(Dot, Ctx), - MCConstantExpr::create(WordSizeBytes, Ctx), Ctx), - Ctx), - WordSizeBytes); - } else { - OutStreamer->emitSymbolValue(Sled.Sled, WordSizeBytes); - OutStreamer->emitSymbolValue(CurrentFnSym, WordSizeBytes); - } + MCSymbol *Dot = Ctx.createTempSymbol(); + OutStreamer->emitLabel(Dot); + OutStreamer->emitValueImpl( + MCBinaryExpr::createSub(MCSymbolRefExpr::create(Sled.Sled, Ctx), + MCSymbolRefExpr::create(Dot, Ctx), Ctx), + WordSizeBytes); + OutStreamer->emitValueImpl( + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(CurrentFnBegin, Ctx), + MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Dot, Ctx), + MCConstantExpr::create(WordSizeBytes, Ctx), + Ctx), + Ctx), + WordSizeBytes); Sled.emit(WordSizeBytes, OutStreamer.get()); } MCSymbol *SledsEnd = OutContext.createTempSymbol("xray_sleds_end", true); @@ -3366,3 +3493,17 @@ uint16_t AsmPrinter::getDwarfVersion() const { void AsmPrinter::setDwarfVersion(uint16_t Version) { OutStreamer->getContext().setDwarfVersion(Version); } + +bool AsmPrinter::isDwarf64() const { + return OutStreamer->getContext().getDwarfFormat() == dwarf::DWARF64; +} + +unsigned int AsmPrinter::getDwarfOffsetByteSize() const { + return dwarf::getDwarfOffsetByteSize( + OutStreamer->getContext().getDwarfFormat()); +} + +unsigned int AsmPrinter::getUnitLengthFieldByteSize() const { + return dwarf::getUnitLengthFieldByteSize( + OutStreamer->getContext().getDwarfFormat()); +} diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index b6a9a9568360..c6e43445e7d0 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" +#include <cstdint> using namespace llvm; #define DEBUG_TYPE "asm-printer" @@ -97,6 +98,12 @@ static const char *DecodeDWARFEncoding(unsigned Encoding) { case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8 : return "indirect pcrel sdata8"; + case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_datarel | + dwarf::DW_EH_PE_sdata4: + return "indirect datarel sdata4"; + case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_datarel | + dwarf::DW_EH_PE_sdata8: + return "indirect datarel sdata8"; } return "<unknown encoding>"; @@ -137,8 +144,7 @@ unsigned AsmPrinter::GetSizeOfEncodedValue(unsigned Encoding) const { } } -void AsmPrinter::emitTTypeReference(const GlobalValue *GV, - unsigned Encoding) const { +void AsmPrinter::emitTTypeReference(const GlobalValue *GV, unsigned Encoding) { if (GV) { const TargetLoweringObjectFile &TLOF = getObjFileLowering(); @@ -154,19 +160,22 @@ void AsmPrinter::emitDwarfSymbolReference(const MCSymbol *Label, if (!ForceOffset) { // On COFF targets, we have to emit the special .secrel32 directive. if (MAI->needsDwarfSectionOffsetDirective()) { + assert(!isDwarf64() && + "emitting DWARF64 is not implemented for COFF targets"); OutStreamer->EmitCOFFSecRel32(Label, /*Offset=*/0); return; } // If the format uses relocations with dwarf, refer to the symbol directly. if (MAI->doesDwarfUseRelocationsAcrossSections()) { - OutStreamer->emitSymbolValue(Label, 4); + OutStreamer->emitSymbolValue(Label, getDwarfOffsetByteSize()); return; } } // Otherwise, emit it as a label difference from the start of the section. - emitLabelDifference(Label, Label->getSection().getBeginSymbol(), 4); + emitLabelDifference(Label, Label->getSection().getBeginSymbol(), + getDwarfOffsetByteSize()); } void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntry S) const { @@ -177,12 +186,38 @@ void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntry S) const { } // Just emit the offset directly; no need for symbol math. - emitInt32(S.Offset); + OutStreamer->emitIntValue(S.Offset, getDwarfOffsetByteSize()); } void AsmPrinter::emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const { - // TODO: Support DWARF64 - emitLabelPlusOffset(Label, Offset, 4); + emitLabelPlusOffset(Label, Offset, getDwarfOffsetByteSize()); +} + +void AsmPrinter::emitDwarfLengthOrOffset(uint64_t Value) const { + assert(isDwarf64() || Value <= UINT32_MAX); + OutStreamer->emitIntValue(Value, getDwarfOffsetByteSize()); +} + +void AsmPrinter::maybeEmitDwarf64Mark() const { + if (!isDwarf64()) + return; + OutStreamer->AddComment("DWARF64 Mark"); + OutStreamer->emitInt32(dwarf::DW_LENGTH_DWARF64); +} + +void AsmPrinter::emitDwarfUnitLength(uint64_t Length, + const Twine &Comment) const { + assert(isDwarf64() || Length <= dwarf::DW_LENGTH_lo_reserved); + maybeEmitDwarf64Mark(); + OutStreamer->AddComment(Comment); + OutStreamer->emitIntValue(Length, getDwarfOffsetByteSize()); +} + +void AsmPrinter::emitDwarfUnitLength(const MCSymbol *Hi, const MCSymbol *Lo, + const Twine &Comment) const { + maybeEmitDwarf64Mark(); + OutStreamer->AddComment(Comment); + OutStreamer->emitAbsoluteSymbolDiff(Hi, Lo, getDwarfOffsetByteSize()); } void AsmPrinter::emitCallSiteOffset(const MCSymbol *Hi, const MCSymbol *Lo, diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 538107cecd8b..4a67b0bc2c4d 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineBasicBlock.h" @@ -146,6 +147,7 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, // we only need MCInstrInfo for asm parsing. We create one unconditionally // because it's not subtarget dependent. std::unique_ptr<MCInstrInfo> MII(TM.getTarget().createMCInstrInfo()); + assert(MII && "Failed to create instruction info"); std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser( STI, *Parser, *MII, MCOptions)); if (!TAP) @@ -232,7 +234,8 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, const char *IDStart = LastEmitted; const char *IDEnd = IDStart; - while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; + while (isDigit(*IDEnd)) + ++IDEnd; unsigned Val; if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) @@ -397,7 +400,8 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, const char *IDStart = LastEmitted; const char *IDEnd = IDStart; - while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; + while (isDigit(*IDEnd)) + ++IDEnd; unsigned Val; if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) @@ -547,22 +551,23 @@ void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const { EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS); // Emit warnings if we use reserved registers on the clobber list, as - // that might give surprising results. - std::vector<std::string> RestrRegs; + // that might lead to undefined behaviour. + SmallVector<Register, 8> RestrRegs; + const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); // Start with the first operand descriptor, and iterate over them. for (unsigned I = InlineAsm::MIOp_FirstOperand, NumOps = MI->getNumOperands(); I < NumOps; ++I) { const MachineOperand &MO = MI->getOperand(I); - if (MO.isImm()) { - unsigned Flags = MO.getImm(); - const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); - if (InlineAsm::getKind(Flags) == InlineAsm::Kind_Clobber && - !TRI->isAsmClobberable(*MF, MI->getOperand(I + 1).getReg())) { - RestrRegs.push_back(TRI->getName(MI->getOperand(I + 1).getReg())); - } - // Skip to one before the next operand descriptor, if it exists. - I += InlineAsm::getNumOperandRegisters(Flags); + if (!MO.isImm()) + continue; + unsigned Flags = MO.getImm(); + if (InlineAsm::getKind(Flags) == InlineAsm::Kind_Clobber) { + Register Reg = MI->getOperand(I + 1).getReg(); + if (!TRI->isAsmClobberable(*MF, Reg)) + RestrRegs.push_back(Reg); } + // Skip to one before the next operand descriptor, if it exists. + I += InlineAsm::getNumOperandRegisters(Flags); } if (!RestrRegs.empty()) { @@ -572,14 +577,15 @@ void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const { SrcMgr.getMemoryBuffer(BufNum)->getBuffer().begin()); std::string Msg = "inline asm clobber list contains reserved registers: "; - for (auto I = RestrRegs.begin(), E = RestrRegs.end(); I != E; I++) { + for (auto I = RestrRegs.begin(), E = RestrRegs.end(); I != E; ++I) { if(I != RestrRegs.begin()) Msg += ", "; - Msg += *I; + Msg += TRI->getName(*I); } - std::string Note = "Reserved registers on the clobber list may not be " - "preserved across the asm statement, and clobbering them may " - "lead to undefined behaviour."; + const char *Note = + "Reserved registers on the clobber list may not be " + "preserved across the asm statement, and clobbering them may " + "lead to undefined behaviour."; SrcMgr.PrintMessage(Loc, SourceMgr::DK_Warning, Msg); SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, Note); } diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h index 90929a217368..5e7db1f2f76c 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h @@ -29,7 +29,7 @@ class ByteStreamer { public: // 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 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 = "", unsigned PadTo = 0) = 0; @@ -41,7 +41,7 @@ private: public: APByteStreamer(AsmPrinter &Asm) : AP(Asm) {} - void EmitInt8(uint8_t Byte, const Twine &Comment) override { + void emitInt8(uint8_t Byte, const Twine &Comment) override { AP.OutStreamer->AddComment(Comment); AP.emitInt8(Byte); } @@ -61,7 +61,7 @@ class HashingByteStreamer final : public ByteStreamer { DIEHash &Hash; public: HashingByteStreamer(DIEHash &H) : Hash(H) {} - void EmitInt8(uint8_t Byte, const Twine &Comment) override { + void emitInt8(uint8_t Byte, const Twine &Comment) override { Hash.update(Byte); } void emitSLEB128(uint64_t DWord, const Twine &Comment) override { @@ -88,7 +88,7 @@ public: std::vector<std::string> &Comments, bool GenerateComments) : Buffer(Buffer), Comments(Comments), GenerateComments(GenerateComments) { } - void EmitInt8(uint8_t Byte, const Twine &Comment) override { + void emitInt8(uint8_t Byte, const Twine &Comment) override { Buffer.push_back(Byte); if (GenerateComments) Comments.push_back(Comment.str()); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 39069e24e061..b15e750aaf85 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -13,15 +13,10 @@ #include "CodeViewDebug.h" #include "DwarfExpression.h" #include "llvm/ADT/APSInt.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/MapVector.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/Triple.h" @@ -40,7 +35,6 @@ #include "llvm/CodeGen/TargetSubtargetInfo.h" #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" @@ -48,14 +42,12 @@ #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" -#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" -#include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" @@ -71,7 +63,6 @@ #include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" @@ -85,12 +76,8 @@ #include <cassert> #include <cctype> #include <cstddef> -#include <cstdint> #include <iterator> #include <limits> -#include <string> -#include <utility> -#include <vector> using namespace llvm; using namespace llvm::codeview; @@ -139,7 +126,9 @@ static CPUType mapArchToCVCPUType(Triple::ArchType Type) { case Triple::ArchType::x86_64: return CPUType::X64; case Triple::ArchType::thumb: - return CPUType::Thumb; + // LLVM currently doesn't support Windows CE and so thumb + // here is indiscriminately mapped to ARMNT specifically. + return CPUType::ARMNT; case Triple::ArchType::aarch64: return CPUType::ARM64; default: @@ -148,28 +137,7 @@ static CPUType mapArchToCVCPUType(Triple::ArchType Type) { } CodeViewDebug::CodeViewDebug(AsmPrinter *AP) - : DebugHandlerBase(AP), OS(*Asm->OutStreamer), TypeTable(Allocator) { - // If module doesn't have named metadata anchors or COFF debug section - // is not available, skip any debug info related stuff. - if (!MMI->getModule()->getNamedMetadata("llvm.dbg.cu") || - !AP->getObjFileLowering().getCOFFDebugSymbolsSection()) { - Asm = nullptr; - MMI->setDebugInfoAvailability(false); - return; - } - // Tell MMI that we have debug info. - MMI->setDebugInfoAvailability(true); - - TheCPU = - mapArchToCVCPUType(Triple(MMI->getModule()->getTargetTriple()).getArch()); - - collectGlobalVariableInfo(); - - // Check if we should emit type record hashes. - ConstantInt *GH = mdconst::extract_or_null<ConstantInt>( - MMI->getModule()->getModuleFlag("CodeViewGHash")); - EmitDebugGlobalHashes = GH && !GH->isZero(); -} + : DebugHandlerBase(AP), OS(*Asm->OutStreamer), TypeTable(Allocator) {} StringRef CodeViewDebug::getFullFilepath(const DIFile *File) { std::string &Filepath = FileToFilepathMap[File]; @@ -507,8 +475,7 @@ void CodeViewDebug::recordLocalVariable(LocalVariable &&Var, static void addLocIfNotPresent(SmallVectorImpl<const DILocation *> &Locs, const DILocation *Loc) { - auto B = Locs.begin(), E = Locs.end(); - if (std::find(B, E, Loc) == E) + if (!llvm::is_contained(Locs, Loc)) Locs.push_back(Loc); } @@ -574,12 +541,31 @@ void CodeViewDebug::emitCodeViewMagicVersion() { OS.emitInt32(COFF::DEBUG_SECTION_MAGIC); } +void CodeViewDebug::beginModule(Module *M) { + // If module doesn't have named metadata anchors or COFF debug section + // is not available, skip any debug info related stuff. + if (!M->getNamedMetadata("llvm.dbg.cu") || + !Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) { + Asm = nullptr; + return; + } + // Tell MMI that we have and need debug info. + MMI->setDebugInfoAvailability(true); + + TheCPU = mapArchToCVCPUType(Triple(M->getTargetTriple()).getArch()); + + collectGlobalVariableInfo(); + + // Check if we should emit type record hashes. + ConstantInt *GH = + mdconst::extract_or_null<ConstantInt>(M->getModuleFlag("CodeViewGHash")); + EmitDebugGlobalHashes = GH && !GH->isZero(); +} + void CodeViewDebug::endModule() { if (!Asm || !MMI->hasDebugInfo()) return; - assert(Asm != nullptr); - // The COFF .debug$S section consists of several subsections, each starting // with a 4-byte control code (e.g. 0xF1, 0xF2, etc) and then a 4-byte length // of the payload followed by the payload itself. The subsections are 4-byte @@ -600,13 +586,18 @@ void CodeViewDebug::endModule() { if (!P.first->isDeclarationForLinker()) emitDebugInfoForFunction(P.first, *P.second); - // Emit global variable debug information. - setCurrentSubprogram(nullptr); - emitDebugInfoForGlobals(); + // Get types used by globals without emitting anything. + // This is meant to collect all static const data members so they can be + // emitted as globals. + collectDebugInfoForGlobals(); // Emit retained types. emitDebugInfoForRetainedTypes(); + // Emit global variable debug information. + setCurrentSubprogram(nullptr); + emitDebugInfoForGlobals(); + // Switch back to the generic .debug$S section after potentially processing // comdat symbol sections. switchToDebugSectionForSymbol(nullptr); @@ -1195,12 +1186,15 @@ void CodeViewDebug::collectVariableInfoFromMFTable( // Get the frame register used and the offset. Register FrameReg; - int FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg); + StackOffset FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg); uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg); + assert(!FrameOffset.getScalable() && + "Frame offsets with a scalable component are not supported"); + // Calculate the label ranges. LocalVarDefRange DefRange = - createDefRangeMem(CVReg, FrameOffset + ExprOffset); + createDefRangeMem(CVReg, FrameOffset.getFixed() + ExprOffset); for (const InsnRange &Range : Scope->getRanges()) { const MCSymbol *Begin = getLabelBeforeInsn(Range.first); @@ -2155,6 +2149,15 @@ void CodeViewDebug::collectMemberInfo(ClassInfo &Info, const DIDerivedType *DDTy) { if (!DDTy->getName().empty()) { Info.Members.push_back({DDTy, 0}); + + // Collect static const data members with values. + if ((DDTy->getFlags() & DINode::FlagStaticMember) == + DINode::FlagStaticMember) { + if (DDTy->getConstant() && (isa<ConstantInt>(DDTy->getConstant()) || + isa<ConstantFP>(DDTy->getConstant()))) + StaticConstMembers.push_back(DDTy); + } + return; } @@ -3057,15 +3060,32 @@ void CodeViewDebug::collectGlobalVariableInfo() { } } +void CodeViewDebug::collectDebugInfoForGlobals() { + for (const CVGlobalVariable &CVGV : GlobalVariables) { + const DIGlobalVariable *DIGV = CVGV.DIGV; + const DIScope *Scope = DIGV->getScope(); + getCompleteTypeIndex(DIGV->getType()); + getFullyQualifiedName(Scope, DIGV->getName()); + } + + for (const CVGlobalVariable &CVGV : ComdatVariables) { + const DIGlobalVariable *DIGV = CVGV.DIGV; + const DIScope *Scope = DIGV->getScope(); + getCompleteTypeIndex(DIGV->getType()); + getFullyQualifiedName(Scope, DIGV->getName()); + } +} + void CodeViewDebug::emitDebugInfoForGlobals() { // First, emit all globals that are not in a comdat in a single symbol // substream. MSVC doesn't like it if the substream is empty, so only open // it if we have at least one global to emit. switchToDebugSectionForSymbol(nullptr); - if (!GlobalVariables.empty()) { + if (!GlobalVariables.empty() || !StaticConstMembers.empty()) { OS.AddComment("Symbol subsection for globals"); MCSymbol *EndLabel = beginCVSubsection(DebugSubsectionKind::Symbols); emitGlobalVariableList(GlobalVariables); + emitStaticConstMemberList(); endCVSubsection(EndLabel); } @@ -3104,6 +3124,61 @@ void CodeViewDebug::emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals) { } } +void CodeViewDebug::emitStaticConstMemberList() { + for (const DIDerivedType *DTy : StaticConstMembers) { + const DIScope *Scope = DTy->getScope(); + + APSInt Value; + if (const ConstantInt *CI = + dyn_cast_or_null<ConstantInt>(DTy->getConstant())) + Value = APSInt(CI->getValue(), + DebugHandlerBase::isUnsignedDIType(DTy->getBaseType())); + else if (const ConstantFP *CFP = + dyn_cast_or_null<ConstantFP>(DTy->getConstant())) + Value = APSInt(CFP->getValueAPF().bitcastToAPInt(), true); + else + llvm_unreachable("cannot emit a constant without a value"); + + std::string QualifiedName = getFullyQualifiedName(Scope, DTy->getName()); + + MCSymbol *SConstantEnd = beginSymbolRecord(SymbolKind::S_CONSTANT); + OS.AddComment("Type"); + OS.emitInt32(getTypeIndex(DTy->getBaseType()).getIndex()); + 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(Value)); + StringRef SRef((char *)Data, Writer.getOffset()); + OS.emitBinaryData(SRef); + + OS.AddComment("Name"); + emitNullTerminatedSymbolName(OS, QualifiedName); + endSymbolRecord(SConstantEnd); + } +} + +static bool isFloatDIType(const DIType *Ty) { + if (isa<DICompositeType>(Ty)) + return false; + + if (auto *DTy = dyn_cast<DIDerivedType>(Ty)) { + dwarf::Tag T = (dwarf::Tag)Ty->getTag(); + if (T == dwarf::DW_TAG_pointer_type || + T == dwarf::DW_TAG_ptr_to_member_type || + T == dwarf::DW_TAG_reference_type || + T == dwarf::DW_TAG_rvalue_reference_type) + return false; + assert(DTy->getBaseType() && "Expected valid base type"); + return isFloatDIType(DTy->getBaseType()); + } + + auto *BTy = cast<DIBasicType>(Ty); + return (BTy->getEncoding() == dwarf::DW_ATE_float); +} + void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) { const DIGlobalVariable *DIGV = CVGV.DIGV; @@ -3139,7 +3214,12 @@ void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) { 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); + + // Use unsigned for floats. + bool isUnsigned = isFloatDIType(DIGV->getType()) + ? true + : DebugHandlerBase::isUnsignedDIType(DIGV->getType()); + APSInt Value(APInt(/*BitWidth=*/64, DIE->getElement(1)), isUnsigned); MCSymbol *SConstantEnd = beginSymbolRecord(SymbolKind::S_CONSTANT); OS.AddComment("Type"); @@ -3150,7 +3230,7 @@ void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) { uint8_t data[10]; BinaryStreamWriter Writer(data, llvm::support::endianness::little); CodeViewRecordIO IO(Writer); - cantFail(IO.mapEncodedInteger(Val)); + cantFail(IO.mapEncodedInteger(Value)); StringRef SRef((char *)data, Writer.getOffset()); OS.emitBinaryData(SRef); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index 82f0293874d0..9eee5492bc81 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -203,6 +203,9 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { // Array of non-COMDAT global variables. SmallVector<CVGlobalVariable, 1> GlobalVariables; + /// List of static const data members to be emitted as S_CONSTANTs. + SmallVector<const DIDerivedType *, 4> StaticConstMembers; + /// The set of comdat .debug$S sections that we've seen so far. Each section /// must start with a magic version number that must only be emitted once. /// This set tracks which sections we've already opened. @@ -227,10 +230,6 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void calculateRanges(LocalVariable &Var, const DbgValueHistoryMap::Entries &Entries); - static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children, - const FunctionInfo &FI, - const InlineSite &Site); - /// Remember some debug info about each function. Keep it in a stable order to /// emit at the end of the TU. MapVector<const Function *, std::unique_ptr<FunctionInfo>> FnDebugInfo; @@ -313,9 +312,11 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void emitDebugInfoForUDTs( const std::vector<std::pair<std::string, const DIType *>> &UDTs); + void collectDebugInfoForGlobals(); void emitDebugInfoForGlobals(); void emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals); void emitDebugInfoForGlobal(const CVGlobalVariable &CVGV); + void emitStaticConstMemberList(); /// 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 @@ -464,6 +465,8 @@ protected: public: CodeViewDebug(AsmPrinter *AP); + void beginModule(Module *M) override; + void setSymbolSize(const MCSymbol *, uint64_t) override {} /// Emit the COFF section that holds the line table information. diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIE.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIE.cpp index edf82fbed650..39b0b027c765 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIE.cpp @@ -194,7 +194,7 @@ DIEAbbrev DIE::generateAbbrev() const { return Abbrev; } -unsigned DIE::getDebugSectionOffset() const { +uint64_t DIE::getDebugSectionOffset() const { const DIEUnit *Unit = getUnit(); assert(Unit && "DIE must be owned by a DIEUnit to get its absolute offset"); return Unit->getDebugSectionOffset() + getOffset(); @@ -313,10 +313,8 @@ unsigned DIE::computeOffsetsAndAbbrevs(const AsmPrinter *AP, //===----------------------------------------------------------------------===// // DIEUnit Implementation //===----------------------------------------------------------------------===// -DIEUnit::DIEUnit(uint16_t V, uint8_t A, dwarf::Tag UnitTag) - : Die(UnitTag), Section(nullptr), Offset(0), Length(0), Version(V), - AddrSize(A) -{ +DIEUnit::DIEUnit(dwarf::Tag UnitTag) + : Die(UnitTag), Section(nullptr), Offset(0) { Die.Owner = this; assert((UnitTag == dwarf::DW_TAG_compile_unit || UnitTag == dwarf::DW_TAG_skeleton_unit || @@ -430,10 +428,10 @@ void DIEInteger::emitValue(const AsmPrinter *Asm, dwarf::Form Form) const { /// SizeOf - Determine size of integer value in bytes. /// unsigned DIEInteger::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { - dwarf::FormParams Params = {0, 0, dwarf::DWARF32}; - if (AP) - Params = {AP->getDwarfVersion(), uint8_t(AP->getPointerSize()), - AP->OutStreamer->getContext().getDwarfFormat()}; + assert(AP && "AsmPrinter is required to set FormParams"); + dwarf::FormParams Params = {AP->getDwarfVersion(), + uint8_t(AP->getPointerSize()), + AP->OutStreamer->getContext().getDwarfFormat()}; if (Optional<uint8_t> FixedSize = dwarf::getFixedFormByteSize(Form, Params)) return *FixedSize; @@ -472,10 +470,16 @@ void DIEExpr::emitValue(const AsmPrinter *AP, dwarf::Form Form) const { /// SizeOf - Determine size of expression value in bytes. /// unsigned DIEExpr::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { - if (Form == dwarf::DW_FORM_data4) return 4; - if (Form == dwarf::DW_FORM_sec_offset) return 4; - if (Form == dwarf::DW_FORM_strp) return 4; - return AP->getPointerSize(); + switch (Form) { + case dwarf::DW_FORM_data4: + return 4; + case dwarf::DW_FORM_data8: + return 8; + case dwarf::DW_FORM_sec_offset: + return AP->getDwarfOffsetByteSize(); + default: + llvm_unreachable("DIE Value form not supported yet"); + } } LLVM_DUMP_METHOD @@ -488,19 +492,26 @@ void DIEExpr::print(raw_ostream &O) const { O << "Expr: " << *Expr; } /// EmitValue - Emit label value. /// void DIELabel::emitValue(const AsmPrinter *AP, dwarf::Form Form) const { - AP->emitLabelReference( - Label, SizeOf(AP, Form), - Form == dwarf::DW_FORM_strp || Form == dwarf::DW_FORM_sec_offset || - Form == dwarf::DW_FORM_ref_addr || Form == dwarf::DW_FORM_data4); + bool IsSectionRelative = Form != dwarf::DW_FORM_addr; + AP->emitLabelReference(Label, SizeOf(AP, Form), IsSectionRelative); } /// SizeOf - Determine size of label value in bytes. /// unsigned DIELabel::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { - if (Form == dwarf::DW_FORM_data4) return 4; - if (Form == dwarf::DW_FORM_sec_offset) return 4; - if (Form == dwarf::DW_FORM_strp) return 4; - return AP->MAI->getCodePointerSize(); + switch (Form) { + case dwarf::DW_FORM_data4: + return 4; + case dwarf::DW_FORM_data8: + return 8; + case dwarf::DW_FORM_sec_offset: + case dwarf::DW_FORM_strp: + return AP->getDwarfOffsetByteSize(); + case dwarf::DW_FORM_addr: + return AP->MAI->getCodePointerSize(); + default: + llvm_unreachable("DIE Value form not supported yet"); + } } LLVM_DUMP_METHOD @@ -536,10 +547,16 @@ void DIEDelta::emitValue(const AsmPrinter *AP, dwarf::Form Form) const { /// SizeOf - Determine size of delta value in bytes. /// unsigned DIEDelta::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { - if (Form == dwarf::DW_FORM_data4) return 4; - if (Form == dwarf::DW_FORM_sec_offset) return 4; - if (Form == dwarf::DW_FORM_strp) return 4; - return AP->MAI->getCodePointerSize(); + switch (Form) { + case dwarf::DW_FORM_data4: + return 4; + case dwarf::DW_FORM_data8: + return 8; + case dwarf::DW_FORM_sec_offset: + return AP->getDwarfOffsetByteSize(); + default: + llvm_unreachable("DIE Value form not supported yet"); + } } LLVM_DUMP_METHOD @@ -645,7 +662,7 @@ void DIEEntry::emitValue(const AsmPrinter *AP, dwarf::Form Form) const { case dwarf::DW_FORM_ref_addr: { // Get the absolute offset for this DIE within the debug info/types section. - unsigned Addr = Entry->getDebugSectionOffset(); + uint64_t Addr = Entry->getDebugSectionOffset(); if (const MCSymbol *SectionSym = Entry->getUnit()->getCrossSectionRelativeBaseAddress()) { AP->emitLabelPlusOffset(SectionSym, Addr, SizeOf(AP, Form), true); @@ -802,13 +819,24 @@ void DIEBlock::print(raw_ostream &O) const { //===----------------------------------------------------------------------===// unsigned DIELocList::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { - if (Form == dwarf::DW_FORM_loclistx) + switch (Form) { + case dwarf::DW_FORM_loclistx: return getULEB128Size(Index); - if (Form == dwarf::DW_FORM_data4) - return 4; - if (Form == dwarf::DW_FORM_sec_offset) + case dwarf::DW_FORM_data4: + assert(!AP->isDwarf64() && + "DW_FORM_data4 is not suitable to emit a pointer to a location list " + "in the 64-bit DWARF format"); return 4; - return AP->MAI->getCodePointerSize(); + case dwarf::DW_FORM_data8: + assert(AP->isDwarf64() && + "DW_FORM_data8 is not suitable to emit a pointer to a location list " + "in the 32-bit DWARF format"); + return 8; + case dwarf::DW_FORM_sec_offset: + return AP->getDwarfOffsetByteSize(); + default: + llvm_unreachable("DIE Value form not supported yet"); + } } /// EmitValue - Emit label value. diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp index f26ef63eedec..da9997efc01f 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -12,6 +12,7 @@ #include "DIEHash.h" #include "ByteStreamer.h" +#include "DwarfCompileUnit.h" #include "DwarfDebug.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" @@ -214,7 +215,15 @@ void DIEHash::hashDIEEntry(dwarf::Attribute Attribute, dwarf::Tag Tag, // all of the data is going to be added as integers. void DIEHash::hashBlockData(const DIE::const_value_range &Values) { for (const auto &V : Values) - Hash.update((uint64_t)V.getDIEInteger().getValue()); + if (V.getType() == DIEValue::isBaseTypeRef) { + const DIE &C = + *CU->ExprRefedBaseTypes[V.getDIEBaseTypeRef().getIndex()].Die; + StringRef Name = getDIEStringAttr(C, dwarf::DW_AT_name); + assert(!Name.empty() && + "Base types referenced from DW_OP_convert should have a name"); + hashNestedType(C, Name); + } else + Hash.update((uint64_t)V.getDIEInteger().getValue()); } // Hash the contents of a loclistptr class. diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIEHash.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIEHash.h index 1a69f6772873..29e1da4c5d60 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIEHash.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DIEHash.h @@ -31,7 +31,8 @@ class DIEHash { }; public: - DIEHash(AsmPrinter *A = nullptr) : AP(A) {} + DIEHash(AsmPrinter *A = nullptr, DwarfCompileUnit *CU = nullptr) + : AP(A), CU(CU) {} /// Computes the CU signature. uint64_t computeCUSignature(StringRef DWOName, const DIE &Die); @@ -101,6 +102,7 @@ private: private: MD5 Hash; AsmPrinter *AP; + DwarfCompileUnit *CU; DenseMap<const DIE *, unsigned> Numbering; }; } diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp index 584b7614915d..1c9131edab83 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -8,9 +8,11 @@ #include "llvm/CodeGen/DbgEntityHistoryCalculator.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" @@ -51,6 +53,37 @@ static Register isDescribedByReg(const MachineInstr &MI) { : Register(); } +void InstructionOrdering::initialize(const MachineFunction &MF) { + // We give meta instructions the same ordinal as the preceding instruction + // because this class is written for the task of comparing positions of + // variable location ranges against scope ranges. To reflect what we'll see + // in the binary, when we look at location ranges we must consider all + // DBG_VALUEs between two real instructions at the same position. And a + // scope range which ends on a meta instruction should be considered to end + // at the last seen real instruction. E.g. + // + // 1 instruction p Both the variable location for x and for y start + // 1 DBG_VALUE for "x" after instruction p so we give them all the same + // 1 DBG_VALUE for "y" number. If a scope range ends at DBG_VALUE for "y", + // 2 instruction q we should treat it as ending after instruction p + // because it will be the last real instruction in the + // range. DBG_VALUEs at or after this position for + // variables declared in the scope will have no effect. + clear(); + unsigned Position = 0; + for (const MachineBasicBlock &MBB : MF) + for (const MachineInstr &MI : MBB) + InstNumberMap[&MI] = MI.isMetaInstruction() ? Position : ++Position; +} + +bool InstructionOrdering::isBefore(const MachineInstr *A, + const MachineInstr *B) const { + assert(A->getParent() && B->getParent() && "Operands must have a parent"); + assert(A->getMF() == B->getMF() && + "Operands must be in the same MachineFunction"); + return InstNumberMap.lookup(A) < InstNumberMap.lookup(B); +} + bool DbgValueHistoryMap::startDbgValue(InlinedEntity Var, const MachineInstr &MI, EntryIndex &NewIndex) { @@ -90,6 +123,156 @@ void DbgValueHistoryMap::Entry::endEntry(EntryIndex Index) { EndIndex = Index; } +/// Check if the instruction range [StartMI, EndMI] intersects any instruction +/// range in Ranges. EndMI can be nullptr to indicate that the range is +/// unbounded. Assumes Ranges is ordered and disjoint. Returns true and points +/// to the first intersecting scope range if one exists. +static Optional<ArrayRef<InsnRange>::iterator> +intersects(const MachineInstr *StartMI, const MachineInstr *EndMI, + const ArrayRef<InsnRange> &Ranges, + const InstructionOrdering &Ordering) { + for (auto RangesI = Ranges.begin(), RangesE = Ranges.end(); + RangesI != RangesE; ++RangesI) { + if (EndMI && Ordering.isBefore(EndMI, RangesI->first)) + return None; + if (EndMI && !Ordering.isBefore(RangesI->second, EndMI)) + return RangesI; + if (Ordering.isBefore(StartMI, RangesI->second)) + return RangesI; + } + return None; +} + +void DbgValueHistoryMap::trimLocationRanges( + const MachineFunction &MF, LexicalScopes &LScopes, + const InstructionOrdering &Ordering) { + // The indices of the entries we're going to remove for each variable. + SmallVector<EntryIndex, 4> ToRemove; + // Entry reference count for each variable. Clobbers left with no references + // will be removed. + SmallVector<int, 4> ReferenceCount; + // Entries reference other entries by index. Offsets is used to remap these + // references if any entries are removed. + SmallVector<size_t, 4> Offsets; + + for (auto &Record : VarEntries) { + auto &HistoryMapEntries = Record.second; + if (HistoryMapEntries.empty()) + continue; + + InlinedEntity Entity = Record.first; + const DILocalVariable *LocalVar = cast<DILocalVariable>(Entity.first); + + LexicalScope *Scope = nullptr; + if (const DILocation *InlinedAt = Entity.second) { + Scope = LScopes.findInlinedScope(LocalVar->getScope(), InlinedAt); + } else { + Scope = LScopes.findLexicalScope(LocalVar->getScope()); + // Ignore variables for non-inlined function level scopes. The scope + // ranges (from scope->getRanges()) will not include any instructions + // before the first one with a debug-location, which could cause us to + // incorrectly drop a location. We could introduce special casing for + // these variables, but it doesn't seem worth it because no out-of-scope + // locations have been observed for variables declared in function level + // scopes. + if (Scope && + (Scope->getScopeNode() == Scope->getScopeNode()->getSubprogram()) && + (Scope->getScopeNode() == LocalVar->getScope())) + continue; + } + + // If there is no scope for the variable then something has probably gone + // wrong. + if (!Scope) + continue; + + ToRemove.clear(); + // Zero the reference counts. + ReferenceCount.assign(HistoryMapEntries.size(), 0); + // Index of the DBG_VALUE which marks the start of the current location + // range. + EntryIndex StartIndex = 0; + ArrayRef<InsnRange> ScopeRanges(Scope->getRanges()); + for (auto EI = HistoryMapEntries.begin(), EE = HistoryMapEntries.end(); + EI != EE; ++EI, ++StartIndex) { + // Only DBG_VALUEs can open location ranges so skip anything else. + if (!EI->isDbgValue()) + continue; + + // Index of the entry which closes this range. + EntryIndex EndIndex = EI->getEndIndex(); + // If this range is closed bump the reference count of the closing entry. + if (EndIndex != NoEntry) + ReferenceCount[EndIndex] += 1; + // Skip this location range if the opening entry is still referenced. It + // may close a location range which intersects a scope range. + // TODO: We could be 'smarter' and trim these kinds of ranges such that + // they do not leak out of the scope ranges if they partially overlap. + if (ReferenceCount[StartIndex] > 0) + continue; + + const MachineInstr *StartMI = EI->getInstr(); + const MachineInstr *EndMI = EndIndex != NoEntry + ? HistoryMapEntries[EndIndex].getInstr() + : nullptr; + // Check if the location range [StartMI, EndMI] intersects with any scope + // range for the variable. + if (auto R = intersects(StartMI, EndMI, ScopeRanges, Ordering)) { + // Adjust ScopeRanges to exclude ranges which subsequent location ranges + // cannot possibly intersect. + ScopeRanges = ArrayRef<InsnRange>(R.getValue(), ScopeRanges.end()); + } else { + // If the location range does not intersect any scope range then the + // DBG_VALUE which opened this location range is usless, mark it for + // removal. + ToRemove.push_back(StartIndex); + // Because we'll be removing this entry we need to update the reference + // count of the closing entry, if one exists. + if (EndIndex != NoEntry) + ReferenceCount[EndIndex] -= 1; + } + } + + // If there is nothing to remove then jump to next variable. + if (ToRemove.empty()) + continue; + + // Mark clobbers that will no longer close any location ranges for removal. + for (size_t i = 0; i < HistoryMapEntries.size(); ++i) + if (ReferenceCount[i] <= 0 && HistoryMapEntries[i].isClobber()) + ToRemove.push_back(i); + + llvm::sort(ToRemove); + + // Build an offset map so we can update the EndIndex of the remaining + // entries. + // Zero the offsets. + Offsets.assign(HistoryMapEntries.size(), 0); + size_t CurOffset = 0; + auto ToRemoveItr = ToRemove.begin(); + for (size_t EntryIdx = *ToRemoveItr; EntryIdx < HistoryMapEntries.size(); + ++EntryIdx) { + // Check if this is an entry which will be removed. + if (ToRemoveItr != ToRemove.end() && *ToRemoveItr == EntryIdx) { + ++ToRemoveItr; + ++CurOffset; + } + Offsets[EntryIdx] = CurOffset; + } + + // Update the EndIndex of the entries to account for those which will be + // removed. + for (auto &Entry : HistoryMapEntries) + if (Entry.isClosed()) + Entry.EndIndex -= Offsets[Entry.EndIndex]; + + // Now actually remove the entries. Iterate backwards so that our remaining + // ToRemove indices are valid after each erase. + for (auto Itr = ToRemove.rbegin(), End = ToRemove.rend(); Itr != End; ++Itr) + HistoryMapEntries.erase(HistoryMapEntries.begin() + *Itr); + } +} + void DbgLabelInstrMap::addInstr(InlinedEntity Label, const MachineInstr &MI) { assert(MI.isDebugLabel() && "not a DBG_LABEL"); LabelInstr[Label] = &MI; @@ -234,7 +417,7 @@ void llvm::calculateDbgEntityHistory(const MachineFunction *MF, DbgValueHistoryMap &DbgValues, DbgLabelInstrMap &DbgLabels) { const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); - unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); + Register SP = TLI->getStackPointerRegisterToSaveRestore(); Register FrameReg = TRI->getFrameRegister(*MF); RegDescribedVarsMap RegVars; DbgValueEntriesMap LiveEntries; diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp index 880791a06d93..68a4bfba42a7 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -21,11 +21,16 @@ #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DebugInfo.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; #define DEBUG_TYPE "dwarfdebug" +/// If true, we drop variable location ranges which exist entirely outside the +/// variable's lexical scope instruction ranges. +static cl::opt<bool> TrimVarLocs("trim-var-locs", cl::Hidden, cl::init(true)); + Optional<DbgVariableLocation> DbgVariableLocation::extractFromMachineInstruction( const MachineInstr &Instruction) { @@ -86,6 +91,11 @@ DbgVariableLocation::extractFromMachineInstruction( DebugHandlerBase::DebugHandlerBase(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {} +void DebugHandlerBase::beginModule(Module *M) { + if (M->debug_compile_units().empty()) + Asm = nullptr; +} + // Each LexicalScope has first instruction and last instruction to mark // beginning and end of a scope respectively. Create an inverse map that list // scopes starts (and ends) with an instruction. One instruction may start (or @@ -153,6 +163,54 @@ uint64_t DebugHandlerBase::getBaseTypeSize(const DIType *Ty) { return getBaseTypeSize(BaseType); } +bool DebugHandlerBase::isUnsignedDIType(const DIType *Ty) { + if (auto *CTy = dyn_cast<DICompositeType>(Ty)) { + // FIXME: Enums without a fixed underlying type have unknown signedness + // here, leading to incorrectly emitted constants. + if (CTy->getTag() == dwarf::DW_TAG_enumeration_type) + return false; + + // (Pieces of) aggregate types that get hacked apart by SROA may be + // represented by a constant. Encode them as unsigned bytes. + return true; + } + + if (auto *DTy = dyn_cast<DIDerivedType>(Ty)) { + dwarf::Tag T = (dwarf::Tag)Ty->getTag(); + // Encode pointer constants as unsigned bytes. This is used at least for + // null pointer constant emission. + // FIXME: reference and rvalue_reference /probably/ shouldn't be allowed + // here, but accept them for now due to a bug in SROA producing bogus + // dbg.values. + if (T == dwarf::DW_TAG_pointer_type || + T == dwarf::DW_TAG_ptr_to_member_type || + T == dwarf::DW_TAG_reference_type || + T == dwarf::DW_TAG_rvalue_reference_type) + return true; + 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); + assert(DTy->getBaseType() && "Expected valid base type"); + return isUnsignedDIType(DTy->getBaseType()); + } + + auto *BTy = cast<DIBasicType>(Ty); + unsigned Encoding = BTy->getEncoding(); + assert((Encoding == dwarf::DW_ATE_unsigned || + Encoding == dwarf::DW_ATE_unsigned_char || + Encoding == dwarf::DW_ATE_signed || + Encoding == dwarf::DW_ATE_signed_char || + Encoding == dwarf::DW_ATE_float || Encoding == dwarf::DW_ATE_UTF || + Encoding == dwarf::DW_ATE_boolean || + (Ty->getTag() == dwarf::DW_TAG_unspecified_type && + Ty->getName() == "decltype(nullptr)")) && + "Unsupported encoding"); + return Encoding == dwarf::DW_ATE_unsigned || + Encoding == dwarf::DW_ATE_unsigned_char || + Encoding == dwarf::DW_ATE_UTF || Encoding == dwarf::DW_ATE_boolean || + Ty->getTag() == dwarf::DW_TAG_unspecified_type; +} + static bool hasDebugInfo(const MachineModuleInfo *MMI, const MachineFunction *MF) { if (!MMI->hasDebugInfo()) @@ -191,6 +249,9 @@ void DebugHandlerBase::beginFunction(const MachineFunction *MF) { assert(DbgLabels.empty() && "DbgLabels map wasn't cleaned!"); calculateDbgEntityHistory(MF, Asm->MF->getSubtarget().getRegisterInfo(), DbgValues, DbgLabels); + InstOrdering.initialize(*MF); + if (TrimVarLocs) + DbgValues.trimLocationRanges(*MF, LScopes, InstOrdering); LLVM_DEBUG(DbgValues.dump()); // Request labels for the full history. @@ -212,10 +273,16 @@ void DebugHandlerBase::beginFunction(const MachineFunction *MF) { // 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. + // FIXME: If the first mention of an argument is in a unique section basic + // block, we cannot always assign the CurrentFnBeginLabel as it lies in a + // different section. Temporarily, we disable generating loc list + // information or DW_AT_const_value when the block is in a different + // section. const DILocalVariable *DIVar = Entries.front().getInstr()->getDebugVariable(); if (DIVar->isParameter() && - getDISubprogram(DIVar->getScope())->describes(&MF->getFunction())) { + getDISubprogram(DIVar->getScope())->describes(&MF->getFunction()) && + Entries.front().getInstr()->getParent()->sameSection(&MF->front())) { if (!IsDescribedByReg(Entries.front().getInstr())) LabelsBeforeInsn[Entries.front().getInstr()] = Asm->getFunctionBegin(); if (Entries.front().getInstr()->getDebugExpression()->isFragment()) { @@ -262,7 +329,7 @@ void DebugHandlerBase::beginFunction(const MachineFunction *MF) { } void DebugHandlerBase::beginInstruction(const MachineInstr *MI) { - if (!MMI->hasDebugInfo()) + if (!Asm || !MMI->hasDebugInfo()) return; assert(CurMI == nullptr); @@ -288,7 +355,7 @@ void DebugHandlerBase::beginInstruction(const MachineInstr *MI) { } void DebugHandlerBase::endInstruction() { - if (!MMI->hasDebugInfo()) + if (!Asm || !MMI->hasDebugInfo()) return; assert(CurMI != nullptr); @@ -320,12 +387,13 @@ void DebugHandlerBase::endInstruction() { } void DebugHandlerBase::endFunction(const MachineFunction *MF) { - if (hasDebugInfo(MMI, MF)) + if (Asm && hasDebugInfo(MMI, MF)) endFunctionImpl(MF); DbgValues.clear(); DbgLabels.clear(); LabelsBeforeInsn.clear(); LabelsAfterInsn.clear(); + InstOrdering.clear(); } void DebugHandlerBase::beginBasicBlock(const MachineBasicBlock &MBB) { diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp index 11ed1062f77e..c20ac6040aef 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -81,8 +81,9 @@ void DwarfCFIException::endModule() { } } -static MCSymbol *getExceptionSym(AsmPrinter *Asm) { - return Asm->getCurExceptionSym(); +static MCSymbol *getExceptionSym(AsmPrinter *Asm, + const MachineBasicBlock *MBB) { + return Asm->getMBBExceptionSym(*MBB); } void DwarfCFIException::beginFunction(const MachineFunction *MF) { @@ -161,7 +162,7 @@ void DwarfCFIException::beginFragment(const MachineBasicBlock *MBB, // Provide LSDA information. if (shouldEmitLSDA) - Asm->OutStreamer->emitCFILsda(ESP(Asm), TLOF.getLSDAEncoding()); + Asm->OutStreamer->emitCFILsda(ESP(Asm, MBB), TLOF.getLSDAEncoding()); } /// endFunction - Gather and emit post-function exception information. diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 296c380ae550..befc4bba19a2 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -12,18 +12,12 @@ #include "DwarfCompileUnit.h" #include "AddressPool.h" -#include "DwarfDebug.h" #include "DwarfExpression.h" -#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" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" -#include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" @@ -32,22 +26,16 @@ #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" -#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolWasm.h" #include "llvm/MC/MachineLocation.h" -#include "llvm/Support/Casting.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" -#include <algorithm> -#include <cassert> -#include <cstdint> #include <iterator> -#include <memory> #include <string> #include <utility> @@ -117,7 +105,7 @@ unsigned DwarfCompileUnit::getOrCreateSourceID(const DIFile *File) { return Asm->OutStreamer->emitDwarfFileDirective(0, "", "", None, None, CUID); return Asm->OutStreamer->emitDwarfFileDirective( - 0, File->getDirectory(), File->getFilename(), getMD5AsBytes(File), + 0, File->getDirectory(), File->getFilename(), DD->getMD5AsBytes(File), File->getSource(), CUID); } @@ -260,7 +248,9 @@ void DwarfCompileUnit::addLocationAttribute( : dwarf::DW_OP_const8u); // 2) containing the (relocated) offset of the TLS variable // within the module's TLS block. - addExpr(*Loc, dwarf::DW_FORM_udata, + addExpr(*Loc, + PointerSize == 4 ? dwarf::DW_FORM_data4 + : dwarf::DW_FORM_data8, Asm->getObjFileLowering().getDebugThreadLocalSymbol(Sym)); } else { addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_GNU_const_index); @@ -432,7 +422,10 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) { // FIXME: duplicated from Target/WebAssembly/WebAssembly.h // don't want to depend on target specific headers in this code? const unsigned TI_GLOBAL_RELOC = 3; - if (FrameBase.Location.WasmLoc.Kind == TI_GLOBAL_RELOC) { + // FIXME: when writing dwo, we need to avoid relocations. Probably + // the "right" solution is to treat globals the way func and data symbols + // are (with entries in .debug_addr). + if (FrameBase.Location.WasmLoc.Kind == TI_GLOBAL_RELOC && !isDwoUnit()) { // These need to be relocatable. assert(FrameBase.Location.WasmLoc.Index == 0); // Only SP so far. auto SPSym = cast<MCSymbolWasm>( @@ -449,8 +442,8 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) { true}); DIELoc *Loc = new (DIEValueAllocator) DIELoc; addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_WASM_location); - addSInt(*Loc, dwarf::DW_FORM_sdata, FrameBase.Location.WasmLoc.Kind); - addLabel(*Loc, dwarf::DW_FORM_udata, SPSym); + addSInt(*Loc, dwarf::DW_FORM_sdata, TI_GLOBAL_RELOC); + addLabel(*Loc, dwarf::DW_FORM_data4, SPSym); DD->addArangeLabel(SymbolCU(this, SPSym)); addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_stack_value); addBlock(*SPDie, dwarf::DW_AT_frame_base, Loc); @@ -565,7 +558,12 @@ void DwarfCompileUnit::addScopeRangeList(DIE &ScopeDIE, void DwarfCompileUnit::attachRangesOrLowHighPC( DIE &Die, SmallVector<RangeSpan, 2> Ranges) { - if (Ranges.size() == 1 || !DD->useRangesSection()) { + assert(!Ranges.empty()); + if (!DD->useRangesSection() || + (Ranges.size() == 1 && + (!DD->alwaysUseRanges() || + DD->getSectionLabel(&Ranges.front().Begin->getSection()) == + Ranges.front().Begin))) { const RangeSpan &Front = Ranges.front(); const RangeSpan &Back = Ranges.back(); attachLowHighPC(Die, Front.Begin, Back.End); @@ -688,9 +686,9 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, // Add variable address. - unsigned Offset = DV.getDebugLocListIndex(); - if (Offset != ~0U) { - addLocationList(*VariableDie, dwarf::DW_AT_location, Offset); + unsigned Index = DV.getDebugLocListIndex(); + if (Index != ~0U) { + addLocationList(*VariableDie, dwarf::DW_AT_location, Index); auto TagOffset = DV.getDebugLocListTagOffset(); if (TagOffset) addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, dwarf::DW_FORM_data1, @@ -722,6 +720,13 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, addConstantFPValue(*VariableDie, DVal->getConstantFP()); } else if (DVal->isConstantInt()) { addConstantValue(*VariableDie, DVal->getConstantInt(), DV.getType()); + } else if (DVal->isTargetIndexLocation()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + const DIBasicType *BT = dyn_cast<DIBasicType>( + static_cast<const Metadata *>(DV.getVariable()->getType())); + DwarfDebug::emitDebugLocValue(*Asm, BT, *DVal, DwarfExpr); + addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); } return VariableDie; } @@ -737,10 +742,14 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, Register FrameReg; const DIExpression *Expr = Fragment.Expr; const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); - int Offset = TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg); + StackOffset Offset = + TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg); DwarfExpr.addFragmentOffset(Expr); + + auto *TRI = Asm->MF->getSubtarget().getRegisterInfo(); SmallVector<uint64_t, 8> Ops; - DIExpression::appendOffset(Ops, Offset); + TRI->getOffsetOpcodes(Offset, Ops); + // 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 @@ -801,6 +810,10 @@ static SmallVector<const DIVariable *, 2> dependencies(DbgVariable *Var) { return Result; if (auto *DLVar = Array->getDataLocation()) Result.push_back(DLVar); + if (auto *AsVar = Array->getAssociated()) + Result.push_back(AsVar); + if (auto *AlVar = Array->getAllocated()) + Result.push_back(AlVar); for (auto *El : Array->getElements()) { if (auto *Subrange = dyn_cast<DISubrange>(El)) { if (auto Count = Subrange->getCount()) @@ -815,6 +828,19 @@ static SmallVector<const DIVariable *, 2> dependencies(DbgVariable *Var) { if (auto ST = Subrange->getStride()) if (auto *Dependency = ST.dyn_cast<DIVariable *>()) Result.push_back(Dependency); + } else if (auto *GenericSubrange = dyn_cast<DIGenericSubrange>(El)) { + if (auto Count = GenericSubrange->getCount()) + if (auto *Dependency = Count.dyn_cast<DIVariable *>()) + Result.push_back(Dependency); + if (auto LB = GenericSubrange->getLowerBound()) + if (auto *Dependency = LB.dyn_cast<DIVariable *>()) + Result.push_back(Dependency); + if (auto UB = GenericSubrange->getUpperBound()) + if (auto *Dependency = UB.dyn_cast<DIVariable *>()) + Result.push_back(Dependency); + if (auto ST = GenericSubrange->getStride()) + if (auto *Dependency = ST.dyn_cast<DIVariable *>()) + Result.push_back(Dependency); } } return Result; @@ -996,7 +1022,7 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE( } bool DwarfCompileUnit::useGNUAnalogForDwarf5Feature() const { - return DD->getDwarfVersion() == 4 && DD->tuneForGDB(); + return DD->getDwarfVersion() == 4 && !DD->tuneForLLDB(); } dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUTag(dwarf::Tag Tag) const { @@ -1352,11 +1378,9 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die, /// Add a Dwarf loclistptr attribute data and value. void DwarfCompileUnit::addLocationList(DIE &Die, dwarf::Attribute Attribute, unsigned Index) { - dwarf::Form Form = dwarf::DW_FORM_data4; - if (DD->getDwarfVersion() == 4) - Form =dwarf::DW_FORM_sec_offset; - if (DD->getDwarfVersion() >= 5) - Form =dwarf::DW_FORM_loclistx; + dwarf::Form Form = (DD->getDwarfVersion() >= 5) + ? dwarf::DW_FORM_loclistx + : DD->getDwarfSectionOffsetForm(); Die.addValue(DIEValueAllocator, Attribute, Form, DIELocList(Index)); } @@ -1417,8 +1441,8 @@ void DwarfCompileUnit::addAddrTableBase() { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); MCSymbol *Label = DD->getAddressPool().getLabel(); addSectionLabel(getUnitDie(), - getDwarfVersion() >= 5 ? dwarf::DW_AT_addr_base - : dwarf::DW_AT_GNU_addr_base, + DD->getDwarfVersion() >= 5 ? dwarf::DW_AT_addr_base + : dwarf::DW_AT_GNU_addr_base, Label, TLOF.getDwarfAddrSection()->getBeginSymbol()); } diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 4ccd8c96dd0d..6d8186a5ee2b 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -22,7 +22,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/DbgEntityHistoryCalculator.h" -#include "llvm/CodeGen/DIE.h" #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/Support/Casting.h" @@ -34,6 +33,9 @@ namespace llvm { class AsmPrinter; +class DIE; +class DIELoc; +class DIEValueList; class DwarfFile; class GlobalVariable; class MCExpr; @@ -55,7 +57,7 @@ class DwarfCompileUnit final : public DwarfUnit { DwarfCompileUnit *Skeleton = nullptr; /// The start of the unit within its section. - MCSymbol *LabelBegin; + MCSymbol *LabelBegin = nullptr; /// The start of the unit macro info within macro section. MCSymbol *MacroLabelBegin; @@ -287,8 +289,8 @@ public: return DwarfUnit::getHeaderSize() + DWOIdSize; } unsigned getLength() { - return sizeof(uint32_t) + // Length field - getHeaderSize() + getUnitDie().getSize(); + return Asm->getUnitLengthFieldByteSize() + // Length field + getHeaderSize() + getUnitDie().getSize(); } void emitHeader(bool UseOffsets) override; @@ -297,7 +299,7 @@ public: void addAddrTableBase(); MCSymbol *getLabelBegin() const { - assert(getSection()); + assert(LabelBegin && "LabelBegin is not initialized"); return LabelBegin; } diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 45ed5256deb9..462682743c6a 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -13,30 +13,18 @@ #include "DwarfDebug.h" #include "ByteStreamer.h" #include "DIEHash.h" -#include "DebugLocEntry.h" -#include "DebugLocStream.h" #include "DwarfCompileUnit.h" #include "DwarfExpression.h" -#include "DwarfFile.h" #include "DwarfUnit.h" #include "llvm/ADT/APInt.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/CodeGen/AccelTable.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/TargetInstrInfo.h" @@ -46,14 +34,11 @@ #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" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" @@ -71,15 +56,10 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" #include <algorithm> -#include <cassert> #include <cstddef> -#include <cstdint> #include <iterator> #include <string> -#include <utility> -#include <vector> using namespace llvm; @@ -87,18 +67,10 @@ using namespace llvm; STATISTIC(NumCSParams, "Number of dbg call site params created"); -static cl::opt<bool> -DisableDebugInfoPrinting("disable-debug-info-print", cl::Hidden, - cl::desc("Disable debug info printing")); - static cl::opt<bool> UseDwarfRangesBaseAddressSpecifier( "use-dwarf-ranges-base-address-specifier", cl::Hidden, cl::desc("Use base address specifiers in debug_ranges"), cl::init(false)); -static cl::opt<bool> EmitDwarfDebugEntryValues( - "emit-debug-entry-values", cl::Hidden, - cl::desc("Emit the debug entry values"), cl::init(false)); - static cl::opt<bool> GenerateARangeSection("generate-arange-section", cl::Hidden, cl::desc("Generate dwarf aranges"), @@ -151,6 +123,18 @@ static cl::opt<DefaultOnOff> DwarfSectionsAsReferences( clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), cl::init(Default)); +static cl::opt<bool> + UseGNUDebugMacro("use-gnu-debug-macro", cl::Hidden, + cl::desc("Emit the GNU .debug_macro format with DWARF <5"), + cl::init(false)); + +static cl::opt<DefaultOnOff> DwarfOpConvert( + "dwarf-op-convert", cl::Hidden, + cl::desc("Enable use of the DWARFv5 DW_OP_convert operator"), + cl::values(clEnumVal(Default, "Default for platform"), + clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), + cl::init(Default)); + enum LinkageNameOption { DefaultLinkageNames, AllLinkageNames, @@ -167,19 +151,23 @@ static cl::opt<LinkageNameOption> "Abstract subprograms")), cl::init(DefaultLinkageNames)); -static cl::opt<unsigned> LocationAnalysisSizeLimit( - "singlevarlocation-input-bb-limit", - cl::desc("Maximum block size to analyze for single-location variables"), - cl::init(30000), cl::Hidden); +static cl::opt<DwarfDebug::MinimizeAddrInV5> MinimizeAddrInV5Option( + "minimize-addr-in-v5", cl::Hidden, + cl::desc("Always use DW_AT_ranges in DWARFv5 whenever it could allow more " + "address pool entry sharing to reduce relocations/object size"), + cl::values(clEnumValN(DwarfDebug::MinimizeAddrInV5::Default, "Default", + "Default address minimization strategy"), + clEnumValN(DwarfDebug::MinimizeAddrInV5::Ranges, "Ranges", + "Use rnglists for contiguous ranges if that allows " + "using a pre-existing base address"), + clEnumValN(DwarfDebug::MinimizeAddrInV5::Disabled, "Disabled", + "Stuff")), + cl::init(DwarfDebug::MinimizeAddrInV5::Default)); -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) { - getActiveStreamer().EmitInt8( + getActiveStreamer().emitInt8( Op, Comment ? Twine(Comment) + " " + dwarf::OperationEncodingString(Op) : dwarf::OperationEncodingString(Op)); } @@ -193,7 +181,7 @@ void DebugLocDwarfExpression::emitUnsigned(uint64_t Value) { } void DebugLocDwarfExpression::emitData1(uint8_t Value) { - getActiveStreamer().EmitInt8(Value, Twine(Value)); + getActiveStreamer().emitInt8(Value, Twine(Value)); } void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) { @@ -202,7 +190,7 @@ void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) { } bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, - unsigned MachineReg) { + llvm::Register MachineReg) { // This information is not available while emitting .debug_loc entries. return false; } @@ -227,7 +215,7 @@ void DebugLocDwarfExpression::commitTemporaryBuffer() { const char *Comment = (Byte.index() < TmpBuf->Comments.size()) ? TmpBuf->Comments[Byte.index()].c_str() : ""; - OutBS.EmitInt8(Byte.value(), Comment); + OutBS.emitInt8(Byte.value(), Comment); } TmpBuf->Bytes.clear(); TmpBuf->Comments.clear(); @@ -242,8 +230,8 @@ static DbgValueLoc getDebugLocValue(const MachineInstr *MI) { const DIExpression *Expr = MI->getDebugExpression(); assert(MI->getNumOperands() == 4); if (MI->getDebugOperand(0).isReg()) { - auto RegOp = MI->getDebugOperand(0); - auto Op1 = MI->getDebugOffset(); + const auto &RegOp = MI->getDebugOperand(0); + const auto &Op1 = MI->getDebugOffset(); // If the second operand is an immediate, this is a // register-indirect address. assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); @@ -251,7 +239,7 @@ static DbgValueLoc getDebugLocValue(const MachineInstr *MI) { return DbgValueLoc(Expr, MLoc); } if (MI->getDebugOperand(0).isTargetIndex()) { - auto Op = MI->getDebugOperand(0); + const auto &Op = MI->getDebugOperand(0); return DbgValueLoc(Expr, TargetIndexLocation(Op.getIndex(), Op.getOffset())); } @@ -354,7 +342,7 @@ static AccelTableKind computeAccelTableKind(unsigned DwarfVersion, return AccelTableKind::None; } -DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) +DwarfDebug::DwarfDebug(AsmPrinter *A) : DebugHandlerBase(A), DebugLocs(A->OutStreamer->isVerboseAsm()), InfoHolder(A, "info_string", DIEValueAllocator), SkeletonHolder(A, "skel_string", DIEValueAllocator), @@ -397,6 +385,11 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) DwarfVersion = TT.isNVPTX() ? 2 : (DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION); + bool Dwarf64 = Asm->TM.Options.MCOptions.Dwarf64 && + DwarfVersion >= 3 && // DWARF64 was introduced in DWARFv3. + TT.isArch64Bit() && // DWARF64 requires 64-bit relocations. + TT.isOSBinFormatELF(); // Support only ELF for now. + UseRangesSection = !NoDwarfRangesSection && !TT.isNVPTX(); // Use sections as references. Force for NVPTX. @@ -406,8 +399,9 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) UseSectionsAsReferences = DwarfSectionsAsReferences == Enable; // Don't generate type units for unsupported object file formats. - GenerateTypeUnits = - A->TM.getTargetTriple().isOSBinFormatELF() && GenerateDwarfTypeUnits; + GenerateTypeUnits = (A->TM.getTargetTriple().isOSBinFormatELF() || + A->TM.getTargetTriple().isOSBinFormatWasm()) && + GenerateDwarfTypeUnits; TheAccelTableKind = computeAccelTableKind( DwarfVersion, GenerateTypeUnits, DebuggerTuning, A->TM.getTargetTriple()); @@ -430,11 +424,31 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) // Emit call-site-param debug info for GDB and LLDB, if the target supports // the debug entry values feature. It can also be enabled explicitly. - EmitDebugEntryValues = (Asm->TM.Options.ShouldEmitDebugEntryValues() && - (tuneForGDB() || tuneForLLDB())) || - EmitDwarfDebugEntryValues; + EmitDebugEntryValues = Asm->TM.Options.ShouldEmitDebugEntryValues(); + + // It is unclear if the GCC .debug_macro extension is well-specified + // for split DWARF. For now, do not allow LLVM to emit it. + UseDebugMacroSection = + DwarfVersion >= 5 || (UseGNUDebugMacro && !useSplitDwarf()); + if (DwarfOpConvert == Default) + EnableOpConvert = !((tuneForGDB() && useSplitDwarf()) || (tuneForLLDB() && !TT.isOSBinFormatMachO())); + else + EnableOpConvert = (DwarfOpConvert == Enable); + + // Split DWARF would benefit object size significantly by trading reductions + // in address pool usage for slightly increased range list encodings. + if (DwarfVersion >= 5) { + MinimizeAddr = MinimizeAddrInV5Option; + // FIXME: In the future, enable this by default for Split DWARF where the + // tradeoff is more pronounced due to being able to offload the range + // lists to the dwo file and shrink object files/reduce relocations there. + if (MinimizeAddr == MinimizeAddrInV5::Default) + MinimizeAddr = MinimizeAddrInV5::Disabled; + } Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); + Asm->OutStreamer->getContext().setDwarfFormat(Dwarf64 ? dwarf::DWARF64 + : dwarf::DWARF32); } // Define out of line so we don't have to include DwarfUnit.h in DwarfDebug.h. @@ -583,7 +597,7 @@ static const DIExpression *combineDIExpressions(const DIExpression *Original, std::vector<uint64_t> Elts = Addition->getElements().vec(); // Avoid multiple DW_OP_stack_values. if (Original->isImplicit() && Addition->isImplicit()) - erase_if(Elts, [](uint64_t Op) { return Op == dwarf::DW_OP_stack_value; }); + erase_value(Elts, dwarf::DW_OP_stack_value); const DIExpression *CombinedExpr = (Elts.size() > 0) ? DIExpression::append(Original, Elts) : Original; return CombinedExpr; @@ -709,11 +723,11 @@ static void interpretValues(const MachineInstr *CurMI, ForwardedRegWorklist[ParamFwdReg], Params); } else if (ParamValue->first.isReg()) { Register RegLoc = ParamValue->first.getReg(); - unsigned SP = TLI.getStackPointerRegisterToSaveRestore(); + Register SP = TLI.getStackPointerRegisterToSaveRestore(); Register FP = TRI.getFrameRegister(*MF); bool IsSPorFP = (RegLoc == SP) || (RegLoc == FP); if (TRI.isCalleeSavedPhysReg(RegLoc, *MF) || IsSPorFP) { - MachineLocation MLoc(RegLoc, /*IsIndirect=*/IsSPorFP); + MachineLocation MLoc(RegLoc, /*Indirect=*/IsSPorFP); finishCallSiteParams(MLoc, ParamValue->second, ForwardedRegWorklist[ParamFwdReg], Params); } else { @@ -797,6 +811,11 @@ static void collectCallSiteParameters(const MachineInstr *CallMI, (void)InsertedReg; } + // Do not emit CSInfo for undef forwarding registers. + for (auto &MO : CallMI->uses()) + if (MO.isReg() && MO.isUndef()) + ForwardedRegWorklist.erase(MO.getReg()); + // We erase, from the ForwardedRegWorklist, those forwarding registers for // which we successfully describe a loaded value (by using // the describeLoadedValue()). For those remaining arguments in the working @@ -1071,9 +1090,8 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) { // compilation directory. if (!Asm->OutStreamer->hasRawTextSupport() || SingleCU) Asm->OutStreamer->emitDwarfFile0Directive( - CompilationDir, DIUnit->getFilename(), - NewCU.getMD5AsBytes(DIUnit->getFile()), DIUnit->getSource(), - NewCU.getUniqueID()); + CompilationDir, DIUnit->getFilename(), getMD5AsBytes(DIUnit->getFile()), + DIUnit->getSource(), NewCU.getUniqueID()); if (useSplitDwarf()) { NewCU.setSkeleton(constructSkeletonCU(NewCU)); @@ -1126,21 +1144,17 @@ sortGlobalExprs(SmallVectorImpl<DwarfCompileUnit::GlobalExpr> &GVEs) { // Emit all Dwarf sections that should come prior to the content. Create // global DIEs and emit initial debug info sections. This is invoked by // the target AsmPrinter. -void DwarfDebug::beginModule() { - NamedRegionTimer T(DbgTimerName, DbgTimerDescription, DWARFGroupName, - DWARFGroupDescription, TimePassesIsEnabled); - if (DisableDebugInfoPrinting) { - MMI->setDebugInfoAvailability(false); - return; - } +void DwarfDebug::beginModule(Module *M) { + DebugHandlerBase::beginModule(M); - const Module *M = MMI->getModule(); + if (!Asm || !MMI->hasDebugInfo()) + return; unsigned NumDebugCUs = std::distance(M->debug_compile_units_begin(), M->debug_compile_units_end()); - // Tell MMI whether we have debug info. - assert(MMI->hasDebugInfo() == (NumDebugCUs > 0) && - "DebugInfoAvailabilty initialized unexpectedly"); + assert(NumDebugCUs > 0 && "Asm unexpectedly initialized"); + assert(MMI->hasDebugInfo() && + "DebugInfoAvailabilty unexpectedly not initialized"); SingleCU = NumDebugCUs == 1; DenseMap<DIGlobalVariable *, SmallVector<DwarfCompileUnit::GlobalExpr, 1>> GVMap; @@ -1292,7 +1306,7 @@ void DwarfDebug::finalizeModuleInfo() { Asm->TM.Options.MCOptions.SplitDwarfFile); // Emit a unique identifier for this CU. uint64_t ID = - DIEHash(Asm).computeCUSignature(DWOName, TheCU.getUnitDie()); + DIEHash(Asm, &TheCU).computeCUSignature(DWOName, TheCU.getUnitDie()); if (getDwarfVersion() >= 5) { TheCU.setDWOId(ID); SkCU->setDWOId(ID); @@ -1353,15 +1367,18 @@ void DwarfDebug::finalizeModuleInfo() { // If compile Unit has macros, emit "DW_AT_macro_info/DW_AT_macros" // attribute. if (CUNode->getMacros()) { - if (getDwarfVersion() >= 5) { + if (UseDebugMacroSection) { if (useSplitDwarf()) TheCU.addSectionDelta( TheCU.getUnitDie(), dwarf::DW_AT_macros, U.getMacroLabelBegin(), TLOF.getDwarfMacroDWOSection()->getBeginSymbol()); - else - U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_macros, - U.getMacroLabelBegin(), + else { + dwarf::Attribute MacrosAttr = getDwarfVersion() >= 5 + ? dwarf::DW_AT_macros + : dwarf::DW_AT_GNU_macros; + U.addSectionLabel(U.getUnitDie(), MacrosAttr, U.getMacroLabelBegin(), TLOF.getDwarfMacroSection()->getBeginSymbol()); + } } else { if (useSplitDwarf()) TheCU.addSectionDelta( @@ -1398,9 +1415,8 @@ void DwarfDebug::endModule() { } // If we aren't actually generating debug info (check beginModule - - // conditionalized on !DisableDebugInfoPrinting and the presence of the - // llvm.dbg.cu metadata node) - if (!MMI->hasDebugInfo()) + // conditionalized on the presence of the llvm.dbg.cu metadata node) + if (!Asm || !MMI->hasDebugInfo()) return; // Finalize the debug info for the module. @@ -1532,7 +1548,8 @@ void DwarfDebug::collectVariableInfoFromMFTable( /// either open or otherwise rolls off the end of the scope. static bool validThroughout(LexicalScopes &LScopes, const MachineInstr *DbgValue, - const MachineInstr *RangeEnd) { + const MachineInstr *RangeEnd, + const InstructionOrdering &Ordering) { assert(DbgValue->getDebugLoc() && "DBG_VALUE without a debug location"); auto MBB = DbgValue->getParent(); auto DL = DbgValue->getDebugLoc(); @@ -1544,34 +1561,30 @@ static bool validThroughout(LexicalScopes &LScopes, 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; - - // If there are instructions belonging to our scope in another block, and - // we're not a constant (see DWARF2 comment below), then we can't be - // validThroughout. - const MachineInstr *LScopeEnd = LSRange.back().second; - if (RangeEnd && LScopeEnd->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)) + // If the scope starts before the DBG_VALUE then we may have a negative + // result. Otherwise the location is live coming into the scope and we + // can skip the following checks. + if (!Ordering.isBefore(DbgValue, LScopeBegin)) { + // 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. @@ -1585,24 +1598,10 @@ static bool validThroughout(LexicalScopes &LScopes, if (DbgValue->getDebugOperand(0).isImm() && MBB->pred_empty()) return true; - // Now check for situations where an "open-ended" DBG_VALUE isn't enough to - // determine eligibility for a single location, e.g. nested scopes, inlined - // functions. - // FIXME: For now we just handle a simple (but common) case where the scope - // is contained in MBB. We could be smarter here. - // - // At this point we know that our scope ends in MBB. So, if RangeEnd exists - // outside of the block we can ignore it; the location is just leaking outside - // its scope. - assert(LScopeEnd->getParent() == MBB && "Scope ends outside MBB"); - if (RangeEnd->getParent() != DbgValue->getParent()) - return true; - - // The location range and variable's enclosing scope are both contained within - // MBB, test if location terminates before end of scope. - for (auto I = RangeEnd->getIterator(); I != MBB->end(); ++I) - if (&*I == LScopeEnd) - return false; + // Test if the location terminates before the end of the scope. + const MachineInstr *LScopeEnd = LSRange.back().second; + if (Ordering.isBefore(RangeEnd, LScopeEnd)) + return false; // There's a single location which starts at the scope start, and ends at or // after the scope end. @@ -1642,10 +1641,8 @@ static bool validThroughout(LexicalScopes &LScopes, // [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, - DenseSet<const MachineBasicBlock *> &VeryLargeBlocks) { +bool DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, + const DbgValueHistoryMap::Entries &Entries) { using OpenRange = std::pair<DbgValueHistoryMap::EntryIndex, DbgValueLoc>; SmallVector<OpenRange, 4> OpenRanges; @@ -1658,9 +1655,7 @@ bool DwarfDebug::buildLocationList( // 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()); + erase_if(OpenRanges, [&](OpenRange &R) { return R.first <= Index; }); // If we are dealing with a clobbering entry, this iteration will result in // a location list entry starting after the clobbering instruction. @@ -1741,14 +1736,8 @@ bool DwarfDebug::buildLocationList( DebugLoc.pop_back(); } - // If there's a single entry, safe for a single location, and not part of - // an over-sized basic block, then ask validThroughout whether this - // location can be represented as a single variable location. - if (DebugLoc.size() != 1 || !isSafeForSingleLocation) - return false; - if (VeryLargeBlocks.count(StartDebugMI->getParent())) - return false; - return validThroughout(LScopes, StartDebugMI, EndMI); + return DebugLoc.size() == 1 && isSafeForSingleLocation && + validThroughout(LScopes, StartDebugMI, EndMI, getInstOrdering()); } DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU, @@ -1780,13 +1769,6 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, // Grab the variable info that was squirreled away in the MMI side-table. collectVariableInfoFromMFTable(TheCU, Processed); - // Identify blocks that are unreasonably sized, so that we can later - // skip lexical scope analysis over them. - DenseSet<const MachineBasicBlock *> VeryLargeBlocks; - for (const auto &MBB : *CurFn) - if (MBB.size() > LocationAnalysisSizeLimit) - VeryLargeBlocks.insert(&MBB); - for (const auto &I : DbgValues) { InlinedEntity IV = I.first; if (Processed.count(IV)) @@ -1823,8 +1805,7 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, if (HistSize == 1 || SingleValueWithClobber) { const auto *End = SingleValueWithClobber ? HistoryMapEntries[1].getInstr() : nullptr; - if (VeryLargeBlocks.count(MInsn->getParent()) == 0 && - validThroughout(LScopes, MInsn, End)) { + if (validThroughout(LScopes, MInsn, End, getInstOrdering())) { RegVar->initializeDbgValue(MInsn); continue; } @@ -1839,8 +1820,7 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, // Build the location list for this variable. SmallVector<DebugLocEntry, 8> Entries; - bool isValidSingleLocation = - buildLocationList(Entries, HistoryMapEntries, VeryLargeBlocks); + 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 @@ -1945,7 +1925,8 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { } DebugHandlerBase::beginInstruction(MI); - assert(CurMI); + if (!CurMI) + return; if (NoDebug) return; @@ -2382,10 +2363,10 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, TheU = Skeleton; // Emit the header. - Asm->OutStreamer->AddComment("Length of Public " + Name + " Info"); MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + Name + "_begin"); MCSymbol *EndLabel = Asm->createTempSymbol("pub" + Name + "_end"); - Asm->emitLabelDifference(EndLabel, BeginLabel, 4); + Asm->emitDwarfUnitLength(EndLabel, BeginLabel, + "Length of Public " + Name + " Info"); Asm->OutStreamer->emitLabel(BeginLabel); @@ -2396,7 +2377,7 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, emitSectionReference(*TheU); Asm->OutStreamer->AddComment("Compilation Unit Length"); - Asm->emitInt32(TheU->getLength()); + Asm->emitDwarfLengthOrOffset(TheU->getLength()); // Emit the pubnames for this compilation unit. for (const auto &GI : Globals) { @@ -2404,7 +2385,7 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, const DIE *Entity = GI.second; Asm->OutStreamer->AddComment("DIE offset"); - Asm->emitInt32(Entity->getOffset()); + Asm->emitDwarfLengthOrOffset(Entity->getOffset()); if (GnuStyle) { dwarf::PubIndexEntryDescriptor Desc = computeIndexValue(TheU, Entity); @@ -2419,7 +2400,7 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, } Asm->OutStreamer->AddComment("End Mark"); - Asm->emitInt32(0); + Asm->emitDwarfLengthOrOffset(0); Asm->OutStreamer->emitLabel(EndLabel); } @@ -2458,7 +2439,7 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, 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++) : ""); + Streamer.emitInt8(Op.getCode(), Comment != End ? *(Comment++) : ""); Offset++; for (unsigned I = 0; I < 2; ++I) { if (Op.getDescription().Op[I] == Encoding::SizeNA) @@ -2474,7 +2455,7 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, Comment++; } else { for (uint64_t J = Offset; J < Op.getOperandEndOffset(I); ++J) - Streamer.EmitInt8(Data.getData()[J], Comment != End ? *(Comment++) : ""); + Streamer.emitInt8(Data.getData()[J], Comment != End ? *(Comment++) : ""); } Offset = Op.getOperandEndOffset(I); } @@ -2511,10 +2492,26 @@ void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, TargetIndexLocation Loc = Value.getTargetIndexLocation(); // TODO TargetIndexLocation is a target-independent. Currently only the WebAssembly-specific // encoding is supported. + assert(AP.TM.getTargetTriple().isWasm()); DwarfExpr.addWasmLocation(Loc.Index, static_cast<uint64_t>(Loc.Offset)); + DwarfExpr.addExpression(std::move(ExprCursor)); + return; } else if (Value.isConstantFP()) { - APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt(); - DwarfExpr.addUnsignedConstant(RawBytes); + if (AP.getDwarfVersion() >= 4 && !AP.getDwarfDebug()->tuneForSCE() && + !ExprCursor) { + DwarfExpr.addConstantFP(Value.getConstantFP()->getValueAPF(), AP); + return; + } + if (Value.getConstantFP()->getValueAPF().bitcastToAPInt().getBitWidth() <= + 64 /*bits*/) + DwarfExpr.addUnsignedConstant( + Value.getConstantFP()->getValueAPF().bitcastToAPInt()); + else + LLVM_DEBUG( + dbgs() + << "Skipped DwarfExpression creation for ConstantFP of size" + << Value.getConstantFP()->getValueAPF().bitcastToAPInt().getBitWidth() + << " bits\n"); } DwarfExpr.addExpression(std::move(ExprCursor)); } @@ -2537,7 +2534,7 @@ void DebugLocEntry::finalize(const AsmPrinter &AP, }) && "all values are expected to be fragments"); assert(llvm::is_sorted(Values) && "fragments are expected to be sorted"); - for (auto Fragment : Values) + for (const auto &Fragment : Values) DwarfDebug::emitDebugLocValue(AP, BT, Fragment, DwarfExpr); } else { @@ -2580,7 +2577,8 @@ static MCSymbol *emitRnglistsTableHeader(AsmPrinter *Asm, Asm->OutStreamer->emitLabel(Holder.getRnglistsTableBaseSym()); for (const RangeSpanList &List : Holder.getRangeLists()) - Asm->emitLabelDifference(List.Label, Holder.getRnglistsTableBaseSym(), 4); + Asm->emitLabelDifference(List.Label, Holder.getRnglistsTableBaseSym(), + Asm->getDwarfOffsetByteSize()); return TableEnd; } @@ -2599,7 +2597,8 @@ static MCSymbol *emitLoclistsTableHeader(AsmPrinter *Asm, Asm->OutStreamer->emitLabel(DebugLocs.getSym()); for (const auto &List : DebugLocs.getLists()) - Asm->emitLabelDifference(List.Label, DebugLocs.getSym(), 4); + Asm->emitLabelDifference(List.Label, DebugLocs.getSym(), + Asm->getDwarfOffsetByteSize()); return TableEnd; } @@ -2881,23 +2880,23 @@ void DwarfDebug::emitDebugARanges() { // Emit size of content not including length itself. unsigned ContentSize = - sizeof(int16_t) + // DWARF ARange version number - sizeof(int32_t) + // Offset of CU in the .debug_info section - sizeof(int8_t) + // Pointer Size (in bytes) - sizeof(int8_t); // Segment Size (in bytes) + sizeof(int16_t) + // DWARF ARange version number + Asm->getDwarfOffsetByteSize() + // Offset of CU in the .debug_info + // section + sizeof(int8_t) + // Pointer Size (in bytes) + sizeof(int8_t); // Segment Size (in bytes) unsigned TupleSize = PtrSize * 2; // 7.20 in the Dwarf specs requires the table to be aligned to a tuple. - unsigned Padding = - offsetToAlignment(sizeof(int32_t) + ContentSize, Align(TupleSize)); + unsigned Padding = offsetToAlignment( + Asm->getUnitLengthFieldByteSize() + ContentSize, Align(TupleSize)); ContentSize += Padding; ContentSize += (List.size() + 1) * TupleSize; // For each compile unit, write the list of spans it covers. - Asm->OutStreamer->AddComment("Length of ARange Set"); - Asm->emitInt32(ContentSize); + Asm->emitDwarfUnitLength(ContentSize, "Length of ARange Set"); Asm->OutStreamer->AddComment("DWARF Arange version number"); Asm->emitInt16(dwarf::DW_ARANGES_VERSION); Asm->OutStreamer->AddComment("Offset Into Debug Info Section"); @@ -2983,25 +2982,30 @@ void DwarfDebug::emitDebugRangesDWO() { Asm->getObjFileLowering().getDwarfRnglistsDWOSection()); } -/// Emit the header of a DWARF 5 macro section. +/// Emit the header of a DWARF 5 macro section, or the GNU extension for +/// DWARF 4. static void emitMacroHeader(AsmPrinter *Asm, const DwarfDebug &DD, - const DwarfCompileUnit &CU) { + const DwarfCompileUnit &CU, uint16_t DwarfVersion) { enum HeaderFlagMask { #define HANDLE_MACRO_FLAG(ID, NAME) MACRO_FLAG_##NAME = ID, #include "llvm/BinaryFormat/Dwarf.def" }; - uint8_t Flags = 0; Asm->OutStreamer->AddComment("Macro information version"); - Asm->emitInt16(5); - // We are setting Offset and line offset flags unconditionally here, - // since we're only supporting DWARF32 and line offset should be mostly - // present. - // FIXME: Add support for DWARF64. - Flags |= MACRO_FLAG_DEBUG_LINE_OFFSET; - Asm->OutStreamer->AddComment("Flags: 32 bit, debug_line_offset present"); - Asm->emitInt8(Flags); + Asm->emitInt16(DwarfVersion >= 5 ? DwarfVersion : 4); + // We emit the line offset flag unconditionally here, since line offset should + // be mostly present. + if (Asm->isDwarf64()) { + Asm->OutStreamer->AddComment("Flags: 64 bit, debug_line_offset present"); + Asm->emitInt8(MACRO_FLAG_OFFSET_SIZE | MACRO_FLAG_DEBUG_LINE_OFFSET); + } else { + Asm->OutStreamer->AddComment("Flags: 32 bit, debug_line_offset present"); + Asm->emitInt8(MACRO_FLAG_DEBUG_LINE_OFFSET); + } Asm->OutStreamer->AddComment("debug_line_offset"); - Asm->OutStreamer->emitSymbolValue(CU.getLineTableStartSym(), /*Size=*/4); + if (DD.useSplitDwarf()) + Asm->emitDwarfLengthOrOffset(0); + else + Asm->emitDwarfSymbolReference(CU.getLineTableStartSym()); } void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U) { @@ -3018,55 +3022,63 @@ void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U) { void DwarfDebug::emitMacro(DIMacro &M) { StringRef Name = M.getName(); StringRef Value = M.getValue(); - bool UseMacro = getDwarfVersion() >= 5; - - if (UseMacro) { - unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define - ? dwarf::DW_MACRO_define_strx - : dwarf::DW_MACRO_undef_strx; - Asm->OutStreamer->AddComment(dwarf::MacroString(Type)); - Asm->emitULEB128(Type); - Asm->OutStreamer->AddComment("Line Number"); - Asm->emitULEB128(M.getLine()); - Asm->OutStreamer->AddComment("Macro String"); - if (!Value.empty()) - Asm->emitULEB128(this->InfoHolder.getStringPool() - .getIndexedEntry(*Asm, (Name + " " + Value).str()) - .getIndex()); - else - // DW_MACRO_undef_strx doesn't have a value, so just emit the macro - // string. - Asm->emitULEB128(this->InfoHolder.getStringPool() - .getIndexedEntry(*Asm, (Name).str()) - .getIndex()); + + // There should be one space between the macro name and the macro value in + // define entries. In undef entries, only the macro name is emitted. + std::string Str = Value.empty() ? Name.str() : (Name + " " + Value).str(); + + if (UseDebugMacroSection) { + if (getDwarfVersion() >= 5) { + unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define + ? dwarf::DW_MACRO_define_strx + : dwarf::DW_MACRO_undef_strx; + Asm->OutStreamer->AddComment(dwarf::MacroString(Type)); + Asm->emitULEB128(Type); + Asm->OutStreamer->AddComment("Line Number"); + Asm->emitULEB128(M.getLine()); + Asm->OutStreamer->AddComment("Macro String"); + Asm->emitULEB128( + InfoHolder.getStringPool().getIndexedEntry(*Asm, Str).getIndex()); + } else { + unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define + ? dwarf::DW_MACRO_GNU_define_indirect + : dwarf::DW_MACRO_GNU_undef_indirect; + Asm->OutStreamer->AddComment(dwarf::GnuMacroString(Type)); + Asm->emitULEB128(Type); + Asm->OutStreamer->AddComment("Line Number"); + Asm->emitULEB128(M.getLine()); + Asm->OutStreamer->AddComment("Macro String"); + Asm->emitDwarfSymbolReference( + InfoHolder.getStringPool().getEntry(*Asm, Str).getSymbol()); + } } else { Asm->OutStreamer->AddComment(dwarf::MacinfoString(M.getMacinfoType())); Asm->emitULEB128(M.getMacinfoType()); Asm->OutStreamer->AddComment("Line Number"); Asm->emitULEB128(M.getLine()); Asm->OutStreamer->AddComment("Macro String"); - Asm->OutStreamer->emitBytes(Name); - if (!Value.empty()) { - // There should be one space between macro name and macro value. - Asm->emitInt8(' '); - Asm->OutStreamer->AddComment("Macro Value="); - Asm->OutStreamer->emitBytes(Value); - } + Asm->OutStreamer->emitBytes(Str); Asm->emitInt8('\0'); } } void DwarfDebug::emitMacroFileImpl( - DIMacroFile &F, DwarfCompileUnit &U, unsigned StartFile, unsigned EndFile, + DIMacroFile &MF, DwarfCompileUnit &U, unsigned StartFile, unsigned EndFile, StringRef (*MacroFormToString)(unsigned Form)) { Asm->OutStreamer->AddComment(MacroFormToString(StartFile)); Asm->emitULEB128(StartFile); Asm->OutStreamer->AddComment("Line Number"); - Asm->emitULEB128(F.getLine()); + Asm->emitULEB128(MF.getLine()); Asm->OutStreamer->AddComment("File Number"); - Asm->emitULEB128(U.getOrCreateSourceID(F.getFile())); - handleMacroNodes(F.getElements(), U); + DIFile &F = *MF.getFile(); + if (useSplitDwarf()) + Asm->emitULEB128(getDwoLineTable(U)->getFile( + F.getDirectory(), F.getFilename(), getMD5AsBytes(&F), + Asm->OutContext.getDwarfVersion(), F.getSource())); + else + Asm->emitULEB128(U.getOrCreateSourceID(&F)); + handleMacroNodes(MF.getElements(), U); Asm->OutStreamer->AddComment(MacroFormToString(EndFile)); Asm->emitULEB128(EndFile); } @@ -3075,10 +3087,10 @@ void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { // DWARFv5 macro and DWARFv4 macinfo share some common encodings, // so for readibility/uniformity, We are explicitly emitting those. assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); - bool UseMacro = getDwarfVersion() >= 5; - if (UseMacro) - emitMacroFileImpl(F, U, dwarf::DW_MACRO_start_file, - dwarf::DW_MACRO_end_file, dwarf::MacroString); + if (UseDebugMacroSection) + emitMacroFileImpl( + F, U, dwarf::DW_MACRO_start_file, dwarf::DW_MACRO_end_file, + (getDwarfVersion() >= 5) ? dwarf::MacroString : dwarf::GnuMacroString); else emitMacroFileImpl(F, U, dwarf::DW_MACINFO_start_file, dwarf::DW_MACINFO_end_file, dwarf::MacinfoString); @@ -3095,8 +3107,8 @@ void DwarfDebug::emitDebugMacinfoImpl(MCSection *Section) { continue; Asm->OutStreamer->SwitchSection(Section); Asm->OutStreamer->emitLabel(U.getMacroLabelBegin()); - if (getDwarfVersion() >= 5) - emitMacroHeader(Asm, *this, U); + if (UseDebugMacroSection) + emitMacroHeader(Asm, *this, U, getDwarfVersion()); handleMacroNodes(Macros, U); Asm->OutStreamer->AddComment("End Of Macro List Mark"); Asm->emitInt8(0); @@ -3106,14 +3118,14 @@ void DwarfDebug::emitDebugMacinfoImpl(MCSection *Section) { /// Emit macros into a debug macinfo/macro section. void DwarfDebug::emitDebugMacinfo() { auto &ObjLower = Asm->getObjFileLowering(); - emitDebugMacinfoImpl(getDwarfVersion() >= 5 + emitDebugMacinfoImpl(UseDebugMacroSection ? ObjLower.getDwarfMacroSection() : ObjLower.getDwarfMacinfoSection()); } void DwarfDebug::emitDebugMacinfoDWO() { auto &ObjLower = Asm->getObjFileLowering(); - emitDebugMacinfoImpl(getDwarfVersion() >= 5 + emitDebugMacinfoImpl(UseDebugMacroSection ? ObjLower.getDwarfMacroDWOSection() : ObjLower.getDwarfMacinfoDWOSection()); } @@ -3200,7 +3212,7 @@ MCDwarfDwoLineTable *DwarfDebug::getDwoLineTable(const DwarfCompileUnit &CU) { const DICompileUnit *DIUnit = CU.getCUNode(); SplitTypeUnitFileTable.maybeSetRootFile( DIUnit->getDirectory(), DIUnit->getFilename(), - CU.getMD5AsBytes(DIUnit->getFile()), DIUnit->getSource()); + getMD5AsBytes(DIUnit->getFile()), DIUnit->getSource()); return &SplitTypeUnitFileTable; } @@ -3303,14 +3315,14 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, DwarfDebug::NonTypeUnitContext::NonTypeUnitContext(DwarfDebug *DD) : DD(DD), - TypeUnitsUnderConstruction(std::move(DD->TypeUnitsUnderConstruction)) { + TypeUnitsUnderConstruction(std::move(DD->TypeUnitsUnderConstruction)), AddrPoolUsed(DD->AddrPool.hasBeenUsed()) { DD->TypeUnitsUnderConstruction.clear(); - assert(TypeUnitsUnderConstruction.empty() || !DD->AddrPool.hasBeenUsed()); + DD->AddrPool.resetUsedFlag(); } DwarfDebug::NonTypeUnitContext::~NonTypeUnitContext() { DD->TypeUnitsUnderConstruction = std::move(TypeUnitsUnderConstruction); - DD->AddrPool.resetUsedFlag(); + DD->AddrPool.resetUsedFlag(AddrPoolUsed); } DwarfDebug::NonTypeUnitContext DwarfDebug::enterNonTypeUnitContext() { @@ -3375,6 +3387,15 @@ uint16_t DwarfDebug::getDwarfVersion() const { return Asm->OutStreamer->getContext().getDwarfVersion(); } +dwarf::Form DwarfDebug::getDwarfSectionOffsetForm() const { + if (Asm->getDwarfVersion() >= 4) + return dwarf::Form::DW_FORM_sec_offset; + assert((!Asm->isDwarf64() || (Asm->getDwarfVersion() == 3)) && + "DWARF64 is not defined prior DWARFv3"); + return Asm->isDwarf64() ? dwarf::Form::DW_FORM_data8 + : dwarf::Form::DW_FORM_data4; +} + const MCSymbol *DwarfDebug::getSectionLabel(const MCSection *S) { return SectionLabels.find(S)->second; } @@ -3383,3 +3404,20 @@ void DwarfDebug::insertSectionLabel(const MCSymbol *S) { if (useSplitDwarf() || getDwarfVersion() >= 5) AddrPool.getIndex(S); } + +Optional<MD5::MD5Result> DwarfDebug::getMD5AsBytes(const DIFile *File) const { + assert(File); + if (getDwarfVersion() < 5) + return None; + Optional<DIFile::ChecksumInfo<StringRef>> Checksum = File->getChecksum(); + if (!Checksum || Checksum->Kind != DIFile::CSK_MD5) + 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); + MD5::MD5Result CKMem; + std::copy(ChecksumString.begin(), ChecksumString.end(), CKMem.Bytes.data()); + return CKMem; +} diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index ad2f2f3edd8e..df19ef458888 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -114,7 +114,7 @@ public: /// /// Variables that have been optimized out use none of these fields. class DbgVariable : public DbgEntity { - /// Offset in DebugLocs. + /// Index of the entry list in DebugLocs. unsigned DebugLocListIndex = ~0u; /// DW_OP_LLVM_tag_offset value from DebugLocs. Optional<uint8_t> DebugLocListTagOffset; @@ -372,6 +372,23 @@ class DwarfDebug : public DebugHandlerBase { /// Generate DWARF v4 type units. bool GenerateTypeUnits; + /// Emit a .debug_macro section instead of .debug_macinfo. + bool UseDebugMacroSection; + + /// Avoid using DW_OP_convert due to consumer incompatibilities. + bool EnableOpConvert; + +public: + enum class MinimizeAddrInV5 { + Default, + Disabled, + Ranges, + }; + +private: + /// Force the use of DW_AT_ranges even for single-entry range lists. + MinimizeAddrInV5 MinimizeAddr = MinimizeAddrInV5::Disabled; + /// DWARF5 Experimental Options /// @{ AccelTableKind TheAccelTableKind; @@ -409,6 +426,9 @@ class DwarfDebug : public DebugHandlerBase { bool SingleCU; bool IsDarwin; + /// Map for tracking Fortran deferred CHARACTER lengths. + DenseMap<const DIStringType *, unsigned> StringTypeLocMap; + AddressPool AddrPool; /// Accelerator tables. @@ -592,10 +612,8 @@ class DwarfDebug : public DebugHandlerBase { /// 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, - DenseSet<const MachineBasicBlock *> &VeryLargeBlocks); + bool buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, + const DbgValueHistoryMap::Entries &Entries); /// Collect variable information from the side table maintained by MF. void collectVariableInfoFromMFTable(DwarfCompileUnit &TheCU, @@ -617,13 +635,13 @@ public: //===--------------------------------------------------------------------===// // Main entry points. // - DwarfDebug(AsmPrinter *A, Module *M); + DwarfDebug(AsmPrinter *A); ~DwarfDebug() override; /// Emit all Dwarf sections that should come prior to the /// content. - void beginModule(); + void beginModule(Module *M) override; /// Emit all Dwarf sections that should come after the content. void endModule() override; @@ -645,6 +663,7 @@ public: class NonTypeUnitContext { DwarfDebug *DD; decltype(DwarfDebug::TypeUnitsUnderConstruction) TypeUnitsUnderConstruction; + bool AddrPoolUsed; friend class DwarfDebug; NonTypeUnitContext(DwarfDebug *DD); public: @@ -681,6 +700,12 @@ public: /// Returns whether ranges section should be emitted. bool useRangesSection() const { return UseRangesSection; } + /// Returns whether range encodings should be used for single entry range + /// lists. + bool alwaysUseRanges() const { + return MinimizeAddr == MinimizeAddrInV5::Ranges; + } + /// Returns whether to use sections as labels rather than temp symbols. bool useSectionsAsReferences() const { return UseSectionsAsReferences; @@ -719,11 +744,21 @@ public: return EmitDebugEntryValues; } + bool useOpConvert() const { + return EnableOpConvert; + } + bool shareAcrossDWOCUs() const; /// Returns the Dwarf Version. uint16_t getDwarfVersion() const; + /// Returns a suitable DWARF form to represent a section offset, i.e. + /// * DW_FORM_sec_offset for DWARF version >= 4; + /// * DW_FORM_data8 for 64-bit DWARFv3; + /// * DW_FORM_data4 for 32-bit DWARFv3 and DWARFv2. + dwarf::Form getDwarfSectionOffsetForm() const; + /// Returns the previous CU that was being updated const DwarfCompileUnit *getPrevCU() const { return PrevCU; } void setPrevCU(const DwarfCompileUnit *PrevCU) { this->PrevCU = PrevCU; } @@ -768,6 +803,16 @@ public: return CUDieMap.lookup(Die); } + unsigned getStringTypeLoc(const DIStringType *ST) const { + return StringTypeLocMap.lookup(ST); + } + + void addStringTypeLoc(const DIStringType *ST, unsigned Loc) { + assert(ST); + if (Loc) + StringTypeLocMap[ST] = Loc; + } + /// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger. /// /// Returns whether we are "tuning" for a given debugger. @@ -777,13 +822,16 @@ public: bool tuneForSCE() const { return DebuggerTuning == DebuggerKind::SCE; } /// @} - void addSectionLabel(const MCSymbol *Sym); const MCSymbol *getSectionLabel(const MCSection *S); void insertSectionLabel(const MCSymbol *S); static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, const DbgValueLoc &Value, DwarfExpression &DwarfExpr); + + /// If the \p File has an MD5 checksum, return it as an MD5Result + /// allocated in the MCContext. + Optional<MD5::MD5Result> getMD5AsBytes(const DIFile *File) const; }; } // end namespace llvm diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfException.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfException.h index c2956380438f..b19b4365383f 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfException.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfException.h @@ -92,6 +92,20 @@ public: /// Gather and emit post-function exception information. void endFunction(const MachineFunction *) override; }; + +class LLVM_LIBRARY_VISIBILITY AIXException : public DwarfCFIExceptionBase { + /// This is AIX's compat unwind section, which unwinder would use + /// to find the location of LSDA area and personality rountine. + void emitExceptionInfoTable(const MCSymbol *LSDA, const MCSymbol *PerSym); + +public: + AIXException(AsmPrinter *A); + + void endModule() override {} + void beginFunction(const MachineFunction *MF) override {} + + void endFunction(const MachineFunction *MF) override; +}; } // End of namespace llvm #endif diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index d4762121d105..59ad7646ce1c 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -17,14 +17,14 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/Register.h" #include "llvm/CodeGen/TargetRegisterInfo.h" -#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DataLayout.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> -#include <cassert> -#include <cstdint> using namespace llvm; +#define DEBUG_TYPE "dwarfdebug" + void DwarfExpression::emitConstu(uint64_t Value) { if (Value < 32) emitOp(dwarf::DW_OP_lit0 + Value); @@ -97,7 +97,8 @@ void DwarfExpression::addAnd(unsigned Mask) { } bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI, - unsigned MachineReg, unsigned MaxSize) { + llvm::Register MachineReg, + unsigned MaxSize) { if (!llvm::Register::isPhysicalRegister(MachineReg)) { if (isFrameRegister(TRI, MachineReg)) { DwarfRegs.push_back(Register::createRegister(-1, nullptr)); @@ -219,9 +220,36 @@ void DwarfExpression::addUnsignedConstant(const APInt &Value) { } } +void DwarfExpression::addConstantFP(const APFloat &APF, const AsmPrinter &AP) { + assert(isImplicitLocation() || isUnknownLocation()); + APInt API = APF.bitcastToAPInt(); + int NumBytes = API.getBitWidth() / 8; + if (NumBytes == 4 /*float*/ || NumBytes == 8 /*double*/) { + // FIXME: Add support for `long double`. + emitOp(dwarf::DW_OP_implicit_value); + emitUnsigned(NumBytes /*Size of the block in bytes*/); + + // The loop below is emitting the value starting at least significant byte, + // so we need to perform a byte-swap to get the byte order correct in case + // of a big-endian target. + if (AP.getDataLayout().isBigEndian()) + API = API.byteSwap(); + + for (int i = 0; i < NumBytes; ++i) { + emitData1(API.getZExtValue() & 0xFF); + API = API.lshr(8); + } + + return; + } + LLVM_DEBUG( + dbgs() << "Skipped DW_OP_implicit_value creation for ConstantFP of size: " + << API.getBitWidth() << " bits\n"); +} + bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI, DIExpressionCursor &ExprCursor, - unsigned MachineReg, + llvm::Register MachineReg, unsigned FragmentOffsetInBits) { auto Fragment = ExprCursor.getFragmentInfo(); if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) { @@ -498,6 +526,7 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, case dwarf::DW_OP_not: case dwarf::DW_OP_dup: case dwarf::DW_OP_push_object_address: + case dwarf::DW_OP_over: emitOp(OpNum); break; case dwarf::DW_OP_deref: @@ -513,10 +542,15 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, assert(!isRegisterLocation()); emitConstu(Op->getArg(0)); break; + case dwarf::DW_OP_consts: + assert(!isRegisterLocation()); + emitOp(dwarf::DW_OP_consts); + emitSigned(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) { + if (DwarfVersion >= 5 && CU.getDwarfDebug().useOpConvert()) { emitOp(dwarf::DW_OP_convert); // If targeting a location-list; simply emit the index into the raw // byte stream as ULEB128, DwarfDebug::emitDebugLocEntry has been diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h index 757b17511453..8fca9f5a630b 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -218,7 +218,7 @@ protected: /// Return whether the given machine register is the frame register in the /// current function. virtual bool isFrameRegister(const TargetRegisterInfo &TRI, - unsigned MachineReg) = 0; + llvm::Register MachineReg) = 0; /// Emit a DW_OP_reg operation. Note that this is only legal inside a DWARF /// register location description. @@ -245,7 +245,7 @@ protected: /// multiple subregisters that alias the register. /// /// \return false if no DWARF register exists for MachineReg. - bool addMachineReg(const TargetRegisterInfo &TRI, unsigned MachineReg, + bool addMachineReg(const TargetRegisterInfo &TRI, llvm::Register MachineReg, unsigned MaxSize = ~1U); /// Emit a DW_OP_piece or DW_OP_bit_piece operation for a variable fragment. @@ -299,6 +299,9 @@ public: /// Emit an unsigned constant. void addUnsignedConstant(const APInt &Value); + /// Emit an floating point constant. + void addConstantFP(const APFloat &Value, const AsmPrinter &AP); + /// Lock this down to become a memory location description. void setMemoryLocationKind() { assert(isUnknownLocation()); @@ -322,7 +325,8 @@ public: /// \return false if no DWARF register exists /// for MachineReg. bool addMachineRegExpression(const TargetRegisterInfo &TRI, - DIExpressionCursor &Expr, unsigned MachineReg, + DIExpressionCursor &Expr, + llvm::Register MachineReg, unsigned FragmentOffsetInBits = 0); /// Begin emission of an entry value dwarf operation. The entry value's @@ -385,7 +389,7 @@ class DebugLocDwarfExpression final : public DwarfExpression { void commitTemporaryBuffer() override; bool isFrameRegister(const TargetRegisterInfo &TRI, - unsigned MachineReg) override; + llvm::Register MachineReg) override; public: DebugLocDwarfExpression(unsigned DwarfVersion, BufferByteStreamer &BS, @@ -415,7 +419,7 @@ class DIEDwarfExpression final : public DwarfExpression { void commitTemporaryBuffer() override; bool isFrameRegister(const TargetRegisterInfo &TRI, - unsigned MachineReg) override; + llvm::Register MachineReg) override; public: DIEDwarfExpression(const AsmPrinter &AP, DwarfCompileUnit &CU, DIELoc &DIE); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp index 812e6383288f..838e1c9a10be 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -10,10 +10,9 @@ #include "DwarfCompileUnit.h" #include "DwarfDebug.h" #include "DwarfUnit.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/DIE.h" #include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/Metadata.h" #include "llvm/MC/MCStreamer.h" #include <algorithm> #include <cstdint> @@ -59,7 +58,7 @@ void DwarfFile::emitUnit(DwarfUnit *TheU, bool UseOffsets) { // Compute the size and offset for each DIE. void DwarfFile::computeSizeAndOffsets() { // Offset from the first CU in the debug info section is 0 initially. - unsigned SecOffset = 0; + uint64_t SecOffset = 0; // Iterate over each compile unit and set the size and offsets for each // DIE within each compile unit. All offsets are CU relative. @@ -75,12 +74,15 @@ void DwarfFile::computeSizeAndOffsets() { TheU->setDebugSectionOffset(SecOffset); SecOffset += computeSizeAndOffsetsForUnit(TheU.get()); } + if (SecOffset > UINT32_MAX && !Asm->isDwarf64()) + report_fatal_error("The generated debug information is too large " + "for the 32-bit DWARF format."); } unsigned DwarfFile::computeSizeAndOffsetsForUnit(DwarfUnit *TheU) { // CU-relative offset is reset to 0 here. - unsigned Offset = sizeof(int32_t) + // Length of Unit Info - TheU->getHeaderSize(); // Unit-specific headers + unsigned Offset = Asm->getUnitLengthFieldByteSize() + // Length of Unit Info + TheU->getHeaderSize(); // Unit-specific headers // The return value here is CU-relative, after laying out // all of the CU DIE. diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h index cf293d7534d0..79a6ce7801b7 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -14,7 +14,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/DIE.h" -#include "llvm/IR/Metadata.h" #include "llvm/Support/Allocator.h" #include <map> #include <memory> @@ -26,10 +25,12 @@ class AsmPrinter; class DbgEntity; class DbgVariable; class DbgLabel; +class DINode; class DwarfCompileUnit; class DwarfUnit; class LexicalScope; class MCSection; +class MDNode; // Data structure to hold a range for range lists. struct RangeSpan { diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp index a43929d8e8f7..a876f8ccace9 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp @@ -8,7 +8,6 @@ #include "DwarfStringPool.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/MC/MCAsmInfo.h" @@ -33,7 +32,6 @@ DwarfStringPool::getEntryImpl(AsmPrinter &Asm, StringRef Str) { Entry.Symbol = ShouldCreateSymbols ? Asm.createTempSymbol(Prefix) : nullptr; NumBytes += Str.size() + 1; - assert(NumBytes > Entry.Offset && "Unexpected overflow"); } return *I.first; } @@ -58,13 +56,13 @@ void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm, if (getNumIndexedStrings() == 0) return; Asm.OutStreamer->SwitchSection(Section); - unsigned EntrySize = 4; - // FIXME: DWARF64 + unsigned EntrySize = Asm.getDwarfOffsetByteSize(); // We are emitting the header for a contribution to the string offsets // table. The header consists of an entry with the contribution's // size (not including the size of the length field), the DWARF version and // 2 bytes of padding. - Asm.emitInt32(getNumIndexedStrings() * EntrySize + 4); + Asm.emitDwarfUnitLength(getNumIndexedStrings() * EntrySize + 4, + "Length of String Offsets Set"); Asm.emitInt16(Asm.getDwarfVersion()); Asm.emitInt16(0); // Define the symbol that marks the start of the contribution. It is @@ -120,7 +118,7 @@ void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, } Asm.OutStreamer->SwitchSection(OffsetSection); - unsigned size = 4; // FIXME: DWARF64 is 8. + unsigned size = Asm.getDwarfOffsetByteSize(); for (const auto &Entry : Entries) if (UseRelativeOffsets) Asm.emitDwarfStringOffset(Entry->getValue()); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfStringPool.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfStringPool.h index c5f5637fdae3..79b5df89e338 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfStringPool.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfStringPool.h @@ -28,7 +28,7 @@ class DwarfStringPool { StringMap<EntryTy, BumpPtrAllocator &> Pool; StringRef Prefix; - unsigned NumBytes = 0; + uint64_t NumBytes = 0; unsigned NumIndexedStrings = 0; bool ShouldCreateSymbols; diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index ceeae14c1073..118b5fcc3bf6 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -13,7 +13,6 @@ #include "DwarfUnit.h" #include "AddressPool.h" #include "DwarfCompileUnit.h" -#include "DwarfDebug.h" #include "DwarfExpression.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" @@ -84,15 +83,14 @@ unsigned DIEDwarfExpression::getTemporaryBufferSize() { void DIEDwarfExpression::commitTemporaryBuffer() { OutDIE.takeValues(TmpDIE); } bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, - unsigned MachineReg) { + llvm::Register MachineReg) { return MachineReg == TRI.getFrameRegister(*AP.MF); } DwarfUnit::DwarfUnit(dwarf::Tag UnitTag, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU) - : DIEUnit(A->getDwarfVersion(), A->MAI->getCodePointerSize(), UnitTag), - CUNode(Node), Asm(A), DD(DW), DU(DWU), IndexTyDie(nullptr) { -} + : DIEUnit(UnitTag), CUNode(Node), Asm(A), DD(DW), DU(DWU), + IndexTyDie(nullptr) {} DwarfTypeUnit::DwarfTypeUnit(DwarfCompileUnit &CU, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU, @@ -301,27 +299,7 @@ void DwarfUnit::addLabel(DIELoc &Die, dwarf::Form Form, const MCSymbol *Label) { void DwarfUnit::addSectionOffset(DIE &Die, dwarf::Attribute Attribute, uint64_t Integer) { - if (DD->getDwarfVersion() >= 4) - addUInt(Die, Attribute, dwarf::DW_FORM_sec_offset, Integer); - else - addUInt(Die, Attribute, dwarf::DW_FORM_data4, Integer); -} - -Optional<MD5::MD5Result> DwarfUnit::getMD5AsBytes(const DIFile *File) const { - assert(File); - if (DD->getDwarfVersion() < 5) - return None; - Optional<DIFile::ChecksumInfo<StringRef>> Checksum = File->getChecksum(); - if (!Checksum || Checksum->Kind != DIFile::CSK_MD5) - 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); - MD5::MD5Result CKMem; - std::copy(ChecksumString.begin(), ChecksumString.end(), CKMem.Bytes.data()); - return CKMem; + addUInt(Die, Attribute, DD->getDwarfSectionOffsetForm(), Integer); } unsigned DwarfTypeUnit::getOrCreateSourceID(const DIFile *File) { @@ -332,10 +310,9 @@ unsigned DwarfTypeUnit::getOrCreateSourceID(const DIFile *File) { // This is a split type unit that needs a line table. addSectionOffset(getUnitDie(), dwarf::DW_AT_stmt_list, 0); } - return SplitLineTable->getFile(File->getDirectory(), File->getFilename(), - getMD5AsBytes(File), - Asm->OutContext.getDwarfVersion(), - File->getSource()); + return SplitLineTable->getFile( + File->getDirectory(), File->getFilename(), DD->getMD5AsBytes(File), + Asm->OutContext.getDwarfVersion(), File->getSource()); } void DwarfUnit::addOpAddress(DIELoc &Die, const MCSymbol *Sym) { @@ -353,7 +330,7 @@ void DwarfUnit::addOpAddress(DIELoc &Die, const MCSymbol *Sym) { } addUInt(Die, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); - addLabel(Die, dwarf::DW_FORM_udata, Sym); + addLabel(Die, dwarf::DW_FORM_addr, Sym); } void DwarfUnit::addLabelDelta(DIE &Die, dwarf::Attribute Attribute, @@ -457,77 +434,6 @@ void DwarfUnit::addSourceLine(DIE &Die, const DIObjCProperty *Ty) { addSourceLine(Die, Ty->getLine(), Ty->getFile()); } -/// Return true if type encoding is unsigned. -static bool isUnsignedDIType(DwarfDebug *DD, const DIType *Ty) { - if (auto *CTy = dyn_cast<DICompositeType>(Ty)) { - // FIXME: Enums without a fixed underlying type have unknown signedness - // here, leading to incorrectly emitted constants. - if (CTy->getTag() == dwarf::DW_TAG_enumeration_type) - return false; - - // (Pieces of) aggregate types that get hacked apart by SROA may be - // represented by a constant. Encode them as unsigned bytes. - return true; - } - - if (auto *DTy = dyn_cast<DIDerivedType>(Ty)) { - dwarf::Tag T = (dwarf::Tag)Ty->getTag(); - // Encode pointer constants as unsigned bytes. This is used at least for - // null pointer constant emission. - // FIXME: reference and rvalue_reference /probably/ shouldn't be allowed - // here, but accept them for now due to a bug in SROA producing bogus - // dbg.values. - if (T == dwarf::DW_TAG_pointer_type || - T == dwarf::DW_TAG_ptr_to_member_type || - T == dwarf::DW_TAG_reference_type || - T == dwarf::DW_TAG_rvalue_reference_type) - return true; - 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); - assert(DTy->getBaseType() && "Expected valid base type"); - return isUnsignedDIType(DD, DTy->getBaseType()); - } - - auto *BTy = cast<DIBasicType>(Ty); - unsigned Encoding = BTy->getEncoding(); - assert((Encoding == dwarf::DW_ATE_unsigned || - Encoding == dwarf::DW_ATE_unsigned_char || - Encoding == dwarf::DW_ATE_signed || - Encoding == dwarf::DW_ATE_signed_char || - Encoding == dwarf::DW_ATE_float || Encoding == dwarf::DW_ATE_UTF || - Encoding == dwarf::DW_ATE_boolean || - (Ty->getTag() == dwarf::DW_TAG_unspecified_type && - Ty->getName() == "decltype(nullptr)")) && - "Unsupported encoding"); - return Encoding == dwarf::DW_ATE_unsigned || - Encoding == dwarf::DW_ATE_unsigned_char || - Encoding == dwarf::DW_ATE_UTF || Encoding == dwarf::DW_ATE_boolean || - Ty->getTag() == dwarf::DW_TAG_unspecified_type; -} - -void DwarfUnit::addConstantFPValue(DIE &Die, const MachineOperand &MO) { - assert(MO.isFPImm() && "Invalid machine operand!"); - DIEBlock *Block = new (DIEValueAllocator) DIEBlock; - APFloat FPImm = MO.getFPImm()->getValueAPF(); - - // Get the raw data form of the floating point. - const APInt FltVal = FPImm.bitcastToAPInt(); - const char *FltPtr = (const char *)FltVal.getRawData(); - - int NumBytes = FltVal.getBitWidth() / 8; // 8 bits per byte. - bool LittleEndian = Asm->getDataLayout().isLittleEndian(); - int Incr = (LittleEndian ? 1 : -1); - int Start = (LittleEndian ? 0 : NumBytes - 1); - int Stop = (LittleEndian ? NumBytes : -1); - - // Output the constant to DWARF one byte at a time. - for (; Start != Stop; Start += Incr) - addUInt(*Block, dwarf::DW_FORM_data1, (unsigned char)0xFF & FltPtr[Start]); - - addBlock(Die, dwarf::DW_AT_const_value, Block); -} - void DwarfUnit::addConstantFPValue(DIE &Die, const ConstantFP *CFP) { // Pass this down to addConstantValue as an unsigned bag of bits. addConstantValue(Die, CFP->getValueAPF().bitcastToAPInt(), true); @@ -538,15 +444,8 @@ void DwarfUnit::addConstantValue(DIE &Die, const ConstantInt *CI, addConstantValue(Die, CI->getValue(), Ty); } -void DwarfUnit::addConstantValue(DIE &Die, const MachineOperand &MO, - const DIType *Ty) { - assert(MO.isImm() && "Invalid machine operand!"); - - addConstantValue(Die, isUnsignedDIType(DD, Ty), MO.getImm()); -} - void DwarfUnit::addConstantValue(DIE &Die, uint64_t Val, const DIType *Ty) { - addConstantValue(Die, isUnsignedDIType(DD, Ty), Val); + addConstantValue(Die, DD->isUnsignedDIType(Ty), Val); } void DwarfUnit::addConstantValue(DIE &Die, bool Unsigned, uint64_t Val) { @@ -557,7 +456,7 @@ void DwarfUnit::addConstantValue(DIE &Die, bool Unsigned, uint64_t Val) { } void DwarfUnit::addConstantValue(DIE &Die, const APInt &Val, const DIType *Ty) { - addConstantValue(Die, Val, isUnsignedDIType(DD, Ty)); + addConstantValue(Die, Val, DD->isUnsignedDIType(Ty)); } void DwarfUnit::addConstantValue(DIE &Die, const APInt &Val, bool Unsigned) { @@ -654,6 +553,8 @@ DIE *DwarfUnit::createTypeDIE(const DIScope *Context, DIE &ContextDIE, if (auto *BT = dyn_cast<DIBasicType>(Ty)) constructTypeDIE(TyDIE, BT); + else if (auto *ST = dyn_cast<DIStringType>(Ty)) + constructTypeDIE(TyDIE, ST); else if (auto *STy = dyn_cast<DISubroutineType>(Ty)) constructTypeDIE(TyDIE, STy); else if (auto *CTy = dyn_cast<DICompositeType>(Ty)) { @@ -772,8 +673,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) { if (BTy->getTag() == dwarf::DW_TAG_unspecified_type) return; - addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, - BTy->getEncoding()); + if (BTy->getTag() != dwarf::DW_TAG_string_type) + addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, + BTy->getEncoding()); uint64_t Size = BTy->getSizeInBits() >> 3; addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size); @@ -784,6 +686,37 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) { addUInt(Buffer, dwarf::DW_AT_endianity, None, dwarf::DW_END_little); } +void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) { + // Get core information. + StringRef Name = STy->getName(); + // Add name if not anonymous or intermediate type. + if (!Name.empty()) + addString(Buffer, dwarf::DW_AT_name, Name); + + if (DIVariable *Var = STy->getStringLength()) { + if (auto *VarDIE = getDIE(Var)) + addDIEEntry(Buffer, dwarf::DW_AT_string_length, *VarDIE); + } else if (DIExpression *Expr = STy->getStringLengthExp()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + // This is to describe the memory location of the + // length of a Fortran deferred length string, so + // lock it down as such. + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(Expr); + addBlock(Buffer, dwarf::DW_AT_string_length, DwarfExpr.finalize()); + } else { + uint64_t Size = STy->getSizeInBits() >> 3; + addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size); + } + + if (STy->getEncoding()) { + // For eventual Unicode support. + addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, + STy->getEncoding()); + } +} + void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) { // Get core information. StringRef Name = DTy->getName(); @@ -910,6 +843,11 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { } } + // Add template parameters to a class, structure or union types. + if (Tag == dwarf::DW_TAG_class_type || + Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) + addTemplateParams(Buffer, CTy->getTemplateParams()); + // Add elements to structure type. DINodeArray Elements = CTy->getElements(); for (const auto *Element : Elements) { @@ -929,7 +867,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, Discriminator->getBaseType())) + if (DD->isUnsignedDIType(Discriminator->getBaseType())) addUInt(Variant, dwarf::DW_AT_discr_value, None, CI->getZExtValue()); else addSInt(Variant, dwarf::DW_AT_discr_value, None, CI->getSExtValue()); @@ -979,12 +917,6 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { if (CTy->isObjcClassComplete()) addFlag(Buffer, dwarf::DW_AT_APPLE_objc_complete_type); - // Add template parameters to a class, structure or union types. - // FIXME: The support isn't in the metadata for this yet. - if (Tag == dwarf::DW_TAG_class_type || - Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) - addTemplateParams(Buffer, CTy->getTemplateParams()); - // Add the type's non-standard calling convention. uint8_t CC = 0; if (CTy->isTypePassByValue()) @@ -1008,8 +940,10 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { // Add size if non-zero (derived types might be zero-sized.) + // Ignore the size if it's a non-enum forward decl. // TODO: Do we care about size for enum forward declarations? - if (Size) + if (Size && + (!CTy->isForwardDecl() || Tag == dwarf::DW_TAG_enumeration_type)) addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size); else if (!CTy->isForwardDecl()) // Add zero size if it is not a forward declaration. @@ -1133,6 +1067,8 @@ DIE *DwarfUnit::getOrCreateModule(const DIModule *M) { getOrCreateSourceID(M->getFile())); if (M->getLineNo()) addUInt(MDie, dwarf::DW_AT_decl_line, None, M->getLineNo()); + if (M->getIsDecl()) + addFlag(MDie, dwarf::DW_AT_declaration); return &MDie; } @@ -1354,7 +1290,7 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, if (auto *CI = SR->getCount().dyn_cast<ConstantInt*>()) Count = CI->getSExtValue(); - auto addBoundTypeEntry = [&](dwarf::Attribute Attr, + auto AddBoundTypeEntry = [&](dwarf::Attribute Attr, DISubrange::BoundType Bound) -> void { if (auto *BV = Bound.dyn_cast<DIVariable *>()) { if (auto *VarDIE = getDIE(BV)) @@ -1372,7 +1308,7 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, } }; - addBoundTypeEntry(dwarf::DW_AT_lower_bound, SR->getLowerBound()); + AddBoundTypeEntry(dwarf::DW_AT_lower_bound, SR->getLowerBound()); if (auto *CV = SR->getCount().dyn_cast<DIVariable*>()) { if (auto *CountVarDIE = getDIE(CV)) @@ -1380,9 +1316,45 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, } else if (Count != -1) addUInt(DW_Subrange, dwarf::DW_AT_count, None, Count); - addBoundTypeEntry(dwarf::DW_AT_upper_bound, SR->getUpperBound()); + AddBoundTypeEntry(dwarf::DW_AT_upper_bound, SR->getUpperBound()); - addBoundTypeEntry(dwarf::DW_AT_byte_stride, SR->getStride()); + AddBoundTypeEntry(dwarf::DW_AT_byte_stride, SR->getStride()); +} + +void DwarfUnit::constructGenericSubrangeDIE(DIE &Buffer, + const DIGenericSubrange *GSR, + DIE *IndexTy) { + DIE &DwGenericSubrange = + createAndAddDIE(dwarf::DW_TAG_generic_subrange, Buffer); + addDIEEntry(DwGenericSubrange, dwarf::DW_AT_type, *IndexTy); + + int64_t DefaultLowerBound = getDefaultLowerBound(); + + auto AddBoundTypeEntry = [&](dwarf::Attribute Attr, + DIGenericSubrange::BoundType Bound) -> void { + if (auto *BV = Bound.dyn_cast<DIVariable *>()) { + if (auto *VarDIE = getDIE(BV)) + addDIEEntry(DwGenericSubrange, Attr, *VarDIE); + } else if (auto *BE = Bound.dyn_cast<DIExpression *>()) { + if (BE->isSignedConstant()) { + if (Attr != dwarf::DW_AT_lower_bound || DefaultLowerBound == -1 || + static_cast<int64_t>(BE->getElement(1)) != DefaultLowerBound) + addSInt(DwGenericSubrange, Attr, dwarf::DW_FORM_sdata, + BE->getElement(1)); + } else { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(BE); + addBlock(DwGenericSubrange, Attr, DwarfExpr.finalize()); + } + } + }; + + AddBoundTypeEntry(dwarf::DW_AT_lower_bound, GSR->getLowerBound()); + AddBoundTypeEntry(dwarf::DW_AT_count, GSR->getCount()); + AddBoundTypeEntry(dwarf::DW_AT_upper_bound, GSR->getUpperBound()); + AddBoundTypeEntry(dwarf::DW_AT_byte_stride, GSR->getStride()); } DIE *DwarfUnit::getIndexTyDie() { @@ -1447,6 +1419,39 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { addBlock(Buffer, dwarf::DW_AT_data_location, DwarfExpr.finalize()); } + if (DIVariable *Var = CTy->getAssociated()) { + if (auto *VarDIE = getDIE(Var)) + addDIEEntry(Buffer, dwarf::DW_AT_associated, *VarDIE); + } else if (DIExpression *Expr = CTy->getAssociatedExp()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(Expr); + addBlock(Buffer, dwarf::DW_AT_associated, DwarfExpr.finalize()); + } + + if (DIVariable *Var = CTy->getAllocated()) { + if (auto *VarDIE = getDIE(Var)) + addDIEEntry(Buffer, dwarf::DW_AT_allocated, *VarDIE); + } else if (DIExpression *Expr = CTy->getAllocatedExp()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(Expr); + addBlock(Buffer, dwarf::DW_AT_allocated, DwarfExpr.finalize()); + } + + if (auto *RankConst = CTy->getRankConst()) { + addSInt(Buffer, dwarf::DW_AT_rank, dwarf::DW_FORM_sdata, + RankConst->getSExtValue()); + } else if (auto *RankExpr = CTy->getRankExp()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(RankExpr); + addBlock(Buffer, dwarf::DW_AT_rank, DwarfExpr.finalize()); + } + // Emit the element type. addType(Buffer, CTy->getBaseType()); @@ -1459,15 +1464,19 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { DINodeArray Elements = CTy->getElements(); for (unsigned i = 0, N = Elements.size(); i < N; ++i) { // FIXME: Should this really be such a loose cast? - if (auto *Element = dyn_cast_or_null<DINode>(Elements[i])) + if (auto *Element = dyn_cast_or_null<DINode>(Elements[i])) { if (Element->getTag() == dwarf::DW_TAG_subrange_type) constructSubrangeDIE(Buffer, cast<DISubrange>(Element), IdxTy); + else if (Element->getTag() == dwarf::DW_TAG_generic_subrange) + constructGenericSubrangeDIE(Buffer, cast<DIGenericSubrange>(Element), + IdxTy); + } } } void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) { const DIType *DTy = CTy->getBaseType(); - bool IsUnsigned = DTy && isUnsignedDIType(DD, DTy); + bool IsUnsigned = DTy && DD->isUnsignedDIType(DTy); if (DTy) { if (DD->getDwarfVersion() >= 3) addType(Buffer, DTy); @@ -1666,15 +1675,15 @@ DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) { void DwarfUnit::emitCommonHeader(bool UseOffsets, dwarf::UnitType UT) { // Emit size of content not including length itself - Asm->OutStreamer->AddComment("Length of Unit"); if (!DD->useSectionsAsReferences()) { StringRef Prefix = isDwoUnit() ? "debug_info_dwo_" : "debug_info_"; MCSymbol *BeginLabel = Asm->createTempSymbol(Prefix + "start"); EndLabel = Asm->createTempSymbol(Prefix + "end"); - Asm->emitLabelDifference(EndLabel, BeginLabel, 4); + Asm->emitDwarfUnitLength(EndLabel, BeginLabel, "Length of Unit"); Asm->OutStreamer->emitLabel(BeginLabel); } else - Asm->emitInt32(getHeaderSize() + getUnitDie().getSize()); + Asm->emitDwarfUnitLength(getHeaderSize() + getUnitDie().getSize(), + "Length of Unit"); Asm->OutStreamer->AddComment("DWARF version number"); unsigned Version = DD->getDwarfVersion(); @@ -1694,7 +1703,7 @@ void DwarfUnit::emitCommonHeader(bool UseOffsets, dwarf::UnitType UT) { Asm->OutStreamer->AddComment("Offset Into Abbrev. Section"); const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); if (UseOffsets) - Asm->emitInt32(0); + Asm->emitDwarfLengthOrOffset(0); else Asm->emitDwarfSymbolReference( TLOF.getDwarfAbbrevSection()->getBeginSymbol(), false); @@ -1713,16 +1722,14 @@ void DwarfTypeUnit::emitHeader(bool UseOffsets) { Asm->OutStreamer->emitIntValue(TypeSignature, sizeof(TypeSignature)); Asm->OutStreamer->AddComment("Type DIE Offset"); // In a skeleton type unit there is no type DIE so emit a zero offset. - Asm->OutStreamer->emitIntValue(Ty ? Ty->getOffset() : 0, - sizeof(Ty->getOffset())); + Asm->emitDwarfLengthOrOffset(Ty ? Ty->getOffset() : 0); } DIE::value_iterator DwarfUnit::addSectionDelta(DIE &Die, dwarf::Attribute Attribute, const MCSymbol *Hi, const MCSymbol *Lo) { return Die.addValue(DIEValueAllocator, Attribute, - DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset - : dwarf::DW_FORM_data4, + DD->getDwarfSectionOffsetForm(), new (DIEValueAllocator) DIEDelta(Hi, Lo)); } @@ -1730,10 +1737,7 @@ DIE::value_iterator DwarfUnit::addSectionLabel(DIE &Die, dwarf::Attribute Attribute, const MCSymbol *Label, const MCSymbol *Sec) { if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) - return addLabel(Die, Attribute, - DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset - : dwarf::DW_FORM_data4, - Label); + return addLabel(Die, Attribute, DD->getDwarfSectionOffsetForm(), Label); return addSectionDelta(Die, Attribute, Label, Sec); } diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 34f3a34ed336..5c643760fd56 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -16,22 +16,19 @@ #include "DwarfDebug.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringMap.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" -#include "llvm/IR/DIBuilder.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/MC/MCDwarf.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCSection.h" +#include <string> namespace llvm { -class MachineOperand; -class ConstantInt; class ConstantFP; +class ConstantInt; class DbgVariable; class DwarfCompileUnit; +class MachineOperand; +class MCDwarfDwoLineTable; +class MCSymbol; //===----------------------------------------------------------------------===// /// This dwarf writer support class manages information associated with a @@ -77,7 +74,6 @@ protected: bool applySubprogramDefinitionAttributes(const DISubprogram *SP, DIE &SPDie); - bool shareAcrossDWOCUs() const; bool isShareableAcrossCUs(const DINode *D) const; public: @@ -86,8 +82,7 @@ public: MCSymbol *getEndLabel() const { return EndLabel; } uint16_t getLanguage() const { return CUNode->getSourceLanguage(); } const DICompileUnit *getCUNode() const { return CUNode; } - - uint16_t getDwarfVersion() const { return DD->getDwarfVersion(); } + DwarfDebug &getDwarfDebug() const { return *DD; } /// Return true if this compile unit has something to write out. bool hasContent() const { return getUnitDie().hasChildren(); } @@ -195,7 +190,6 @@ public: void addSourceLine(DIE &Die, const DIObjCProperty *Ty); /// Add constant value entry in variable DIE. - void addConstantValue(DIE &Die, const MachineOperand &MO, const DIType *Ty); 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); @@ -203,7 +197,6 @@ public: void addConstantValue(DIE &Die, bool Unsigned, uint64_t Val); /// Add constant value entry in variable DIE. - void addConstantFPValue(DIE &Die, const MachineOperand &MO); void addConstantFPValue(DIE &Die, const ConstantFP *CFP); /// Add a linkage name, if it isn't empty. @@ -255,9 +248,9 @@ public: /// Compute the size of a header for this unit, not including the initial /// length field. virtual unsigned getHeaderSize() const { - return sizeof(int16_t) + // DWARF version number - sizeof(int32_t) + // Offset Into Abbrev. Section - sizeof(int8_t) + // Pointer Size (in bytes) + return sizeof(int16_t) + // DWARF version number + Asm->getDwarfOffsetByteSize() + // Offset Into Abbrev. Section + sizeof(int8_t) + // Pointer Size (in bytes) (DD->getDwarfVersion() >= 5 ? sizeof(int8_t) : 0); // DWARF v5 unit type } @@ -284,10 +277,6 @@ public: const MCSymbol *Label, const MCSymbol *Sec); - /// If the \p File has an MD5 checksum, return it as an MD5Result - /// allocated in the MCContext. - Optional<MD5::MD5Result> getMD5AsBytes(const DIFile *File) const; - /// Get context owner's DIE. DIE *createTypeDIE(const DICompositeType *Ty); @@ -306,9 +295,12 @@ protected: private: void constructTypeDIE(DIE &Buffer, const DIBasicType *BTy); + void constructTypeDIE(DIE &Buffer, const DIStringType *BTy); void constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy); void constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy); void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy); + void constructGenericSubrangeDIE(DIE &Buffer, const DIGenericSubrange *SR, + DIE *IndexTy); void constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy); void constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy); DIE &constructMemberDIE(DIE &Buffer, const DIDerivedType *DT); @@ -361,7 +353,7 @@ public: void emitHeader(bool UseOffsets) override; unsigned getHeaderSize() const override { return DwarfUnit::getHeaderSize() + sizeof(uint64_t) + // Type Signature - sizeof(uint32_t); // Type DIE Offset + Asm->getDwarfOffsetByteSize(); // Type DIE Offset } void addGlobalName(StringRef Name, const DIE &Die, const DIScope *Context) override; diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp index 99ee4567fa58..2ffe8a7b0469 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -44,15 +44,9 @@ EHStreamer::~EHStreamer() = default; unsigned EHStreamer::sharedTypeIDs(const LandingPadInfo *L, const LandingPadInfo *R) { const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds; - unsigned LSize = LIds.size(), RSize = RIds.size(); - unsigned MinSize = LSize < RSize ? LSize : RSize; - unsigned Count = 0; - - for (; Count != MinSize; ++Count) - if (LIds[Count] != RIds[Count]) - return Count; - - return Count; + return std::mismatch(LIds.begin(), LIds.end(), RIds.begin(), RIds.end()) + .first - + LIds.begin(); } /// Compute the actions table and gather the first action index for each landing @@ -220,15 +214,30 @@ void EHStreamer::computePadMap( /// the landing pad and the action. Calls marked 'nounwind' have no entry and /// must not be contained in the try-range of any entry - they form gaps in the /// table. Entries must be ordered by try-range address. -void EHStreamer:: -computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, - const SmallVectorImpl<const LandingPadInfo *> &LandingPads, - const SmallVectorImpl<unsigned> &FirstActions) { +/// +/// Call-sites are split into one or more call-site ranges associated with +/// different sections of the function. +/// +/// - Without -basic-block-sections, all call-sites are grouped into one +/// call-site-range corresponding to the function section. +/// +/// - With -basic-block-sections, one call-site range is created for each +/// section, with its FragmentBeginLabel and FragmentEndLabel respectively +// set to the beginning and ending of the corresponding section and its +// ExceptionLabel set to the exception symbol dedicated for this section. +// Later, one LSDA header will be emitted for each call-site range with its +// call-sites following. The action table and type info table will be +// shared across all ranges. +void EHStreamer::computeCallSiteTable( + SmallVectorImpl<CallSiteEntry> &CallSites, + SmallVectorImpl<CallSiteRange> &CallSiteRanges, + const SmallVectorImpl<const LandingPadInfo *> &LandingPads, + const SmallVectorImpl<unsigned> &FirstActions) { RangeMapType PadMap; computePadMap(LandingPads, PadMap); // The end label of the previous invoke or nounwind try-range. - MCSymbol *LastLabel = nullptr; + MCSymbol *LastLabel = Asm->getFunctionBegin(); // Whether there is a potentially throwing instruction (currently this means // an ordinary call) between the end of the previous try-range and now. @@ -241,6 +250,21 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, // Visit all instructions in order of address. for (const auto &MBB : *Asm->MF) { + if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) { + // We start a call-site range upon function entry and at the beginning of + // every basic block section. + CallSiteRanges.push_back( + {Asm->MBBSectionRanges[MBB.getSectionIDNum()].BeginLabel, + Asm->MBBSectionRanges[MBB.getSectionIDNum()].EndLabel, + Asm->getMBBExceptionSym(MBB), CallSites.size()}); + PreviousIsInvoke = false; + SawPotentiallyThrowing = false; + LastLabel = nullptr; + } + + if (MBB.isEHPad()) + CallSiteRanges.back().IsLPRange = true; + for (const auto &MI : MBB) { if (!MI.isEHLabel()) { if (MI.isCall()) @@ -264,13 +288,14 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && "Inconsistent landing pad map!"); - // For Dwarf exception handling (SjLj handling doesn't use this). If some - // instruction between the previous try-range and this one may throw, - // create a call-site entry with no landing pad for the region between the - // try-ranges. - if (SawPotentiallyThrowing && Asm->MAI->usesCFIForEH()) { - CallSiteEntry Site = { LastLabel, BeginLabel, nullptr, 0 }; - CallSites.push_back(Site); + // For Dwarf and AIX exception handling (SjLj handling doesn't use this). + // If some instruction between the previous try-range and this one may + // throw, create a call-site entry with no landing pad for the region + // between the try-ranges. + if (SawPotentiallyThrowing && + (Asm->MAI->usesCFIForEH() || + Asm->MAI->getExceptionHandlingType() == ExceptionHandling::AIX)) { + CallSites.push_back({LastLabel, BeginLabel, nullptr, 0}); PreviousIsInvoke = false; } @@ -313,14 +338,21 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, PreviousIsInvoke = true; } } - } - // If some instruction between the previous try-range and the end of the - // function may throw, create a call-site entry with no landing pad for the - // region following the try-range. - if (SawPotentiallyThrowing && !IsSJLJ) { - CallSiteEntry Site = { LastLabel, nullptr, nullptr, 0 }; - CallSites.push_back(Site); + // We end the call-site range upon function exit and at the end of every + // basic block section. + if (&MBB == &Asm->MF->back() || MBB.isEndSection()) { + // If some instruction between the previous try-range and the end of the + // function may throw, create a call-site entry with no landing pad for + // the region following the try-range. + if (SawPotentiallyThrowing && !IsSJLJ) { + CallSiteEntry Site = {LastLabel, CallSiteRanges.back().FragmentEndLabel, + nullptr, 0}; + CallSites.push_back(Site); + SawPotentiallyThrowing = false; + } + CallSiteRanges.back().CallSiteEndIdx = CallSites.size(); + } } } @@ -371,19 +403,25 @@ MCSymbol *EHStreamer::emitExceptionTable() { SmallVector<unsigned, 64> FirstActions; computeActionsTable(LandingPads, Actions, FirstActions); - // Compute the call-site table. + // Compute the call-site table and call-site ranges. Normally, there is only + // one call-site-range which covers the whole funciton. With + // -basic-block-sections, there is one call-site-range per basic block + // section. SmallVector<CallSiteEntry, 64> CallSites; - computeCallSiteTable(CallSites, LandingPads, FirstActions); + SmallVector<CallSiteRange, 4> CallSiteRanges; + computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions); bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm; + bool HasLEB128Directives = Asm->MAI->hasLEB128Directives(); unsigned CallSiteEncoding = IsSJLJ ? static_cast<unsigned>(dwarf::DW_EH_PE_udata4) : Asm->getObjFileLowering().getCallSiteEncoding(); bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty(); // Type infos. - MCSection *LSDASection = Asm->getObjFileLowering().getLSDASection(); + MCSection *LSDASection = + Asm->getObjFileLowering().getSectionForLSDA(MF->getFunction(), Asm->TM); unsigned TTypeEncoding; if (!HaveTTData) { @@ -433,35 +471,122 @@ MCSymbol *EHStreamer::emitExceptionTable() { Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+ Twine(Asm->getFunctionNumber())); Asm->OutStreamer->emitLabel(GCCETSym); - Asm->OutStreamer->emitLabel(Asm->getCurExceptionSym()); - - // Emit the LSDA header. - Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); - Asm->emitEncodingByte(TTypeEncoding, "@TType"); + MCSymbol *CstEndLabel = Asm->createTempSymbol( + CallSiteRanges.size() > 1 ? "action_table_base" : "cst_end"); MCSymbol *TTBaseLabel = nullptr; - if (HaveTTData) { - // N.B.: There is a dependency loop between the size of the TTBase uleb128 - // here and the amount of padding before the aligned type table. The - // assembler must sometimes pad this uleb128 or insert extra padding before - // the type table. See PR35809 or GNU as bug 4029. - MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); + if (HaveTTData) TTBaseLabel = Asm->createTempSymbol("ttbase"); - Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); - Asm->OutStreamer->emitLabel(TTBaseRefLabel); - } - bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); + const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); + + // Helper for emitting references (offsets) for type table and the end of the + // call-site table (which marks the beginning of the action table). + // * For Itanium, these references will be emitted for every callsite range. + // * For SJLJ and Wasm, they will be emitted only once in the LSDA header. + auto EmitTypeTableRefAndCallSiteTableEndRef = [&]() { + Asm->emitEncodingByte(TTypeEncoding, "@TType"); + if (HaveTTData) { + // N.B.: There is a dependency loop between the size of the TTBase uleb128 + // here and the amount of padding before the aligned type table. The + // assembler must sometimes pad this uleb128 or insert extra padding + // before the type table. See PR35809 or GNU as bug 4029. + MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); + Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); + Asm->OutStreamer->emitLabel(TTBaseRefLabel); + } + + // The Action table follows the call-site table. So we emit the + // label difference from here (start of the call-site table for SJLJ and + // Wasm, and start of a call-site range for Itanium) to the end of the + // whole call-site table (end of the last call-site range for Itanium). + MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); + Asm->emitEncodingByte(CallSiteEncoding, "Call site"); + Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); + Asm->OutStreamer->emitLabel(CstBeginLabel); + }; + + // An alternative path to EmitTypeTableRefAndCallSiteTableEndRef. + // For some platforms, the system assembler does not accept the form of + // `.uleb128 label2 - label1`. In those situations, we would need to calculate + // the size between label1 and label2 manually. + // In this case, we would need to calculate the LSDA size and the call + // site table size. + auto EmitTypeTableOffsetAndCallSiteTableOffset = [&]() { + assert(CallSiteEncoding == dwarf::DW_EH_PE_udata4 && !HasLEB128Directives && + "Targets supporting .uleb128 do not need to take this path."); + if (CallSiteRanges.size() > 1) + report_fatal_error( + "-fbasic-block-sections is not yet supported on " + "platforms that do not have general LEB128 directive support."); + + uint64_t CallSiteTableSize = 0; + const CallSiteRange &CSRange = CallSiteRanges.back(); + for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx; + CallSiteIdx < CSRange.CallSiteEndIdx; ++CallSiteIdx) { + const CallSiteEntry &S = CallSites[CallSiteIdx]; + // Each call site entry consists of 3 udata4 fields (12 bytes) and + // 1 ULEB128 field. + CallSiteTableSize += 12 + getULEB128Size(S.Action); + assert(isUInt<32>(CallSiteTableSize) && "CallSiteTableSize overflows."); + } + + Asm->emitEncodingByte(TTypeEncoding, "@TType"); + if (HaveTTData) { + const unsigned ByteSizeOfCallSiteOffset = + getULEB128Size(CallSiteTableSize); + uint64_t ActionTableSize = 0; + for (const ActionEntry &Action : Actions) { + // Each action entry consists of two SLEB128 fields. + ActionTableSize += getSLEB128Size(Action.ValueForTypeID) + + getSLEB128Size(Action.NextAction); + assert(isUInt<32>(ActionTableSize) && "ActionTableSize overflows."); + } + + const unsigned TypeInfoSize = + Asm->GetSizeOfEncodedValue(TTypeEncoding) * MF->getTypeInfos().size(); + + const uint64_t LSDASizeBeforeAlign = + 1 // Call site encoding byte. + + ByteSizeOfCallSiteOffset // ULEB128 encoding of CallSiteTableSize. + + CallSiteTableSize // Call site table content. + + ActionTableSize; // Action table content. + + const uint64_t LSDASizeWithoutAlign = LSDASizeBeforeAlign + TypeInfoSize; + const unsigned ByteSizeOfLSDAWithoutAlign = + getULEB128Size(LSDASizeWithoutAlign); + const uint64_t DisplacementBeforeAlign = + 2 // LPStartEncoding and TypeTableEncoding. + + ByteSizeOfLSDAWithoutAlign + LSDASizeBeforeAlign; + + // The type info area starts with 4 byte alignment. + const unsigned NeedAlignVal = (4 - DisplacementBeforeAlign % 4) % 4; + uint64_t LSDASizeWithAlign = LSDASizeWithoutAlign + NeedAlignVal; + const unsigned ByteSizeOfLSDAWithAlign = + getULEB128Size(LSDASizeWithAlign); + + // The LSDASizeWithAlign could use 1 byte less padding for alignment + // when the data we use to represent the LSDA Size "needs" to be 1 byte + // larger than the one previously calculated without alignment. + if (ByteSizeOfLSDAWithAlign > ByteSizeOfLSDAWithoutAlign) + LSDASizeWithAlign -= 1; + + Asm->OutStreamer->emitULEB128IntValue(LSDASizeWithAlign, + ByteSizeOfLSDAWithAlign); + } - // Emit the landing pad call site table. - MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); - MCSymbol *CstEndLabel = Asm->createTempSymbol("cst_end"); - Asm->emitEncodingByte(CallSiteEncoding, "Call site"); - Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); - Asm->OutStreamer->emitLabel(CstBeginLabel); + Asm->emitEncodingByte(CallSiteEncoding, "Call site"); + Asm->OutStreamer->emitULEB128IntValue(CallSiteTableSize); + }; // SjLj / Wasm Exception handling if (IsSJLJ || IsWasm) { + Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front())); + + // emit the LSDA header. + Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); + EmitTypeTableRefAndCallSiteTableEndRef(); + unsigned idx = 0; for (SmallVectorImpl<CallSiteEntry>::const_iterator I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) { @@ -486,6 +611,7 @@ MCSymbol *EHStreamer::emitExceptionTable() { } Asm->emitULEB128(S.Action); } + Asm->OutStreamer->emitLabel(CstEndLabel); } else { // Itanium LSDA exception handling @@ -507,57 +633,127 @@ MCSymbol *EHStreamer::emitExceptionTable() { // A missing entry in the call-site table indicates that a call is not // supposed to throw. + assert(CallSiteRanges.size() != 0 && "No call-site ranges!"); + + // There should be only one call-site range which includes all the landing + // pads. Find that call-site range here. + const CallSiteRange *LandingPadRange = nullptr; + for (const CallSiteRange &CSRange : CallSiteRanges) { + if (CSRange.IsLPRange) { + assert(LandingPadRange == nullptr && + "All landing pads must be in a single callsite range."); + LandingPadRange = &CSRange; + } + } + + // The call-site table is split into its call-site ranges, each being + // emitted as: + // [ LPStartEncoding | LPStart ] + // [ TypeTableEncoding | TypeTableOffset ] + // [ CallSiteEncoding | CallSiteTableEndOffset ] + // cst_begin -> { call-site entries contained in this range } + // + // and is followed by the next call-site range. + // + // For each call-site range, CallSiteTableEndOffset is computed as the + // difference between cst_begin of that range and the last call-site-table's + // end label. This offset is used to find the action table. + unsigned Entry = 0; - for (SmallVectorImpl<CallSiteEntry>::const_iterator - I = CallSites.begin(), E = CallSites.end(); I != E; ++I) { - const CallSiteEntry &S = *I; + for (const CallSiteRange &CSRange : CallSiteRanges) { + if (CSRange.CallSiteBeginIdx != 0) { + // Align the call-site range for all ranges except the first. The + // first range is already aligned due to the exception table alignment. + Asm->emitAlignment(Align(4)); + } + Asm->OutStreamer->emitLabel(CSRange.ExceptionLabel); + + // Emit the LSDA header. + // If only one call-site range exists, LPStart is omitted as it is the + // same as the function entry. + if (CallSiteRanges.size() == 1) { + Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); + } else if (!Asm->isPositionIndependent()) { + // For more than one call-site ranges, LPStart must be explicitly + // specified. + // For non-PIC we can simply use the absolute value. + Asm->emitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart"); + Asm->OutStreamer->emitSymbolValue(LandingPadRange->FragmentBeginLabel, + Asm->MAI->getCodePointerSize()); + } else { + // For PIC mode, we Emit a PC-relative address for LPStart. + Asm->emitEncodingByte(dwarf::DW_EH_PE_pcrel, "@LPStart"); + MCContext &Context = Asm->OutStreamer->getContext(); + MCSymbol *Dot = Context.createTempSymbol(); + Asm->OutStreamer->emitLabel(Dot); + Asm->OutStreamer->emitValue( + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(LandingPadRange->FragmentBeginLabel, + Context), + MCSymbolRefExpr::create(Dot, Context), Context), + Asm->MAI->getCodePointerSize()); + } + + if (HasLEB128Directives) + EmitTypeTableRefAndCallSiteTableEndRef(); + else + EmitTypeTableOffsetAndCallSiteTableOffset(); + + for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx; + CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) { + const CallSiteEntry &S = CallSites[CallSiteIdx]; + + MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel; + MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel; - MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); - - MCSymbol *BeginLabel = S.BeginLabel; - if (!BeginLabel) - BeginLabel = EHFuncBeginSym; - MCSymbol *EndLabel = S.EndLabel; - if (!EndLabel) - EndLabel = Asm->getFunctionEnd(); - - // Offset of the call site relative to the start of the procedure. - if (VerboseAsm) - Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + " <<"); - Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); - if (VerboseAsm) - Asm->OutStreamer->AddComment(Twine(" Call between ") + - BeginLabel->getName() + " and " + - EndLabel->getName()); - Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding); - - // Offset of the landing pad relative to the start of the procedure. - if (!S.LPad) { + MCSymbol *BeginLabel = S.BeginLabel; + if (!BeginLabel) + BeginLabel = EHFuncBeginSym; + MCSymbol *EndLabel = S.EndLabel; + if (!EndLabel) + EndLabel = EHFuncEndSym; + + // Offset of the call site relative to the start of the procedure. if (VerboseAsm) - Asm->OutStreamer->AddComment(" has no landing pad"); - Asm->emitCallSiteValue(0, CallSiteEncoding); - } else { + Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + + " <<"); + Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); if (VerboseAsm) - Asm->OutStreamer->AddComment(Twine(" jumps to ") + - S.LPad->LandingPadLabel->getName()); - Asm->emitCallSiteOffset(S.LPad->LandingPadLabel, EHFuncBeginSym, - CallSiteEncoding); - } + Asm->OutStreamer->AddComment(Twine(" Call between ") + + BeginLabel->getName() + " and " + + EndLabel->getName()); + Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding); + + // Offset of the landing pad relative to the start of the landing pad + // fragment. + if (!S.LPad) { + if (VerboseAsm) + Asm->OutStreamer->AddComment(" has no landing pad"); + Asm->emitCallSiteValue(0, CallSiteEncoding); + } else { + if (VerboseAsm) + Asm->OutStreamer->AddComment(Twine(" jumps to ") + + S.LPad->LandingPadLabel->getName()); + Asm->emitCallSiteOffset(S.LPad->LandingPadLabel, + LandingPadRange->FragmentBeginLabel, + CallSiteEncoding); + } - // Offset of the first associated action record, relative to the start of - // the action table. This value is biased by 1 (1 indicates the start of - // the action table), and 0 indicates that there are no actions. - if (VerboseAsm) { - if (S.Action == 0) - Asm->OutStreamer->AddComment(" On action: cleanup"); - else - Asm->OutStreamer->AddComment(" On action: " + - Twine((S.Action - 1) / 2 + 1)); + // Offset of the first associated action record, relative to the start + // of the action table. This value is biased by 1 (1 indicates the start + // of the action table), and 0 indicates that there are no actions. + if (VerboseAsm) { + if (S.Action == 0) + Asm->OutStreamer->AddComment(" On action: cleanup"); + else + Asm->OutStreamer->AddComment(" On action: " + + Twine((S.Action - 1) / 2 + 1)); + } + Asm->emitULEB128(S.Action); } - Asm->emitULEB128(S.Action); } + Asm->OutStreamer->emitLabel(CstEndLabel); } - Asm->OutStreamer->emitLabel(CstEndLabel); // Emit the Action Table. int Entry = 0; @@ -587,15 +783,12 @@ MCSymbol *EHStreamer::emitExceptionTable() { Asm->emitSLEB128(Action.ValueForTypeID); // Action Record - // - // Self-relative signed displacement in bytes of the next action record, - // or 0 if there is no next action record. if (VerboseAsm) { - if (Action.NextAction == 0) { + if (Action.Previous == unsigned(-1)) { Asm->OutStreamer->AddComment(" No further actions"); } else { - unsigned NextAction = Entry + (Action.NextAction + 1) / 2; - Asm->OutStreamer->AddComment(" Continue to action "+Twine(NextAction)); + Asm->OutStreamer->AddComment(" Continue to action " + + Twine(Action.Previous + 1)); } } Asm->emitSLEB128(Action.NextAction); @@ -615,7 +808,7 @@ void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) { const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos(); const std::vector<unsigned> &FilterIds = MF->getFilterIds(); - bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); + const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); int Entry = 0; // Emit the Catch TypeInfos. diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h index e62cf17a05d4..234e62506a56 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -69,23 +69,48 @@ protected: unsigned Action; }; + /// Structure describing a contiguous range of call-sites which reside + /// in the same procedure fragment. With -fbasic-block-sections, there will + /// be one call site range per basic block section. Otherwise, we will have + /// one call site range containing all the call sites in the function. + struct CallSiteRange { + // Symbol marking the beginning of the precedure fragment. + MCSymbol *FragmentBeginLabel = nullptr; + // Symbol marking the end of the procedure fragment. + MCSymbol *FragmentEndLabel = nullptr; + // LSDA symbol for this call-site range. + MCSymbol *ExceptionLabel = nullptr; + // Index of the first call-site entry in the call-site table which + // belongs to this range. + size_t CallSiteBeginIdx = 0; + // Index just after the last call-site entry in the call-site table which + // belongs to this range. + size_t CallSiteEndIdx = 0; + // Whether this is the call-site range containing all the landing pads. + bool IsLPRange = false; + }; + /// Compute the actions table and gather the first action index for each /// landing pad site. - void computeActionsTable(const SmallVectorImpl<const LandingPadInfo *> &LandingPads, - SmallVectorImpl<ActionEntry> &Actions, - SmallVectorImpl<unsigned> &FirstActions); + void computeActionsTable( + const SmallVectorImpl<const LandingPadInfo *> &LandingPads, + SmallVectorImpl<ActionEntry> &Actions, + SmallVectorImpl<unsigned> &FirstActions); void computePadMap(const SmallVectorImpl<const LandingPadInfo *> &LandingPads, RangeMapType &PadMap); - /// Compute the call-site table. The entry for an invoke has a try-range - /// containing the call, a non-zero landing pad and an appropriate action. - /// The entry for an ordinary call has a try-range containing the call and - /// zero for the landing pad and the action. Calls marked 'nounwind' have - /// no entry and must not be contained in the try-range of any entry - they - /// form gaps in the table. Entries must be ordered by try-range address. + /// Compute the call-site table and the call-site ranges. The entry for an + /// invoke has a try-range containing the call, a non-zero landing pad and an + /// appropriate action. The entry for an ordinary call has a try-range + /// containing the call and zero for the landing pad and the action. Calls + /// marked 'nounwind' have no entry and must not be contained in the try-range + /// of any entry - they form gaps in the table. Entries must be ordered by + /// try-range address. CallSiteRanges vector is only populated for Itanium + /// exception handling. virtual void computeCallSiteTable( SmallVectorImpl<CallSiteEntry> &CallSites, + SmallVectorImpl<CallSiteRange> &CallSiteRanges, const SmallVectorImpl<const LandingPadInfo *> &LandingPads, const SmallVectorImpl<unsigned> &FirstActions); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp index 8fa83f515910..354b638b47a2 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp @@ -145,9 +145,10 @@ void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Frame size " + - Twine(FrameSize) + ">= 65536.\n" - "(" + - Twine(uintptr_t(&FI)) + ")"); + Twine(FrameSize) + + ">= 65536.\n" + "(" + + Twine(reinterpret_cast<uintptr_t>(&FI)) + ")"); } AP.OutStreamer->AddComment("live roots for " + diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp new file mode 100644 index 000000000000..e8636052c54c --- /dev/null +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.cpp @@ -0,0 +1,84 @@ +//===- llvm/CodeGen/PseudoProbePrinter.cpp - Pseudo Probe Emission -------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing pseudo probe info into asm files. +// +//===----------------------------------------------------------------------===// + +#include "PseudoProbePrinter.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PseudoProbe.h" +#include "llvm/MC/MCPseudoProbe.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +#define DEBUG_TYPE "pseudoprobe" + +PseudoProbeHandler::~PseudoProbeHandler() = default; + +PseudoProbeHandler::PseudoProbeHandler(AsmPrinter *A, Module *M) : Asm(A) { + NamedMDNode *FuncInfo = M->getNamedMetadata(PseudoProbeDescMetadataName); + assert(FuncInfo && "Pseudo probe descriptors are missing"); + for (const auto *Operand : FuncInfo->operands()) { + const auto *MD = cast<MDNode>(Operand); + auto GUID = + mdconst::dyn_extract<ConstantInt>(MD->getOperand(0))->getZExtValue(); + auto Name = cast<MDString>(MD->getOperand(2))->getString(); + // We may see pairs with same name but different GUIDs here in LTO mode, due + // to static same-named functions inlined from other modules into this + // module. Function profiles with the same name will be merged no matter + // whether they are collected on the same function. Therefore we just pick + // up the last <Name, GUID> pair here to represent the same-named function + // collection and all probes from the collection will be merged into a + // single profile eventually. + Names[Name] = GUID; + } + + LLVM_DEBUG(dump()); +} + +void PseudoProbeHandler::emitPseudoProbe(uint64_t Guid, uint64_t Index, + uint64_t Type, uint64_t Attr, + const DILocation *DebugLoc) { + // Gather all the inlined-at nodes. + // When it's done ReversedInlineStack looks like ([66, B], [88, A]) + // which means, Function A inlines function B at calliste with a probe id 88, + // and B inlines C at probe 66 where C is represented by Guid. + SmallVector<InlineSite, 8> ReversedInlineStack; + auto *InlinedAt = DebugLoc ? DebugLoc->getInlinedAt() : nullptr; + while (InlinedAt) { + const DISubprogram *SP = InlinedAt->getScope()->getSubprogram(); + // Use linkage name for C++ if possible. + auto Name = SP->getLinkageName(); + if (Name.empty()) + Name = SP->getName(); + assert(Names.count(Name) && "Pseudo probe descriptor missing for function"); + uint64_t CallerGuid = Names[Name]; + uint64_t CallerProbeId = PseudoProbeDwarfDiscriminator::extractProbeIndex( + InlinedAt->getDiscriminator()); + ReversedInlineStack.emplace_back(CallerGuid, CallerProbeId); + InlinedAt = InlinedAt->getInlinedAt(); + } + + SmallVector<InlineSite, 8> InlineStack(ReversedInlineStack.rbegin(), + ReversedInlineStack.rend()); + Asm->OutStreamer->emitPseudoProbe(Guid, Index, Type, Attr, InlineStack); +} + +#ifndef NDEBUG +void PseudoProbeHandler::dump() const { + dbgs() << "\n=============================\n"; + dbgs() << "\nFunction Name to GUID map:\n"; + dbgs() << "\n=============================\n"; + for (const auto &Item : Names) + dbgs() << "Func: " << Item.first << " GUID: " << Item.second << "\n"; +} +#endif diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.h new file mode 100644 index 000000000000..bea07ceae9d4 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/PseudoProbePrinter.h @@ -0,0 +1,53 @@ +//===- PseudoProbePrinter.h - Pseudo probe encoding support -----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing pseudo probe info into asm files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_PSEUDOPROBEPRINTER_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_PSEUDOPROBEPRINTER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/AsmPrinterHandler.h" + +namespace llvm { + +class AsmPrinter; +class MCStreamer; +class Module; +class DILocation; + +class PseudoProbeHandler : public AsmPrinterHandler { + // Target of pseudo probe emission. + AsmPrinter *Asm; + // Name to GUID map + DenseMap<StringRef, uint64_t> Names; + +public: + PseudoProbeHandler(AsmPrinter *A, Module *M); + ~PseudoProbeHandler() override; + + void emitPseudoProbe(uint64_t Guid, uint64_t Index, uint64_t Type, + uint64_t Attr, const DILocation *DebugLoc); + + // Unused. + void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} + void endModule() override {} + void beginFunction(const MachineFunction *MF) override {} + void endFunction(const MachineFunction *MF) override {} + void beginInstruction(const MachineInstr *MI) override {} + void endInstruction() override {} + +#ifndef NDEBUG + void dump() const; +#endif +}; + +} // namespace llvm +#endif // LLVM_LIB_CODEGEN_ASMPRINTER_PSEUDOPROBEPRINTER_H diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp index baef4d2cc849..352a33e8639d 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp @@ -18,11 +18,11 @@ using namespace llvm; void WasmException::endModule() { - // 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 'br_on_exn' instruction in the module, and emit the - // symbol only if so. + // This is the symbol used in 'throw' and 'catch' 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 'catch' instruction in the module, and emit the symbol + // only if so. SmallString<60> NameStr; Mangler::getNameWithPrefix(NameStr, "__cpp_exception", Asm->getDataLayout()); if (Asm->OutContext.lookupSymbol(NameStr)) { @@ -76,6 +76,7 @@ void WasmException::endFunction(const MachineFunction *MF) { // information. void WasmException::computeCallSiteTable( SmallVectorImpl<CallSiteEntry> &CallSites, + SmallVectorImpl<CallSiteRange> &CallSiteRanges, const SmallVectorImpl<const LandingPadInfo *> &LandingPads, const SmallVectorImpl<unsigned> &FirstActions) { MachineFunction &MF = *Asm->MF; diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WasmException.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WasmException.h index 1893b6b2df43..f06de786bd76 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WasmException.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WasmException.h @@ -32,6 +32,7 @@ protected: // Compute the call site table for wasm EH. void computeCallSiteTable( SmallVectorImpl<CallSiteEntry> &CallSites, + SmallVectorImpl<CallSiteRange> &CallSiteRanges, const SmallVectorImpl<const LandingPadInfo *> &LandingPads, const SmallVectorImpl<unsigned> &FirstActions) override; }; diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp index 914308d9147e..1e3f33e70715 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // // This file contains support for writing the metadata for Windows Control Flow -// Guard, including address-taken functions, and valid longjmp targets. +// Guard, including address-taken functions and valid longjmp targets. // //===----------------------------------------------------------------------===// @@ -17,8 +17,8 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/IR/Constants.h" -#include "llvm/IR/Metadata.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/Metadata.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCStreamer.h" @@ -38,8 +38,7 @@ void WinCFGuard::endFunction(const MachineFunction *MF) { return; // Copy the function's longjmp targets to a module-level list. - LongjmpTargets.insert(LongjmpTargets.end(), MF->getLongjmpTargets().begin(), - MF->getLongjmpTargets().end()); + llvm::append_range(LongjmpTargets, MF->getLongjmpTargets()); } /// Returns true if this function's address is escaped in a way that might make @@ -78,20 +77,50 @@ static bool isPossibleIndirectCallTarget(const Function *F) { return false; } +MCSymbol *WinCFGuard::lookupImpSymbol(const MCSymbol *Sym) { + if (Sym->getName().startswith("__imp_")) + return nullptr; + return Asm->OutContext.lookupSymbol(Twine("__imp_") + Sym->getName()); +} + void WinCFGuard::endModule() { const Module *M = Asm->MMI->getModule(); - std::vector<const Function *> Functions; - for (const Function &F : *M) - if (isPossibleIndirectCallTarget(&F)) - Functions.push_back(&F); - if (Functions.empty() && LongjmpTargets.empty()) + std::vector<const MCSymbol *> GFIDsEntries; + std::vector<const MCSymbol *> GIATsEntries; + for (const Function &F : *M) { + if (isPossibleIndirectCallTarget(&F)) { + // If F is a dllimport and has an "__imp_" symbol already defined, add the + // "__imp_" symbol to the .giats section. + if (F.hasDLLImportStorageClass()) { + if (MCSymbol *impSym = lookupImpSymbol(Asm->getSymbol(&F))) { + GIATsEntries.push_back(impSym); + } + } + // Add the function's symbol to the .gfids section. + // Note: For dllimport functions, MSVC sometimes does not add this symbol + // to the .gfids section, but only adds the corresponding "__imp_" symbol + // to the .giats section. Here we always add the symbol to the .gfids + // section, since this does not introduce security risks. + GFIDsEntries.push_back(Asm->getSymbol(&F)); + } + } + + if (GFIDsEntries.empty() && GIATsEntries.empty() && LongjmpTargets.empty()) return; + + // Emit the symbol index of each GFIDs entry to form the .gfids section. auto &OS = *Asm->OutStreamer; OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGFIDsSection()); - for (const Function *F : Functions) - OS.EmitCOFFSymbolIndex(Asm->getSymbol(F)); + for (const MCSymbol *S : GFIDsEntries) + OS.EmitCOFFSymbolIndex(S); + + // Emit the symbol index of each GIATs entry to form the .giats section. + OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGIATsSection()); + for (const MCSymbol *S : GIATsEntries) { + OS.EmitCOFFSymbolIndex(S); + } - // Emit the symbol index of each longjmp target. + // Emit the symbol index of each longjmp target to form the .gljmp section. OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGLJMPSection()); for (const MCSymbol *S : LongjmpTargets) { OS.EmitCOFFSymbolIndex(S); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.h b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.h index 494a153b05ba..0e472af52c8f 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.h +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.h @@ -24,6 +24,7 @@ class LLVM_LIBRARY_VISIBILITY WinCFGuard : public AsmPrinterHandler { /// Target of directive emission. AsmPrinter *Asm; std::vector<const MCSymbol *> LongjmpTargets; + MCSymbol *lookupImpSymbol(const MCSymbol *Sym); public: WinCFGuard(AsmPrinter *A); diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index cd8077e7d548..3a9c9df79783 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -137,8 +137,8 @@ void WinException::endFunction(const MachineFunction *MF) { endFuncletImpl(); - // endFunclet will emit the necessary .xdata tables for x64 SEH. - if (Per == EHPersonality::MSVC_Win64SEH && MF->hasEHFunclets()) + // endFunclet will emit the necessary .xdata tables for table-based SEH. + if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets()) return; if (shouldEmitPersonality || shouldEmitLSDA) { @@ -151,7 +151,7 @@ void WinException::endFunction(const MachineFunction *MF) { // Emit the tables appropriate to the personality function in use. If we // don't recognize the personality, assume it uses an Itanium-style LSDA. - if (Per == EHPersonality::MSVC_Win64SEH) + if (Per == EHPersonality::MSVC_TableSEH) emitCSpecificHandlerTable(MF); else if (Per == EHPersonality::MSVC_X86SEH) emitExceptHandlerTable(MF); @@ -258,31 +258,35 @@ void WinException::endFuncletImpl() { if (F.hasPersonalityFn()) Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts()); - // On funclet exit, we emit a fake "function" end marker, so that the call - // to EmitWinEHHandlerData below can calculate the size of the funclet or - // function. - if (isAArch64) { - MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection( - Asm->OutStreamer->getCurrentSectionOnly()); - Asm->OutStreamer->SwitchSection(XData); - } - - // Emit an UNWIND_INFO struct describing the prologue. - Asm->OutStreamer->EmitWinEHHandlerData(); - if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality && !CurrentFuncletEntry->isCleanupFuncletEntry()) { + // Emit an UNWIND_INFO struct describing the prologue. + Asm->OutStreamer->EmitWinEHHandlerData(); + // If this is a C++ catch funclet (or the parent function), // emit a reference to the LSDA for the parent function. StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName()); MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol( Twine("$cppxdata$", FuncLinkageName)); Asm->OutStreamer->emitValue(create32bitRef(FuncInfoXData), 4); - } else if (Per == EHPersonality::MSVC_Win64SEH && MF->hasEHFunclets() && + } else if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets() && !CurrentFuncletEntry->isEHFuncletEntry()) { + // Emit an UNWIND_INFO struct describing the prologue. + Asm->OutStreamer->EmitWinEHHandlerData(); + // If this is the parent function in Win64 SEH, emit the LSDA immediately // following .seh_handlerdata. emitCSpecificHandlerTable(MF); + } else if (shouldEmitPersonality || shouldEmitLSDA) { + // Emit an UNWIND_INFO struct describing the prologue. + Asm->OutStreamer->EmitWinEHHandlerData(); + // In these cases, no further info is written to the .xdata section + // right here, but is written by e.g. emitExceptionTable in endFunction() + // above. + } else { + // No need to emit the EH handler data right here if nothing needs + // writing to the .xdata section; it will be emitted for all + // functions that need it in the end anyway. } // Switch back to the funclet start .text section now that we are done @@ -339,22 +343,24 @@ int WinException::getFrameIndexOffset(int FrameIndex, const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering(); Register UnusedReg; if (Asm->MAI->usesWindowsCFI()) { - int Offset = + StackOffset Offset = TFI.getFrameIndexReferencePreferSP(*Asm->MF, FrameIndex, UnusedReg, /*IgnoreSPUpdates*/ true); assert(UnusedReg == Asm->MF->getSubtarget() .getTargetLowering() ->getStackPointerRegisterToSaveRestore()); - return Offset; + return Offset.getFixed(); } // For 32-bit, offsets should be relative to the end of the EH registration // node. For 64-bit, it's relative to SP at the end of the prologue. assert(FuncInfo.EHRegNodeEndOffset != INT_MAX); - int Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg); - Offset += FuncInfo.EHRegNodeEndOffset; - return Offset; + StackOffset Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg); + Offset += StackOffset::getFixed(FuncInfo.EHRegNodeEndOffset); + assert(!Offset.getScalable() && + "Frame offsets with a scalable component are not supported"); + return Offset.getFixed(); } namespace { @@ -951,7 +957,7 @@ void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo, int FI = FuncInfo.EHRegNodeFrameIndex; if (FI != INT_MAX) { const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); - Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI); + Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI).getFixed(); } MCContext &Ctx = Asm->OutContext; @@ -1015,7 +1021,8 @@ void WinException::emitExceptHandlerTable(const MachineFunction *MF) { Register UnusedReg; const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); int SSPIdx = MFI.getStackProtectorIndex(); - GSCookieOffset = TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg); + GSCookieOffset = + TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg).getFixed(); } // Retrieve the EH Guard slot. @@ -1025,7 +1032,8 @@ void WinException::emitExceptHandlerTable(const MachineFunction *MF) { Register UnusedReg; const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); int EHGuardIdx = FuncInfo.EHGuardFrameIndex; - EHCookieOffset = TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg); + EHCookieOffset = + TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg).getFixed(); } AddComment("GSCookieOffset"); |