diff options
Diffstat (limited to 'contrib/llvm/lib/CodeGen/AsmPrinter')
33 files changed, 3601 insertions, 1575 deletions
diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp index ade2d71..5294c98 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "DwarfException.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" @@ -28,7 +27,6 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Target/TargetFrameLowering.h" diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/AddressPool.h b/contrib/llvm/lib/CodeGen/AsmPrinter/AddressPool.h index 211fc98..ba3e3b7 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/AddressPool.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/AddressPool.h @@ -11,10 +11,10 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_ADDRESSPOOL_H #include "llvm/ADT/DenseMap.h" +#include "llvm/MC/MCSymbol.h" namespace llvm { class MCSection; -class MCSymbol; class AsmPrinter; // Collection of addresses for this unit and assorted labels. // A Symbol->unsigned mapping of addresses used by indirect diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 5f67d3d..272bace 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -12,11 +12,10 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/AsmPrinter.h" +#include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" #include "WinException.h" -#include "WinCodeViewLineTables.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/CodeGen/Analysis.h" @@ -125,6 +124,10 @@ AsmPrinter::~AsmPrinter() { } } +bool AsmPrinter::isPositionIndependent() const { + return TM.isPositionIndependent(); +} + /// getFunctionNumber - Return a unique ID for the current function. /// unsigned AsmPrinter::getFunctionNumber() const { @@ -248,12 +251,13 @@ bool AsmPrinter::doInitialization(Module &M) { if (MAI->doesSupportDebugInformation()) { bool EmitCodeView = MMI->getModule()->getCodeViewFlag(); if (EmitCodeView && TM.getTargetTriple().isKnownWindowsMSVCEnvironment()) { - Handlers.push_back(HandlerInfo(new WinCodeViewLineTables(this), + Handlers.push_back(HandlerInfo(new CodeViewDebug(this), DbgTimerName, CodeViewLineTablesGroupName)); } if (!EmitCodeView || MMI->getModule()->getDwarfVersion()) { DD = new DwarfDebug(this, &M); + DD->beginModule(); Handlers.push_back(HandlerInfo(DD, DbgTimerName, DWARFGroupName)); } } @@ -319,21 +323,17 @@ void AsmPrinter::EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const { OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Weak); } return; - case GlobalValue::AppendingLinkage: - // FIXME: appending linkage variables should go into a section of - // their name or something. For now, just emit them as external. case GlobalValue::ExternalLinkage: - // If external or appending, declare as a global symbol. - // .globl _foo + // If external, declare as a global symbol: .globl _foo OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Global); return; case GlobalValue::PrivateLinkage: case GlobalValue::InternalLinkage: return; + case GlobalValue::AppendingLinkage: case GlobalValue::AvailableExternallyLinkage: - llvm_unreachable("Should never emit this"); case GlobalValue::ExternalWeakLinkage: - llvm_unreachable("Don't know how to emit these"); + llvm_unreachable("Should never emit this"); } llvm_unreachable("Unknown linkage type!"); } @@ -347,51 +347,17 @@ MCSymbol *AsmPrinter::getSymbol(const GlobalValue *GV) const { return TM.getSymbol(GV, *Mang); } -static MCSymbol *getOrCreateEmuTLSControlSym(MCSymbol *GVSym, MCContext &C) { - return C.getOrCreateSymbol(Twine("__emutls_v.") + GVSym->getName()); -} - -static MCSymbol *getOrCreateEmuTLSInitSym(MCSymbol *GVSym, MCContext &C) { - return C.getOrCreateSymbol(Twine("__emutls_t.") + GVSym->getName()); -} - -/// EmitEmulatedTLSControlVariable - Emit the control variable for an emulated TLS variable. -void AsmPrinter::EmitEmulatedTLSControlVariable(const GlobalVariable *GV, - MCSymbol *EmittedSym, - bool AllZeroInitValue) { - MCSection *TLSVarSection = getObjFileLowering().getDataSection(); - OutStreamer->SwitchSection(TLSVarSection); - MCSymbol *GVSym = getSymbol(GV); - EmitLinkage(GV, EmittedSym); // same linkage as GV - const DataLayout &DL = GV->getParent()->getDataLayout(); - uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); - unsigned AlignLog = getGVAlignmentLog2(GV, DL); - unsigned WordSize = DL.getPointerSize(); - unsigned Alignment = DL.getPointerABIAlignment(); - EmitAlignment(Log2_32(Alignment)); - OutStreamer->EmitLabel(EmittedSym); - OutStreamer->EmitIntValue(Size, WordSize); - OutStreamer->EmitIntValue((1 << AlignLog), WordSize); - OutStreamer->EmitIntValue(0, WordSize); - if (GV->hasInitializer() && !AllZeroInitValue) { - OutStreamer->EmitSymbolValue( - getOrCreateEmuTLSInitSym(GVSym, OutContext), WordSize); - } else - OutStreamer->EmitIntValue(0, WordSize); - if (MAI->hasDotTypeDotSizeDirective()) - OutStreamer->emitELFSize(cast<MCSymbolELF>(EmittedSym), - MCConstantExpr::create(4 * WordSize, OutContext)); - OutStreamer->AddBlankLine(); // End of the __emutls_v.* variable. -} - /// EmitGlobalVariable - Emit the specified global variable to the .s file. void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { - bool IsEmuTLSVar = - GV->getThreadLocalMode() != llvm::GlobalVariable::NotThreadLocal && - TM.Options.EmulatedTLS; + bool IsEmuTLSVar = TM.Options.EmulatedTLS && GV->isThreadLocal(); assert(!(IsEmuTLSVar && GV->hasCommonLinkage()) && "No emulated TLS variables in the common section"); + // Never emit TLS variable xyz in emulated TLS model. + // The initialization value is in __emutls_t.xyz instead of xyz. + if (IsEmuTLSVar) + return; + if (GV->hasInitializer()) { // Check to see if this is a special global used by LLVM, if so, emit it. if (EmitSpecialLLVMGlobal(GV)) @@ -402,7 +368,7 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { if (GlobalGOTEquivs.count(getSymbol(GV))) return; - if (isVerbose() && !IsEmuTLSVar) { + if (isVerbose()) { // When printing the control variable __emutls_v.*, // we don't need to print the original TLS variable name. GV->printAsOperand(OutStreamer->GetCommentOS(), @@ -412,11 +378,11 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { } MCSymbol *GVSym = getSymbol(GV); - MCSymbol *EmittedSym = IsEmuTLSVar ? - getOrCreateEmuTLSControlSym(GVSym, OutContext) : GVSym; - // getOrCreateEmuTLSControlSym only creates the symbol with name and default attributes. - // GV's or GVSym's attributes will be used for the EmittedSym. + MCSymbol *EmittedSym = GVSym; + // getOrCreateEmuTLSControlSym only creates the symbol with name and default + // attributes. + // GV's or GVSym's attributes will be used for the EmittedSym. EmitVisibility(EmittedSym, GV->getVisibility(), !GV->isDeclaration()); if (!GV->hasInitializer()) // External globals require no extra code. @@ -440,48 +406,47 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { // sections and expected to be contiguous (e.g. ObjC metadata). unsigned AlignLog = getGVAlignmentLog2(GV, DL); - bool AllZeroInitValue = false; - const Constant *InitValue = GV->getInitializer(); - if (isa<ConstantAggregateZero>(InitValue)) - AllZeroInitValue = true; - else { - const ConstantInt *InitIntValue = dyn_cast<ConstantInt>(InitValue); - if (InitIntValue && InitIntValue->isZero()) - AllZeroInitValue = true; - } - if (IsEmuTLSVar) - EmitEmulatedTLSControlVariable(GV, EmittedSym, AllZeroInitValue); - for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerGroupName, TimePassesIsEnabled); HI.Handler->setSymbolSize(GVSym, Size); } - // Handle common and BSS local symbols (.lcomm). - if (GVKind.isCommon() || GVKind.isBSSLocal()) { - assert(!(IsEmuTLSVar && GVKind.isCommon()) && - "No emulated TLS variables in the common section"); + // Handle common symbols + if (GVKind.isCommon()) { if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. unsigned Align = 1 << AlignLog; + if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) + Align = 0; - // Handle common symbols. - if (GVKind.isCommon()) { - if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) - Align = 0; + // .comm _foo, 42, 4 + OutStreamer->EmitCommonSymbol(GVSym, Size, Align); + return; + } - // .comm _foo, 42, 4 - OutStreamer->EmitCommonSymbol(GVSym, Size, Align); - return; - } + // Determine to which section this global should be emitted. + MCSection *TheSection = + getObjFileLowering().SectionForGlobal(GV, GVKind, *Mang, TM); - // Handle local BSS symbols. - if (MAI->hasMachoZeroFillDirective()) { - MCSection *TheSection = - getObjFileLowering().SectionForGlobal(GV, GVKind, *Mang, TM); - // .zerofill __DATA, __bss, _foo, 400, 5 - OutStreamer->EmitZerofill(TheSection, GVSym, Size, Align); - return; - } + // If we have a bss global going to a section that supports the + // zerofill directive, do so here. + if (GVKind.isBSS() && MAI->hasMachoZeroFillDirective() && + TheSection->isVirtualSection()) { + if (Size == 0) + Size = 1; // zerofill of 0 bytes is undefined. + unsigned Align = 1 << AlignLog; + EmitLinkage(GV, GVSym); + // .zerofill __DATA, __bss, _foo, 400, 5 + OutStreamer->EmitZerofill(TheSection, GVSym, Size, Align); + return; + } + + // If this is a BSS local symbol and we are emitting in the BSS + // section use .lcomm/.comm directive. + if (GVKind.isBSSLocal() && + getObjFileLowering().getBSSSection() == TheSection) { + if (Size == 0) + Size = 1; // .comm Foo, 0 is undefined, avoid it. + unsigned Align = 1 << AlignLog; // Use .lcomm only if it supports user-specified alignment. // Otherwise, while it would still be correct to use .lcomm in some @@ -505,30 +470,6 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { return; } - if (IsEmuTLSVar && AllZeroInitValue) - return; // No need of initialization values. - - MCSymbol *EmittedInitSym = IsEmuTLSVar ? - getOrCreateEmuTLSInitSym(GVSym, OutContext) : GVSym; - // getOrCreateEmuTLSInitSym only creates the symbol with name and default attributes. - // GV's or GVSym's attributes will be used for the EmittedInitSym. - - MCSection *TheSection = IsEmuTLSVar ? - getObjFileLowering().getReadOnlySection() : - getObjFileLowering().SectionForGlobal(GV, GVKind, *Mang, TM); - - // Handle the zerofill directive on darwin, which is a special form of BSS - // emission. - if (GVKind.isBSSExtern() && MAI->hasMachoZeroFillDirective() && !IsEmuTLSVar) { - if (Size == 0) Size = 1; // zerofill of 0 bytes is undefined. - - // .globl _foo - OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Global); - // .zerofill __DATA, __common, _foo, 400, 5 - OutStreamer->EmitZerofill(TheSection, GVSym, Size, 1 << AlignLog); - return; - } - // Handle thread local data for mach-o which requires us to output an // additional structure of data and mangle the original symbol so that we // can reference it later. @@ -539,7 +480,7 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { // TLOF class. This will also make it more obvious that stuff like // MCStreamer::EmitTBSSSymbol is macho specific and only called from macho // specific code. - if (GVKind.isThreadLocal() && MAI->hasMachoTBSSDirective() && !IsEmuTLSVar) { + if (GVKind.isThreadLocal() && MAI->hasMachoTBSSDirective()) { // Emit the .tbss symbol MCSymbol *MangSym = OutContext.getOrCreateSymbol(GVSym->getName() + Twine("$tlv$init")); @@ -581,11 +522,11 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { return; } + MCSymbol *EmittedInitSym = GVSym; + OutStreamer->SwitchSection(TheSection); - // emutls_t.* symbols are only used in the current compilation unit. - if (!IsEmuTLSVar) - EmitLinkage(GV, EmittedInitSym); + EmitLinkage(GV, EmittedInitSym); EmitAlignment(AlignLog, GV); OutStreamer->EmitLabel(EmittedInitSym); @@ -696,20 +637,20 @@ static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) { // We assume a single instruction only has a spill or reload, not // both. const MachineMemOperand *MMO; - if (TII->isLoadFromStackSlotPostFE(&MI, FI)) { + if (TII->isLoadFromStackSlotPostFE(MI, FI)) { if (FrameInfo->isSpillSlotObjectIndex(FI)) { MMO = *MI.memoperands_begin(); CommentOS << MMO->getSize() << "-byte Reload\n"; } - } else if (TII->hasLoadFromStackSlot(&MI, MMO, FI)) { + } else if (TII->hasLoadFromStackSlot(MI, MMO, FI)) { if (FrameInfo->isSpillSlotObjectIndex(FI)) CommentOS << MMO->getSize() << "-byte Folded Reload\n"; - } else if (TII->isStoreToStackSlotPostFE(&MI, FI)) { + } else if (TII->isStoreToStackSlotPostFE(MI, FI)) { if (FrameInfo->isSpillSlotObjectIndex(FI)) { MMO = *MI.memoperands_begin(); CommentOS << MMO->getSize() << "-byte Spill\n"; } - } else if (TII->hasStoreToStackSlot(&MI, MMO, FI)) { + } else if (TII->hasStoreToStackSlot(MI, MMO, FI)) { if (FrameInfo->isSpillSlotObjectIndex(FI)) CommentOS << MMO->getSize() << "-byte Folded Spill\n"; } @@ -745,7 +686,7 @@ static void emitKill(const MachineInstr *MI, AsmPrinter &AP) { AP.MF->getSubtarget().getRegisterInfo()) << (Op.isDef() ? "<def>" : "<kill>"); } - AP.OutStreamer->AddComment(Str); + AP.OutStreamer->AddComment(OS.str()); AP.OutStreamer->AddBlankLine(); } @@ -1065,8 +1006,9 @@ static bool isGOTEquivalentCandidate(const GlobalVariable *GV, // Global GOT equivalents are unnamed private globals with a constant // pointer initializer to another global symbol. They must point to a // GlobalVariable or Function, i.e., as GlobalValue. - if (!GV->hasUnnamedAddr() || !GV->hasInitializer() || !GV->isConstant() || - !GV->isDiscardableIfUnused() || !dyn_cast<GlobalValue>(GV->getOperand(0))) + if (!GV->hasGlobalUnnamedAddr() || !GV->hasInitializer() || + !GV->isConstant() || !GV->isDiscardableIfUnused() || + !dyn_cast<GlobalValue>(GV->getOperand(0))) return false; // To be a got equivalent, at least one of its users need to be a constant @@ -1118,6 +1060,52 @@ void AsmPrinter::emitGlobalGOTEquivs() { EmitGlobalVariable(GV); } +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"); + + // Set the symbol type to function if the alias has a function type. + // This affects codegen when the aliasee is not a function. + if (GIS.getType()->getPointerElementType()->isFunctionTy()) { + OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction); + if (isa<GlobalIFunc>(GIS)) + OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction); + } + + EmitVisibility(Name, GIS.getVisibility()); + + const MCExpr *Expr = lowerConstant(GIS.getIndirectSymbol()); + + if (isa<GlobalAlias>(&GIS) && MAI->hasAltEntry() && isa<MCBinaryExpr>(Expr)) + OutStreamer->EmitSymbolAttribute(Name, MCSA_AltEntry); + + // Emit the directives as assignments aka .set: + OutStreamer->EmitAssignment(Name, Expr); + + if (auto *GA = dyn_cast<GlobalAlias>(&GIS)) { + // If the aliasee does not correspond to a symbol in the output, i.e. the + // alias is not of an object or the aliased object is private, then set the + // size of the alias symbol from the type of the alias. We don't do this in + // other situations as the alias and aliasee having differing types but same + // size may be intentional. + const GlobalObject *BaseObject = GA->getBaseObject(); + if (MAI->hasDotTypeDotSizeDirective() && GA->getValueType()->isSized() && + (!BaseObject || BaseObject->hasPrivateLinkage())) { + const DataLayout &DL = M.getDataLayout(); + uint64_t Size = DL.getTypeAllocSize(GA->getValueType()); + OutStreamer->emitELFSize(cast<MCSymbolELF>(Name), + MCConstantExpr::create(Size, OutContext)); + } + } +} + bool AsmPrinter::doFinalization(Module &M) { // Set the MachineFunction to nullptr so that we can catch attempted // accesses to MF specific features at the module level and so that @@ -1191,55 +1179,35 @@ bool AsmPrinter::doFinalization(Module &M) { // to notice uses in operands (due to constant exprs etc). This should // happen with the MC stuff eventually. - // Print out module-level global variables here. - for (const auto &G : M.globals()) { - if (!G.hasExternalWeakLinkage()) + // Print out module-level global objects here. + for (const auto &GO : M.global_objects()) { + if (!GO.hasExternalWeakLinkage()) continue; - OutStreamer->EmitSymbolAttribute(getSymbol(&G), MCSA_WeakReference); - } - - for (const auto &F : M) { - if (!F.hasExternalWeakLinkage()) - continue; - OutStreamer->EmitSymbolAttribute(getSymbol(&F), MCSA_WeakReference); + OutStreamer->EmitSymbolAttribute(getSymbol(&GO), MCSA_WeakReference); } } OutStreamer->AddBlankLine(); - for (const auto &Alias : M.aliases()) { - MCSymbol *Name = getSymbol(&Alias); - - if (Alias.hasExternalLinkage() || !MAI->getWeakRefDirective()) - OutStreamer->EmitSymbolAttribute(Name, MCSA_Global); - else if (Alias.hasWeakLinkage() || Alias.hasLinkOnceLinkage()) - OutStreamer->EmitSymbolAttribute(Name, MCSA_WeakReference); - else - assert(Alias.hasLocalLinkage() && "Invalid alias 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 (Alias.getType()->getPointerElementType()->isFunctionTy()) - OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction); - - EmitVisibility(Name, Alias.getVisibility()); - // Emit the directives as assignments aka .set: - OutStreamer->EmitAssignment(Name, lowerConstant(Alias.getAliasee())); - - // If the aliasee does not correspond to a symbol in the output, i.e. the - // alias is not of an object or the aliased object is private, then set the - // size of the alias symbol from the type of the alias. We don't do this in - // other situations as the alias and aliasee having differing types but same - // size may be intentional. - const GlobalObject *BaseObject = Alias.getBaseObject(); - if (MAI->hasDotTypeDotSizeDirective() && Alias.getValueType()->isSized() && - (!BaseObject || BaseObject->hasPrivateLinkage())) { - const DataLayout &DL = M.getDataLayout(); - uint64_t Size = DL.getTypeAllocSize(Alias.getValueType()); - OutStreamer->emitELFSize(cast<MCSymbolELF>(Name), - MCConstantExpr::create(Size, OutContext)); + // Print aliases in topological order, that is, for each alias a = b, + // b must be printed before a. + // This is because on some targets (e.g. PowerPC) linker expects aliases in + // such an order to generate correct TOC information. + SmallVector<const GlobalAlias *, 16> AliasStack; + SmallPtrSet<const GlobalAlias *, 16> AliasVisited; + for (const auto &Alias : M.aliases()) { + for (const GlobalAlias *Cur = &Alias; Cur; + Cur = dyn_cast<GlobalAlias>(Cur->getAliasee())) { + if (!AliasVisited.insert(Cur).second) + break; + AliasStack.push_back(Cur); } + for (const GlobalAlias *AncestorAlias : reverse(AliasStack)) + emitGlobalIndirectSymbol(M, *AncestorAlias); + AliasStack.clear(); } + for (const auto &IFunc : M.ifuncs()) + emitGlobalIndirectSymbol(M, IFunc); GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>(); assert(MI && "AsmPrinter didn't require GCModuleInfo?"); @@ -1252,9 +1220,10 @@ bool AsmPrinter::doFinalization(Module &M) { // Emit __morestack address if needed for indirect calls. if (MMI->usesMorestackAddr()) { + unsigned Align = 1; MCSection *ReadOnlySection = getObjFileLowering().getSectionForConstant( getDataLayout(), SectionKind::getReadOnly(), - /*C=*/nullptr); + /*C=*/nullptr, Align); OutStreamer->SwitchSection(ReadOnlySection); MCSymbol *AddrSymbol = @@ -1344,8 +1313,8 @@ void AsmPrinter::EmitConstantPool() { if (!CPE.isMachineConstantPoolEntry()) C = CPE.Val.ConstVal; - MCSection *S = - getObjFileLowering().getSectionForConstant(getDataLayout(), Kind, C); + MCSection *S = getObjFileLowering().getSectionForConstant(getDataLayout(), + Kind, C, Align); // The number of sections are small, just do a linear search from the // last section to the first. @@ -1443,7 +1412,7 @@ void AsmPrinter::EmitJumpTableInfo() { // For the EK_LabelDifference32 entry, if using .set avoids a relocation, /// emit a .set directive for each unique entry. if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 && - MAI->doesSetDirectiveSuppressesReloc()) { + MAI->doesSetDirectiveSuppressReloc()) { SmallPtrSet<const MachineBasicBlock*, 16> EmittedSets; const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF,JTI,OutContext); @@ -1524,7 +1493,7 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, // If the .set directive avoids relocations, this is emitted as: // .set L4_5_set_123, LBB123 - LJTI1_2 // .word L4_5_set_123 - if (MAI->doesSetDirectiveSuppressesReloc()) { + if (MAI->doesSetDirectiveSuppressReloc()) { Value = MCSymbolRefExpr::create(GetJTSetSymbol(UID, MBB->getNumber()), OutContext); break; @@ -1555,7 +1524,7 @@ bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) { } // Ignore debug and non-emitted data. This handles llvm.compiler.used. - if (StringRef(GV->getSection()) == "llvm.metadata" || + if (GV->getSection() == "llvm.metadata" || GV->hasAvailableExternallyLinkage()) return true; @@ -1589,7 +1558,7 @@ bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) { return true; } - return false; + report_fatal_error("unknown special variable"); } /// EmitLLVMUsedList - For targets that define a MAI::UsedDirective, mark each @@ -1648,7 +1617,8 @@ void AsmPrinter::EmitXXStructorList(const DataLayout &DL, const Constant *List, S.Priority = Priority->getLimitedValue(65535); S.Func = CS->getOperand(1); if (ETy->getNumElements() == 3 && !CS->getOperand(2)->isNullValue()) - S.ComdatKey = dyn_cast<GlobalValue>(CS->getOperand(2)->stripPointerCasts()); + S.ComdatKey = + dyn_cast<GlobalValue>(CS->getOperand(2)->stripPointerCasts()); } // Emit the function pointers in the target-specific order @@ -1789,10 +1759,6 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { llvm_unreachable("Unknown constant value to lower!"); } - if (const MCExpr *RelocExpr - = getObjFileLowering().getExecutableRelativeSymbol(CE, *Mang, TM)) - return RelocExpr; - switch (CE->getOpcode()) { default: // If the code isn't optimized, there may be outstanding folding @@ -1868,10 +1834,34 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { return MCBinaryExpr::createAnd(OpExpr, MaskExpr, Ctx); } + case Instruction::Sub: { + GlobalValue *LHSGV; + APInt LHSOffset; + if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHSGV, LHSOffset, + getDataLayout())) { + GlobalValue *RHSGV; + APInt RHSOffset; + if (IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset, + getDataLayout())) { + const MCExpr *RelocExpr = getObjFileLowering().lowerRelativeReference( + LHSGV, RHSGV, *Mang, TM); + if (!RelocExpr) + RelocExpr = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(getSymbol(LHSGV), Ctx), + MCSymbolRefExpr::create(getSymbol(RHSGV), Ctx), Ctx); + int64_t Addend = (LHSOffset - RHSOffset).getSExtValue(); + if (Addend != 0) + RelocExpr = MCBinaryExpr::createAdd( + RelocExpr, MCConstantExpr::create(Addend, Ctx), Ctx); + return RelocExpr; + } + } + } + // else fallthrough + // The MC library also has a right-shift operator, but it isn't consistently // signed or unsigned between different targets. case Instruction::Add: - case Instruction::Sub: case Instruction::Mul: case Instruction::SDiv: case Instruction::SRem: @@ -1964,7 +1954,7 @@ static void emitGlobalConstantDataSequential(const DataLayout &DL, uint64_t Bytes = DL.getTypeAllocSize(CDS->getType()); // Don't emit a 1-byte object as a .fill. if (Bytes > 1) - return AP.OutStreamer->EmitFill(Bytes, Value); + return AP.OutStreamer->emitFill(Bytes, Value); } // If this can be emitted with .ascii/.asciz, emit it as such. @@ -2003,7 +1993,7 @@ static void emitGlobalConstantArray(const DataLayout &DL, if (Value != -1) { uint64_t Bytes = DL.getTypeAllocSize(CA->getType()); - AP.OutStreamer->EmitFill(Bytes, Value); + AP.OutStreamer->emitFill(Bytes, Value); } else { for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { @@ -2582,7 +2572,7 @@ isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { // If we are the operands of one of the branches, this is not a fall // through. Note that targets with delay slots will usually bundle // terminators with the delay slot instruction. - for (ConstMIBundleOperands OP(&MI); OP.isValid(); ++OP) { + for (ConstMIBundleOperands OP(MI); OP.isValid(); ++OP) { if (OP->isJTI()) return false; if (OP->isMBB() && OP->getMBB() == MBB) diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index 504c5d2..60f40d0 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -178,8 +178,7 @@ void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntryRef S) const { /// EmitDwarfRegOp - Emit dwarf register operation. void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer, const MachineLocation &MLoc) const { - DebugLocDwarfExpression Expr(*MF->getSubtarget().getRegisterInfo(), - getDwarfDebug()->getDwarfVersion(), Streamer); + DebugLocDwarfExpression Expr(getDwarfDebug()->getDwarfVersion(), Streamer); const MCRegisterInfo *MRI = MMI->getContext().getRegisterInfo(); int Reg = MRI->getDwarfRegNum(MLoc.getReg(), false); if (Reg < 0) { @@ -193,7 +192,8 @@ void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer, "nop (could not find a dwarf register number)"); // Attempt to find a valid super- or sub-register. - if (!Expr.AddMachineRegPiece(MLoc.getReg())) + if (!Expr.AddMachineRegPiece(*MF->getSubtarget().getRegisterInfo(), + MLoc.getReg())) Expr.EmitOp(dwarf::DW_OP_nop, "nop (could not find a dwarf register number)"); return; diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterHandler.h b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterHandler.h index e59961f..638226e 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterHandler.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterHandler.h @@ -19,11 +19,14 @@ namespace llvm { +class AsmPrinter; class MachineBasicBlock; class MachineFunction; class MachineInstr; class MCSymbol; +typedef MCSymbol *ExceptionSymbolProvider(AsmPrinter *Asm); + /// \brief Collects and handles AsmPrinter objects required to build debug /// or EH information. class AsmPrinterHandler { @@ -51,6 +54,10 @@ public: /// beginFunction at all. virtual void endFunction(const MachineFunction *MF) = 0; + virtual void beginFragment(const MachineBasicBlock *MBB, + ExceptionSymbolProvider ESP) {} + virtual void endFragment() {} + /// \brief Emit target-specific EH funclet machinery. virtual void beginFunclet(const MachineBasicBlock &MBB, MCSymbol *Sym = nullptr) {} diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 5633aa4..2ce6c18 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -23,10 +23,10 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCTargetAsmParser.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h b/contrib/llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h index df1997b..aaf6180 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h @@ -16,7 +16,6 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_BYTESTREAMER_H #include "DIEHash.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Support/LEB128.h" diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp new file mode 100644 index 0000000..ebf80de --- /dev/null +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -0,0 +1,2075 @@ +//===-- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp --*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing Microsoft CodeView debug info. +// +//===----------------------------------------------------------------------===// + +#include "CodeViewDebug.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/DebugInfo/CodeView/ByteStream.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeDumper.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/IR/Constants.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +using namespace llvm; +using namespace llvm::codeview; + +CodeViewDebug::CodeViewDebug(AsmPrinter *AP) + : DebugHandlerBase(AP), OS(*Asm->OutStreamer), CurFn(nullptr) { + // 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; + return; + } + + // Tell MMI that we have debug info. + MMI->setDebugInfoAvailability(true); +} + +StringRef CodeViewDebug::getFullFilepath(const DIFile *File) { + std::string &Filepath = FileToFilepathMap[File]; + if (!Filepath.empty()) + return Filepath; + + StringRef Dir = File->getDirectory(), Filename = File->getFilename(); + + // Clang emits directory and relative filename info into the IR, but CodeView + // operates on full paths. We could change Clang to emit full paths too, but + // that would increase the IR size and probably not needed for other users. + // For now, just concatenate and canonicalize the path here. + if (Filename.find(':') == 1) + Filepath = Filename; + else + Filepath = (Dir + "\\" + Filename).str(); + + // Canonicalize the path. We have to do it textually because we may no longer + // have access the file in the filesystem. + // First, replace all slashes with backslashes. + std::replace(Filepath.begin(), Filepath.end(), '/', '\\'); + + // Remove all "\.\" with "\". + size_t Cursor = 0; + while ((Cursor = Filepath.find("\\.\\", Cursor)) != std::string::npos) + Filepath.erase(Cursor, 2); + + // Replace all "\XXX\..\" with "\". Don't try too hard though as the original + // path should be well-formatted, e.g. start with a drive letter, etc. + Cursor = 0; + while ((Cursor = Filepath.find("\\..\\", Cursor)) != std::string::npos) { + // Something's wrong if the path starts with "\..\", abort. + if (Cursor == 0) + break; + + size_t PrevSlash = Filepath.rfind('\\', Cursor - 1); + if (PrevSlash == std::string::npos) + // Something's wrong, abort. + break; + + Filepath.erase(PrevSlash, Cursor + 3 - PrevSlash); + // The next ".." might be following the one we've just erased. + Cursor = PrevSlash; + } + + // Remove all duplicate backslashes. + Cursor = 0; + while ((Cursor = Filepath.find("\\\\", Cursor)) != std::string::npos) + Filepath.erase(Cursor, 1); + + return Filepath; +} + +unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) { + unsigned NextId = FileIdMap.size() + 1; + auto Insertion = FileIdMap.insert(std::make_pair(F, NextId)); + if (Insertion.second) { + // We have to compute the full filepath and emit a .cv_file directive. + StringRef FullPath = getFullFilepath(F); + NextId = OS.EmitCVFileDirective(NextId, FullPath); + assert(NextId == FileIdMap.size() && ".cv_file directive failed"); + } + return Insertion.first->second; +} + +CodeViewDebug::InlineSite & +CodeViewDebug::getInlineSite(const DILocation *InlinedAt, + const DISubprogram *Inlinee) { + auto SiteInsertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()}); + InlineSite *Site = &SiteInsertion.first->second; + if (SiteInsertion.second) { + Site->SiteFuncId = NextFuncId++; + Site->Inlinee = Inlinee; + InlinedSubprograms.insert(Inlinee); + getFuncIdForSubprogram(Inlinee); + } + return *Site; +} + +static StringRef getPrettyScopeName(const DIScope *Scope) { + StringRef ScopeName = Scope->getName(); + if (!ScopeName.empty()) + return ScopeName; + + switch (Scope->getTag()) { + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_union_type: + return "<unnamed-tag>"; + case dwarf::DW_TAG_namespace: + return "`anonymous namespace'"; + } + + return StringRef(); +} + +static const DISubprogram *getQualifiedNameComponents( + const DIScope *Scope, SmallVectorImpl<StringRef> &QualifiedNameComponents) { + const DISubprogram *ClosestSubprogram = nullptr; + while (Scope != nullptr) { + if (ClosestSubprogram == nullptr) + ClosestSubprogram = dyn_cast<DISubprogram>(Scope); + StringRef ScopeName = getPrettyScopeName(Scope); + if (!ScopeName.empty()) + QualifiedNameComponents.push_back(ScopeName); + Scope = Scope->getScope().resolve(); + } + return ClosestSubprogram; +} + +static std::string getQualifiedName(ArrayRef<StringRef> QualifiedNameComponents, + StringRef TypeName) { + std::string FullyQualifiedName; + for (StringRef QualifiedNameComponent : reverse(QualifiedNameComponents)) { + FullyQualifiedName.append(QualifiedNameComponent); + FullyQualifiedName.append("::"); + } + FullyQualifiedName.append(TypeName); + return FullyQualifiedName; +} + +static std::string getFullyQualifiedName(const DIScope *Scope, StringRef Name) { + SmallVector<StringRef, 5> QualifiedNameComponents; + getQualifiedNameComponents(Scope, QualifiedNameComponents); + return getQualifiedName(QualifiedNameComponents, Name); +} + +struct CodeViewDebug::TypeLoweringScope { + TypeLoweringScope(CodeViewDebug &CVD) : CVD(CVD) { ++CVD.TypeEmissionLevel; } + ~TypeLoweringScope() { + // Don't decrement TypeEmissionLevel until after emitting deferred types, so + // inner TypeLoweringScopes don't attempt to emit deferred types. + if (CVD.TypeEmissionLevel == 1) + CVD.emitDeferredCompleteTypes(); + --CVD.TypeEmissionLevel; + } + CodeViewDebug &CVD; +}; + +static std::string getFullyQualifiedName(const DIScope *Ty) { + const DIScope *Scope = Ty->getScope().resolve(); + return getFullyQualifiedName(Scope, getPrettyScopeName(Ty)); +} + +TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) { + // No scope means global scope and that uses the zero index. + if (!Scope || isa<DIFile>(Scope)) + return TypeIndex(); + + assert(!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"); + + // Check if we've already translated this scope. + auto I = TypeIndices.find({Scope, nullptr}); + if (I != TypeIndices.end()) + return I->second; + + // Build the fully qualified name of the scope. + std::string ScopeName = getFullyQualifiedName(Scope); + TypeIndex TI = + TypeTable.writeStringId(StringIdRecord(TypeIndex(), ScopeName)); + return recordTypeIndexForDINode(Scope, TI); +} + +TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) { + assert(SP); + + // Check if we've already translated this subprogram. + auto I = TypeIndices.find({SP, nullptr}); + if (I != TypeIndices.end()) + return I->second; + + // The display name includes function template arguments. Drop them to match + // MSVC. + StringRef DisplayName = SP->getDisplayName().split('<').first; + + const DIScope *Scope = SP->getScope().resolve(); + TypeIndex TI; + if (const auto *Class = dyn_cast_or_null<DICompositeType>(Scope)) { + // If the scope is a DICompositeType, then this must be a method. Member + // function types take some special handling, and require access to the + // subprogram. + TypeIndex ClassType = getTypeIndex(Class); + MemberFuncIdRecord MFuncId(ClassType, getMemberFunctionType(SP, Class), + DisplayName); + TI = TypeTable.writeMemberFuncId(MFuncId); + } else { + // Otherwise, this must be a free function. + TypeIndex ParentScope = getScopeIndex(Scope); + FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName); + TI = TypeTable.writeFuncId(FuncId); + } + + return recordTypeIndexForDINode(SP, TI); +} + +TypeIndex CodeViewDebug::getMemberFunctionType(const DISubprogram *SP, + const DICompositeType *Class) { + // Always use the method declaration as the key for the function type. The + // method declaration contains the this adjustment. + if (SP->getDeclaration()) + SP = SP->getDeclaration(); + assert(!SP->getDeclaration() && "should use declaration as key"); + + // Key the MemberFunctionRecord into the map as {SP, Class}. It won't collide + // with the MemberFuncIdRecord, which is keyed in as {SP, nullptr}. + auto I = TypeIndices.find({SP, Class}); + if (I != TypeIndices.end()) + return I->second; + + // Make sure complete type info for the class is emitted *after* the member + // function type, as the complete class type is likely to reference this + // member function type. + TypeLoweringScope S(*this); + TypeIndex TI = + lowerTypeMemberFunction(SP->getType(), Class, SP->getThisAdjustment()); + return recordTypeIndexForDINode(SP, TI, Class); +} + +TypeIndex CodeViewDebug::recordTypeIndexForDINode(const DINode *Node, + TypeIndex TI, + const DIType *ClassTy) { + auto InsertResult = TypeIndices.insert({{Node, ClassTy}, TI}); + (void)InsertResult; + assert(InsertResult.second && "DINode was already assigned a type index"); + return TI; +} + +unsigned CodeViewDebug::getPointerSizeInBytes() { + return MMI->getModule()->getDataLayout().getPointerSizeInBits() / 8; +} + +void CodeViewDebug::recordLocalVariable(LocalVariable &&Var, + const DILocation *InlinedAt) { + if (InlinedAt) { + // This variable was inlined. Associate it with the InlineSite. + const DISubprogram *Inlinee = Var.DIVar->getScope()->getSubprogram(); + InlineSite &Site = getInlineSite(InlinedAt, Inlinee); + Site.InlinedLocals.emplace_back(Var); + } else { + // This variable goes in the main ProcSym. + CurFn->Locals.emplace_back(Var); + } +} + +static void addLocIfNotPresent(SmallVectorImpl<const DILocation *> &Locs, + const DILocation *Loc) { + auto B = Locs.begin(), E = Locs.end(); + if (std::find(B, E, Loc) == E) + Locs.push_back(Loc); +} + +void CodeViewDebug::maybeRecordLocation(const DebugLoc &DL, + const MachineFunction *MF) { + // Skip this instruction if it has the same location as the previous one. + if (DL == CurFn->LastLoc) + return; + + const DIScope *Scope = DL.get()->getScope(); + if (!Scope) + return; + + // Skip this line if it is longer than the maximum we can record. + LineInfo LI(DL.getLine(), DL.getLine(), /*IsStatement=*/true); + if (LI.getStartLine() != DL.getLine() || LI.isAlwaysStepInto() || + LI.isNeverStepInto()) + return; + + ColumnInfo CI(DL.getCol(), /*EndColumn=*/0); + if (CI.getStartColumn() != DL.getCol()) + return; + + if (!CurFn->HaveLineInfo) + CurFn->HaveLineInfo = true; + unsigned FileId = 0; + if (CurFn->LastLoc.get() && CurFn->LastLoc->getFile() == DL->getFile()) + FileId = CurFn->LastFileId; + else + FileId = CurFn->LastFileId = maybeRecordFile(DL->getFile()); + CurFn->LastLoc = DL; + + unsigned FuncId = CurFn->FuncId; + if (const DILocation *SiteLoc = DL->getInlinedAt()) { + const DILocation *Loc = DL.get(); + + // If this location was actually inlined from somewhere else, give it the ID + // of the inline call site. + FuncId = + getInlineSite(SiteLoc, Loc->getScope()->getSubprogram()).SiteFuncId; + + // Ensure we have links in the tree of inline call sites. + bool FirstLoc = true; + while ((SiteLoc = Loc->getInlinedAt())) { + InlineSite &Site = + getInlineSite(SiteLoc, Loc->getScope()->getSubprogram()); + if (!FirstLoc) + addLocIfNotPresent(Site.ChildSites, Loc); + FirstLoc = false; + Loc = SiteLoc; + } + addLocIfNotPresent(CurFn->ChildSites, Loc); + } + + OS.EmitCVLocDirective(FuncId, FileId, DL.getLine(), DL.getCol(), + /*PrologueEnd=*/false, + /*IsStmt=*/false, DL->getFilename()); +} + +void CodeViewDebug::emitCodeViewMagicVersion() { + OS.EmitValueToAlignment(4); + OS.AddComment("Debug section magic"); + OS.EmitIntValue(COFF::DEBUG_SECTION_MAGIC, 4); +} + +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 + // aligned. + + // Use the generic .debug$S section, and make a subsection for all the inlined + // subprograms. + switchToDebugSectionForSymbol(nullptr); + emitInlineeLinesSubsection(); + + // Emit per-function debug information. + for (auto &P : FnDebugInfo) + if (!P.first->isDeclarationForLinker()) + emitDebugInfoForFunction(P.first, P.second); + + // Emit global variable debug information. + setCurrentSubprogram(nullptr); + emitDebugInfoForGlobals(); + + // Emit retained types. + emitDebugInfoForRetainedTypes(); + + // Switch back to the generic .debug$S section after potentially processing + // comdat symbol sections. + switchToDebugSectionForSymbol(nullptr); + + // Emit UDT records for any types used by global variables. + if (!GlobalUDTs.empty()) { + MCSymbol *SymbolsEnd = beginCVSubsection(ModuleSubstreamKind::Symbols); + emitDebugInfoForUDTs(GlobalUDTs); + endCVSubsection(SymbolsEnd); + } + + // This subsection holds a file index to offset in string table table. + OS.AddComment("File index to string table offset subsection"); + OS.EmitCVFileChecksumsDirective(); + + // This subsection holds the string table. + OS.AddComment("String table"); + OS.EmitCVStringTableDirective(); + + // Emit type information last, so that any types we translate while emitting + // function info are included. + emitTypeInformation(); + + clear(); +} + +static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S) { + // Microsoft's linker seems to have trouble with symbol names longer than + // 0xffd8 bytes. + S = S.substr(0, 0xffd8); + SmallString<32> NullTerminatedString(S); + NullTerminatedString.push_back('\0'); + OS.EmitBytes(NullTerminatedString); +} + +void CodeViewDebug::emitTypeInformation() { + // Do nothing if we have no debug info or if no non-trivial types were emitted + // to TypeTable during codegen. + NamedMDNode *CU_Nodes = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + if (!CU_Nodes) + return; + if (TypeTable.empty()) + return; + + // Start the .debug$T section with 0x4. + OS.SwitchSection(Asm->getObjFileLowering().getCOFFDebugTypesSection()); + emitCodeViewMagicVersion(); + + SmallString<8> CommentPrefix; + if (OS.isVerboseAsm()) { + CommentPrefix += '\t'; + CommentPrefix += Asm->MAI->getCommentString(); + CommentPrefix += ' '; + } + + CVTypeDumper CVTD(nullptr, /*PrintRecordBytes=*/false); + TypeTable.ForEachRecord( + [&](TypeIndex Index, StringRef Record) { + if (OS.isVerboseAsm()) { + // Emit a block comment describing the type record for readability. + SmallString<512> CommentBlock; + raw_svector_ostream CommentOS(CommentBlock); + ScopedPrinter SP(CommentOS); + SP.setPrefix(CommentPrefix); + CVTD.setPrinter(&SP); + Error E = CVTD.dump({Record.bytes_begin(), Record.bytes_end()}); + if (E) { + logAllUnhandledErrors(std::move(E), errs(), "error: "); + llvm_unreachable("produced malformed type record"); + } + // emitRawComment will insert its own tab and comment string before + // the first line, so strip off our first one. It also prints its own + // newline. + OS.emitRawComment( + CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim()); + } else { +#ifndef NDEBUG + // Assert that the type data is valid even if we aren't dumping + // comments. The MSVC linker doesn't do much type record validation, + // so the first link of an invalid type record can succeed while + // subsequent links will fail with LNK1285. + ByteStream<> Stream({Record.bytes_begin(), Record.bytes_end()}); + CVTypeArray Types; + StreamReader Reader(Stream); + Error E = Reader.readArray(Types, Reader.getLength()); + if (!E) { + TypeVisitorCallbacks C; + E = CVTypeVisitor(C).visitTypeStream(Types); + } + if (E) { + logAllUnhandledErrors(std::move(E), errs(), "error: "); + llvm_unreachable("produced malformed type record"); + } +#endif + } + OS.EmitBinaryData(Record); + }); +} + +void CodeViewDebug::emitInlineeLinesSubsection() { + if (InlinedSubprograms.empty()) + return; + + OS.AddComment("Inlinee lines subsection"); + MCSymbol *InlineEnd = beginCVSubsection(ModuleSubstreamKind::InlineeLines); + + // We don't provide any extra file info. + // FIXME: Find out if debuggers use this info. + OS.AddComment("Inlinee lines signature"); + OS.EmitIntValue(unsigned(InlineeLinesSignature::Normal), 4); + + for (const DISubprogram *SP : InlinedSubprograms) { + assert(TypeIndices.count({SP, nullptr})); + TypeIndex InlineeIdx = TypeIndices[{SP, nullptr}]; + + OS.AddBlankLine(); + unsigned FileId = maybeRecordFile(SP->getFile()); + OS.AddComment("Inlined function " + SP->getDisplayName() + " starts at " + + SP->getFilename() + Twine(':') + Twine(SP->getLine())); + OS.AddBlankLine(); + // The filechecksum table uses 8 byte entries for now, and file ids start at + // 1. + unsigned FileOffset = (FileId - 1) * 8; + OS.AddComment("Type index of inlined function"); + OS.EmitIntValue(InlineeIdx.getIndex(), 4); + OS.AddComment("Offset into filechecksum table"); + OS.EmitIntValue(FileOffset, 4); + OS.AddComment("Starting line number"); + OS.EmitIntValue(SP->getLine(), 4); + } + + endCVSubsection(InlineEnd); +} + +void CodeViewDebug::collectInlineSiteChildren( + SmallVectorImpl<unsigned> &Children, const FunctionInfo &FI, + const InlineSite &Site) { + for (const DILocation *ChildSiteLoc : Site.ChildSites) { + auto I = FI.InlineSites.find(ChildSiteLoc); + const InlineSite &ChildSite = I->second; + Children.push_back(ChildSite.SiteFuncId); + collectInlineSiteChildren(Children, FI, ChildSite); + } +} + +void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI, + const DILocation *InlinedAt, + const InlineSite &Site) { + MCSymbol *InlineBegin = MMI->getContext().createTempSymbol(), + *InlineEnd = MMI->getContext().createTempSymbol(); + + assert(TypeIndices.count({Site.Inlinee, nullptr})); + TypeIndex InlineeIdx = TypeIndices[{Site.Inlinee, nullptr}]; + + // SymbolRecord + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(InlineEnd, InlineBegin, 2); // RecordLength + OS.EmitLabel(InlineBegin); + OS.AddComment("Record kind: S_INLINESITE"); + OS.EmitIntValue(SymbolKind::S_INLINESITE, 2); // RecordKind + + OS.AddComment("PtrParent"); + OS.EmitIntValue(0, 4); + OS.AddComment("PtrEnd"); + OS.EmitIntValue(0, 4); + OS.AddComment("Inlinee type index"); + OS.EmitIntValue(InlineeIdx.getIndex(), 4); + + unsigned FileId = maybeRecordFile(Site.Inlinee->getFile()); + unsigned StartLineNum = Site.Inlinee->getLine(); + SmallVector<unsigned, 3> SecondaryFuncIds; + collectInlineSiteChildren(SecondaryFuncIds, FI, Site); + + OS.EmitCVInlineLinetableDirective(Site.SiteFuncId, FileId, StartLineNum, + FI.Begin, FI.End, SecondaryFuncIds); + + OS.EmitLabel(InlineEnd); + + emitLocalVariableList(Site.InlinedLocals); + + // Recurse on child inlined call sites before closing the scope. + for (const DILocation *ChildSite : Site.ChildSites) { + auto I = FI.InlineSites.find(ChildSite); + assert(I != FI.InlineSites.end() && + "child site not in function inline site map"); + emitInlinedCallSite(FI, ChildSite, I->second); + } + + // Close the scope. + OS.AddComment("Record length"); + OS.EmitIntValue(2, 2); // RecordLength + OS.AddComment("Record kind: S_INLINESITE_END"); + OS.EmitIntValue(SymbolKind::S_INLINESITE_END, 2); // RecordKind +} + +void CodeViewDebug::switchToDebugSectionForSymbol(const MCSymbol *GVSym) { + // If we have a symbol, it may be in a section that is COMDAT. If so, find the + // comdat key. A section may be comdat because of -ffunction-sections or + // because it is comdat in the IR. + MCSectionCOFF *GVSec = + GVSym ? dyn_cast<MCSectionCOFF>(&GVSym->getSection()) : nullptr; + const MCSymbol *KeySym = GVSec ? GVSec->getCOMDATSymbol() : nullptr; + + MCSectionCOFF *DebugSec = cast<MCSectionCOFF>( + Asm->getObjFileLowering().getCOFFDebugSymbolsSection()); + DebugSec = OS.getContext().getAssociativeCOFFSection(DebugSec, KeySym); + + OS.SwitchSection(DebugSec); + + // Emit the magic version number if this is the first time we've switched to + // this section. + if (ComdatDebugSections.insert(DebugSec).second) + emitCodeViewMagicVersion(); +} + +void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, + FunctionInfo &FI) { + // For each function there is a separate subsection + // which holds the PC to file:line table. + const MCSymbol *Fn = Asm->getSymbol(GV); + assert(Fn); + + // Switch to the to a comdat section, if appropriate. + switchToDebugSectionForSymbol(Fn); + + std::string FuncName; + auto *SP = GV->getSubprogram(); + assert(SP); + setCurrentSubprogram(SP); + + // If we have a display name, build the fully qualified name by walking the + // chain of scopes. + if (!SP->getDisplayName().empty()) + FuncName = + getFullyQualifiedName(SP->getScope().resolve(), SP->getDisplayName()); + + // If our DISubprogram name is empty, use the mangled name. + if (FuncName.empty()) + FuncName = GlobalValue::getRealLinkageName(GV->getName()); + + // Emit a symbol subsection, required by VS2012+ to find function boundaries. + OS.AddComment("Symbol subsection for " + Twine(FuncName)); + MCSymbol *SymbolsEnd = beginCVSubsection(ModuleSubstreamKind::Symbols); + { + MCSymbol *ProcRecordBegin = MMI->getContext().createTempSymbol(), + *ProcRecordEnd = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(ProcRecordEnd, ProcRecordBegin, 2); + OS.EmitLabel(ProcRecordBegin); + + if (GV->hasLocalLinkage()) { + OS.AddComment("Record kind: S_LPROC32_ID"); + OS.EmitIntValue(unsigned(SymbolKind::S_LPROC32_ID), 2); + } else { + OS.AddComment("Record kind: S_GPROC32_ID"); + OS.EmitIntValue(unsigned(SymbolKind::S_GPROC32_ID), 2); + } + + // These fields are filled in by tools like CVPACK which run after the fact. + OS.AddComment("PtrParent"); + OS.EmitIntValue(0, 4); + OS.AddComment("PtrEnd"); + OS.EmitIntValue(0, 4); + OS.AddComment("PtrNext"); + OS.EmitIntValue(0, 4); + // This is the important bit that tells the debugger where the function + // code is located and what's its size: + OS.AddComment("Code size"); + OS.emitAbsoluteSymbolDiff(FI.End, Fn, 4); + OS.AddComment("Offset after prologue"); + OS.EmitIntValue(0, 4); + OS.AddComment("Offset before epilogue"); + OS.EmitIntValue(0, 4); + OS.AddComment("Function type index"); + OS.EmitIntValue(getFuncIdForSubprogram(GV->getSubprogram()).getIndex(), 4); + OS.AddComment("Function section relative address"); + OS.EmitCOFFSecRel32(Fn); + OS.AddComment("Function section index"); + OS.EmitCOFFSectionIndex(Fn); + OS.AddComment("Flags"); + OS.EmitIntValue(0, 1); + // Emit the function display name as a null-terminated string. + OS.AddComment("Function name"); + // Truncate the name so we won't overflow the record length field. + emitNullTerminatedSymbolName(OS, FuncName); + OS.EmitLabel(ProcRecordEnd); + + emitLocalVariableList(FI.Locals); + + // Emit inlined call site information. Only emit functions inlined directly + // into the parent function. We'll emit the other sites recursively as part + // of their parent inline site. + for (const DILocation *InlinedAt : FI.ChildSites) { + auto I = FI.InlineSites.find(InlinedAt); + assert(I != FI.InlineSites.end() && + "child site not in function inline site map"); + emitInlinedCallSite(FI, InlinedAt, I->second); + } + + if (SP != nullptr) + emitDebugInfoForUDTs(LocalUDTs); + + // We're done with this function. + OS.AddComment("Record length"); + OS.EmitIntValue(0x0002, 2); + OS.AddComment("Record kind: S_PROC_ID_END"); + OS.EmitIntValue(unsigned(SymbolKind::S_PROC_ID_END), 2); + } + endCVSubsection(SymbolsEnd); + + // We have an assembler directive that takes care of the whole line table. + OS.EmitCVLinetableDirective(FI.FuncId, Fn, FI.End); +} + +CodeViewDebug::LocalVarDefRange +CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) { + LocalVarDefRange DR; + DR.InMemory = -1; + DR.DataOffset = Offset; + assert(DR.DataOffset == Offset && "truncation"); + DR.StructOffset = 0; + DR.CVRegister = CVRegister; + return DR; +} + +CodeViewDebug::LocalVarDefRange +CodeViewDebug::createDefRangeReg(uint16_t CVRegister) { + LocalVarDefRange DR; + DR.InMemory = 0; + DR.DataOffset = 0; + DR.StructOffset = 0; + DR.CVRegister = CVRegister; + return DR; +} + +void CodeViewDebug::collectVariableInfoFromMMITable( + DenseSet<InlinedVariable> &Processed) { + const TargetSubtargetInfo &TSI = Asm->MF->getSubtarget(); + const TargetFrameLowering *TFI = TSI.getFrameLowering(); + const TargetRegisterInfo *TRI = TSI.getRegisterInfo(); + + for (const MachineModuleInfo::VariableDbgInfo &VI : + MMI->getVariableDbgInfo()) { + if (!VI.Var) + continue; + assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) && + "Expected inlined-at fields to agree"); + + Processed.insert(InlinedVariable(VI.Var, VI.Loc->getInlinedAt())); + LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc); + + // If variable scope is not found then skip this variable. + if (!Scope) + continue; + + // Get the frame register used and the offset. + unsigned FrameReg = 0; + int FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg); + uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg); + + // Calculate the label ranges. + LocalVarDefRange DefRange = createDefRangeMem(CVReg, FrameOffset); + for (const InsnRange &Range : Scope->getRanges()) { + const MCSymbol *Begin = getLabelBeforeInsn(Range.first); + const MCSymbol *End = getLabelAfterInsn(Range.second); + End = End ? End : Asm->getFunctionEnd(); + DefRange.Ranges.emplace_back(Begin, End); + } + + LocalVariable Var; + Var.DIVar = VI.Var; + Var.DefRanges.emplace_back(std::move(DefRange)); + recordLocalVariable(std::move(Var), VI.Loc->getInlinedAt()); + } +} + +void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { + DenseSet<InlinedVariable> Processed; + // Grab the variable info that was squirreled away in the MMI side-table. + collectVariableInfoFromMMITable(Processed); + + const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo(); + + for (const auto &I : DbgValues) { + InlinedVariable IV = I.first; + if (Processed.count(IV)) + continue; + const DILocalVariable *DIVar = IV.first; + const DILocation *InlinedAt = IV.second; + + // Instruction ranges, specifying where IV is accessible. + const auto &Ranges = I.second; + + LexicalScope *Scope = nullptr; + if (InlinedAt) + Scope = LScopes.findInlinedScope(DIVar->getScope(), InlinedAt); + else + Scope = LScopes.findLexicalScope(DIVar->getScope()); + // If variable scope is not found then skip this variable. + if (!Scope) + continue; + + LocalVariable Var; + Var.DIVar = DIVar; + + // Calculate the definition ranges. + for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { + const InsnRange &Range = *I; + const MachineInstr *DVInst = Range.first; + assert(DVInst->isDebugValue() && "Invalid History entry"); + const DIExpression *DIExpr = DVInst->getDebugExpression(); + + // Bail if there is a complex DWARF expression for now. + if (DIExpr && DIExpr->getNumElements() > 0) + continue; + + // Bail if operand 0 is not a valid register. This means the variable is a + // simple constant, or is described by a complex expression. + // FIXME: Find a way to represent constant variables, since they are + // relatively common. + unsigned Reg = + DVInst->getOperand(0).isReg() ? DVInst->getOperand(0).getReg() : 0; + if (Reg == 0) + continue; + + // Handle the two cases we can handle: indirect in memory and in register. + bool IsIndirect = DVInst->getOperand(1).isImm(); + unsigned CVReg = TRI->getCodeViewRegNum(DVInst->getOperand(0).getReg()); + { + LocalVarDefRange DefRange; + if (IsIndirect) { + int64_t Offset = DVInst->getOperand(1).getImm(); + DefRange = createDefRangeMem(CVReg, Offset); + } else { + DefRange = createDefRangeReg(CVReg); + } + if (Var.DefRanges.empty() || + Var.DefRanges.back().isDifferentLocation(DefRange)) { + Var.DefRanges.emplace_back(std::move(DefRange)); + } + } + + // Compute the label range. + const MCSymbol *Begin = getLabelBeforeInsn(Range.first); + const MCSymbol *End = getLabelAfterInsn(Range.second); + if (!End) { + if (std::next(I) != E) + End = getLabelBeforeInsn(std::next(I)->first); + else + End = Asm->getFunctionEnd(); + } + + // If the last range end is our begin, just extend the last range. + // Otherwise make a new range. + SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &Ranges = + Var.DefRanges.back().Ranges; + if (!Ranges.empty() && Ranges.back().second == Begin) + Ranges.back().second = End; + else + Ranges.emplace_back(Begin, End); + + // FIXME: Do more range combining. + } + + recordLocalVariable(std::move(Var), InlinedAt); + } +} + +void CodeViewDebug::beginFunction(const MachineFunction *MF) { + assert(!CurFn && "Can't process two functions at once!"); + + if (!Asm || !MMI->hasDebugInfo() || !MF->getFunction()->getSubprogram()) + return; + + DebugHandlerBase::beginFunction(MF); + + const Function *GV = MF->getFunction(); + assert(FnDebugInfo.count(GV) == false); + CurFn = &FnDebugInfo[GV]; + CurFn->FuncId = NextFuncId++; + CurFn->Begin = Asm->getFunctionBegin(); + + // Find the end of the function prolog. First known non-DBG_VALUE and + // non-frame setup location marks the beginning of the function body. + // FIXME: is there a simpler a way to do this? Can we just search + // for the first instruction of the function, not the last of the prolog? + DebugLoc PrologEndLoc; + bool EmptyPrologue = true; + for (const auto &MBB : *MF) { + for (const auto &MI : MBB) { + if (!MI.isDebugValue() && !MI.getFlag(MachineInstr::FrameSetup) && + MI.getDebugLoc()) { + PrologEndLoc = MI.getDebugLoc(); + break; + } else if (!MI.isDebugValue()) { + EmptyPrologue = false; + } + } + } + + // Record beginning of function if we have a non-empty prologue. + if (PrologEndLoc && !EmptyPrologue) { + DebugLoc FnStartDL = PrologEndLoc.getFnDebugLoc(); + maybeRecordLocation(FnStartDL, MF); + } +} + +void CodeViewDebug::addToUDTs(const DIType *Ty, TypeIndex TI) { + // Don't record empty UDTs. + if (Ty->getName().empty()) + return; + + SmallVector<StringRef, 5> QualifiedNameComponents; + const DISubprogram *ClosestSubprogram = getQualifiedNameComponents( + Ty->getScope().resolve(), QualifiedNameComponents); + + std::string FullyQualifiedName = + getQualifiedName(QualifiedNameComponents, getPrettyScopeName(Ty)); + + if (ClosestSubprogram == nullptr) + GlobalUDTs.emplace_back(std::move(FullyQualifiedName), TI); + else if (ClosestSubprogram == CurrentSubprogram) + LocalUDTs.emplace_back(std::move(FullyQualifiedName), TI); + + // TODO: What if the ClosestSubprogram is neither null or the current + // subprogram? Currently, the UDT just gets dropped on the floor. + // + // The current behavior is not desirable. To get maximal fidelity, we would + // need to perform all type translation before beginning emission of .debug$S + // and then make LocalUDTs a member of FunctionInfo +} + +TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) { + // Generic dispatch for lowering an unknown type. + switch (Ty->getTag()) { + case dwarf::DW_TAG_array_type: + return lowerTypeArray(cast<DICompositeType>(Ty)); + case dwarf::DW_TAG_typedef: + return lowerTypeAlias(cast<DIDerivedType>(Ty)); + case dwarf::DW_TAG_base_type: + return lowerTypeBasic(cast<DIBasicType>(Ty)); + case dwarf::DW_TAG_pointer_type: + case dwarf::DW_TAG_reference_type: + case dwarf::DW_TAG_rvalue_reference_type: + return lowerTypePointer(cast<DIDerivedType>(Ty)); + case dwarf::DW_TAG_ptr_to_member_type: + return lowerTypeMemberPointer(cast<DIDerivedType>(Ty)); + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_volatile_type: + return lowerTypeModifier(cast<DIDerivedType>(Ty)); + case dwarf::DW_TAG_subroutine_type: + if (ClassTy) { + // The member function type of a member function pointer has no + // ThisAdjustment. + return lowerTypeMemberFunction(cast<DISubroutineType>(Ty), ClassTy, + /*ThisAdjustment=*/0); + } + return lowerTypeFunction(cast<DISubroutineType>(Ty)); + case dwarf::DW_TAG_enumeration_type: + return lowerTypeEnum(cast<DICompositeType>(Ty)); + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_structure_type: + return lowerTypeClass(cast<DICompositeType>(Ty)); + case dwarf::DW_TAG_union_type: + return lowerTypeUnion(cast<DICompositeType>(Ty)); + default: + // Use the null type index. + return TypeIndex(); + } +} + +TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) { + DITypeRef UnderlyingTypeRef = Ty->getBaseType(); + TypeIndex UnderlyingTypeIndex = getTypeIndex(UnderlyingTypeRef); + StringRef TypeName = Ty->getName(); + + addToUDTs(Ty, UnderlyingTypeIndex); + + if (UnderlyingTypeIndex == TypeIndex(SimpleTypeKind::Int32Long) && + TypeName == "HRESULT") + return TypeIndex(SimpleTypeKind::HResult); + if (UnderlyingTypeIndex == TypeIndex(SimpleTypeKind::UInt16Short) && + TypeName == "wchar_t") + return TypeIndex(SimpleTypeKind::WideCharacter); + + return UnderlyingTypeIndex; +} + +TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { + DITypeRef ElementTypeRef = Ty->getBaseType(); + TypeIndex ElementTypeIndex = getTypeIndex(ElementTypeRef); + // IndexType is size_t, which depends on the bitness of the target. + TypeIndex IndexType = Asm->MAI->getPointerSize() == 8 + ? TypeIndex(SimpleTypeKind::UInt64Quad) + : TypeIndex(SimpleTypeKind::UInt32Long); + + uint64_t ElementSize = getBaseTypeSize(ElementTypeRef) / 8; + + bool UndefinedSubrange = false; + + // FIXME: + // There is a bug in the front-end where an array of a structure, which was + // declared as incomplete structure first, ends up not getting a size assigned + // to it. (PR28303) + // Example: + // struct A(*p)[3]; + // struct A { int f; } a[3]; + // + // This needs to be fixed in the front-end, but in the meantime we don't want + // to trigger an assertion because of this. + if (Ty->getSizeInBits() == 0) { + UndefinedSubrange = true; + } + + // Add subranges to array type. + DINodeArray Elements = Ty->getElements(); + for (int i = Elements.size() - 1; i >= 0; --i) { + const DINode *Element = Elements[i]; + assert(Element->getTag() == dwarf::DW_TAG_subrange_type); + + const DISubrange *Subrange = cast<DISubrange>(Element); + assert(Subrange->getLowerBound() == 0 && + "codeview doesn't support subranges with lower bounds"); + int64_t Count = Subrange->getCount(); + + // Variable Length Array (VLA) has Count equal to '-1'. + // Replace with Count '1', assume it is the minimum VLA length. + // FIXME: Make front-end support VLA subrange and emit LF_DIMVARLU. + if (Count == -1) { + Count = 1; + UndefinedSubrange = true; + } + + StringRef Name = (i == 0) ? Ty->getName() : ""; + // Update the element size and element type index for subsequent subranges. + ElementSize *= Count; + ElementTypeIndex = TypeTable.writeArray( + ArrayRecord(ElementTypeIndex, IndexType, ElementSize, Name)); + } + + (void)UndefinedSubrange; + assert(UndefinedSubrange || ElementSize == (Ty->getSizeInBits() / 8)); + + return ElementTypeIndex; +} + +TypeIndex CodeViewDebug::lowerTypeBasic(const DIBasicType *Ty) { + TypeIndex Index; + dwarf::TypeKind Kind; + uint32_t ByteSize; + + Kind = static_cast<dwarf::TypeKind>(Ty->getEncoding()); + ByteSize = Ty->getSizeInBits() / 8; + + SimpleTypeKind STK = SimpleTypeKind::None; + switch (Kind) { + case dwarf::DW_ATE_address: + // FIXME: Translate + break; + case dwarf::DW_ATE_boolean: + switch (ByteSize) { + case 1: STK = SimpleTypeKind::Boolean8; break; + case 2: STK = SimpleTypeKind::Boolean16; break; + case 4: STK = SimpleTypeKind::Boolean32; break; + case 8: STK = SimpleTypeKind::Boolean64; break; + case 16: STK = SimpleTypeKind::Boolean128; break; + } + break; + case dwarf::DW_ATE_complex_float: + switch (ByteSize) { + case 2: STK = SimpleTypeKind::Complex16; break; + case 4: STK = SimpleTypeKind::Complex32; break; + case 8: STK = SimpleTypeKind::Complex64; break; + case 10: STK = SimpleTypeKind::Complex80; break; + case 16: STK = SimpleTypeKind::Complex128; break; + } + break; + case dwarf::DW_ATE_float: + switch (ByteSize) { + case 2: STK = SimpleTypeKind::Float16; break; + case 4: STK = SimpleTypeKind::Float32; break; + case 6: STK = SimpleTypeKind::Float48; break; + case 8: STK = SimpleTypeKind::Float64; break; + case 10: STK = SimpleTypeKind::Float80; break; + case 16: STK = SimpleTypeKind::Float128; break; + } + break; + case dwarf::DW_ATE_signed: + switch (ByteSize) { + case 1: STK = SimpleTypeKind::SByte; break; + case 2: STK = SimpleTypeKind::Int16Short; break; + case 4: STK = SimpleTypeKind::Int32; break; + case 8: STK = SimpleTypeKind::Int64Quad; break; + case 16: STK = SimpleTypeKind::Int128Oct; break; + } + break; + case dwarf::DW_ATE_unsigned: + switch (ByteSize) { + case 1: STK = SimpleTypeKind::Byte; break; + case 2: STK = SimpleTypeKind::UInt16Short; break; + case 4: STK = SimpleTypeKind::UInt32; break; + case 8: STK = SimpleTypeKind::UInt64Quad; break; + case 16: STK = SimpleTypeKind::UInt128Oct; break; + } + break; + case dwarf::DW_ATE_UTF: + switch (ByteSize) { + case 2: STK = SimpleTypeKind::Character16; break; + case 4: STK = SimpleTypeKind::Character32; break; + } + break; + case dwarf::DW_ATE_signed_char: + if (ByteSize == 1) + STK = SimpleTypeKind::SignedCharacter; + break; + case dwarf::DW_ATE_unsigned_char: + if (ByteSize == 1) + STK = SimpleTypeKind::UnsignedCharacter; + break; + default: + break; + } + + // Apply some fixups based on the source-level type name. + if (STK == SimpleTypeKind::Int32 && Ty->getName() == "long int") + STK = SimpleTypeKind::Int32Long; + if (STK == SimpleTypeKind::UInt32 && Ty->getName() == "long unsigned int") + STK = SimpleTypeKind::UInt32Long; + if (STK == SimpleTypeKind::UInt16Short && + (Ty->getName() == "wchar_t" || Ty->getName() == "__wchar_t")) + STK = SimpleTypeKind::WideCharacter; + if ((STK == SimpleTypeKind::SignedCharacter || + STK == SimpleTypeKind::UnsignedCharacter) && + Ty->getName() == "char") + STK = SimpleTypeKind::NarrowCharacter; + + return TypeIndex(STK); +} + +TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) { + TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType()); + + // While processing the type being pointed to it is possible we already + // created this pointer type. If so, we check here and return the existing + // pointer type. + auto I = TypeIndices.find({Ty, nullptr}); + if (I != TypeIndices.end()) + return I->second; + + // Pointers to simple types can use SimpleTypeMode, rather than having a + // dedicated pointer type record. + if (PointeeTI.isSimple() && + PointeeTI.getSimpleMode() == SimpleTypeMode::Direct && + Ty->getTag() == dwarf::DW_TAG_pointer_type) { + SimpleTypeMode Mode = Ty->getSizeInBits() == 64 + ? SimpleTypeMode::NearPointer64 + : SimpleTypeMode::NearPointer32; + return TypeIndex(PointeeTI.getSimpleKind(), Mode); + } + + PointerKind PK = + Ty->getSizeInBits() == 64 ? PointerKind::Near64 : PointerKind::Near32; + PointerMode PM = PointerMode::Pointer; + switch (Ty->getTag()) { + default: llvm_unreachable("not a pointer tag type"); + case dwarf::DW_TAG_pointer_type: + PM = PointerMode::Pointer; + break; + case dwarf::DW_TAG_reference_type: + PM = PointerMode::LValueReference; + break; + case dwarf::DW_TAG_rvalue_reference_type: + PM = PointerMode::RValueReference; + break; + } + // FIXME: MSVC folds qualifiers into PointerOptions in the context of a method + // 'this' pointer, but not normal contexts. Figure out what we're supposed to + // do. + PointerOptions PO = PointerOptions::None; + PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8); + return TypeTable.writePointer(PR); +} + +static PointerToMemberRepresentation +translatePtrToMemberRep(unsigned SizeInBytes, bool IsPMF, unsigned Flags) { + // SizeInBytes being zero generally implies that the member pointer type was + // incomplete, which can happen if it is part of a function prototype. In this + // case, use the unknown model instead of the general model. + if (IsPMF) { + switch (Flags & DINode::FlagPtrToMemberRep) { + case 0: + return SizeInBytes == 0 ? PointerToMemberRepresentation::Unknown + : PointerToMemberRepresentation::GeneralFunction; + case DINode::FlagSingleInheritance: + return PointerToMemberRepresentation::SingleInheritanceFunction; + case DINode::FlagMultipleInheritance: + return PointerToMemberRepresentation::MultipleInheritanceFunction; + case DINode::FlagVirtualInheritance: + return PointerToMemberRepresentation::VirtualInheritanceFunction; + } + } else { + switch (Flags & DINode::FlagPtrToMemberRep) { + case 0: + return SizeInBytes == 0 ? PointerToMemberRepresentation::Unknown + : PointerToMemberRepresentation::GeneralData; + case DINode::FlagSingleInheritance: + return PointerToMemberRepresentation::SingleInheritanceData; + case DINode::FlagMultipleInheritance: + return PointerToMemberRepresentation::MultipleInheritanceData; + case DINode::FlagVirtualInheritance: + return PointerToMemberRepresentation::VirtualInheritanceData; + } + } + llvm_unreachable("invalid ptr to member representation"); +} + +TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) { + assert(Ty->getTag() == dwarf::DW_TAG_ptr_to_member_type); + TypeIndex ClassTI = getTypeIndex(Ty->getClassType()); + TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType(), Ty->getClassType()); + PointerKind PK = Asm->MAI->getPointerSize() == 8 ? PointerKind::Near64 + : PointerKind::Near32; + bool IsPMF = isa<DISubroutineType>(Ty->getBaseType()); + PointerMode PM = IsPMF ? PointerMode::PointerToMemberFunction + : PointerMode::PointerToDataMember; + PointerOptions PO = PointerOptions::None; // FIXME + assert(Ty->getSizeInBits() / 8 <= 0xff && "pointer size too big"); + uint8_t SizeInBytes = Ty->getSizeInBits() / 8; + MemberPointerInfo MPI( + ClassTI, translatePtrToMemberRep(SizeInBytes, IsPMF, Ty->getFlags())); + PointerRecord PR(PointeeTI, PK, PM, PO, SizeInBytes, MPI); + return TypeTable.writePointer(PR); +} + +/// Given a DWARF calling convention, get the CodeView equivalent. If we don't +/// have a translation, use the NearC convention. +static CallingConvention dwarfCCToCodeView(unsigned DwarfCC) { + switch (DwarfCC) { + case dwarf::DW_CC_normal: return CallingConvention::NearC; + case dwarf::DW_CC_BORLAND_msfastcall: return CallingConvention::NearFast; + case dwarf::DW_CC_BORLAND_thiscall: return CallingConvention::ThisCall; + case dwarf::DW_CC_BORLAND_stdcall: return CallingConvention::NearStdCall; + case dwarf::DW_CC_BORLAND_pascal: return CallingConvention::NearPascal; + case dwarf::DW_CC_LLVM_vectorcall: return CallingConvention::NearVector; + } + return CallingConvention::NearC; +} + +TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) { + ModifierOptions Mods = ModifierOptions::None; + bool IsModifier = true; + const DIType *BaseTy = Ty; + while (IsModifier && BaseTy) { + // FIXME: Need to add DWARF tag for __unaligned. + switch (BaseTy->getTag()) { + case dwarf::DW_TAG_const_type: + Mods |= ModifierOptions::Const; + break; + case dwarf::DW_TAG_volatile_type: + Mods |= ModifierOptions::Volatile; + break; + default: + IsModifier = false; + break; + } + if (IsModifier) + BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType().resolve(); + } + TypeIndex ModifiedTI = getTypeIndex(BaseTy); + + // While processing the type being pointed to, it is possible we already + // created this modifier type. If so, we check here and return the existing + // modifier type. + auto I = TypeIndices.find({Ty, nullptr}); + if (I != TypeIndices.end()) + return I->second; + + ModifierRecord MR(ModifiedTI, Mods); + return TypeTable.writeModifier(MR); +} + +TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) { + SmallVector<TypeIndex, 8> ReturnAndArgTypeIndices; + for (DITypeRef ArgTypeRef : Ty->getTypeArray()) + ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef)); + + TypeIndex ReturnTypeIndex = TypeIndex::Void(); + ArrayRef<TypeIndex> ArgTypeIndices = None; + if (!ReturnAndArgTypeIndices.empty()) { + auto ReturnAndArgTypesRef = makeArrayRef(ReturnAndArgTypeIndices); + ReturnTypeIndex = ReturnAndArgTypesRef.front(); + ArgTypeIndices = ReturnAndArgTypesRef.drop_front(); + } + + ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); + TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec); + + CallingConvention CC = dwarfCCToCodeView(Ty->getCC()); + + ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None, + ArgTypeIndices.size(), ArgListIndex); + return TypeTable.writeProcedure(Procedure); +} + +TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, + const DIType *ClassTy, + int ThisAdjustment) { + // Lower the containing class type. + TypeIndex ClassType = getTypeIndex(ClassTy); + + SmallVector<TypeIndex, 8> ReturnAndArgTypeIndices; + for (DITypeRef ArgTypeRef : Ty->getTypeArray()) + ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef)); + + TypeIndex ReturnTypeIndex = TypeIndex::Void(); + ArrayRef<TypeIndex> ArgTypeIndices = None; + if (!ReturnAndArgTypeIndices.empty()) { + auto ReturnAndArgTypesRef = makeArrayRef(ReturnAndArgTypeIndices); + ReturnTypeIndex = ReturnAndArgTypesRef.front(); + ArgTypeIndices = ReturnAndArgTypesRef.drop_front(); + } + TypeIndex ThisTypeIndex = TypeIndex::Void(); + if (!ArgTypeIndices.empty()) { + ThisTypeIndex = ArgTypeIndices.front(); + ArgTypeIndices = ArgTypeIndices.drop_front(); + } + + ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); + TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec); + + CallingConvention CC = dwarfCCToCodeView(Ty->getCC()); + + // TODO: Need to use the correct values for: + // FunctionOptions + // ThisPointerAdjustment. + TypeIndex TI = TypeTable.writeMemberFunction(MemberFunctionRecord( + ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FunctionOptions::None, + ArgTypeIndices.size(), ArgListIndex, ThisAdjustment)); + + return TI; +} + +static MemberAccess translateAccessFlags(unsigned RecordTag, unsigned Flags) { + switch (Flags & DINode::FlagAccessibility) { + case DINode::FlagPrivate: return MemberAccess::Private; + case DINode::FlagPublic: return MemberAccess::Public; + case DINode::FlagProtected: return MemberAccess::Protected; + case 0: + // If there was no explicit access control, provide the default for the tag. + return RecordTag == dwarf::DW_TAG_class_type ? MemberAccess::Private + : MemberAccess::Public; + } + llvm_unreachable("access flags are exclusive"); +} + +static MethodOptions translateMethodOptionFlags(const DISubprogram *SP) { + if (SP->isArtificial()) + return MethodOptions::CompilerGenerated; + + // FIXME: Handle other MethodOptions. + + return MethodOptions::None; +} + +static MethodKind translateMethodKindFlags(const DISubprogram *SP, + bool Introduced) { + switch (SP->getVirtuality()) { + case dwarf::DW_VIRTUALITY_none: + break; + case dwarf::DW_VIRTUALITY_virtual: + return Introduced ? MethodKind::IntroducingVirtual : MethodKind::Virtual; + case dwarf::DW_VIRTUALITY_pure_virtual: + return Introduced ? MethodKind::PureIntroducingVirtual + : MethodKind::PureVirtual; + default: + llvm_unreachable("unhandled virtuality case"); + } + + // FIXME: Get Clang to mark DISubprogram as static and do something with it. + + return MethodKind::Vanilla; +} + +static TypeRecordKind getRecordKind(const DICompositeType *Ty) { + switch (Ty->getTag()) { + case dwarf::DW_TAG_class_type: return TypeRecordKind::Class; + case dwarf::DW_TAG_structure_type: return TypeRecordKind::Struct; + } + llvm_unreachable("unexpected tag"); +} + +/// Return ClassOptions that should be present on both the forward declaration +/// and the defintion of a tag type. +static ClassOptions getCommonClassOptions(const DICompositeType *Ty) { + ClassOptions CO = ClassOptions::None; + + // MSVC always sets this flag, even for local types. Clang doesn't always + // appear to give every type a linkage name, which may be problematic for us. + // FIXME: Investigate the consequences of not following them here. + if (!Ty->getIdentifier().empty()) + CO |= ClassOptions::HasUniqueName; + + // Put the Nested flag on a type if it appears immediately inside a tag type. + // Do not walk the scope chain. Do not attempt to compute ContainsNestedClass + // here. That flag is only set on definitions, and not forward declarations. + const DIScope *ImmediateScope = Ty->getScope().resolve(); + if (ImmediateScope && isa<DICompositeType>(ImmediateScope)) + CO |= ClassOptions::Nested; + + // Put the Scoped flag on function-local types. + for (const DIScope *Scope = ImmediateScope; Scope != nullptr; + Scope = Scope->getScope().resolve()) { + if (isa<DISubprogram>(Scope)) { + CO |= ClassOptions::Scoped; + break; + } + } + + return CO; +} + +TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) { + ClassOptions CO = getCommonClassOptions(Ty); + TypeIndex FTI; + unsigned EnumeratorCount = 0; + + if (Ty->isForwardDecl()) { + CO |= ClassOptions::ForwardReference; + } else { + FieldListRecordBuilder Fields; + for (const DINode *Element : Ty->getElements()) { + // We assume that the frontend provides all members in source declaration + // order, which is what MSVC does. + if (auto *Enumerator = dyn_cast_or_null<DIEnumerator>(Element)) { + Fields.writeEnumerator(EnumeratorRecord( + MemberAccess::Public, APSInt::getUnsigned(Enumerator->getValue()), + Enumerator->getName())); + EnumeratorCount++; + } + } + FTI = TypeTable.writeFieldList(Fields); + } + + std::string FullName = getFullyQualifiedName(Ty); + + return TypeTable.writeEnum(EnumRecord(EnumeratorCount, CO, FTI, FullName, + Ty->getIdentifier(), + getTypeIndex(Ty->getBaseType()))); +} + +//===----------------------------------------------------------------------===// +// ClassInfo +//===----------------------------------------------------------------------===// + +struct llvm::ClassInfo { + struct MemberInfo { + const DIDerivedType *MemberTypeNode; + uint64_t BaseOffset; + }; + // [MemberInfo] + typedef std::vector<MemberInfo> MemberList; + + typedef TinyPtrVector<const DISubprogram *> MethodsList; + // MethodName -> MethodsList + typedef MapVector<MDString *, MethodsList> MethodsMap; + + /// Base classes. + std::vector<const DIDerivedType *> Inheritance; + + /// Direct members. + MemberList Members; + // Direct overloaded methods gathered by name. + MethodsMap Methods; + + std::vector<const DICompositeType *> NestedClasses; +}; + +void CodeViewDebug::clear() { + assert(CurFn == nullptr); + FileIdMap.clear(); + FnDebugInfo.clear(); + FileToFilepathMap.clear(); + LocalUDTs.clear(); + GlobalUDTs.clear(); + TypeIndices.clear(); + CompleteTypeIndices.clear(); +} + +void CodeViewDebug::collectMemberInfo(ClassInfo &Info, + const DIDerivedType *DDTy) { + if (!DDTy->getName().empty()) { + Info.Members.push_back({DDTy, 0}); + return; + } + // An unnamed member must represent a nested struct or union. Add all the + // indirect fields to the current record. + assert((DDTy->getOffsetInBits() % 8) == 0 && "Unnamed bitfield member!"); + uint64_t Offset = DDTy->getOffsetInBits(); + const DIType *Ty = DDTy->getBaseType().resolve(); + const DICompositeType *DCTy = cast<DICompositeType>(Ty); + ClassInfo NestedInfo = collectClassInfo(DCTy); + for (const ClassInfo::MemberInfo &IndirectField : NestedInfo.Members) + Info.Members.push_back( + {IndirectField.MemberTypeNode, IndirectField.BaseOffset + Offset}); +} + +ClassInfo CodeViewDebug::collectClassInfo(const DICompositeType *Ty) { + ClassInfo Info; + // Add elements to structure type. + DINodeArray Elements = Ty->getElements(); + for (auto *Element : Elements) { + // We assume that the frontend provides all members in source declaration + // order, which is what MSVC does. + if (!Element) + continue; + if (auto *SP = dyn_cast<DISubprogram>(Element)) { + Info.Methods[SP->getRawName()].push_back(SP); + } else if (auto *DDTy = dyn_cast<DIDerivedType>(Element)) { + if (DDTy->getTag() == dwarf::DW_TAG_member) { + collectMemberInfo(Info, DDTy); + } else if (DDTy->getTag() == dwarf::DW_TAG_inheritance) { + Info.Inheritance.push_back(DDTy); + } else if (DDTy->getTag() == dwarf::DW_TAG_friend) { + // Ignore friend members. It appears that MSVC emitted info about + // friends in the past, but modern versions do not. + } + // FIXME: Get Clang to emit function virtual table here and handle it. + } else if (auto *Composite = dyn_cast<DICompositeType>(Element)) { + Info.NestedClasses.push_back(Composite); + } + // Skip other unrecognized kinds of elements. + } + return Info; +} + +TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) { + // First, construct the forward decl. Don't look into Ty to compute the + // forward decl options, since it might not be available in all TUs. + TypeRecordKind Kind = getRecordKind(Ty); + ClassOptions CO = + ClassOptions::ForwardReference | getCommonClassOptions(Ty); + std::string FullName = getFullyQualifiedName(Ty); + TypeIndex FwdDeclTI = TypeTable.writeClass(ClassRecord( + Kind, 0, CO, HfaKind::None, WindowsRTClassKind::None, TypeIndex(), + TypeIndex(), TypeIndex(), 0, FullName, Ty->getIdentifier())); + if (!Ty->isForwardDecl()) + DeferredCompleteTypes.push_back(Ty); + return FwdDeclTI; +} + +TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) { + // Construct the field list and complete type record. + TypeRecordKind Kind = getRecordKind(Ty); + ClassOptions CO = getCommonClassOptions(Ty); + TypeIndex FieldTI; + TypeIndex VShapeTI; + unsigned FieldCount; + bool ContainsNestedClass; + std::tie(FieldTI, VShapeTI, FieldCount, ContainsNestedClass) = + lowerRecordFieldList(Ty); + + if (ContainsNestedClass) + CO |= ClassOptions::ContainsNestedClass; + + std::string FullName = getFullyQualifiedName(Ty); + + uint64_t SizeInBytes = Ty->getSizeInBits() / 8; + + TypeIndex ClassTI = TypeTable.writeClass(ClassRecord( + Kind, FieldCount, CO, HfaKind::None, WindowsRTClassKind::None, FieldTI, + TypeIndex(), VShapeTI, SizeInBytes, FullName, Ty->getIdentifier())); + + TypeTable.writeUdtSourceLine(UdtSourceLineRecord( + ClassTI, TypeTable.writeStringId(StringIdRecord( + TypeIndex(0x0), getFullFilepath(Ty->getFile()))), + Ty->getLine())); + + addToUDTs(Ty, ClassTI); + + return ClassTI; +} + +TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) { + ClassOptions CO = + ClassOptions::ForwardReference | getCommonClassOptions(Ty); + std::string FullName = getFullyQualifiedName(Ty); + TypeIndex FwdDeclTI = + TypeTable.writeUnion(UnionRecord(0, CO, HfaKind::None, TypeIndex(), 0, + FullName, Ty->getIdentifier())); + if (!Ty->isForwardDecl()) + DeferredCompleteTypes.push_back(Ty); + return FwdDeclTI; +} + +TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) { + ClassOptions CO = ClassOptions::Sealed | getCommonClassOptions(Ty); + TypeIndex FieldTI; + unsigned FieldCount; + bool ContainsNestedClass; + std::tie(FieldTI, std::ignore, FieldCount, ContainsNestedClass) = + lowerRecordFieldList(Ty); + + if (ContainsNestedClass) + CO |= ClassOptions::ContainsNestedClass; + + uint64_t SizeInBytes = Ty->getSizeInBits() / 8; + std::string FullName = getFullyQualifiedName(Ty); + + TypeIndex UnionTI = TypeTable.writeUnion( + UnionRecord(FieldCount, CO, HfaKind::None, FieldTI, SizeInBytes, FullName, + Ty->getIdentifier())); + + TypeTable.writeUdtSourceLine(UdtSourceLineRecord( + UnionTI, TypeTable.writeStringId(StringIdRecord( + TypeIndex(0x0), getFullFilepath(Ty->getFile()))), + Ty->getLine())); + + addToUDTs(Ty, UnionTI); + + return UnionTI; +} + +std::tuple<TypeIndex, TypeIndex, unsigned, bool> +CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { + // Manually count members. MSVC appears to count everything that generates a + // field list record. Each individual overload in a method overload group + // contributes to this count, even though the overload group is a single field + // list record. + unsigned MemberCount = 0; + ClassInfo Info = collectClassInfo(Ty); + FieldListRecordBuilder Fields; + + // Create base classes. + for (const DIDerivedType *I : Info.Inheritance) { + if (I->getFlags() & DINode::FlagVirtual) { + // Virtual base. + // FIXME: Emit VBPtrOffset when the frontend provides it. + unsigned VBPtrOffset = 0; + // FIXME: Despite the accessor name, the offset is really in bytes. + unsigned VBTableIndex = I->getOffsetInBits() / 4; + Fields.writeVirtualBaseClass(VirtualBaseClassRecord( + translateAccessFlags(Ty->getTag(), I->getFlags()), + getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset, + VBTableIndex)); + } else { + assert(I->getOffsetInBits() % 8 == 0 && + "bases must be on byte boundaries"); + Fields.writeBaseClass(BaseClassRecord( + translateAccessFlags(Ty->getTag(), I->getFlags()), + getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8)); + } + } + + // Create members. + for (ClassInfo::MemberInfo &MemberInfo : Info.Members) { + const DIDerivedType *Member = MemberInfo.MemberTypeNode; + TypeIndex MemberBaseType = getTypeIndex(Member->getBaseType()); + StringRef MemberName = Member->getName(); + MemberAccess Access = + translateAccessFlags(Ty->getTag(), Member->getFlags()); + + if (Member->isStaticMember()) { + Fields.writeStaticDataMember( + StaticDataMemberRecord(Access, MemberBaseType, MemberName)); + MemberCount++; + continue; + } + + // Data member. + uint64_t MemberOffsetInBits = + Member->getOffsetInBits() + MemberInfo.BaseOffset; + if (Member->isBitField()) { + uint64_t StartBitOffset = MemberOffsetInBits; + if (const auto *CI = + dyn_cast_or_null<ConstantInt>(Member->getStorageOffsetInBits())) { + MemberOffsetInBits = CI->getZExtValue() + MemberInfo.BaseOffset; + } + StartBitOffset -= MemberOffsetInBits; + MemberBaseType = TypeTable.writeBitField(BitFieldRecord( + MemberBaseType, Member->getSizeInBits(), StartBitOffset)); + } + uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8; + Fields.writeDataMember(DataMemberRecord(Access, MemberBaseType, + MemberOffsetInBytes, MemberName)); + MemberCount++; + } + + // Create methods + for (auto &MethodItr : Info.Methods) { + StringRef Name = MethodItr.first->getString(); + + std::vector<OneMethodRecord> Methods; + for (const DISubprogram *SP : MethodItr.second) { + TypeIndex MethodType = getMemberFunctionType(SP, Ty); + bool Introduced = SP->getFlags() & DINode::FlagIntroducedVirtual; + + unsigned VFTableOffset = -1; + if (Introduced) + VFTableOffset = SP->getVirtualIndex() * getPointerSizeInBytes(); + + Methods.push_back( + OneMethodRecord(MethodType, translateMethodKindFlags(SP, Introduced), + translateMethodOptionFlags(SP), + translateAccessFlags(Ty->getTag(), SP->getFlags()), + VFTableOffset, Name)); + MemberCount++; + } + assert(Methods.size() > 0 && "Empty methods map entry"); + if (Methods.size() == 1) + Fields.writeOneMethod(Methods[0]); + else { + TypeIndex MethodList = + TypeTable.writeMethodOverloadList(MethodOverloadListRecord(Methods)); + Fields.writeOverloadedMethod( + OverloadedMethodRecord(Methods.size(), MethodList, Name)); + } + } + + // Create nested classes. + for (const DICompositeType *Nested : Info.NestedClasses) { + NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName()); + Fields.writeNestedType(R); + MemberCount++; + } + + TypeIndex FieldTI = TypeTable.writeFieldList(Fields); + return std::make_tuple(FieldTI, TypeIndex(), MemberCount, + !Info.NestedClasses.empty()); +} + +TypeIndex CodeViewDebug::getVBPTypeIndex() { + if (!VBPType.getIndex()) { + // Make a 'const int *' type. + ModifierRecord MR(TypeIndex::Int32(), ModifierOptions::Const); + TypeIndex ModifiedTI = TypeTable.writeModifier(MR); + + PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64 + : PointerKind::Near32; + PointerMode PM = PointerMode::Pointer; + PointerOptions PO = PointerOptions::None; + PointerRecord PR(ModifiedTI, PK, PM, PO, getPointerSizeInBytes()); + + VBPType = TypeTable.writePointer(PR); + } + + return VBPType; +} + +TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef) { + const DIType *Ty = TypeRef.resolve(); + const DIType *ClassTy = ClassTyRef.resolve(); + + // The null DIType is the void type. Don't try to hash it. + if (!Ty) + return TypeIndex::Void(); + + // Check if we've already translated this type. Don't try to do a + // get-or-create style insertion that caches the hash lookup across the + // lowerType call. It will update the TypeIndices map. + auto I = TypeIndices.find({Ty, ClassTy}); + if (I != TypeIndices.end()) + return I->second; + + TypeLoweringScope S(*this); + TypeIndex TI = lowerType(Ty, ClassTy); + return recordTypeIndexForDINode(Ty, TI, ClassTy); +} + +TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { + const DIType *Ty = TypeRef.resolve(); + + // The null DIType is the void type. Don't try to hash it. + if (!Ty) + return TypeIndex::Void(); + + // If this is a non-record type, the complete type index is the same as the + // normal type index. Just call getTypeIndex. + switch (Ty->getTag()) { + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_union_type: + break; + default: + return getTypeIndex(Ty); + } + + // Check if we've already translated the complete record type. Lowering a + // complete type should never trigger lowering another complete type, so we + // can reuse the hash table lookup result. + const auto *CTy = cast<DICompositeType>(Ty); + auto InsertResult = CompleteTypeIndices.insert({CTy, TypeIndex()}); + if (!InsertResult.second) + return InsertResult.first->second; + + TypeLoweringScope S(*this); + + // Make sure the forward declaration is emitted first. It's unclear if this + // is necessary, but MSVC does it, and we should follow suit until we can show + // otherwise. + TypeIndex FwdDeclTI = getTypeIndex(CTy); + + // Just use the forward decl if we don't have complete type info. This might + // happen if the frontend is using modules and expects the complete definition + // to be emitted elsewhere. + if (CTy->isForwardDecl()) + return FwdDeclTI; + + TypeIndex TI; + switch (CTy->getTag()) { + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_structure_type: + TI = lowerCompleteTypeClass(CTy); + break; + case dwarf::DW_TAG_union_type: + TI = lowerCompleteTypeUnion(CTy); + break; + default: + llvm_unreachable("not a record"); + } + + InsertResult.first->second = TI; + return TI; +} + +/// Emit all the deferred complete record types. Try to do this in FIFO order, +/// and do this until fixpoint, as each complete record type typically +/// references +/// many other record types. +void CodeViewDebug::emitDeferredCompleteTypes() { + SmallVector<const DICompositeType *, 4> TypesToEmit; + while (!DeferredCompleteTypes.empty()) { + std::swap(DeferredCompleteTypes, TypesToEmit); + for (const DICompositeType *RecordTy : TypesToEmit) + getCompleteTypeIndex(RecordTy); + TypesToEmit.clear(); + } +} + +void CodeViewDebug::emitLocalVariableList(ArrayRef<LocalVariable> Locals) { + // Get the sorted list of parameters and emit them first. + SmallVector<const LocalVariable *, 6> Params; + for (const LocalVariable &L : Locals) + if (L.DIVar->isParameter()) + Params.push_back(&L); + std::sort(Params.begin(), Params.end(), + [](const LocalVariable *L, const LocalVariable *R) { + return L->DIVar->getArg() < R->DIVar->getArg(); + }); + for (const LocalVariable *L : Params) + emitLocalVariable(*L); + + // Next emit all non-parameters in the order that we found them. + for (const LocalVariable &L : Locals) + if (!L.DIVar->isParameter()) + emitLocalVariable(L); +} + +void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { + // LocalSym record, see SymbolRecord.h for more info. + MCSymbol *LocalBegin = MMI->getContext().createTempSymbol(), + *LocalEnd = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(LocalEnd, LocalBegin, 2); + OS.EmitLabel(LocalBegin); + + OS.AddComment("Record kind: S_LOCAL"); + OS.EmitIntValue(unsigned(SymbolKind::S_LOCAL), 2); + + LocalSymFlags Flags = LocalSymFlags::None; + if (Var.DIVar->isParameter()) + Flags |= LocalSymFlags::IsParameter; + if (Var.DefRanges.empty()) + Flags |= LocalSymFlags::IsOptimizedOut; + + OS.AddComment("TypeIndex"); + TypeIndex TI = getCompleteTypeIndex(Var.DIVar->getType()); + OS.EmitIntValue(TI.getIndex(), 4); + OS.AddComment("Flags"); + OS.EmitIntValue(static_cast<uint16_t>(Flags), 2); + // Truncate the name so we won't overflow the record length field. + emitNullTerminatedSymbolName(OS, Var.DIVar->getName()); + OS.EmitLabel(LocalEnd); + + // Calculate the on disk prefix of the appropriate def range record. The + // records and on disk formats are described in SymbolRecords.h. BytePrefix + // should be big enough to hold all forms without memory allocation. + SmallString<20> BytePrefix; + for (const LocalVarDefRange &DefRange : Var.DefRanges) { + BytePrefix.clear(); + // FIXME: Handle bitpieces. + if (DefRange.StructOffset != 0) + continue; + + if (DefRange.InMemory) { + DefRangeRegisterRelSym Sym(DefRange.CVRegister, 0, DefRange.DataOffset, 0, + 0, 0, ArrayRef<LocalVariableAddrGap>()); + ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL); + BytePrefix += + StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind)); + BytePrefix += + StringRef(reinterpret_cast<const char *>(&Sym.Header), + sizeof(Sym.Header) - sizeof(LocalVariableAddrRange)); + } else { + assert(DefRange.DataOffset == 0 && "unexpected offset into register"); + // Unclear what matters here. + DefRangeRegisterSym Sym(DefRange.CVRegister, 0, 0, 0, 0, + ArrayRef<LocalVariableAddrGap>()); + ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER); + BytePrefix += + StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind)); + BytePrefix += + StringRef(reinterpret_cast<const char *>(&Sym.Header), + sizeof(Sym.Header) - sizeof(LocalVariableAddrRange)); + } + OS.EmitCVDefRangeDirective(DefRange.Ranges, BytePrefix); + } +} + +void CodeViewDebug::endFunction(const MachineFunction *MF) { + if (!Asm || !CurFn) // We haven't created any debug info for this function. + return; + + const Function *GV = MF->getFunction(); + assert(FnDebugInfo.count(GV)); + assert(CurFn == &FnDebugInfo[GV]); + + collectVariableInfo(GV->getSubprogram()); + + DebugHandlerBase::endFunction(MF); + + // Don't emit anything if we don't have any line tables. + if (!CurFn->HaveLineInfo) { + FnDebugInfo.erase(GV); + CurFn = nullptr; + return; + } + + CurFn->End = Asm->getFunctionEnd(); + + CurFn = nullptr; +} + +void CodeViewDebug::beginInstruction(const MachineInstr *MI) { + DebugHandlerBase::beginInstruction(MI); + + // Ignore DBG_VALUE locations and function prologue. + if (!Asm || !CurFn || MI->isDebugValue() || + MI->getFlag(MachineInstr::FrameSetup)) + return; + DebugLoc DL = MI->getDebugLoc(); + if (DL == PrevInstLoc || !DL) + return; + maybeRecordLocation(DL, Asm->MF); +} + +MCSymbol *CodeViewDebug::beginCVSubsection(ModuleSubstreamKind Kind) { + MCSymbol *BeginLabel = MMI->getContext().createTempSymbol(), + *EndLabel = MMI->getContext().createTempSymbol(); + OS.EmitIntValue(unsigned(Kind), 4); + OS.AddComment("Subsection size"); + OS.emitAbsoluteSymbolDiff(EndLabel, BeginLabel, 4); + OS.EmitLabel(BeginLabel); + return EndLabel; +} + +void CodeViewDebug::endCVSubsection(MCSymbol *EndLabel) { + OS.EmitLabel(EndLabel); + // Every subsection must be aligned to a 4-byte boundary. + OS.EmitValueToAlignment(4); +} + +void CodeViewDebug::emitDebugInfoForUDTs( + ArrayRef<std::pair<std::string, TypeIndex>> UDTs) { + for (const std::pair<std::string, codeview::TypeIndex> &UDT : UDTs) { + MCSymbol *UDTRecordBegin = MMI->getContext().createTempSymbol(), + *UDTRecordEnd = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(UDTRecordEnd, UDTRecordBegin, 2); + OS.EmitLabel(UDTRecordBegin); + + OS.AddComment("Record kind: S_UDT"); + OS.EmitIntValue(unsigned(SymbolKind::S_UDT), 2); + + OS.AddComment("Type"); + OS.EmitIntValue(UDT.second.getIndex(), 4); + + emitNullTerminatedSymbolName(OS, UDT.first); + OS.EmitLabel(UDTRecordEnd); + } +} + +void CodeViewDebug::emitDebugInfoForGlobals() { + NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + for (const MDNode *Node : CUs->operands()) { + const auto *CU = cast<DICompileUnit>(Node); + + // 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); + MCSymbol *EndLabel = nullptr; + for (const DIGlobalVariable *G : CU->getGlobalVariables()) { + if (const auto *GV = dyn_cast_or_null<GlobalVariable>(G->getVariable())) { + if (!GV->hasComdat() && !GV->isDeclarationForLinker()) { + if (!EndLabel) { + OS.AddComment("Symbol subsection for globals"); + EndLabel = beginCVSubsection(ModuleSubstreamKind::Symbols); + } + emitDebugInfoForGlobal(G, Asm->getSymbol(GV)); + } + } + } + if (EndLabel) + endCVSubsection(EndLabel); + + // Second, emit each global that is in a comdat into its own .debug$S + // section along with its own symbol substream. + for (const DIGlobalVariable *G : CU->getGlobalVariables()) { + if (const auto *GV = dyn_cast_or_null<GlobalVariable>(G->getVariable())) { + if (GV->hasComdat()) { + MCSymbol *GVSym = Asm->getSymbol(GV); + OS.AddComment("Symbol subsection for " + + Twine(GlobalValue::getRealLinkageName(GV->getName()))); + switchToDebugSectionForSymbol(GVSym); + EndLabel = beginCVSubsection(ModuleSubstreamKind::Symbols); + emitDebugInfoForGlobal(G, GVSym); + endCVSubsection(EndLabel); + } + } + } + } +} + +void CodeViewDebug::emitDebugInfoForRetainedTypes() { + NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + for (const MDNode *Node : CUs->operands()) { + for (auto *Ty : cast<DICompileUnit>(Node)->getRetainedTypes()) { + if (DIType *RT = dyn_cast<DIType>(Ty)) { + getTypeIndex(RT); + // FIXME: Add to global/local DTU list. + } + } + } +} + +void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, + MCSymbol *GVSym) { + // DataSym record, see SymbolRecord.h for more info. + // FIXME: Thread local data, etc + MCSymbol *DataBegin = MMI->getContext().createTempSymbol(), + *DataEnd = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(DataEnd, DataBegin, 2); + OS.EmitLabel(DataBegin); + const auto *GV = cast<GlobalVariable>(DIGV->getVariable()); + if (DIGV->isLocalToUnit()) { + if (GV->isThreadLocal()) { + OS.AddComment("Record kind: S_LTHREAD32"); + OS.EmitIntValue(unsigned(SymbolKind::S_LTHREAD32), 2); + } else { + OS.AddComment("Record kind: S_LDATA32"); + OS.EmitIntValue(unsigned(SymbolKind::S_LDATA32), 2); + } + } else { + if (GV->isThreadLocal()) { + OS.AddComment("Record kind: S_GTHREAD32"); + OS.EmitIntValue(unsigned(SymbolKind::S_GTHREAD32), 2); + } else { + OS.AddComment("Record kind: S_GDATA32"); + OS.EmitIntValue(unsigned(SymbolKind::S_GDATA32), 2); + } + } + OS.AddComment("Type"); + OS.EmitIntValue(getCompleteTypeIndex(DIGV->getType()).getIndex(), 4); + OS.AddComment("DataOffset"); + OS.EmitCOFFSecRel32(GVSym); + OS.AddComment("Segment"); + OS.EmitCOFFSectionIndex(GVSym); + OS.AddComment("Name"); + emitNullTerminatedSymbolName(OS, DIGV->getName()); + OS.EmitLabel(DataEnd); +} diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h new file mode 100644 index 0000000..e4bbd61 --- /dev/null +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -0,0 +1,310 @@ +//===-- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing Microsoft CodeView debug info. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H + +#include "DebugHandlerBase.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Target/TargetLoweringObjectFile.h" + +namespace llvm { + +class StringRef; +class LexicalScope; +struct ClassInfo; + +/// \brief Collects and handles line tables information in a CodeView format. +class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { + MCStreamer &OS; + codeview::MemoryTypeTableBuilder TypeTable; + + /// Represents the most general definition range. + struct LocalVarDefRange { + /// Indicates that variable data is stored in memory relative to the + /// specified register. + int InMemory : 1; + + /// Offset of variable data in memory. + int DataOffset : 31; + + /// Offset of the data into the user level struct. If zero, no splitting + /// occurred. + uint16_t StructOffset; + + /// Register containing the data or the register base of the memory + /// location containing the data. + uint16_t CVRegister; + + /// Compares all location fields. This includes all fields except the label + /// ranges. + bool isDifferentLocation(LocalVarDefRange &O) { + return InMemory != O.InMemory || DataOffset != O.DataOffset || + StructOffset != O.StructOffset || CVRegister != O.CVRegister; + } + + SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 1> Ranges; + }; + + static LocalVarDefRange createDefRangeMem(uint16_t CVRegister, int Offset); + static LocalVarDefRange createDefRangeReg(uint16_t CVRegister); + + /// Similar to DbgVariable in DwarfDebug, but not dwarf-specific. + struct LocalVariable { + const DILocalVariable *DIVar = nullptr; + SmallVector<LocalVarDefRange, 1> DefRanges; + }; + + struct InlineSite { + SmallVector<LocalVariable, 1> InlinedLocals; + SmallVector<const DILocation *, 1> ChildSites; + const DISubprogram *Inlinee = nullptr; + + /// The ID of the inline site or function used with .cv_loc. Not a type + /// index. + unsigned SiteFuncId = 0; + }; + + // For each function, store a vector of labels to its instructions, as well as + // to the end of the function. + struct FunctionInfo { + /// Map from inlined call site to inlined instructions and child inlined + /// call sites. Listed in program order. + std::unordered_map<const DILocation *, InlineSite> InlineSites; + + /// Ordered list of top-level inlined call sites. + SmallVector<const DILocation *, 1> ChildSites; + + SmallVector<LocalVariable, 1> Locals; + + DebugLoc LastLoc; + const MCSymbol *Begin = nullptr; + const MCSymbol *End = nullptr; + unsigned FuncId = 0; + unsigned LastFileId = 0; + bool HaveLineInfo = false; + }; + FunctionInfo *CurFn; + + /// 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. + DenseSet<MCSectionCOFF *> ComdatDebugSections; + + /// Switch to the appropriate .debug$S section for GVSym. If GVSym, the symbol + /// of an emitted global value, is in a comdat COFF section, this will switch + /// to a new .debug$S section in that comdat. This method ensures that the + /// section starts with the magic version number on first use. If GVSym is + /// null, uses the main .debug$S section. + void switchToDebugSectionForSymbol(const MCSymbol *GVSym); + + /// The next available function index for use with our .cv_* directives. Not + /// to be confused with type indices for LF_FUNC_ID records. + unsigned NextFuncId = 0; + + InlineSite &getInlineSite(const DILocation *InlinedAt, + const DISubprogram *Inlinee); + + codeview::TypeIndex getFuncIdForSubprogram(const DISubprogram *SP); + + 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 *, FunctionInfo> FnDebugInfo; + + /// Map from DIFile to .cv_file id. + DenseMap<const DIFile *, unsigned> FileIdMap; + + /// All inlined subprograms in the order they should be emitted. + SmallSetVector<const DISubprogram *, 4> InlinedSubprograms; + + /// Map from a pair of DI metadata nodes and its DI type (or scope) that can + /// be nullptr, to CodeView type indices. Primarily indexed by + /// {DIType*, DIType*} and {DISubprogram*, DIType*}. + /// + /// The second entry in the key is needed for methods as DISubroutineType + /// representing static method type are shared with non-method function type. + DenseMap<std::pair<const DINode *, const DIType *>, codeview::TypeIndex> + TypeIndices; + + /// Map from DICompositeType* to complete type index. Non-record types are + /// always looked up in the normal TypeIndices map. + DenseMap<const DICompositeType *, codeview::TypeIndex> CompleteTypeIndices; + + /// Complete record types to emit after all active type lowerings are + /// finished. + SmallVector<const DICompositeType *, 4> DeferredCompleteTypes; + + /// Number of type lowering frames active on the stack. + unsigned TypeEmissionLevel = 0; + + codeview::TypeIndex VBPType; + + const DISubprogram *CurrentSubprogram = nullptr; + + // The UDTs we have seen while processing types; each entry is a pair of type + // index and type name. + std::vector<std::pair<std::string, codeview::TypeIndex>> LocalUDTs, + GlobalUDTs; + + typedef std::map<const DIFile *, std::string> FileToFilepathMapTy; + FileToFilepathMapTy FileToFilepathMap; + StringRef getFullFilepath(const DIFile *S); + + unsigned maybeRecordFile(const DIFile *F); + + void maybeRecordLocation(const DebugLoc &DL, const MachineFunction *MF); + + void clear(); + + void setCurrentSubprogram(const DISubprogram *SP) { + CurrentSubprogram = SP; + LocalUDTs.clear(); + } + + /// Emit the magic version number at the start of a CodeView type or symbol + /// section. Appears at the front of every .debug$S or .debug$T section. + void emitCodeViewMagicVersion(); + + void emitTypeInformation(); + + void emitInlineeLinesSubsection(); + + void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI); + + void emitDebugInfoForGlobals(); + + void emitDebugInfoForRetainedTypes(); + + void emitDebugInfoForUDTs( + ArrayRef<std::pair<std::string, codeview::TypeIndex>> UDTs); + + void emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, MCSymbol *GVSym); + + /// 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 + /// finished. + MCSymbol *beginCVSubsection(codeview::ModuleSubstreamKind Kind); + + void endCVSubsection(MCSymbol *EndLabel); + + void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, + const InlineSite &Site); + + typedef DbgValueHistoryMap::InlinedVariable InlinedVariable; + + void collectVariableInfo(const DISubprogram *SP); + + void collectVariableInfoFromMMITable(DenseSet<InlinedVariable> &Processed); + + /// Records information about a local variable in the appropriate scope. In + /// particular, locals from inlined code live inside the inlining site. + void recordLocalVariable(LocalVariable &&Var, const DILocation *Loc); + + /// Emits local variables in the appropriate order. + void emitLocalVariableList(ArrayRef<LocalVariable> Locals); + + /// Emits an S_LOCAL record and its associated defined ranges. + void emitLocalVariable(const LocalVariable &Var); + + /// Translates the DIType to codeview if necessary and returns a type index + /// for it. + codeview::TypeIndex getTypeIndex(DITypeRef TypeRef, + DITypeRef ClassTyRef = DITypeRef()); + + codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP, + const DICompositeType *Class); + + codeview::TypeIndex getScopeIndex(const DIScope *Scope); + + codeview::TypeIndex getVBPTypeIndex(); + + void addToUDTs(const DIType *Ty, codeview::TypeIndex TI); + + codeview::TypeIndex lowerType(const DIType *Ty, const DIType *ClassTy); + codeview::TypeIndex lowerTypeAlias(const DIDerivedType *Ty); + codeview::TypeIndex lowerTypeArray(const DICompositeType *Ty); + codeview::TypeIndex lowerTypeBasic(const DIBasicType *Ty); + codeview::TypeIndex lowerTypePointer(const DIDerivedType *Ty); + codeview::TypeIndex lowerTypeMemberPointer(const DIDerivedType *Ty); + codeview::TypeIndex lowerTypeModifier(const DIDerivedType *Ty); + codeview::TypeIndex lowerTypeFunction(const DISubroutineType *Ty); + codeview::TypeIndex lowerTypeMemberFunction(const DISubroutineType *Ty, + const DIType *ClassTy, + int ThisAdjustment); + codeview::TypeIndex lowerTypeEnum(const DICompositeType *Ty); + codeview::TypeIndex lowerTypeClass(const DICompositeType *Ty); + codeview::TypeIndex lowerTypeUnion(const DICompositeType *Ty); + + /// Symbol records should point to complete types, but type records should + /// always point to incomplete types to avoid cycles in the type graph. Only + /// use this entry point when generating symbol records. The complete and + /// incomplete type indices only differ for record types. All other types use + /// the same index. + codeview::TypeIndex getCompleteTypeIndex(DITypeRef TypeRef); + + codeview::TypeIndex lowerCompleteTypeClass(const DICompositeType *Ty); + codeview::TypeIndex lowerCompleteTypeUnion(const DICompositeType *Ty); + + struct TypeLoweringScope; + + void emitDeferredCompleteTypes(); + + void collectMemberInfo(ClassInfo &Info, const DIDerivedType *DDTy); + ClassInfo collectClassInfo(const DICompositeType *Ty); + + /// Common record member lowering functionality for record types, which are + /// structs, classes, and unions. Returns the field list index and the member + /// count. + std::tuple<codeview::TypeIndex, codeview::TypeIndex, unsigned, bool> + lowerRecordFieldList(const DICompositeType *Ty); + + /// Inserts {{Node, ClassTy}, TI} into TypeIndices and checks for duplicates. + codeview::TypeIndex recordTypeIndexForDINode(const DINode *Node, + codeview::TypeIndex TI, + const DIType *ClassTy = nullptr); + + unsigned getPointerSizeInBytes(); + +public: + CodeViewDebug(AsmPrinter *Asm); + + void setSymbolSize(const llvm::MCSymbol *, uint64_t) override {} + + /// \brief Emit the COFF section that holds the line table information. + void endModule() override; + + /// \brief Gather pre-function debug information. + void beginFunction(const MachineFunction *MF) override; + + /// \brief Gather post-function debug information. + void endFunction(const MachineFunction *) override; + + /// \brief Process beginning of an instruction. + void beginInstruction(const MachineInstr *MI) override; +}; +} // End of namespace llvm + +#endif diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DIE.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DIE.cpp index 7b0cdbd..2aaa85a 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DIE.cpp @@ -32,39 +32,6 @@ using namespace llvm; //===----------------------------------------------------------------------===// -// EmittingAsmStreamer Implementation -//===----------------------------------------------------------------------===// -unsigned EmittingAsmStreamer::emitULEB128(uint64_t Value, const char *Desc, - unsigned PadTo) { - AP->EmitULEB128(Value, Desc, PadTo); - return 0; -} - -unsigned EmittingAsmStreamer::emitInt8(unsigned char Value) { - AP->EmitInt8(Value); - return 0; -} - -unsigned EmittingAsmStreamer::emitBytes(StringRef Data) { - AP->OutStreamer->EmitBytes(Data); - return 0; -} - -//===----------------------------------------------------------------------===// -// SizeReporterAsmStreamer Implementation -//===----------------------------------------------------------------------===// -unsigned SizeReporterAsmStreamer::emitULEB128(uint64_t Value, const char *Desc, - unsigned PadTo) { - return getULEB128Size(Value); -} - -unsigned SizeReporterAsmStreamer::emitInt8(unsigned char Value) { return 1; } - -unsigned SizeReporterAsmStreamer::emitBytes(StringRef Data) { - return Data.size(); -} - -//===----------------------------------------------------------------------===// // DIEAbbrevData Implementation //===----------------------------------------------------------------------===// @@ -512,20 +479,6 @@ void DIEEntry::print(raw_ostream &O) const { } //===----------------------------------------------------------------------===// -// DIETypeSignature Implementation -//===----------------------------------------------------------------------===// -void DIETypeSignature::EmitValue(const AsmPrinter *Asm, - dwarf::Form Form) const { - assert(Form == dwarf::DW_FORM_ref_sig8); - Asm->OutStreamer->EmitIntValue(Unit->getTypeSignature(), 8); -} - -LLVM_DUMP_METHOD -void DIETypeSignature::print(raw_ostream &O) const { - O << format("Type Unit: 0x%lx", Unit->getTypeSignature()); -} - -//===----------------------------------------------------------------------===// // DIELoc Implementation //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp index 0201065..74c47d1 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -279,7 +279,7 @@ void DIEHash::hashLocList(const DIELocList &LocList) { // Hash an individual attribute \param Attr based on the type of attribute and // the form. -void DIEHash::hashAttribute(DIEValue Value, dwarf::Tag Tag) { +void DIEHash::hashAttribute(const DIEValue &Value, dwarf::Tag Tag) { dwarf::Attribute Attribute = Value.getAttribute(); // Other attribute values use the letter 'A' as the marker, and the value @@ -353,7 +353,6 @@ void DIEHash::hashAttribute(DIEValue Value, dwarf::Tag Tag) { case DIEValue::isExpr: case DIEValue::isLabel: case DIEValue::isDelta: - case DIEValue::isTypeSignature: llvm_unreachable("Add support for additional value types."); } } diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DIEHash.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DIEHash.h index 44f0ce8..996cd7e 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DIEHash.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DIEHash.h @@ -131,7 +131,7 @@ private: void hashLocList(const DIELocList &LocList); /// \brief Hashes an individual attribute. - void hashAttribute(DIEValue Value, dwarf::Tag Tag); + void hashAttribute(const DIEValue &Value, dwarf::Tag Tag); /// \brief Hashes an attribute that refers to another DIE. void hashDIEEntry(dwarf::Attribute Attribute, dwarf::Tag Tag, diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp index 3c46a99..adc536f 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -15,7 +15,9 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" #include <algorithm> #include <map> using namespace llvm; @@ -40,7 +42,7 @@ void DbgValueHistoryMap::startInstrRange(InlinedVariable Var, assert(MI.isDebugValue() && "not a DBG_VALUE"); auto &Ranges = VarInstrRanges[Var]; if (!Ranges.empty() && Ranges.back().second == nullptr && - Ranges.back().first->isIdenticalTo(&MI)) { + Ranges.back().first->isIdenticalTo(MI)) { DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" << "\t" << Ranges.back().first << "\t" << MI << "\n"); return; @@ -122,26 +124,6 @@ static void clobberRegisterUses(RegDescribedVarsMap &RegVars, unsigned RegNo, clobberRegisterUses(RegVars, I, HistMap, ClobberingInstr); } -// \brief Collect all registers clobbered by @MI and apply the functor -// @Func to their RegNo. -// @Func should be a functor with a void(unsigned) signature. We're -// not using std::function here for performance reasons. It has a -// small but measurable impact. By using a functor instead of a -// std::set& here, we can avoid the overhead of constructing -// temporaries in calculateDbgValueHistory, which has a significant -// performance impact. -template<typename Callable> -static void applyToClobberedRegisters(const MachineInstr &MI, - const TargetRegisterInfo *TRI, - Callable Func) { - for (const MachineOperand &MO : MI.operands()) { - if (!MO.isReg() || !MO.isDef() || !MO.getReg()) - continue; - for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); ++AI) - Func(*AI); - } -} - // \brief Returns the first instruction in @MBB which corresponds to // the function epilogue, or nullptr if @MBB doesn't contain an epilogue. static const MachineInstr *getFirstEpilogueInst(const MachineBasicBlock &MBB) { @@ -156,12 +138,12 @@ static const MachineInstr *getFirstEpilogueInst(const MachineBasicBlock &MBB) { E = MBB.rend(); I != E; ++I) { if (I->getDebugLoc() != LastLoc) - return Res; + return &*Res; Res = &*I; } // If all instructions have the same debug location, assume whole MBB is // an epilogue. - return MBB.begin(); + return &*MBB.begin(); } // \brief Collect registers that are modified in the function body (their @@ -173,10 +155,23 @@ static void collectChangingRegs(const MachineFunction *MF, auto FirstEpilogueInst = getFirstEpilogueInst(MBB); for (const auto &MI : MBB) { + // Avoid looking at prologue or epilogue instructions. if (&MI == FirstEpilogueInst) break; - if (!MI.getFlag(MachineInstr::FrameSetup)) - applyToClobberedRegisters(MI, TRI, [&](unsigned r) { Regs.set(r); }); + if (MI.getFlag(MachineInstr::FrameSetup)) + continue; + + // Look for register defs and register masks. Register masks are + // typically on calls and they clobber everything not in the mask. + for (const MachineOperand &MO : MI.operands()) { + if (MO.isReg() && MO.isDef() && MO.getReg()) { + for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); + ++AI) + Regs.set(*AI); + } else if (MO.isRegMask()) { + Regs.setBitsNotInMask(MO.getRegMask()); + } + } } } } @@ -187,16 +182,35 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF, BitVector ChangingRegs(TRI->getNumRegs()); collectChangingRegs(MF, TRI, ChangingRegs); + const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); + unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); RegDescribedVarsMap RegVars; for (const auto &MBB : *MF) { for (const auto &MI : MBB) { if (!MI.isDebugValue()) { // Not a DBG_VALUE instruction. It may clobber registers which describe // some variables. - applyToClobberedRegisters(MI, TRI, [&](unsigned RegNo) { - if (ChangingRegs.test(RegNo)) - clobberRegisterUses(RegVars, RegNo, Result, MI); - }); + for (const MachineOperand &MO : MI.operands()) { + if (MO.isReg() && MO.isDef() && MO.getReg()) { + // If this is a register def operand, it may end a debug value + // range. + for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); + ++AI) + if (ChangingRegs.test(*AI)) + clobberRegisterUses(RegVars, *AI, Result, MI); + } else if (MO.isRegMask()) { + // If this is a register mask operand, clobber all debug values in + // non-CSRs. + for (int I = ChangingRegs.find_first(); I != -1; + I = ChangingRegs.find_next(I)) { + // Don't consider SP to be clobbered by register masks. + if (unsigned(I) != SP && TRI->isPhysicalRegister(I) && + MO.clobbersPhysReg(I)) { + clobberRegisterUses(RegVars, I, Result, MI); + } + } + } + } continue; } diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h index 546d1b4..16d2d7f 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h @@ -12,13 +12,12 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/DebugInfoMetadata.h" namespace llvm { class MachineFunction; class MachineInstr; -class DILocalVariable; -class DILocation; class TargetRegisterInfo; // For each user variable, keep a list of instruction ranges where this variable diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp new file mode 100644 index 0000000..16ffe2e --- /dev/null +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -0,0 +1,230 @@ +//===-- llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp -------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Common functionality for different debug information format backends. +// LLVM currently supports DWARF and CodeView. +// +//===----------------------------------------------------------------------===// + +#include "DebugHandlerBase.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +using namespace llvm; + +DebugHandlerBase::DebugHandlerBase(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {} + +// 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 +// end) multiple scopes. Ignore scopes that are not reachable. +void DebugHandlerBase::identifyScopeMarkers() { + SmallVector<LexicalScope *, 4> WorkList; + WorkList.push_back(LScopes.getCurrentFunctionScope()); + while (!WorkList.empty()) { + LexicalScope *S = WorkList.pop_back_val(); + + const SmallVectorImpl<LexicalScope *> &Children = S->getChildren(); + if (!Children.empty()) + WorkList.append(Children.begin(), Children.end()); + + if (S->isAbstractScope()) + continue; + + for (const InsnRange &R : S->getRanges()) { + assert(R.first && "InsnRange does not have first instruction!"); + assert(R.second && "InsnRange does not have second instruction!"); + requestLabelBeforeInsn(R.first); + requestLabelAfterInsn(R.second); + } + } +} + +// Return Label preceding the instruction. +MCSymbol *DebugHandlerBase::getLabelBeforeInsn(const MachineInstr *MI) { + MCSymbol *Label = LabelsBeforeInsn.lookup(MI); + assert(Label && "Didn't insert label before instruction"); + return Label; +} + +// Return Label immediately following the instruction. +MCSymbol *DebugHandlerBase::getLabelAfterInsn(const MachineInstr *MI) { + return LabelsAfterInsn.lookup(MI); +} + +// Determine the relative position of the pieces described by P1 and P2. +// Returns -1 if P1 is entirely before P2, 0 if P1 and P2 overlap, +// 1 if P1 is entirely after P2. +int DebugHandlerBase::pieceCmp(const DIExpression *P1, const DIExpression *P2) { + unsigned l1 = P1->getBitPieceOffset(); + unsigned l2 = P2->getBitPieceOffset(); + unsigned r1 = l1 + P1->getBitPieceSize(); + unsigned r2 = l2 + P2->getBitPieceSize(); + if (r1 <= l2) + return -1; + else if (r2 <= l1) + return 1; + else + return 0; +} + +/// Determine whether two variable pieces overlap. +bool DebugHandlerBase::piecesOverlap(const DIExpression *P1, const DIExpression *P2) { + if (!P1->isBitPiece() || !P2->isBitPiece()) + return true; + return pieceCmp(P1, P2) == 0; +} + +/// If this type is derived from a base type then return base type size. +uint64_t DebugHandlerBase::getBaseTypeSize(const DITypeRef TyRef) { + DIType *Ty = TyRef.resolve(); + assert(Ty); + DIDerivedType *DDTy = dyn_cast<DIDerivedType>(Ty); + if (!DDTy) + return Ty->getSizeInBits(); + + unsigned Tag = DDTy->getTag(); + + if (Tag != dwarf::DW_TAG_member && Tag != dwarf::DW_TAG_typedef && + Tag != dwarf::DW_TAG_const_type && Tag != dwarf::DW_TAG_volatile_type && + Tag != dwarf::DW_TAG_restrict_type) + return DDTy->getSizeInBits(); + + DIType *BaseType = DDTy->getBaseType().resolve(); + + assert(BaseType && "Unexpected invalid base type"); + + // If this is a derived type, go ahead and get the base type, unless it's a + // reference then it's just the size of the field. Pointer types have no need + // of this since they're a different type of qualification on the type. + if (BaseType->getTag() == dwarf::DW_TAG_reference_type || + BaseType->getTag() == dwarf::DW_TAG_rvalue_reference_type) + return Ty->getSizeInBits(); + + return getBaseTypeSize(BaseType); +} + +void DebugHandlerBase::beginFunction(const MachineFunction *MF) { + // Grab the lexical scopes for the function, if we don't have any of those + // then we're not going to be able to do anything. + LScopes.initialize(*MF); + if (LScopes.empty()) + return; + + // Make sure that each lexical scope will have a begin/end label. + identifyScopeMarkers(); + + // Calculate history for local variables. + assert(DbgValues.empty() && "DbgValues map wasn't cleaned!"); + calculateDbgValueHistory(MF, Asm->MF->getSubtarget().getRegisterInfo(), + DbgValues); + + // Request labels for the full history. + for (const auto &I : DbgValues) { + const auto &Ranges = I.second; + if (Ranges.empty()) + continue; + + // The first mention of a function argument gets the CurrentFnBegin + // label, so arguments are visible when breaking at function entry. + const DILocalVariable *DIVar = Ranges.front().first->getDebugVariable(); + if (DIVar->isParameter() && + getDISubprogram(DIVar->getScope())->describes(MF->getFunction())) { + LabelsBeforeInsn[Ranges.front().first] = Asm->getFunctionBegin(); + if (Ranges.front().first->getDebugExpression()->isBitPiece()) { + // Mark all non-overlapping initial pieces. + for (auto I = Ranges.begin(); I != Ranges.end(); ++I) { + const DIExpression *Piece = I->first->getDebugExpression(); + if (std::all_of(Ranges.begin(), I, + [&](DbgValueHistoryMap::InstrRange Pred) { + return !piecesOverlap(Piece, Pred.first->getDebugExpression()); + })) + LabelsBeforeInsn[I->first] = Asm->getFunctionBegin(); + else + break; + } + } + } + + for (const auto &Range : Ranges) { + requestLabelBeforeInsn(Range.first); + if (Range.second) + requestLabelAfterInsn(Range.second); + } + } + + PrevInstLoc = DebugLoc(); + PrevLabel = Asm->getFunctionBegin(); +} + +void DebugHandlerBase::beginInstruction(const MachineInstr *MI) { + if (!MMI->hasDebugInfo()) + return; + + assert(CurMI == nullptr); + CurMI = MI; + + // Insert labels where requested. + DenseMap<const MachineInstr *, MCSymbol *>::iterator I = + LabelsBeforeInsn.find(MI); + + // No label needed. + if (I == LabelsBeforeInsn.end()) + return; + + // Label already assigned. + if (I->second) + return; + + if (!PrevLabel) { + PrevLabel = MMI->getContext().createTempSymbol(); + Asm->OutStreamer->EmitLabel(PrevLabel); + } + I->second = PrevLabel; +} + +void DebugHandlerBase::endInstruction() { + if (!MMI->hasDebugInfo()) + return; + + assert(CurMI != nullptr); + // Don't create a new label after DBG_VALUE instructions. + // They don't generate code. + if (!CurMI->isDebugValue()) + PrevLabel = nullptr; + + DenseMap<const MachineInstr *, MCSymbol *>::iterator I = + LabelsAfterInsn.find(CurMI); + CurMI = nullptr; + + // No label needed. + if (I == LabelsAfterInsn.end()) + return; + + // Label already assigned. + if (I->second) + return; + + // We need a label after this instruction. + if (!PrevLabel) { + PrevLabel = MMI->getContext().createTempSymbol(); + Asm->OutStreamer->EmitLabel(PrevLabel); + } + I->second = PrevLabel; +} + +void DebugHandlerBase::endFunction(const MachineFunction *MF) { + DbgValues.clear(); + LabelsBeforeInsn.clear(); + LabelsAfterInsn.clear(); +} diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h new file mode 100644 index 0000000..b8bbcec --- /dev/null +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h @@ -0,0 +1,109 @@ +//===-- llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h --------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Common functionality for different debug information format backends. +// LLVM currently supports DWARF and CodeView. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGHANDLERBASE_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGHANDLERBASE_H + +#include "AsmPrinterHandler.h" +#include "DbgValueHistoryCalculator.h" +#include "llvm/CodeGen/LexicalScopes.h" +#include "llvm/CodeGen/MachineInstr.h" + +namespace llvm { + +class AsmPrinter; +class MachineModuleInfo; + +/// Base class for debug information backends. Common functionality related to +/// tracking which variables and scopes are alive at a given PC live here. +class DebugHandlerBase : public AsmPrinterHandler { +protected: + DebugHandlerBase(AsmPrinter *A); + + /// Target of debug info emission. + AsmPrinter *Asm; + + /// Collected machine module information. + MachineModuleInfo *MMI; + + /// Previous instruction's location information. This is used to + /// determine label location to indicate scope boundries in dwarf + /// debug info. + DebugLoc PrevInstLoc; + MCSymbol *PrevLabel = nullptr; + + /// This location indicates end of function prologue and beginning of + /// function body. + DebugLoc PrologEndLoc; + + /// If nonnull, stores the current machine instruction we're processing. + const MachineInstr *CurMI = nullptr; + + LexicalScopes LScopes; + + /// History of DBG_VALUE and clobber instructions for each user + /// variable. Variables are listed in order of appearance. + DbgValueHistoryMap DbgValues; + + /// Maps instruction with label emitted before instruction. + /// FIXME: Make this private from DwarfDebug, we have the necessary accessors + /// for it. + DenseMap<const MachineInstr *, MCSymbol *> LabelsBeforeInsn; + + /// Maps instruction with label emitted after instruction. + DenseMap<const MachineInstr *, MCSymbol *> LabelsAfterInsn; + + /// Indentify instructions that are marking the beginning of or + /// ending of a scope. + void identifyScopeMarkers(); + + /// Ensure that a label will be emitted before MI. + void requestLabelBeforeInsn(const MachineInstr *MI) { + LabelsBeforeInsn.insert(std::make_pair(MI, nullptr)); + } + + /// Ensure that a label will be emitted after MI. + void requestLabelAfterInsn(const MachineInstr *MI) { + LabelsAfterInsn.insert(std::make_pair(MI, nullptr)); + } + + // AsmPrinterHandler overrides. +public: + void beginInstruction(const MachineInstr *MI) override; + void endInstruction() override; + + void beginFunction(const MachineFunction *MF) override; + void endFunction(const MachineFunction *MF) override; + + /// Return Label preceding the instruction. + MCSymbol *getLabelBeforeInsn(const MachineInstr *MI); + + /// Return Label immediately following the instruction. + MCSymbol *getLabelAfterInsn(const MachineInstr *MI); + + /// Determine the relative position of the pieces described by P1 and P2. + /// Returns -1 if P1 is entirely before P2, 0 if P1 and P2 overlap, + /// 1 if P1 is entirely after P2. + static int pieceCmp(const DIExpression *P1, const DIExpression *P2); + + /// Determine whether two variable pieces overlap. + static bool piecesOverlap(const DIExpression *P1, const DIExpression *P2); + + /// If this type is derived from a base type then return base type size. + static uint64_t getBaseTypeSize(const DITypeRef TyRef); +}; + +} + +#endif diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h index b60ab91..20acd45 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -11,11 +11,11 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H #include "DebugLocStream.h" -#include "llvm/ADT/SmallString.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MachineLocation.h" +#include "llvm/Support/Debug.h" namespace llvm { class AsmPrinter; @@ -76,6 +76,20 @@ public: const DIExpression *getExpression() const { return Expression; } friend bool operator==(const Value &, const Value &); friend bool operator<(const Value &, const Value &); + void dump() const { + if (isLocation()) { + llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " "; + if (Loc.isIndirect()) + llvm::dbgs() << '+' << Loc.getOffset(); + llvm::dbgs() << "} "; + } + else if (isConstantInt()) + Constant.CIP->dump(); + else if (isConstantFP()) + Constant.CFP->dump(); + if (Expression) + Expression->dump(); + } }; private: diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp index 6665c16..2eae1b2 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "DwarfException.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" @@ -43,8 +42,7 @@ DwarfCFIExceptionBase::DwarfCFIExceptionBase(AsmPrinter *A) : EHStreamer(A), shouldEmitCFI(false) {} void DwarfCFIExceptionBase::markFunctionEnd() { - if (shouldEmitCFI) - Asm->OutStreamer->EmitCFIEndProc(); + endFragment(); if (MMI->getLandingPads().empty()) return; @@ -53,23 +51,28 @@ void DwarfCFIExceptionBase::markFunctionEnd() { MMI->TidyLandingPads(); } +void DwarfCFIExceptionBase::endFragment() { + if (shouldEmitCFI) + Asm->OutStreamer->EmitCFIEndProc(); +} + DwarfCFIException::DwarfCFIException(AsmPrinter *A) : DwarfCFIExceptionBase(A), shouldEmitPersonality(false), - shouldEmitLSDA(false), shouldEmitMoves(false), - moveTypeModule(AsmPrinter::CFI_M_None) {} + forceEmitPersonality(false), shouldEmitLSDA(false), + shouldEmitMoves(false), moveTypeModule(AsmPrinter::CFI_M_None) {} DwarfCFIException::~DwarfCFIException() {} /// endModule - Emit all exception information that should come after the /// content. void DwarfCFIException::endModule() { - if (moveTypeModule == AsmPrinter::CFI_M_Debug) - Asm->OutStreamer->EmitCFISections(false, true); - // SjLj uses this pass and it doesn't need this info. if (!Asm->MAI->usesCFIForEH()) return; + if (moveTypeModule == AsmPrinter::CFI_M_Debug) + Asm->OutStreamer->EmitCFISections(false, true); + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); unsigned PerEncoding = TLOF.getPersonalityEncoding(); @@ -86,6 +89,10 @@ void DwarfCFIException::endModule() { } } +static MCSymbol *getExceptionSym(AsmPrinter *Asm) { + return Asm->getCurExceptionSym(); +} + void DwarfCFIException::beginFunction(const MachineFunction *MF) { shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false; const Function *F = MF->getFunction(); @@ -109,7 +116,7 @@ void DwarfCFIException::beginFunction(const MachineFunction *MF) { Per = dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); // Emit a personality function even when there are no landing pads - bool forceEmitPersonality = + forceEmitPersonality = // ...if a personality function is explicitly specified F->hasPersonalityFn() && // ... and it's not known to be a noop in the absence of invokes @@ -126,7 +133,13 @@ void DwarfCFIException::beginFunction(const MachineFunction *MF) { shouldEmitLSDA = shouldEmitPersonality && LSDAEncoding != dwarf::DW_EH_PE_omit; - shouldEmitCFI = shouldEmitPersonality || shouldEmitMoves; + shouldEmitCFI = MF->getMMI().getContext().getAsmInfo()->usesCFIForEH() && + (shouldEmitPersonality || shouldEmitMoves); + beginFragment(&*MF->begin(), getExceptionSym); +} + +void DwarfCFIException::beginFragment(const MachineBasicBlock *MBB, + ExceptionSymbolProvider ESP) { if (!shouldEmitCFI) return; @@ -136,20 +149,24 @@ void DwarfCFIException::beginFunction(const MachineFunction *MF) { if (!shouldEmitPersonality) return; + auto *F = MBB->getParent()->getFunction(); + auto *P = dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts()); + assert(P && "Expected personality function"); + // If we are forced to emit this personality, make sure to record // it because it might not appear in any landingpad if (forceEmitPersonality) - MMI->addPersonality(Per); + MMI->addPersonality(P); + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + unsigned PerEncoding = TLOF.getPersonalityEncoding(); const MCSymbol *Sym = - TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI); + TLOF.getCFIPersonalitySymbol(P, *Asm->Mang, Asm->TM, MMI); Asm->OutStreamer->EmitCFIPersonality(Sym, PerEncoding); // Provide LSDA information. - if (!shouldEmitLSDA) - return; - - Asm->OutStreamer->EmitCFILsda(Asm->getCurExceptionSym(), LSDAEncoding); + if (shouldEmitLSDA) + Asm->OutStreamer->EmitCFILsda(ESP(Asm), TLOF.getLSDAEncoding()); } /// endFunction - Gather and emit post-function exception information. diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 725063a..7822814c 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -19,9 +19,10 @@ namespace llvm { DwarfCompileUnit::DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU) - : DwarfUnit(UID, dwarf::DW_TAG_compile_unit, Node, A, DW, DWU), + : DwarfUnit(dwarf::DW_TAG_compile_unit, Node, A, DW, DWU), UniqueID(UID), Skeleton(nullptr), BaseAddress(nullptr) { insertDIE(Node, &getUnitDie()); + MacroLabelBegin = Asm->createTempSymbol("cu_macro_begin"); } /// addLabelAddress - Add a dwarf label attribute data and value using @@ -83,8 +84,8 @@ static const ConstantExpr *getMergedGlobalExpr(const Value *V) { // First operand points to a global struct. Value *Ptr = CE->getOperand(0); - if (!isa<GlobalValue>(Ptr) || - !isa<StructType>(cast<PointerType>(Ptr->getType())->getElementType())) + GlobalValue *GV = dyn_cast<GlobalValue>(Ptr); + if (!GV || !isa<StructType>(GV->getValueType())) return nullptr; // Second operand is zero. @@ -147,61 +148,69 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( // Add location. bool addToAccelTable = false; if (auto *Global = dyn_cast_or_null<GlobalVariable>(GV->getVariable())) { - addToAccelTable = true; - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - const MCSymbol *Sym = Asm->getSymbol(Global); - if (Global->isThreadLocal()) { - if (Asm->TM.Options.EmulatedTLS) { - // TODO: add debug info for emulated thread local mode. - } else { - // FIXME: Make this work with -gsplit-dwarf. - unsigned PointerSize = Asm->getDataLayout().getPointerSize(); - assert((PointerSize == 4 || PointerSize == 8) && - "Add support for other sizes if necessary"); - // Based on GCC's support for TLS: - if (!DD->useSplitDwarf()) { - // 1) Start with a constNu of the appropriate pointer size - addUInt(*Loc, dwarf::DW_FORM_data1, PointerSize == 4 - ? dwarf::DW_OP_const4u - : 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, - Asm->getObjFileLowering().getDebugThreadLocalSymbol(Sym)); + // We cannot describe the location of dllimport'd variables: the computation + // of their address requires loads from the IAT. + if (!Global->hasDLLImportStorageClass()) { + addToAccelTable = true; + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + const MCSymbol *Sym = Asm->getSymbol(Global); + if (Global->isThreadLocal()) { + if (Asm->TM.Options.EmulatedTLS) { + // TODO: add debug info for emulated thread local mode. } else { - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_GNU_const_index); - addUInt(*Loc, dwarf::DW_FORM_udata, - DD->getAddressPool().getIndex(Sym, /* TLS */ true)); + // FIXME: Make this work with -gsplit-dwarf. + unsigned PointerSize = Asm->getDataLayout().getPointerSize(); + assert((PointerSize == 4 || PointerSize == 8) && + "Add support for other sizes if necessary"); + // Based on GCC's support for TLS: + if (!DD->useSplitDwarf()) { + // 1) Start with a constNu of the appropriate pointer size + addUInt(*Loc, dwarf::DW_FORM_data1, PointerSize == 4 + ? dwarf::DW_OP_const4u + : 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, + Asm->getObjFileLowering().getDebugThreadLocalSymbol(Sym)); + } else { + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_GNU_const_index); + addUInt(*Loc, dwarf::DW_FORM_udata, + DD->getAddressPool().getIndex(Sym, /* TLS */ true)); + } + // 3) followed by an OP to make the debugger do a TLS lookup. + addUInt(*Loc, dwarf::DW_FORM_data1, + DD->useGNUTLSOpcode() ? dwarf::DW_OP_GNU_push_tls_address + : dwarf::DW_OP_form_tls_address); } - // 3) followed by an OP to make the debugger do a TLS lookup. - addUInt(*Loc, dwarf::DW_FORM_data1, - DD->useGNUTLSOpcode() ? dwarf::DW_OP_GNU_push_tls_address - : dwarf::DW_OP_form_tls_address); + } else { + DD->addArangeLabel(SymbolCU(this, Sym)); + addOpAddress(*Loc, Sym); } - } else { - DD->addArangeLabel(SymbolCU(this, Sym)); - addOpAddress(*Loc, Sym); - } - addBlock(*VariableDIE, dwarf::DW_AT_location, Loc); - addLinkageName(*VariableDIE, GV->getLinkageName()); + addBlock(*VariableDIE, dwarf::DW_AT_location, Loc); + if (DD->useAllLinkageNames()) + addLinkageName(*VariableDIE, GV->getLinkageName()); + } } else if (const ConstantInt *CI = dyn_cast_or_null<ConstantInt>(GV->getVariable())) { addConstantValue(*VariableDIE, CI, GTy); } else if (const ConstantExpr *CE = getMergedGlobalExpr(GV->getVariable())) { - addToAccelTable = true; - // GV is a merged global. - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - Value *Ptr = CE->getOperand(0); - MCSymbol *Sym = Asm->getSymbol(cast<GlobalValue>(Ptr)); - DD->addArangeLabel(SymbolCU(this, Sym)); - addOpAddress(*Loc, Sym); - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); - SmallVector<Value *, 3> Idx(CE->op_begin() + 1, CE->op_end()); - addUInt(*Loc, dwarf::DW_FORM_udata, - Asm->getDataLayout().getIndexedOffset(Ptr->getType(), Idx)); - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus); - addBlock(*VariableDIE, dwarf::DW_AT_location, Loc); + auto *Ptr = cast<GlobalValue>(CE->getOperand(0)); + if (!Ptr->hasDLLImportStorageClass()) { + addToAccelTable = true; + // GV is a merged global. + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + MCSymbol *Sym = Asm->getSymbol(Ptr); + DD->addArangeLabel(SymbolCU(this, Sym)); + addOpAddress(*Loc, Sym); + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); + SmallVector<Value *, 3> Idx(CE->op_begin() + 1, CE->op_end()); + addUInt(*Loc, dwarf::DW_FORM_udata, + Asm->getDataLayout().getIndexedOffsetInType(Ptr->getValueType(), + Idx)); + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus); + addBlock(*VariableDIE, dwarf::DW_AT_location, Loc); + } } if (addToAccelTable) { @@ -285,7 +294,8 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) { DIE *SPDie = getOrCreateSubprogramDIE(SP, includeMinimalInlineScopes()); attachLowHighPC(*SPDie, Asm->getFunctionBegin(), Asm->getFunctionEnd()); - if (!DD->getCurrentFunction()->getTarget().Options.DisableFramePointerElim( + if (DD->useAppleExtensionAttributes() && + !DD->getCurrentFunction()->getTarget().Options.DisableFramePointerElim( *DD->getCurrentFunction())) addFlag(*SPDie, dwarf::DW_AT_APPLE_omit_frame_ptr); @@ -503,9 +513,20 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, addVariableAddress(DV, *VariableDie, Location); } else if (RegOp.getReg()) addVariableAddress(DV, *VariableDie, MachineLocation(RegOp.getReg())); - } else if (DVInsn->getOperand(0).isImm()) - addConstantValue(*VariableDie, DVInsn->getOperand(0), DV.getType()); - else if (DVInsn->getOperand(0).isFPImm()) + } else if (DVInsn->getOperand(0).isImm()) { + // This variable is described by a single constant. + // Check whether it has a DIExpression. + auto *Expr = DV.getSingleExpression(); + if (Expr && Expr->getNumElements()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + // If there is an expression, emit raw unsigned bytes. + DwarfExpr.AddUnsignedConstant(DVInsn->getOperand(0).getImm()); + DwarfExpr.AddExpression(Expr->expr_op_begin(), Expr->expr_op_end()); + addBlock(*VariableDie, dwarf::DW_AT_location, Loc); + } else + addConstantValue(*VariableDie, DVInsn->getOperand(0), DV.getType()); + } else if (DVInsn->getOperand(0).isFPImm()) addConstantFPValue(*VariableDie, DVInsn->getOperand(0)); else if (DVInsn->getOperand(0).isCImm()) addConstantValue(*VariableDie, DVInsn->getOperand(0).getCImm(), @@ -526,7 +547,8 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg); assert(Expr != DV.getExpression().end() && "Wrong number of expressions"); - DwarfExpr.AddMachineRegIndirect(FrameReg, Offset); + DwarfExpr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(), + FrameReg, Offset); DwarfExpr.AddExpression((*Expr)->expr_op_begin(), (*Expr)->expr_op_end()); ++Expr; } @@ -683,25 +705,6 @@ void DwarfCompileUnit::finishSubprogramDefinition(const DISubprogram *SP) { applySubprogramAttributesToDefinition(SP, *D); } } -void DwarfCompileUnit::collectDeadVariables(const DISubprogram *SP) { - assert(SP && "CU's subprogram list contains a non-subprogram"); - assert(SP->isDefinition() && - "CU's subprogram list contains a subprogram declaration"); - auto Variables = SP->getVariables(); - if (Variables.size() == 0) - return; - - DIE *SPDIE = DU->getAbstractSPDies().lookup(SP); - if (!SPDIE) - SPDIE = getDIE(SP); - assert(SPDIE); - for (const DILocalVariable *DV : Variables) { - DbgVariable NewVar(DV, /* IA */ nullptr, DD); - auto VariableDie = constructVariableDIE(NewVar); - applyVariableAttributes(NewVar, *VariableDie); - SPDIE->addChild(std::move(VariableDie)); - } -} void DwarfCompileUnit::emitHeader(bool UseOffsets) { // Don't bother labeling the .dwo unit, as its offset isn't used. @@ -770,16 +773,16 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die, const MachineLocation &Location) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); - assert(DV.getExpression().size() == 1); - const DIExpression *Expr = DV.getExpression().back(); + const DIExpression *Expr = DV.getSingleExpression(); bool ValidReg; + const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); if (Location.getOffset()) { - ValidReg = DwarfExpr.AddMachineRegIndirect(Location.getReg(), + ValidReg = DwarfExpr.AddMachineRegIndirect(TRI, Location.getReg(), Location.getOffset()); if (ValidReg) DwarfExpr.AddExpression(Expr->expr_op_begin(), Expr->expr_op_end()); } else - ValidReg = DwarfExpr.AddMachineRegExpression(Expr, Location.getReg()); + ValidReg = DwarfExpr.AddMachineRegExpression(TRI, Expr, Location.getReg()); // Now attach the location information to the DIE. if (ValidReg) @@ -824,7 +827,7 @@ bool DwarfCompileUnit::isDwoUnit() const { } bool DwarfCompileUnit::includeMinimalInlineScopes() const { - return getCUNode()->getEmissionKind() == DIBuilder::LineTablesOnly || + return getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly || (DD->useSplitDwarf() && !Skeleton); } } // end llvm namespace diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 2e28467..90f74a3 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -15,12 +15,12 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFCOMPILEUNIT_H #include "DwarfUnit.h" -#include "llvm/ADT/StringRef.h" #include "llvm/IR/DebugInfo.h" #include "llvm/Support/Dwarf.h" namespace llvm { +class StringRef; class AsmPrinter; class DIE; class DwarfDebug; @@ -29,6 +29,12 @@ class MCSymbol; class LexicalScope; class DwarfCompileUnit : public DwarfUnit { + /// A numeric ID unique among all CUs in the module + unsigned UniqueID; + + /// Offset of the UnitDie from beginning of debug info section. + unsigned DebugInfoOffset = 0; + /// The attribute index of DW_AT_stmt_list in the compile unit DIE, avoiding /// the need to search for it in applyStmtList. DIE::value_iterator StmtListValue; @@ -39,6 +45,9 @@ class DwarfCompileUnit : public DwarfUnit { /// The start of the unit within its section. MCSymbol *LabelBegin; + /// The start of the unit macro info within macro section. + MCSymbol *MacroLabelBegin; + typedef llvm::SmallVector<const MDNode *, 8> ImportedEntityList; typedef llvm::DenseMap<const MDNode *, ImportedEntityList> ImportedEntityMap; @@ -74,6 +83,10 @@ public: DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU); + unsigned getUniqueID() const { return UniqueID; } + unsigned getDebugInfoOffset() const { return DebugInfoOffset; } + void setDebugInfoOffset(unsigned DbgInfoOff) { DebugInfoOffset = DbgInfoOff; } + DwarfCompileUnit *getSkeleton() const { return Skeleton; } @@ -105,7 +118,14 @@ public: unsigned getOrCreateSourceID(StringRef FileName, StringRef DirName) override; void addImportedEntity(const DIImportedEntity* IE) { - ImportedEntities[IE->getScope()].push_back(IE); + DIScope *Scope = IE->getScope(); + assert(Scope && "Invalid Scope encoding!"); + if (!isa<DILocalScope>(Scope)) + // No need to add imported enities that are not local declaration. + return; + + auto *LocalScope = cast<DILocalScope>(Scope)->getNonLexicalBlockFileScope(); + ImportedEntities[LocalScope].push_back(IE); } /// addRange - Add an address range to the list of ranges for this unit. @@ -167,8 +187,6 @@ public: void finishSubprogramDefinition(const DISubprogram *SP); - void collectDeadVariables(const DISubprogram *SP); - /// Set the skeleton unit associated with this unit. void setSkeleton(DwarfCompileUnit &Skel) { Skeleton = &Skel; } @@ -189,6 +207,10 @@ public: return LabelBegin; } + MCSymbol *getMacroLabelBegin() const { + return MacroLabelBegin; + } + /// Add a new global name to the compile unit. void addGlobalName(StringRef Name, DIE &Die, const DIScope *Context) override; diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index f56c8e4..7fba768 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -26,7 +26,6 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/IR/Constants.h" -#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/Instructions.h" @@ -54,6 +53,7 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" + using namespace llvm; #define DEBUG_TYPE "dwarfdebug" @@ -105,13 +105,21 @@ DwarfPubSections("generate-dwarf-pub-sections", cl::Hidden, clEnumVal(Disable, "Disabled"), clEnumValEnd), cl::init(Default)); -static cl::opt<DefaultOnOff> -DwarfLinkageNames("dwarf-linkage-names", cl::Hidden, - cl::desc("Emit DWARF linkage-name attributes."), - cl::values(clEnumVal(Default, "Default for platform"), - clEnumVal(Enable, "Enabled"), - clEnumVal(Disable, "Disabled"), clEnumValEnd), - cl::init(Default)); +enum LinkageNameOption { + DefaultLinkageNames, + AllLinkageNames, + AbstractLinkageNames +}; +static cl::opt<LinkageNameOption> + DwarfLinkageNames("dwarf-linkage-names", cl::Hidden, + cl::desc("Which DWARF linkage-name attributes to emit."), + cl::values(clEnumValN(DefaultLinkageNames, "Default", + "Default for platform"), + clEnumValN(AllLinkageNames, "All", "All"), + clEnumValN(AbstractLinkageNames, "Abstract", + "Abstract subprograms"), + clEnumValEnd), + cl::init(DefaultLinkageNames)); static const char *const DWARFGroupName = "DWARF Emission"; static const char *const DbgTimerName = "DWARF Debug Writer"; @@ -130,28 +138,21 @@ void DebugLocDwarfExpression::EmitUnsigned(uint64_t Value) { BS.EmitULEB128(Value, Twine(Value)); } -bool DebugLocDwarfExpression::isFrameRegister(unsigned MachineReg) { +bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, + unsigned MachineReg) { // This information is not available while emitting .debug_loc entries. return false; } //===----------------------------------------------------------------------===// -/// resolve - Look in the DwarfDebug map for the MDNode that -/// corresponds to the reference. -template <typename T> T *DbgVariable::resolve(TypedDINodeRef<T> Ref) const { - return DD->resolve(Ref); -} - bool DbgVariable::isBlockByrefVariable() const { assert(Var && "Invalid complex DbgVariable!"); - return Var->getType() - .resolve(DD->getTypeIdentifierMap()) - ->isBlockByrefStruct(); + return Var->getType().resolve()->isBlockByrefStruct(); } const DIType *DbgVariable::getType() const { - DIType *Ty = Var->getType().resolve(DD->getTypeIdentifierMap()); + DIType *Ty = Var->getType().resolve(); // FIXME: isBlockByrefVariable should be reformulated in terms of complex // addresses instead. if (Ty->isBlockByrefStruct()) { @@ -201,8 +202,8 @@ static LLVM_CONSTEXPR DwarfAccelTable::Atom TypeAtoms[] = { DwarfAccelTable::Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)}; DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) - : Asm(A), MMI(Asm->MMI), DebugLocs(A->OutStreamer->isVerboseAsm()), - PrevLabel(nullptr), InfoHolder(A, "info_string", DIEValueAllocator), + : DebugHandlerBase(A), DebugLocs(A->OutStreamer->isVerboseAsm()), + InfoHolder(A, "info_string", DIEValueAllocator), SkeletonHolder(A, "skel_string", DIEValueAllocator), IsDarwin(Triple(A->getTargetTriple()).isOSDarwin()), AccelNames(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, @@ -214,7 +215,6 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) AccelTypes(TypeAtoms), DebuggerTuning(DebuggerKind::Default) { CurFn = nullptr; - CurMI = nullptr; Triple TT(Asm->getTargetTriple()); // Make sure we know our "debugger tuning." The target option takes @@ -234,6 +234,8 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) else HasDwarfAccelTables = DwarfAccelTables == Enable; + HasAppleExtensionAttributes = tuneForLLDB(); + // Handle split DWARF. Off by default for now. if (SplitDwarf == Default) HasSplitDwarf = false; @@ -246,11 +248,11 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) else HasDwarfPubSections = DwarfPubSections == Enable; - // SCE does not use linkage names. - if (DwarfLinkageNames == Default) - UseLinkageNames = !tuneForSCE(); + // SCE defaults to linkage names only for abstract subprograms. + if (DwarfLinkageNames == DefaultLinkageNames) + UseAllLinkageNames = !tuneForSCE(); else - UseLinkageNames = DwarfLinkageNames == Enable; + UseAllLinkageNames = DwarfLinkageNames == AllLinkageNames; unsigned DwarfVersionNumber = Asm->TM.Options.MCOptions.DwarfVersion; DwarfVersion = DwarfVersionNumber ? DwarfVersionNumber @@ -265,12 +267,10 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) // https://sourceware.org/bugzilla/show_bug.cgi?id=11616 UseGNUTLSOpcode = tuneForGDB() || DwarfVersion < 3; - Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); + // GDB does not fully support the DWARF 4 representation for bitfields. + UseDWARF2Bitfields = (DwarfVersion < 4) || tuneForGDB(); - { - NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); - beginModule(); - } + Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); } // Define out of line so we don't have to include DwarfUnit.h in DwarfDebug.h. @@ -297,7 +297,6 @@ static void getObjCClassCategory(StringRef In, StringRef &Class, Class = In.slice(In.find('[') + 1, In.find('(')); Category = In.slice(In.find('[') + 1, In.find(' ')); - return; } static StringRef getObjCMethodName(StringRef In) { @@ -367,8 +366,8 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(LexicalScope *Scope) { // Find the subprogram's DwarfCompileUnit in the SPMap in case the subprogram // was inlined from another compile unit. - auto &CU = SPMap[SP]; - forBothCUs(*CU, [&](DwarfCompileUnit &CU) { + auto &CU = *CUMap.lookup(cast<DISubprogram>(SP)->getUnit()); + forBothCUs(CU, [&](DwarfCompileUnit &CU) { CU.constructAbstractSubprogramScopeDIE(Scope); }); } @@ -392,8 +391,11 @@ DwarfDebug::constructDwarfCompileUnit(const DICompileUnit *DIUnit) { DwarfCompileUnit &NewCU = *OwnedUnit; DIE &Die = NewCU.getUnitDie(); InfoHolder.addUnit(std::move(OwnedUnit)); - if (useSplitDwarf()) + if (useSplitDwarf()) { NewCU.setSkeleton(constructSkeletonCU(NewCU)); + NewCU.addString(Die, dwarf::DW_AT_GNU_dwo_name, + DIUnit->getSplitDebugFilename()); + } // LTO with assembly output shares a single line table amongst multiple CUs. // To avoid the compilation directory being ambiguous, let the line table @@ -419,16 +421,18 @@ DwarfDebug::constructDwarfCompileUnit(const DICompileUnit *DIUnit) { addGnuPubAttributes(NewCU, Die); } - if (DIUnit->isOptimized()) - NewCU.addFlag(Die, dwarf::DW_AT_APPLE_optimized); + if (useAppleExtensionAttributes()) { + if (DIUnit->isOptimized()) + NewCU.addFlag(Die, dwarf::DW_AT_APPLE_optimized); - StringRef Flags = DIUnit->getFlags(); - if (!Flags.empty()) - NewCU.addString(Die, dwarf::DW_AT_APPLE_flags, Flags); + StringRef Flags = DIUnit->getFlags(); + if (!Flags.empty()) + NewCU.addString(Die, dwarf::DW_AT_APPLE_flags, Flags); - if (unsigned RVer = DIUnit->getRuntimeVersion()) - NewCU.addUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers, - dwarf::DW_FORM_data1, RVer); + if (unsigned RVer = DIUnit->getRuntimeVersion()) + NewCU.addUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers, + dwarf::DW_FORM_data1, RVer); + } if (useSplitDwarf()) NewCU.initSection(Asm->getObjFileLowering().getDwarfInfoDWOSection()); @@ -460,48 +464,42 @@ void DwarfDebug::constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU, // global DIEs and emit initial debug info sections. This is invoked by // the target AsmPrinter. void DwarfDebug::beginModule() { + NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); if (DisableDebugInfoPrinting) return; const Module *M = MMI->getModule(); - NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); - if (!CU_Nodes) - return; - TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); - - SingleCU = CU_Nodes->getNumOperands() == 1; + unsigned NumDebugCUs = std::distance(M->debug_compile_units_begin(), + M->debug_compile_units_end()); + // Tell MMI whether we have debug info. + MMI->setDebugInfoAvailability(NumDebugCUs > 0); + SingleCU = NumDebugCUs == 1; - for (MDNode *N : CU_Nodes->operands()) { - auto *CUNode = cast<DICompileUnit>(N); + for (DICompileUnit *CUNode : M->debug_compile_units()) { DwarfCompileUnit &CU = constructDwarfCompileUnit(CUNode); for (auto *IE : CUNode->getImportedEntities()) CU.addImportedEntity(IE); for (auto *GV : CUNode->getGlobalVariables()) CU.getOrCreateGlobalVariableDIE(GV); - for (auto *SP : CUNode->getSubprograms()) - SPMap.insert(std::make_pair(SP, &CU)); for (auto *Ty : CUNode->getEnumTypes()) { // The enum types array by design contains pointers to // MDNodes rather than DIRefs. Unique them here. - CU.getOrCreateTypeDIE(cast<DIType>(resolve(Ty->getRef()))); + CU.getOrCreateTypeDIE(cast<DIType>(Ty)); } for (auto *Ty : CUNode->getRetainedTypes()) { // The retained types array by design contains pointers to // MDNodes rather than DIRefs. Unique them here. - DIType *RT = cast<DIType>(resolve(Ty->getRef())); - if (!RT->isExternalTypeRef()) - // There is no point in force-emitting a forward declaration. - CU.getOrCreateTypeDIE(RT); + if (DIType *RT = dyn_cast<DIType>(Ty)) + if (!RT->isExternalTypeRef()) + // There is no point in force-emitting a forward declaration. + CU.getOrCreateTypeDIE(RT); } // Emit imported_modules last so that the relevant context is already // available. for (auto *IE : CUNode->getImportedEntities()) constructAndAddImportedEntityDIE(CU, IE); } - - // Tell MMI that we have debug info. - MMI->setDebugInfoAvailability(true); } void DwarfDebug::finishVariableDefinitions() { @@ -524,31 +522,13 @@ void DwarfDebug::finishVariableDefinitions() { } void DwarfDebug::finishSubprogramDefinitions() { - for (const auto &P : SPMap) - forBothCUs(*P.second, [&](DwarfCompileUnit &CU) { - CU.finishSubprogramDefinition(cast<DISubprogram>(P.first)); - }); -} - - -// Collect info for variables that were optimized out. -void DwarfDebug::collectDeadVariables() { - const Module *M = MMI->getModule(); - - if (NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu")) { - for (MDNode *N : CU_Nodes->operands()) { - auto *TheCU = cast<DICompileUnit>(N); - // Construct subprogram DIE and add variables DIEs. - DwarfCompileUnit *SPCU = - static_cast<DwarfCompileUnit *>(CUMap.lookup(TheCU)); - assert(SPCU && "Unable to find Compile Unit!"); - for (auto *SP : TheCU->getSubprograms()) { - if (ProcessedSPNodes.count(SP) != 0) - continue; - SPCU->collectDeadVariables(SP); - } - } - } + for (auto &F : MMI->getModule()->functions()) + if (auto *SP = F.getSubprogram()) + if (ProcessedSPNodes.count(SP) && + SP->getUnit()->getEmissionKind() != DICompileUnit::NoDebug) + forBothCUs(*CUMap.lookup(SP->getUnit()), [&](DwarfCompileUnit &CU) { + CU.finishSubprogramDefinition(SP); + }); } void DwarfDebug::finalizeModuleInfo() { @@ -558,11 +538,6 @@ void DwarfDebug::finalizeModuleInfo() { finishVariableDefinitions(); - // Collect info for variables that were optimized out. - collectDeadVariables(); - - unsigned MacroOffset = 0; - std::unique_ptr<AsmStreamerBase> AS(new SizeReporterAsmStreamer(Asm)); // Handle anything that needs to be done on a per-unit basis after // all other generation. for (const auto &P : CUMap) { @@ -617,13 +592,11 @@ void DwarfDebug::finalizeModuleInfo() { } auto *CUNode = cast<DICompileUnit>(P.first); - if (CUNode->getMacros()) { - // Compile Unit has macros, emit "DW_AT_macro_info" attribute. - U.addUInt(U.getUnitDie(), dwarf::DW_AT_macro_info, - dwarf::DW_FORM_sec_offset, MacroOffset); - // Update macro section offset - MacroOffset += handleMacroNodes(AS.get(), CUNode->getMacros(), U); - } + // If compile Unit has macros, emit "DW_AT_macro_info" attribute. + if (CUNode->getMacros()) + U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_macro_info, + U.getMacroLabelBegin(), + TLOF.getDwarfMacinfoSection()->getBeginSymbol()); } // Compute DIE offsets and sizes. @@ -694,7 +667,6 @@ void DwarfDebug::endModule() { } // clean up. - SPMap.clear(); AbstractVariables.clear(); } @@ -717,7 +689,7 @@ DbgVariable *DwarfDebug::getExistingAbstractVariable(InlinedVariable IV) { void DwarfDebug::createAbstractVariable(const DILocalVariable *Var, LexicalScope *Scope) { - auto AbsDbgVariable = make_unique<DbgVariable>(Var, /* IA */ nullptr, this); + auto AbsDbgVariable = make_unique<DbgVariable>(Var, /* IA */ nullptr); InfoHolder.addScopeVariable(Scope, AbsDbgVariable.get()); AbstractVariables[Var] = std::move(AbsDbgVariable); } @@ -761,7 +733,7 @@ void DwarfDebug::collectVariableInfoFromMMITable( continue; ensureAbstractVariableIsCreatedIfScoped(Var, Scope->getScopeNode()); - auto RegVar = make_unique<DbgVariable>(Var.first, Var.second, this); + auto RegVar = make_unique<DbgVariable>(Var.first, Var.second); RegVar->initializeMMI(VI.Expr, VI.Slot); if (InfoHolder.addScopeVariable(Scope, RegVar.get())) ConcreteVariables.push_back(std::move(RegVar)); @@ -793,29 +765,6 @@ static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); } -// Determine the relative position of the pieces described by P1 and P2. -// Returns -1 if P1 is entirely before P2, 0 if P1 and P2 overlap, -// 1 if P1 is entirely after P2. -static int pieceCmp(const DIExpression *P1, const DIExpression *P2) { - unsigned l1 = P1->getBitPieceOffset(); - unsigned l2 = P2->getBitPieceOffset(); - unsigned r1 = l1 + P1->getBitPieceSize(); - unsigned r2 = l2 + P2->getBitPieceSize(); - if (r1 <= l2) - return -1; - else if (r2 <= l1) - return 1; - else - return 0; -} - -/// Determine whether two variable pieces overlap. -static bool piecesOverlap(const DIExpression *P1, const DIExpression *P2) { - if (!P1->isBitPiece() || !P2->isBitPiece()) - return true; - return pieceCmp(P1, P2) == 0; -} - /// \brief If this and Next are describing different pieces of the same /// variable, merge them by appending Next's values to the current /// list of values. @@ -832,8 +781,9 @@ bool DebugLocEntry::MergeValues(const DebugLocEntry &Next) { // sorted. for (unsigned i = 0, j = 0; i < Values.size(); ++i) { for (; j < Next.Values.size(); ++j) { - int res = pieceCmp(cast<DIExpression>(Values[i].Expression), - cast<DIExpression>(Next.Values[j].Expression)); + int res = DebugHandlerBase::pieceCmp( + cast<DIExpression>(Values[i].Expression), + cast<DIExpression>(Next.Values[j].Expression)); if (res == 0) // The two expressions overlap, we can't merge. return false; // Values[i] is entirely before Next.Values[j], @@ -944,7 +894,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, DEBUG({ dbgs() << CurEntry->getValues().size() << " Values:\n"; for (auto &Value : CurEntry->getValues()) - Value.getExpression()->dump(); + Value.dump(); dbgs() << "-----\n"; }); @@ -957,12 +907,23 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, DbgVariable *DwarfDebug::createConcreteVariable(LexicalScope &Scope, InlinedVariable IV) { ensureAbstractVariableIsCreatedIfScoped(IV, Scope.getScopeNode()); - ConcreteVariables.push_back( - make_unique<DbgVariable>(IV.first, IV.second, this)); + ConcreteVariables.push_back(make_unique<DbgVariable>(IV.first, IV.second)); InfoHolder.addScopeVariable(&Scope, ConcreteVariables.back().get()); return ConcreteVariables.back().get(); } +// Determine whether this DBG_VALUE is valid at the beginning of the function. +static bool validAtEntry(const MachineInstr *MInsn) { + auto MBB = MInsn->getParent(); + // Is it in the entry basic block? + if (!MBB->pred_empty()) + return false; + for (MachineBasicBlock::const_reverse_iterator I(MInsn); I != MBB->rend(); ++I) + if (!(I->isDebugValue() || I->getFlag(MachineInstr::FrameSetup))) + return false; + return true; +} + // Find variables for each lexical scope. void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, @@ -995,8 +956,11 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, const MachineInstr *MInsn = Ranges.front().first; assert(MInsn->isDebugValue() && "History must begin with debug value"); - // Check if the first DBG_VALUE is valid for the rest of the function. - if (Ranges.size() == 1 && Ranges.front().second == nullptr) { + // Check if there is a single DBG_VALUE, valid throughout the function. + // A single constant is also considered valid for the entire function. + if (Ranges.size() == 1 && + (MInsn->getOperand(0).isImm() || + (validAtEntry(MInsn) && Ranges.front().second == nullptr))) { RegVar->initializeDbgValue(MInsn); continue; } @@ -1008,7 +972,7 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, SmallVector<DebugLocEntry, 8> Entries; buildLocationList(Entries, Ranges); - // If the variable has an DIBasicType, extract it. Basic types cannot have + // If the variable has a DIBasicType, extract it. Basic types cannot have // unique identifiers, so don't bother resolving the type with the // identifier map. const DIBasicType *BT = dyn_cast<DIBasicType>( @@ -1027,25 +991,14 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, } } -// Return Label preceding the instruction. -MCSymbol *DwarfDebug::getLabelBeforeInsn(const MachineInstr *MI) { - MCSymbol *Label = LabelsBeforeInsn.lookup(MI); - assert(Label && "Didn't insert label before instruction"); - return Label; -} - -// Return Label immediately following the instruction. -MCSymbol *DwarfDebug::getLabelAfterInsn(const MachineInstr *MI) { - return LabelsAfterInsn.lookup(MI); -} - // Process beginning of an instruction. void DwarfDebug::beginInstruction(const MachineInstr *MI) { - assert(CurMI == nullptr); - CurMI = MI; + DebugHandlerBase::beginInstruction(MI); + assert(CurMI); + // Check if source location changes, but ignore DBG_VALUE locations. if (!MI->isDebugValue()) { - DebugLoc DL = MI->getDebugLoc(); + const DebugLoc &DL = MI->getDebugLoc(); if (DL != PrevInstLoc) { if (DL) { unsigned Flags = 0; @@ -1067,78 +1020,6 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { } } } - - // Insert labels where requested. - DenseMap<const MachineInstr *, MCSymbol *>::iterator I = - LabelsBeforeInsn.find(MI); - - // No label needed. - if (I == LabelsBeforeInsn.end()) - return; - - // Label already assigned. - if (I->second) - return; - - if (!PrevLabel) { - PrevLabel = MMI->getContext().createTempSymbol(); - Asm->OutStreamer->EmitLabel(PrevLabel); - } - I->second = PrevLabel; -} - -// Process end of an instruction. -void DwarfDebug::endInstruction() { - assert(CurMI != nullptr); - // Don't create a new label after DBG_VALUE instructions. - // They don't generate code. - if (!CurMI->isDebugValue()) - PrevLabel = nullptr; - - DenseMap<const MachineInstr *, MCSymbol *>::iterator I = - LabelsAfterInsn.find(CurMI); - CurMI = nullptr; - - // No label needed. - if (I == LabelsAfterInsn.end()) - return; - - // Label already assigned. - if (I->second) - return; - - // We need a label after this instruction. - if (!PrevLabel) { - PrevLabel = MMI->getContext().createTempSymbol(); - Asm->OutStreamer->EmitLabel(PrevLabel); - } - I->second = PrevLabel; -} - -// 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 -// end) multiple scopes. Ignore scopes that are not reachable. -void DwarfDebug::identifyScopeMarkers() { - SmallVector<LexicalScope *, 4> WorkList; - WorkList.push_back(LScopes.getCurrentFunctionScope()); - while (!WorkList.empty()) { - LexicalScope *S = WorkList.pop_back_val(); - - const SmallVectorImpl<LexicalScope *> &Children = S->getChildren(); - if (!Children.empty()) - WorkList.append(Children.begin(), Children.end()); - - if (S->isAbstractScope()) - continue; - - for (const InsnRange &R : S->getRanges()) { - assert(R.first && "InsnRange does not have first instruction!"); - assert(R.second && "InsnRange does not have second instruction!"); - requestLabelBeforeInsn(R.first); - requestLabelAfterInsn(R.second); - } - } } static DebugLoc findPrologueEndLoc(const MachineFunction *MF) { @@ -1167,15 +1048,10 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { // Grab the lexical scopes for the function, if we don't have any of those // then we're not going to be able to do anything. - LScopes.initialize(*MF); + DebugHandlerBase::beginFunction(MF); if (LScopes.empty()) return; - assert(DbgValues.empty() && "DbgValues map wasn't cleaned!"); - - // Make sure that each lexical scope will have a begin/end label. - identifyScopeMarkers(); - // Set DwarfDwarfCompileUnitID in MCContext to the Compile Unit this function // belongs to so that we add to the correct per-cu line table in the // non-asm case. @@ -1188,55 +1064,19 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { // isn't structurally identical (see: file path/name info from clang, which // includes the directory of the cpp file being built, even when the file name // is absolute (such as an <> lookup header))) - DwarfCompileUnit *TheCU = SPMap.lookup(FnScope->getScopeNode()); - assert(TheCU && "Unable to find compile unit!"); + auto *SP = cast<DISubprogram>(FnScope->getScopeNode()); + DwarfCompileUnit *TheCU = CUMap.lookup(SP->getUnit()); + if (!TheCU) { + assert(SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug && + "DICompileUnit missing from llvm.dbg.cu?"); + return; + } if (Asm->OutStreamer->hasRawTextSupport()) // Use a single line table if we are generating assembly. Asm->OutStreamer->getContext().setDwarfCompileUnitID(0); else Asm->OutStreamer->getContext().setDwarfCompileUnitID(TheCU->getUniqueID()); - // Calculate history for local variables. - calculateDbgValueHistory(MF, Asm->MF->getSubtarget().getRegisterInfo(), - DbgValues); - - // Request labels for the full history. - for (const auto &I : DbgValues) { - const auto &Ranges = I.second; - if (Ranges.empty()) - continue; - - // The first mention of a function argument gets the CurrentFnBegin - // label, so arguments are visible when breaking at function entry. - const DILocalVariable *DIVar = Ranges.front().first->getDebugVariable(); - if (DIVar->isParameter() && - getDISubprogram(DIVar->getScope())->describes(MF->getFunction())) { - LabelsBeforeInsn[Ranges.front().first] = Asm->getFunctionBegin(); - if (Ranges.front().first->getDebugExpression()->isBitPiece()) { - // Mark all non-overlapping initial pieces. - for (auto I = Ranges.begin(); I != Ranges.end(); ++I) { - const DIExpression *Piece = I->first->getDebugExpression(); - if (std::all_of(Ranges.begin(), I, - [&](DbgValueHistoryMap::InstrRange Pred) { - return !piecesOverlap(Piece, Pred.first->getDebugExpression()); - })) - LabelsBeforeInsn[I->first] = Asm->getFunctionBegin(); - else - break; - } - } - } - - for (const auto &Range : Ranges) { - requestLabelBeforeInsn(Range.first); - if (Range.second) - requestLabelAfterInsn(Range.second); - } - } - - PrevInstLoc = DebugLoc(); - PrevLabel = Asm->getFunctionBegin(); - // Record beginning of function. PrologEndLoc = findPrologueEndLoc(MF); if (DILocation *L = PrologEndLoc) { @@ -1252,13 +1092,19 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { assert(CurFn == MF && "endFunction should be called with the same function as beginFunction"); - if (!MMI->hasDebugInfo() || LScopes.empty() || - !MF->getFunction()->getSubprogram()) { + const DISubprogram *SP = MF->getFunction()->getSubprogram(); + if (!MMI->hasDebugInfo() || LScopes.empty() || !SP || + SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug) { // If we don't have a lexical scope for this function then there will // be a hole in the range information. Keep note of this by setting the // previously used section to nullptr. PrevCU = nullptr; CurFn = nullptr; + DebugHandlerBase::endFunction(MF); + // Mark functions with no debug info on any instructions, but a + // valid DISubprogram as processed. + if (SP) + ProcessedSPNodes.insert(SP); return; } @@ -1266,8 +1112,8 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { Asm->OutStreamer->getContext().setDwarfCompileUnitID(0); LexicalScope *FnScope = LScopes.getCurrentFunctionScope(); - auto *SP = cast<DISubprogram>(FnScope->getScopeNode()); - DwarfCompileUnit &TheCU = *SPMap.lookup(SP); + SP = cast<DISubprogram>(FnScope->getScopeNode()); + DwarfCompileUnit &TheCU = *CUMap.lookup(SP->getUnit()); DenseSet<InlinedVariable> ProcessedVars; collectVariableInfo(TheCU, SP, ProcessedVars); @@ -1277,17 +1123,16 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { // Under -gmlt, skip building the subprogram if there are no inlined // subroutines inside it. - if (TheCU.getCUNode()->getEmissionKind() == DIBuilder::LineTablesOnly && + if (TheCU.getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly && LScopes.getAbstractScopesList().empty() && !IsDarwin) { assert(InfoHolder.getScopeVariables().empty()); assert(DbgValues.empty()); // FIXME: This wouldn't be true in LTO with a -g (with inlining) CU followed // by a -gmlt CU. Add a test and remove this assertion. assert(AbstractVariables.empty()); - LabelsBeforeInsn.clear(); - LabelsAfterInsn.clear(); PrevLabel = nullptr; CurFn = nullptr; + DebugHandlerBase::endFunction(MF); return; } @@ -1319,11 +1164,9 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { // DbgVariables except those that are also in AbstractVariables (since they // can be used cross-function) InfoHolder.getScopeVariables().clear(); - DbgValues.clear(); - LabelsBeforeInsn.clear(); - LabelsAfterInsn.clear(); PrevLabel = nullptr; CurFn = nullptr; + DebugHandlerBase::endFunction(MF); } // Register a source line with debug info. Returns the unique label that was @@ -1535,7 +1378,7 @@ void DwarfDebug::emitDebugPubTypes(bool GnuStyle) { &DwarfCompileUnit::getGlobalTypes); } -// Emit visible names into a debug str section. +/// Emit null-terminated strings into a debug str section. void DwarfDebug::emitDebugStr() { DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection()); @@ -1554,8 +1397,7 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, ByteStreamer &Streamer, const DebugLocEntry::Value &Value, unsigned PieceOffsetInBits) { - DebugLocDwarfExpression DwarfExpr(*AP.MF->getSubtarget().getRegisterInfo(), - AP.getDwarfDebug()->getDwarfVersion(), + DebugLocDwarfExpression DwarfExpr(AP.getDwarfDebug()->getDwarfVersion(), Streamer); // Regular entry. if (Value.isInt()) { @@ -1572,18 +1414,19 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, AP.EmitDwarfRegOp(Streamer, Loc); else { // Complex address entry. + const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo(); if (Loc.getOffset()) { - DwarfExpr.AddMachineRegIndirect(Loc.getReg(), Loc.getOffset()); + DwarfExpr.AddMachineRegIndirect(TRI, Loc.getReg(), Loc.getOffset()); DwarfExpr.AddExpression(Expr->expr_op_begin(), Expr->expr_op_end(), PieceOffsetInBits); } else - DwarfExpr.AddMachineRegExpression(Expr, Loc.getReg(), + DwarfExpr.AddMachineRegExpression(TRI, Expr, Loc.getReg(), PieceOffsetInBits); } + } else if (Value.isConstantFP()) { + APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt(); + DwarfExpr.AddUnsignedConstant(RawBytes); } - // else ... ignore constant fp. There is not any good way to - // to represent them here in dwarf. - // FIXME: ^ } void DebugLocEntry::finalize(const AsmPrinter &AP, @@ -1608,8 +1451,7 @@ void DebugLocEntry::finalize(const AsmPrinter &AP, assert(Offset <= PieceOffset && "overlapping or duplicate pieces"); if (Offset < PieceOffset) { // The DWARF spec seriously mandates pieces with no locations for gaps. - DebugLocDwarfExpression Expr(*AP.MF->getSubtarget().getRegisterInfo(), - AP.getDwarfDebug()->getDwarfVersion(), + DebugLocDwarfExpression Expr(AP.getDwarfDebug()->getDwarfVersion(), Streamer); Expr.AddOpPiece(PieceOffset-Offset, 0); Offset += PieceOffset-Offset; @@ -1708,24 +1550,12 @@ void DwarfDebug::emitDebugARanges() { } } - // Add terminating symbols for each section. - for (const auto &I : SectionMap) { - MCSection *Section = I.first; - MCSymbol *Sym = nullptr; - - if (Section) - Sym = Asm->OutStreamer->endSection(Section); - - // Insert a final terminator. - SectionMap[Section].push_back(SymbolCU(nullptr, Sym)); - } - DenseMap<DwarfCompileUnit *, std::vector<ArangeSpan>> Spans; for (auto &I : SectionMap) { - const MCSection *Section = I.first; + MCSection *Section = I.first; SmallVector<SymbolCU, 8> &List = I.second; - if (List.size() < 2) + if (List.size() < 1) continue; // If we have no section (e.g. common), just write out @@ -1735,26 +1565,29 @@ void DwarfDebug::emitDebugARanges() { ArangeSpan Span; Span.Start = Cur.Sym; Span.End = nullptr; - if (Cur.CU) - Spans[Cur.CU].push_back(Span); + assert(Cur.CU); + Spans[Cur.CU].push_back(Span); } continue; } // Sort the symbols by offset within the section. - std::sort(List.begin(), List.end(), - [&](const SymbolCU &A, const SymbolCU &B) { - unsigned IA = A.Sym ? Asm->OutStreamer->GetSymbolOrder(A.Sym) : 0; - unsigned IB = B.Sym ? Asm->OutStreamer->GetSymbolOrder(B.Sym) : 0; - - // Symbols with no order assigned should be placed at the end. - // (e.g. section end labels) - if (IA == 0) - return false; - if (IB == 0) - return true; - return IA < IB; - }); + std::sort( + List.begin(), List.end(), [&](const SymbolCU &A, const SymbolCU &B) { + unsigned IA = A.Sym ? Asm->OutStreamer->GetSymbolOrder(A.Sym) : 0; + unsigned IB = B.Sym ? Asm->OutStreamer->GetSymbolOrder(B.Sym) : 0; + + // Symbols with no order assigned should be placed at the end. + // (e.g. section end labels) + if (IA == 0) + return false; + if (IB == 0) + return true; + return IA < IB; + }); + + // Insert a final terminator. + List.push_back(SymbolCU(nullptr, Asm->OutStreamer->endSection(Section))); // Build spans between each label. const MCSymbol *StartSym = List[0].Sym; @@ -1767,6 +1600,7 @@ void DwarfDebug::emitDebugARanges() { ArangeSpan Span; Span.Start = StartSym; Span.End = Cur.Sym; + assert(Prev.CU); Spans[Prev.CU].push_back(Span); StartSym = Cur.Sym; } @@ -1787,9 +1621,10 @@ void DwarfDebug::emitDebugARanges() { } // Sort the CU list (again, to ensure consistent output order). - std::sort(CUs.begin(), CUs.end(), [](const DwarfUnit *A, const DwarfUnit *B) { - return A->getUniqueID() < B->getUniqueID(); - }); + std::sort(CUs.begin(), CUs.end(), + [](const DwarfCompileUnit *A, const DwarfCompileUnit *B) { + return A->getUniqueID() < B->getUniqueID(); + }); // Emit an arange table for each CU we used. for (DwarfCompileUnit *CU : CUs) { @@ -1827,7 +1662,7 @@ void DwarfDebug::emitDebugARanges() { Asm->OutStreamer->AddComment("Segment Size (in bytes)"); Asm->EmitInt8(0); - Asm->OutStreamer->EmitFill(Padding, 0xff); + Asm->OutStreamer->emitFill(Padding, 0xff); for (const ArangeSpan &Span : List) { Asm->EmitLabelReference(Span.Start, PtrSize); @@ -1852,7 +1687,7 @@ void DwarfDebug::emitDebugARanges() { } } -// Emit visible names into a debug ranges section. +/// Emit address ranges into a debug ranges section. void DwarfDebug::emitDebugRanges() { // Start the dwarf ranges section. Asm->OutStreamer->SwitchSection( @@ -1894,65 +1729,56 @@ void DwarfDebug::emitDebugRanges() { } } -unsigned DwarfDebug::handleMacroNodes(AsmStreamerBase *AS, - DIMacroNodeArray Nodes, - DwarfCompileUnit &U) { - unsigned Size = 0; +void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U) { for (auto *MN : Nodes) { if (auto *M = dyn_cast<DIMacro>(MN)) - Size += emitMacro(AS, *M); + emitMacro(*M); else if (auto *F = dyn_cast<DIMacroFile>(MN)) - Size += emitMacroFile(AS, *F, U); + emitMacroFile(*F, U); else llvm_unreachable("Unexpected DI type!"); } - return Size; } -unsigned DwarfDebug::emitMacro(AsmStreamerBase *AS, DIMacro &M) { - int Size = 0; - Size += AS->emitULEB128(M.getMacinfoType()); - Size += AS->emitULEB128(M.getLine()); +void DwarfDebug::emitMacro(DIMacro &M) { + Asm->EmitULEB128(M.getMacinfoType()); + Asm->EmitULEB128(M.getLine()); StringRef Name = M.getName(); StringRef Value = M.getValue(); - Size += AS->emitBytes(Name); + Asm->OutStreamer->EmitBytes(Name); if (!Value.empty()) { // There should be one space between macro name and macro value. - Size += AS->emitInt8(' '); - Size += AS->emitBytes(Value); + Asm->EmitInt8(' '); + Asm->OutStreamer->EmitBytes(Value); } - Size += AS->emitInt8('\0'); - return Size; + Asm->EmitInt8('\0'); } -unsigned DwarfDebug::emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F, - DwarfCompileUnit &U) { - int Size = 0; +void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); - Size += AS->emitULEB128(dwarf::DW_MACINFO_start_file); - Size += AS->emitULEB128(F.getLine()); + Asm->EmitULEB128(dwarf::DW_MACINFO_start_file); + Asm->EmitULEB128(F.getLine()); DIFile *File = F.getFile(); unsigned FID = U.getOrCreateSourceID(File->getFilename(), File->getDirectory()); - Size += AS->emitULEB128(FID); - Size += handleMacroNodes(AS, F.getElements(), U); - Size += AS->emitULEB128(dwarf::DW_MACINFO_end_file); - return Size; + Asm->EmitULEB128(FID); + handleMacroNodes(F.getElements(), U); + Asm->EmitULEB128(dwarf::DW_MACINFO_end_file); } -// Emit visible names into a debug macinfo section. +/// Emit macros into a debug macinfo section. void DwarfDebug::emitDebugMacinfo() { - if (MCSection *Macinfo = Asm->getObjFileLowering().getDwarfMacinfoSection()) { - // Start the dwarf macinfo section. - Asm->OutStreamer->SwitchSection(Macinfo); - } - std::unique_ptr<AsmStreamerBase> AS(new EmittingAsmStreamer(Asm)); + // Start the dwarf macinfo section. + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfMacinfoSection()); + for (const auto &P : CUMap) { auto &TheCU = *P.second; auto *SkCU = TheCU.getSkeleton(); DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; auto *CUNode = cast<DICompileUnit>(P.first); - handleMacroNodes(AS.get(), CUNode->getMacros(), U); + Asm->OutStreamer->EmitLabel(U.getMacroLabelBegin()); + handleMacroNodes(CUNode->getMacros(), U); } Asm->OutStreamer->AddComment("End Of Macro List Mark"); Asm->EmitInt8(0); @@ -1961,7 +1787,7 @@ void DwarfDebug::emitDebugMacinfo() { // DWARF5 Experimental Separate Dwarf emitters. void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die, - std::unique_ptr<DwarfUnit> NewU) { + std::unique_ptr<DwarfCompileUnit> NewU) { NewU->addString(Die, dwarf::DW_AT_GNU_dwo_name, U.getCUNode()->getSplitDebugFilename()); @@ -2050,21 +1876,19 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, if (!TypeUnitsUnderConstruction.empty() && AddrPool.hasBeenUsed()) return; - const DwarfTypeUnit *&TU = DwarfTypeUnits[CTy]; - if (TU) { - CU.addDIETypeSignature(RefDie, *TU); + auto Ins = TypeSignatures.insert(std::make_pair(CTy, 0)); + if (!Ins.second) { + CU.addDIETypeSignature(RefDie, Ins.first->second); return; } bool TopLevelType = TypeUnitsUnderConstruction.empty(); AddrPool.resetUsedFlag(); - auto OwnedUnit = make_unique<DwarfTypeUnit>( - InfoHolder.getUnits().size() + TypeUnitsUnderConstruction.size(), CU, Asm, - this, &InfoHolder, getDwoLineTable(CU)); + auto OwnedUnit = make_unique<DwarfTypeUnit>(CU, Asm, this, &InfoHolder, + getDwoLineTable(CU)); DwarfTypeUnit &NewTU = *OwnedUnit; DIE &UnitDie = NewTU.getUnitDie(); - TU = &NewTU; TypeUnitsUnderConstruction.push_back( std::make_pair(std::move(OwnedUnit), CTy)); @@ -2073,6 +1897,7 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, uint64_t Signature = makeTypeSignature(Identifier); NewTU.setTypeSignature(Signature); + Ins.first->second = Signature; if (useSplitDwarf()) NewTU.initSection(Asm->getObjFileLowering().getDwarfTypesDWOSection()); @@ -2096,7 +1921,7 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, // This is pessimistic as some of these types might not be dependent on // the type that used an address. for (const auto &TU : TypeUnitsToAdd) - DwarfTypeUnits.erase(TU.second); + TypeSignatures.erase(TU.second); // Construct this type in the CU directly. // This is inefficient because all the dependent types will be rebuilt @@ -2108,10 +1933,12 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, // If the type wasn't dependent on fission addresses, finish adding the type // and all its dependent types. - for (auto &TU : TypeUnitsToAdd) - InfoHolder.addUnit(std::move(TU.first)); + for (auto &TU : TypeUnitsToAdd) { + InfoHolder.computeSizeAndOffsetsForUnit(TU.first.get()); + InfoHolder.emitUnit(TU.first.get(), useSplitDwarf()); + } } - CU.addDIETypeSignature(RefDie, NewTU); + CU.addDIETypeSignature(RefDie, Signature); } // Accelerator table mutators - add each name along with its companion diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index 460c186..6b06757 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -14,14 +14,13 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H -#include "AsmPrinterHandler.h" #include "DbgValueHistoryCalculator.h" +#include "DebugHandlerBase.h" #include "DebugLocStream.h" #include "DwarfAccelTable.h" #include "DwarfFile.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" @@ -69,15 +68,14 @@ class DbgVariable { unsigned DebugLocListIndex = ~0u; /// Offset in DebugLocs. const MachineInstr *MInsn = nullptr; /// DBG_VALUE instruction. SmallVector<int, 1> FrameIndex; /// Frame index. - DwarfDebug *DD; public: /// Construct a DbgVariable. /// /// Creates a variable without any DW_AT_location. Call \a initializeMMI() /// for MMI entries, or \a initializeDbgValue() for DBG_VALUE instructions. - DbgVariable(const DILocalVariable *V, const DILocation *IA, DwarfDebug *DD) - : Var(V), IA(IA), DD(DD) {} + DbgVariable(const DILocalVariable *V, const DILocation *IA) + : Var(V), IA(IA) {} /// Initialize from the MMI table. void initializeMMI(const DIExpression *E, int FI) { @@ -111,6 +109,10 @@ public: const DILocalVariable *getVariable() const { return Var; } const DILocation *getInlinedAt() const { return IA; } ArrayRef<const DIExpression *> getExpression() const { return Expr; } + const DIExpression *getSingleExpression() const { + assert(MInsn && Expr.size() <= 1); + return Expr.size() ? Expr[0] : nullptr; + } void setDIE(DIE &D) { TheDIE = &D; } DIE *getDIE() const { return TheDIE; } void setDebugLocListIndex(unsigned O) { DebugLocListIndex = O; } @@ -174,9 +176,9 @@ public: const DIType *getType() const; private: - /// Look in the DwarfDebug map for the MDNode that - /// corresponds to the reference. - template <typename T> T *resolve(TypedDINodeRef<T> Ref) const; + template <typename T> T *resolve(TypedDINodeRef<T> Ref) const { + return Ref.resolve(); + } }; @@ -188,22 +190,13 @@ struct SymbolCU { }; /// Collects and handles dwarf debug information. -class DwarfDebug : public AsmPrinterHandler { - /// Target of Dwarf emission. - AsmPrinter *Asm; - - /// Collected machine module information. - MachineModuleInfo *MMI; - +class DwarfDebug : public DebugHandlerBase { /// All DIEValues are allocated through this allocator. BumpPtrAllocator DIEValueAllocator; /// Maps MDNode with its corresponding DwarfCompileUnit. MapVector<const MDNode *, DwarfCompileUnit *> CUMap; - /// Maps subprogram MDNode with its corresponding DwarfCompileUnit. - MapVector<const MDNode *, DwarfCompileUnit *> SPMap; - /// Maps a CU DIE with its corresponding DwarfCompileUnit. DenseMap<const DIE *, DwarfCompileUnit *> CUDieMap; @@ -213,8 +206,6 @@ class DwarfDebug : public AsmPrinterHandler { /// Size of each symbol emitted (for those symbols that have a specific size). DenseMap<const MCSymbol *, uint64_t> SymSize; - LexicalScopes LScopes; - /// Collection of abstract variables. DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> AbstractVariables; SmallVector<std::unique_ptr<DbgVariable>, 64> ConcreteVariables; @@ -227,32 +218,9 @@ class DwarfDebug : public AsmPrinterHandler { /// create DIEs. SmallPtrSet<const MDNode *, 16> ProcessedSPNodes; - /// Maps instruction with label emitted before instruction. - DenseMap<const MachineInstr *, MCSymbol *> LabelsBeforeInsn; - - /// Maps instruction with label emitted after instruction. - DenseMap<const MachineInstr *, MCSymbol *> LabelsAfterInsn; - - /// History of DBG_VALUE and clobber instructions for each user - /// variable. Variables are listed in order of appearance. - DbgValueHistoryMap DbgValues; - - /// Previous instruction's location information. This is used to - /// determine label location to indicate scope boundries in dwarf - /// debug info. - DebugLoc PrevInstLoc; - MCSymbol *PrevLabel; - - /// This location indicates end of function prologue and beginning of - /// function body. - DebugLoc PrologEndLoc; - /// If nonnull, stores the current machine function we're processing. const MachineFunction *CurFn; - /// If nonnull, stores the current machine instruction we're processing. - const MachineInstr *CurMI; - /// If nonnull, stores the CU in which the previous subprogram was contained. const DwarfCompileUnit *PrevCU; @@ -266,9 +234,9 @@ class DwarfDebug : public AsmPrinterHandler { /// Holders for the various debug information flags that we might need to /// have exposed. See accessor functions below for description. - /// Map from MDNodes for user-defined types to the type units that - /// describe them. - DenseMap<const MDNode *, const DwarfTypeUnit *> DwarfTypeUnits; + /// Map from MDNodes for user-defined types to their type signatures. Also + /// used to keep track of which types we have emitted type units for. + DenseMap<const MDNode *, uint64_t> TypeSignatures; SmallVector< std::pair<std::unique_ptr<DwarfTypeUnit>, const DICompositeType *>, 1> @@ -280,18 +248,19 @@ class DwarfDebug : public AsmPrinterHandler { /// Whether to use the GNU TLS opcode (instead of the standard opcode). bool UseGNUTLSOpcode; - /// Whether to emit DW_AT_[MIPS_]linkage_name. - bool UseLinkageNames; + /// Whether to use DWARF 2 bitfields (instead of the DWARF 4 format). + bool UseDWARF2Bitfields; + + /// Whether to emit all linkage names, or just abstract subprograms. + bool UseAllLinkageNames; /// Version of dwarf we're emitting. unsigned DwarfVersion; - /// Maps from a type identifier to the actual MDNode. - DITypeIdentifierMap TypeIdentifierMap; - /// DWARF5 Experimental Options /// @{ bool HasDwarfAccelTables; + bool HasAppleExtensionAttributes; bool HasSplitDwarf; /// Separated Dwarf Variables @@ -324,9 +293,19 @@ class DwarfDebug : public AsmPrinterHandler { // Identify a debugger for "tuning" the debug info. DebuggerKind DebuggerTuning; + /// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger. + /// + /// Returns whether we are "tuning" for a given debugger. + /// Should be used only within the constructor, to set feature flags. + /// @{ + bool tuneForGDB() const { return DebuggerTuning == DebuggerKind::GDB; } + bool tuneForLLDB() const { return DebuggerTuning == DebuggerKind::LLDB; } + bool tuneForSCE() const { return DebuggerTuning == DebuggerKind::SCE; } + /// @} + MCDwarfDwoLineTable *getDwoLineTable(const DwarfCompileUnit &); - const SmallVectorImpl<std::unique_ptr<DwarfUnit>> &getUnits() { + const SmallVectorImpl<std::unique_ptr<DwarfCompileUnit>> &getUnits() { return InfoHolder.getUnits(); } @@ -347,9 +326,6 @@ class DwarfDebug : public AsmPrinterHandler { /// Construct a DIE for this abstract scope. void constructAbstractSubprogramScopeDIE(LexicalScope *Scope); - /// Collect info for variables that were optimized out. - void collectDeadVariables(); - void finishVariableDefinitions(); void finishSubprogramDefinitions(); @@ -397,7 +373,7 @@ class DwarfDebug : public AsmPrinterHandler { bool GnuStyle, MCSection *PSec, StringRef Name, const StringMap<const DIE *> &(DwarfCompileUnit::*Accessor)() const); - /// Emit visible names into a debug str section. + /// Emit null-terminated strings into a debug str section. void emitDebugStr(); /// Emit variable locations into a debug loc section. @@ -414,17 +390,15 @@ class DwarfDebug : public AsmPrinterHandler { /// Emit macros into a debug macinfo section. void emitDebugMacinfo(); - unsigned emitMacro(AsmStreamerBase *AS, DIMacro &M); - unsigned emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F, - DwarfCompileUnit &U); - unsigned handleMacroNodes(AsmStreamerBase *AS, DIMacroNodeArray Nodes, - DwarfCompileUnit &U); + void emitMacro(DIMacro &M); + void emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U); + void handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U); /// DWARF 5 Experimental Split Dwarf Emitters /// Initialize common features of skeleton units. void initSkeletonUnit(const DwarfUnit &U, DIE &Die, - std::unique_ptr<DwarfUnit> NewU); + std::unique_ptr<DwarfCompileUnit> NewU); /// Construct the split debug info compile unit for the debug info /// section. @@ -460,10 +434,6 @@ class DwarfDebug : public AsmPrinterHandler { void recordSourceLine(unsigned Line, unsigned Col, const MDNode *Scope, unsigned Flags); - /// Indentify instructions that are marking the beginning of or - /// ending of a scope. - void identifyScopeMarkers(); - /// Populate LexicalScope entries with variables' info. void collectVariableInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, DenseSet<InlinedVariable> &ProcessedVars); @@ -477,16 +447,6 @@ class DwarfDebug : public AsmPrinterHandler { /// by MMI. void collectVariableInfoFromMMITable(DenseSet<InlinedVariable> &P); - /// Ensure that a label will be emitted before MI. - void requestLabelBeforeInsn(const MachineInstr *MI) { - LabelsBeforeInsn.insert(std::make_pair(MI, nullptr)); - } - - /// Ensure that a label will be emitted after MI. - void requestLabelAfterInsn(const MachineInstr *MI) { - LabelsAfterInsn.insert(std::make_pair(MI, nullptr)); - } - public: //===--------------------------------------------------------------------===// // Main entry points. @@ -511,9 +471,6 @@ public: /// Process beginning of an instruction. void beginInstruction(const MachineInstr *MI) override; - /// Process end of an instruction. - void endInstruction() override; - /// Perform an MD5 checksum of \p Identifier and return the lower 64 bits. static uint64_t makeTypeSignature(StringRef Identifier); @@ -531,21 +488,17 @@ public: SymSize[Sym] = Size; } - /// Returns whether to emit DW_AT_[MIPS_]linkage_name. - bool useLinkageNames() const { return UseLinkageNames; } + /// Returns whether we should emit all DW_AT_[MIPS_]linkage_name. + /// If not, we still might emit certain cases. + bool useAllLinkageNames() const { return UseAllLinkageNames; } /// Returns whether to use DW_OP_GNU_push_tls_address, instead of the /// standard DW_OP_form_tls_address opcode bool useGNUTLSOpcode() const { return UseGNUTLSOpcode; } - /// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger. - /// - /// Returns whether we are "tuning" for a given debugger. - /// @{ - bool tuneForGDB() const { return DebuggerTuning == DebuggerKind::GDB; } - bool tuneForLLDB() const { return DebuggerTuning == DebuggerKind::LLDB; } - bool tuneForSCE() const { return DebuggerTuning == DebuggerKind::SCE; } - /// @} + /// Returns whether to use the DWARF2 format for bitfields instyead of the + /// DWARF4 format. + bool useDWARF2Bitfields() const { return UseDWARF2Bitfields; } // Experimental DWARF5 features. @@ -553,6 +506,10 @@ public: /// use to accelerate lookup. bool useDwarfAccelTables() const { return HasDwarfAccelTables; } + bool useAppleExtensionAttributes() const { + return HasAppleExtensionAttributes; + } + /// Returns whether or not to change the current debug info for the /// split dwarf proposal support. bool useSplitDwarf() const { return HasSplitDwarf; } @@ -577,12 +534,7 @@ public: /// Find the MDNode for the given reference. template <typename T> T *resolve(TypedDINodeRef<T> Ref) const { - return Ref.resolve(TypeIdentifierMap); - } - - /// Return the TypeIdentifierMap. - const DITypeIdentifierMap &getTypeIdentifierMap() const { - return TypeIdentifierMap; + return Ref.resolve(); } /// Find the DwarfCompileUnit for the given CU Die. @@ -608,12 +560,6 @@ public: /// going to be null. bool isLexicalScopeDIENull(LexicalScope *Scope); - /// Return Label preceding the instruction. - MCSymbol *getLabelBeforeInsn(const MachineInstr *MI); - - /// Return Label immediately following the instruction. - MCSymbol *getLabelAfterInsn(const MachineInstr *MI); - // FIXME: Sink these functions down into DwarfFile/Dwarf*Unit. SmallPtrSet<const MDNode *, 16> &getProcessedSPNodes() { diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfException.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfException.h index f4667b4..8287f28 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfException.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfException.h @@ -16,6 +16,7 @@ #include "EHStreamer.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/MC/MCDwarf.h" namespace llvm { class MachineFunction; @@ -29,12 +30,16 @@ protected: bool shouldEmitCFI; void markFunctionEnd() override; + void endFragment() override; }; class LLVM_LIBRARY_VISIBILITY DwarfCFIException : public DwarfCFIExceptionBase { /// Per-function flag to indicate if .cfi_personality should be emitted. bool shouldEmitPersonality; + /// Per-function flag to indicate if .cfi_personality must be emitted. + bool forceEmitPersonality; + /// Per-function flag to indicate if .cfi_lsda should be emitted. bool shouldEmitLSDA; @@ -59,6 +64,9 @@ public: /// Gather and emit post-function exception information. void endFunction(const MachineFunction *) override; + + void beginFragment(const MachineBasicBlock *MBB, + ExceptionSymbolProvider ESP) override; }; class LLVM_LIBRARY_VISIBILITY ARMException : public DwarfCFIExceptionBase { diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index 7b5b831..7dbc6cb 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -65,8 +65,9 @@ void DwarfExpression::AddShr(unsigned ShiftBy) { EmitOp(dwarf::DW_OP_shr); } -bool DwarfExpression::AddMachineRegIndirect(unsigned MachineReg, int Offset) { - if (isFrameRegister(MachineReg)) { +bool DwarfExpression::AddMachineRegIndirect(const TargetRegisterInfo &TRI, + unsigned MachineReg, int Offset) { + if (isFrameRegister(TRI, MachineReg)) { // If variable offset is based in frame register then use fbreg. EmitOp(dwarf::DW_OP_fbreg); EmitSigned(Offset); @@ -81,7 +82,8 @@ bool DwarfExpression::AddMachineRegIndirect(unsigned MachineReg, int Offset) { return true; } -bool DwarfExpression::AddMachineRegPiece(unsigned MachineReg, +bool DwarfExpression::AddMachineRegPiece(const TargetRegisterInfo &TRI, + unsigned MachineReg, unsigned PieceSizeInBits, unsigned PieceOffsetInBits) { if (!TRI.isPhysicalRegister(MachineReg)) @@ -159,29 +161,37 @@ bool DwarfExpression::AddMachineRegPiece(unsigned MachineReg, return CurPos > PieceOffsetInBits; } -void DwarfExpression::AddSignedConstant(int Value) { - EmitOp(dwarf::DW_OP_consts); - EmitSigned(Value); - // The proper way to describe a constant value is - // DW_OP_constu <const>, DW_OP_stack_value. - // Unfortunately, DW_OP_stack_value was not available until DWARF-4, - // so we will continue to generate DW_OP_constu <const> for DWARF-2 - // and DWARF-3. Technically, this is incorrect since DW_OP_const <const> - // actually describes a value at a constant addess, not a constant value. - // However, in the past there was no better way to describe a constant - // value, so the producers and consumers started to rely on heuristics - // to disambiguate the value vs. location status of the expression. - // See PR21176 for more details. +void DwarfExpression::AddStackValue() { if (DwarfVersion >= 4) EmitOp(dwarf::DW_OP_stack_value); } -void DwarfExpression::AddUnsignedConstant(unsigned Value) { +void DwarfExpression::AddSignedConstant(int64_t Value) { + EmitOp(dwarf::DW_OP_consts); + EmitSigned(Value); + AddStackValue(); +} + +void DwarfExpression::AddUnsignedConstant(uint64_t Value) { EmitOp(dwarf::DW_OP_constu); EmitUnsigned(Value); - // cf. comment in DwarfExpression::AddSignedConstant(). - if (DwarfVersion >= 4) - EmitOp(dwarf::DW_OP_stack_value); + AddStackValue(); +} + +void DwarfExpression::AddUnsignedConstant(const APInt &Value) { + unsigned Size = Value.getBitWidth(); + const uint64_t *Data = Value.getRawData(); + + // Chop it up into 64-bit pieces, because that's the maximum that + // AddUnsignedConstant takes. + unsigned Offset = 0; + while (Offset < Size) { + AddUnsignedConstant(*Data++); + if (Offset == 0 && Size <= 64) + break; + AddOpPiece(std::min(Size-Offset, 64u), Offset); + Offset += 64; + } } static unsigned getOffsetOrZero(unsigned OffsetInBits, @@ -192,13 +202,14 @@ static unsigned getOffsetOrZero(unsigned OffsetInBits, return OffsetInBits; } -bool DwarfExpression::AddMachineRegExpression(const DIExpression *Expr, +bool DwarfExpression::AddMachineRegExpression(const TargetRegisterInfo &TRI, + const DIExpression *Expr, unsigned MachineReg, unsigned PieceOffsetInBits) { auto I = Expr->expr_op_begin(); auto E = Expr->expr_op_end(); if (I == E) - return AddMachineRegPiece(MachineReg); + return AddMachineRegPiece(TRI, MachineReg); // Pattern-match combinations for which more efficient representations exist // first. @@ -208,7 +219,7 @@ bool DwarfExpression::AddMachineRegExpression(const DIExpression *Expr, unsigned OffsetInBits = I->getArg(0); unsigned SizeInBits = I->getArg(1); // Piece always comes at the end of the expression. - return AddMachineRegPiece(MachineReg, SizeInBits, + return AddMachineRegPiece(TRI, MachineReg, SizeInBits, getOffsetOrZero(OffsetInBits, PieceOffsetInBits)); } case dwarf::DW_OP_plus: @@ -219,15 +230,15 @@ bool DwarfExpression::AddMachineRegExpression(const DIExpression *Expr, if (N != E && N->getOp() == dwarf::DW_OP_deref) { unsigned Offset = I->getArg(0); ValidReg = AddMachineRegIndirect( - MachineReg, I->getOp() == dwarf::DW_OP_plus ? Offset : -Offset); + TRI, MachineReg, I->getOp() == dwarf::DW_OP_plus ? Offset : -Offset); std::advance(I, 2); break; } else - ValidReg = AddMachineRegPiece(MachineReg); + ValidReg = AddMachineRegPiece(TRI, MachineReg); } case dwarf::DW_OP_deref: { // [DW_OP_reg,DW_OP_deref] --> [DW_OP_breg]. - ValidReg = AddMachineRegIndirect(MachineReg); + ValidReg = AddMachineRegIndirect(TRI, MachineReg); ++I; break; } diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h index 78ec937..5fff28d 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -31,13 +31,10 @@ class DIELoc; class DwarfExpression { protected: // Various convenience accessors that extract things out of AsmPrinter. - const TargetRegisterInfo &TRI; unsigned DwarfVersion; public: - DwarfExpression(const TargetRegisterInfo &TRI, - unsigned DwarfVersion) - : TRI(TRI), DwarfVersion(DwarfVersion) {} + DwarfExpression(unsigned DwarfVersion) : DwarfVersion(DwarfVersion) {} virtual ~DwarfExpression() {} /// Output a dwarf operand and an optional assembler comment. @@ -48,7 +45,7 @@ public: virtual void EmitUnsigned(uint64_t Value) = 0; /// Return whether the given machine register is the frame register in the /// current function. - virtual bool isFrameRegister(unsigned MachineReg) = 0; + virtual bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) = 0; /// Emit a dwarf register operation. void AddReg(int DwarfReg, const char *Comment = nullptr); @@ -61,10 +58,24 @@ public: void AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits = 0); /// Emit a shift-right dwarf expression. void AddShr(unsigned ShiftBy); + /// Emit a DW_OP_stack_value, if supported. + /// + /// The proper way to describe a constant value is + /// DW_OP_constu <const>, DW_OP_stack_value. + /// Unfortunately, DW_OP_stack_value was not available until DWARF-4, + /// so we will continue to generate DW_OP_constu <const> for DWARF-2 + /// and DWARF-3. Technically, this is incorrect since DW_OP_const <const> + /// actually describes a value at a constant addess, not a constant value. + /// However, in the past there was no better way to describe a constant + /// value, so the producers and consumers started to rely on heuristics + /// to disambiguate the value vs. location status of the expression. + /// See PR21176 for more details. + void AddStackValue(); /// Emit an indirect dwarf register operation for the given machine register. /// \return false if no DWARF register exists for MachineReg. - bool AddMachineRegIndirect(unsigned MachineReg, int Offset = 0); + bool AddMachineRegIndirect(const TargetRegisterInfo &TRI, unsigned MachineReg, + int Offset = 0); /// \brief Emit a partial DWARF register operation. /// \param MachineReg the register @@ -80,20 +91,24 @@ public: /// subregisters that alias the register. /// /// \return false if no DWARF register exists for MachineReg. - bool AddMachineRegPiece(unsigned MachineReg, unsigned PieceSizeInBits = 0, + bool AddMachineRegPiece(const TargetRegisterInfo &TRI, unsigned MachineReg, + unsigned PieceSizeInBits = 0, unsigned PieceOffsetInBits = 0); /// Emit a signed constant. - void AddSignedConstant(int Value); + void AddSignedConstant(int64_t Value); + /// Emit an unsigned constant. + void AddUnsignedConstant(uint64_t Value); /// Emit an unsigned constant. - void AddUnsignedConstant(unsigned Value); + void AddUnsignedConstant(const APInt &Value); /// \brief Emit an entire expression on top of a machine register location. /// /// \param PieceOffsetInBits If this is one piece out of a fragmented /// location, this is the offset of the piece inside the entire variable. /// \return false if no DWARF register exists for MachineReg. - bool AddMachineRegExpression(const DIExpression *Expr, unsigned MachineReg, + bool AddMachineRegExpression(const TargetRegisterInfo &TRI, + const DIExpression *Expr, unsigned MachineReg, unsigned PieceOffsetInBits = 0); /// Emit a the operations remaining the DIExpressionIterator I. /// \param PieceOffsetInBits If this is one piece out of a fragmented @@ -108,14 +123,14 @@ class DebugLocDwarfExpression : public DwarfExpression { ByteStreamer &BS; public: - DebugLocDwarfExpression(const TargetRegisterInfo &TRI, - unsigned DwarfVersion, ByteStreamer &BS) - : DwarfExpression(TRI, DwarfVersion), BS(BS) {} + DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS) + : DwarfExpression(DwarfVersion), BS(BS) {} void EmitOp(uint8_t Op, const char *Comment = nullptr) override; void EmitSigned(int64_t Value) override; void EmitUnsigned(uint64_t Value) override; - bool isFrameRegister(unsigned MachineReg) override; + bool isFrameRegister(const TargetRegisterInfo &TRI, + unsigned MachineReg) override; }; /// DwarfExpression implementation for singular DW_AT_location. @@ -129,7 +144,8 @@ public: void EmitOp(uint8_t Op, const char *Comment = nullptr) override; void EmitSigned(int64_t Value) override; void EmitUnsigned(uint64_t Value) override; - bool isFrameRegister(unsigned MachineReg) override; + bool isFrameRegister(const TargetRegisterInfo &TRI, + unsigned MachineReg) override; }; } diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp index 51b27b4..e9fe98a 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "DwarfFile.h" +#include "DwarfCompileUnit.h" #include "DwarfDebug.h" #include "DwarfUnit.h" #include "llvm/ADT/STLExtras.h" @@ -50,22 +51,25 @@ DIEAbbrev &DwarfFile::assignAbbrevNumber(DIE &Die) { return *New; } -void DwarfFile::addUnit(std::unique_ptr<DwarfUnit> U) { +void DwarfFile::addUnit(std::unique_ptr<DwarfCompileUnit> U) { CUs.push_back(std::move(U)); } // Emit the various dwarf units to the unit section USection with // the abbreviations going into ASection. void DwarfFile::emitUnits(bool UseOffsets) { - for (const auto &TheU : CUs) { - DIE &Die = TheU->getUnitDie(); - MCSection *USection = TheU->getSection(); - Asm->OutStreamer->SwitchSection(USection); + for (const auto &TheU : CUs) + emitUnit(TheU.get(), UseOffsets); +} - TheU->emitHeader(UseOffsets); +void DwarfFile::emitUnit(DwarfUnit *TheU, bool UseOffsets) { + DIE &Die = TheU->getUnitDie(); + MCSection *USection = TheU->getSection(); + Asm->OutStreamer->SwitchSection(USection); - Asm->emitDwarfDIE(Die); - } + TheU->emitHeader(UseOffsets); + + Asm->emitDwarfDIE(Die); } // Compute the size and offset for each DIE. @@ -77,17 +81,20 @@ void DwarfFile::computeSizeAndOffsets() { // DIE within each compile unit. All offsets are CU relative. for (const auto &TheU : CUs) { TheU->setDebugInfoOffset(SecOffset); + SecOffset += computeSizeAndOffsetsForUnit(TheU.get()); + } +} - // CU-relative offset is reset to 0 here. - unsigned Offset = sizeof(int32_t) + // Length of Unit Info - TheU->getHeaderSize(); // Unit-specific headers +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 - // EndOffset here is CU-relative, after laying out - // all of the CU DIE. - unsigned EndOffset = computeSizeAndOffset(TheU->getUnitDie(), Offset); - SecOffset += EndOffset; - } + // The return value here is CU-relative, after laying out + // all of the CU DIE. + return computeSizeAndOffset(TheU->getUnitDie(), Offset); } + // Compute the size and offset of a DIE. The offset is relative to start of the // CU. It returns the offset after laying out the DIE. unsigned DwarfFile::computeSizeAndOffset(DIE &Die, unsigned Offset) { diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h index 8402027..b73d89b 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -16,14 +16,15 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/IR/Metadata.h" #include "llvm/Support/Allocator.h" #include <memory> -#include <string> #include <vector> namespace llvm { class AsmPrinter; class DbgVariable; +class DwarfCompileUnit; class DwarfUnit; class DIEAbbrev; class MCSymbol; @@ -46,7 +47,7 @@ class DwarfFile { std::vector<DIEAbbrev *> Abbreviations; // A pointer to all units in the section. - SmallVector<std::unique_ptr<DwarfUnit>, 1> CUs; + SmallVector<std::unique_ptr<DwarfCompileUnit>, 1> CUs; DwarfStringPool StrPool; @@ -66,7 +67,9 @@ public: ~DwarfFile(); - const SmallVectorImpl<std::unique_ptr<DwarfUnit>> &getUnits() { return CUs; } + const SmallVectorImpl<std::unique_ptr<DwarfCompileUnit>> &getUnits() { + return CUs; + } /// \brief Compute the size and offset of a DIE given an incoming Offset. unsigned computeSizeAndOffset(DIE &Die, unsigned Offset); @@ -74,6 +77,10 @@ public: /// \brief Compute the size and offset of all the DIEs. void computeSizeAndOffsets(); + /// \brief Compute the size and offset of all the DIEs in the given unit. + /// \returns The size of the root DIE. + unsigned computeSizeAndOffsetsForUnit(DwarfUnit *TheU); + /// Define a unique number for the abbreviation. /// /// Compute the abbreviation for \c Die, look up its unique number, and @@ -81,12 +88,15 @@ public: DIEAbbrev &assignAbbrevNumber(DIE &Die); /// \brief Add a unit to the list of CUs. - void addUnit(std::unique_ptr<DwarfUnit> U); + void addUnit(std::unique_ptr<DwarfCompileUnit> U); /// \brief Emit all of the units to the section listed with the given /// abbreviation section. void emitUnits(bool UseOffsets); + /// \brief Emit the given unit to its section. + void emitUnit(DwarfUnit *U, bool UseOffsets); + /// \brief Emit a set of abbreviations to the specific section. void emitAbbrevs(MCSection *); diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index d75fea5..4100d72 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -46,9 +46,8 @@ GenerateDwarfTypeUnits("generate-type-units", cl::Hidden, DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU, DIELoc &DIE) - : DwarfExpression(*AP.MF->getSubtarget().getRegisterInfo(), - AP.getDwarfDebug()->getDwarfVersion()), - AP(AP), DU(DU), DIE(DIE) {} + : DwarfExpression(AP.getDwarfDebug()->getDwarfVersion()), AP(AP), DU(DU), + DIE(DIE) {} void DIEDwarfExpression::EmitOp(uint8_t Op, const char* Comment) { DU.addUInt(DIE, dwarf::DW_FORM_data1, Op); @@ -59,25 +58,24 @@ void DIEDwarfExpression::EmitSigned(int64_t Value) { void DIEDwarfExpression::EmitUnsigned(uint64_t Value) { DU.addUInt(DIE, dwarf::DW_FORM_udata, Value); } -bool DIEDwarfExpression::isFrameRegister(unsigned MachineReg) { +bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, + unsigned MachineReg) { return MachineReg == TRI.getFrameRegister(*AP.MF); } -DwarfUnit::DwarfUnit(unsigned UID, dwarf::Tag UnitTag, - const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, - DwarfFile *DWU) - : UniqueID(UID), CUNode(Node), - UnitDie(*DIE::get(DIEValueAllocator, UnitTag)), DebugInfoOffset(0), - Asm(A), DD(DW), DU(DWU), IndexTyDie(nullptr), Section(nullptr) { +DwarfUnit::DwarfUnit(dwarf::Tag UnitTag, const DICompileUnit *Node, + AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU) + : CUNode(Node), UnitDie(*DIE::get(DIEValueAllocator, UnitTag)), Asm(A), + DD(DW), DU(DWU), IndexTyDie(nullptr), Section(nullptr) { assert(UnitTag == dwarf::DW_TAG_compile_unit || UnitTag == dwarf::DW_TAG_type_unit); } -DwarfTypeUnit::DwarfTypeUnit(unsigned UID, DwarfCompileUnit &CU, AsmPrinter *A, +DwarfTypeUnit::DwarfTypeUnit(DwarfCompileUnit &CU, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU, MCDwarfDwoLineTable *SplitLineTable) - : DwarfUnit(UID, dwarf::DW_TAG_type_unit, CU.getCUNode(), A, DW, DWU), - CU(CU), SplitLineTable(SplitLineTable) { + : DwarfUnit(dwarf::DW_TAG_type_unit, CU.getCUNode(), A, DW, DWU), CU(CU), + SplitLineTable(SplitLineTable) { if (SplitLineTable) addSectionOffset(UnitDie, dwarf::DW_AT_stmt_list, 0); } @@ -268,7 +266,7 @@ void DwarfUnit::addDIEEntry(DIE &Die, dwarf::Attribute Attribute, DIE &Entry) { addDIEEntry(Die, Attribute, DIEEntry(Entry)); } -void DwarfUnit::addDIETypeSignature(DIE &Die, const DwarfTypeUnit &Type) { +void DwarfUnit::addDIETypeSignature(DIE &Die, uint64_t Signature) { // Flag the type unit reference as a declaration so that if it contains // members (implicit special members, static data member definitions, member // declarations for definitions in this CU, etc) consumers don't get confused @@ -276,7 +274,7 @@ void DwarfUnit::addDIETypeSignature(DIE &Die, const DwarfTypeUnit &Type) { addFlag(Die, dwarf::DW_AT_declaration); Die.addValue(DIEValueAllocator, dwarf::DW_AT_signature, - dwarf::DW_FORM_ref_sig8, DIETypeSignature(Type)); + dwarf::DW_FORM_ref_sig8, DIEInteger(Signature)); } void DwarfUnit::addDIETypeSignature(DIE &Die, dwarf::Attribute Attribute, @@ -370,14 +368,16 @@ void DwarfUnit::addSourceLine(DIE &Die, const DINamespace *NS) { bool DwarfUnit::addRegisterOpPiece(DIELoc &TheDie, unsigned Reg, unsigned SizeInBits, unsigned OffsetInBits) { DIEDwarfExpression Expr(*Asm, *this, TheDie); - Expr.AddMachineRegPiece(Reg, SizeInBits, OffsetInBits); + Expr.AddMachineRegPiece(*Asm->MF->getSubtarget().getRegisterInfo(), Reg, + SizeInBits, OffsetInBits); return true; } bool DwarfUnit::addRegisterOffset(DIELoc &TheDie, unsigned Reg, int64_t Offset) { DIEDwarfExpression Expr(*Asm, *this, TheDie); - return Expr.AddMachineRegIndirect(Reg, Offset); + return Expr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(), + Reg, Offset); } /* Byref variables, in Blocks, are declared by the programmer as "SomeType @@ -561,32 +561,6 @@ static bool isUnsignedDIType(DwarfDebug *DD, const DIType *Ty) { Ty->getTag() == dwarf::DW_TAG_unspecified_type; } -/// If this type is derived from a base type then return base type size. -static uint64_t getBaseTypeSize(DwarfDebug *DD, const DIDerivedType *Ty) { - unsigned Tag = Ty->getTag(); - - if (Tag != dwarf::DW_TAG_member && Tag != dwarf::DW_TAG_typedef && - Tag != dwarf::DW_TAG_const_type && Tag != dwarf::DW_TAG_volatile_type && - Tag != dwarf::DW_TAG_restrict_type) - return Ty->getSizeInBits(); - - auto *BaseType = DD->resolve(Ty->getBaseType()); - - assert(BaseType && "Unexpected invalid base type"); - - // If this is a derived type, go ahead and get the base type, unless it's a - // reference then it's just the size of the field. Pointer types have no need - // of this since they're a different type of qualification on the type. - if (BaseType->getTag() == dwarf::DW_TAG_reference_type || - BaseType->getTag() == dwarf::DW_TAG_rvalue_reference_type) - return Ty->getSizeInBits(); - - if (auto *DT = dyn_cast<DIDerivedType>(BaseType)) - return getBaseTypeSize(DD, DT); - - return BaseType->getSizeInBits(); -} - void DwarfUnit::addConstantFPValue(DIE &Die, const MachineOperand &MO) { assert(MO.isFPImm() && "Invalid machine operand!"); DIEBlock *Block = new (DIEValueAllocator) DIEBlock; @@ -667,7 +641,7 @@ void DwarfUnit::addConstantValue(DIE &Die, const APInt &Val, bool Unsigned) { } void DwarfUnit::addLinkageName(DIE &Die, StringRef LinkageName) { - if (!LinkageName.empty() && DD->useLinkageNames()) + if (!LinkageName.empty()) addString(Die, DD->getDwarfVersion() >= 4 ? dwarf::DW_AT_linkage_name : dwarf::DW_AT_MIPS_linkage_name, @@ -720,8 +694,6 @@ DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) { return nullptr; auto *Ty = cast<DIType>(TyNode); - assert(Ty == resolve(Ty->getRef()) && - "type was not uniqued, possible ODR violation."); // DW_TAG_restrict_type is not supported in DWARF2 if (Ty->getTag() == dwarf::DW_TAG_restrict_type && DD->getDwarfVersion() <= 2) @@ -903,6 +875,11 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy) { Language == dwarf::DW_LANG_ObjC)) addFlag(Buffer, dwarf::DW_AT_prototyped); + // Add a DW_AT_calling_convention if this has an explicit convention. + if (CTy->getCC() && CTy->getCC() != dwarf::DW_CC_normal) + addUInt(Buffer, dwarf::DW_AT_calling_convention, dwarf::DW_FORM_data1, + CTy->getCC()); + if (CTy->isLValueReference()) addFlag(Buffer, dwarf::DW_AT_reference); @@ -1050,14 +1027,18 @@ void DwarfUnit::constructTemplateValueParameterDIE( if (ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Val)) addConstantValue(ParamDIE, CI, resolve(VP->getType())); else if (GlobalValue *GV = mdconst::dyn_extract<GlobalValue>(Val)) { - // For declaration non-type template parameters (such as global values and - // functions) - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - addOpAddress(*Loc, Asm->getSymbol(GV)); - // Emit DW_OP_stack_value to use the address as the immediate value of the - // parameter, rather than a pointer to it. - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_stack_value); - addBlock(ParamDIE, dwarf::DW_AT_location, Loc); + // We cannot describe the location of dllimport'd entities: the + // computation of their address requires loads from the IAT. + if (!GV->hasDLLImportStorageClass()) { + // For declaration non-type template parameters (such as global values + // and functions) + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + addOpAddress(*Loc, Asm->getSymbol(GV)); + // Emit DW_OP_stack_value to use the address as the immediate value of + // the parameter, rather than a pointer to it. + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_stack_value); + addBlock(ParamDIE, dwarf::DW_AT_location, Loc); + } } else if (VP->getTag() == dwarf::DW_TAG_GNU_template_template_param) { assert(isa<MDString>(Val)); addString(ParamDIE, dwarf::DW_AT_GNU_template_name, @@ -1171,7 +1152,9 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP, assert(((LinkageName.empty() || DeclLinkageName.empty()) || LinkageName == DeclLinkageName) && "decl has a linkage name and it is different"); - if (DeclLinkageName.empty()) + if (DeclLinkageName.empty() && + // Always emit it for abstract subprograms. + (DD->useAllLinkageNames() || DU->getAbstractSPDies().lookup(SP))) addLinkageName(SPDie, LinkageName); if (!DeclDie) @@ -1207,9 +1190,16 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, Language == dwarf::DW_LANG_ObjC)) addFlag(SPDie, dwarf::DW_AT_prototyped); + unsigned CC = 0; DITypeRefArray Args; - if (const DISubroutineType *SPTy = SP->getType()) + if (const DISubroutineType *SPTy = SP->getType()) { Args = SPTy->getTypeArray(); + CC = SPTy->getCC(); + } + + // Add a DW_AT_calling_convention if this has an explicit convention. + if (CC && CC != dwarf::DW_CC_normal) + addUInt(SPDie, dwarf::DW_AT_calling_convention, dwarf::DW_FORM_data1, CC); // Add a return type. If this is a type like a C/C++ void type we don't add a // return type. @@ -1220,10 +1210,12 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, unsigned VK = SP->getVirtuality(); if (VK) { addUInt(SPDie, dwarf::DW_AT_virtuality, dwarf::DW_FORM_data1, VK); - DIELoc *Block = getDIELoc(); - addUInt(*Block, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); - addUInt(*Block, dwarf::DW_FORM_udata, SP->getVirtualIndex()); - addBlock(SPDie, dwarf::DW_AT_vtable_elem_location, Block); + if (SP->getVirtualIndex() != -1u) { + DIELoc *Block = getDIELoc(); + addUInt(*Block, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); + addUInt(*Block, dwarf::DW_FORM_udata, SP->getVirtualIndex()); + addBlock(SPDie, dwarf::DW_AT_vtable_elem_location, Block); + } ContainingTypeMap.insert( std::make_pair(&SPDie, resolve(SP->getContainingType()))); } @@ -1242,11 +1234,13 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, if (!SP->isLocalToUnit()) addFlag(SPDie, dwarf::DW_AT_external); - if (SP->isOptimized()) - addFlag(SPDie, dwarf::DW_AT_APPLE_optimized); + if (DD->useAppleExtensionAttributes()) { + if (SP->isOptimized()) + addFlag(SPDie, dwarf::DW_AT_APPLE_optimized); - if (unsigned isa = Asm->getISAEncoding()) - addUInt(SPDie, dwarf::DW_AT_APPLE_isa, dwarf::DW_FORM_flag, isa); + if (unsigned isa = Asm->getISAEncoding()) + addUInt(SPDie, dwarf::DW_AT_APPLE_isa, dwarf::DW_FORM_flag, isa); + } if (SP->isLValueReference()) addFlag(SPDie, dwarf::DW_AT_reference); @@ -1388,58 +1382,49 @@ void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { addBlock(MemberDie, dwarf::DW_AT_data_member_location, VBaseLocationDie); } else { uint64_t Size = DT->getSizeInBits(); - uint64_t FieldSize = getBaseTypeSize(DD, DT); + uint64_t FieldSize = DD->getBaseTypeSize(DT); uint64_t OffsetInBytes; - if (FieldSize && Size != FieldSize) { + bool IsBitfield = FieldSize && Size != FieldSize; + if (IsBitfield) { // Handle bitfield, assume bytes are 8 bits. - addUInt(MemberDie, dwarf::DW_AT_byte_size, None, FieldSize/8); + if (DD->useDWARF2Bitfields()) + addUInt(MemberDie, dwarf::DW_AT_byte_size, None, FieldSize/8); addUInt(MemberDie, dwarf::DW_AT_bit_size, None, Size); - // - // The DWARF 2 DW_AT_bit_offset is counting the bits between the most - // significant bit of the aligned storage unit containing the bit field to - // the most significan bit of the bit field. - // - // FIXME: DWARF 4 states that DW_AT_data_bit_offset (which - // counts from the beginning, regardless of endianness) should - // be used instead. - // - // - // Struct Align Align Align - // v v v v - // +-----------+-----*-----+-----*-----+-- - // | ... |b1|b2|b3|b4| - // +-----------+-----*-----+-----*-----+-- - // | | |<-- Size ->| | - // |<---- Offset --->| |<--->| - // | | | \_ DW_AT_bit_offset (little endian) - // | |<--->| - // |<--------->| \_ StartBitOffset = DW_AT_bit_offset (big endian) - // \ = DW_AT_data_bit_offset (biendian) - // \_ OffsetInBytes + uint64_t Offset = DT->getOffsetInBits(); uint64_t Align = DT->getAlignInBits() ? DT->getAlignInBits() : FieldSize; uint64_t AlignMask = ~(Align - 1); // The bits from the start of the storage unit to the start of the field. uint64_t StartBitOffset = Offset - (Offset & AlignMask); - // The endian-dependent DWARF 2 offset. - uint64_t DwarfBitOffset = Asm->getDataLayout().isLittleEndian() - ? OffsetToAlignment(Offset + Size, Align) - : StartBitOffset; - // The byte offset of the field's aligned storage unit inside the struct. OffsetInBytes = (Offset - StartBitOffset) / 8; - addUInt(MemberDie, dwarf::DW_AT_bit_offset, None, DwarfBitOffset); - } else + + if (DD->useDWARF2Bitfields()) { + uint64_t HiMark = (Offset + FieldSize) & AlignMask; + uint64_t FieldOffset = (HiMark - FieldSize); + Offset -= FieldOffset; + + // Maybe we need to work from the other end. + if (Asm->getDataLayout().isLittleEndian()) + Offset = FieldSize - (Offset + Size); + + addUInt(MemberDie, dwarf::DW_AT_bit_offset, None, Offset); + OffsetInBytes = FieldOffset >> 3; + } else { + addUInt(MemberDie, dwarf::DW_AT_data_bit_offset, None, Offset); + } + } else { // This is not a bitfield. OffsetInBytes = DT->getOffsetInBits() / 8; + } if (DD->getDwarfVersion() <= 2) { DIELoc *MemLocationDie = new (DIEValueAllocator) DIELoc; addUInt(*MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); addUInt(*MemLocationDie, dwarf::DW_FORM_udata, OffsetInBytes); addBlock(MemberDie, dwarf::DW_AT_data_member_location, MemLocationDie); - } else + } else if (!IsBitfield || DD->useDWARF2Bitfields()) addUInt(MemberDie, dwarf::DW_AT_data_member_location, None, OffsetInBytes); } @@ -1524,8 +1509,11 @@ void DwarfUnit::emitHeader(bool UseOffsets) { // start of the section. Use a relocatable offset where needed to ensure // linking doesn't invalidate that offset. const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - Asm->emitDwarfSymbolReference(TLOF.getDwarfAbbrevSection()->getBeginSymbol(), - UseOffsets); + if (UseOffsets) + Asm->EmitInt32(0); + else + Asm->emitDwarfSymbolReference( + TLOF.getDwarfAbbrevSection()->getBeginSymbol(), false); Asm->OutStreamer->AddComment("Address Size (in bytes)"); Asm->EmitInt8(Asm->getDataLayout().getPointerSize()); diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 82760bf..e225f92 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -67,9 +67,6 @@ public: /// source file. class DwarfUnit { protected: - /// A numeric ID unique among all CUs in the module - unsigned UniqueID; - /// MDNode for the compile unit. const DICompileUnit *CUNode; @@ -79,9 +76,6 @@ protected: /// Unit debug information entry. DIE &UnitDie; - /// Offset of the UnitDie from beginning of debug info section. - unsigned DebugInfoOffset; - /// Target of Dwarf emission. AsmPrinter *Asm; @@ -110,8 +104,8 @@ protected: /// The section this unit will be emitted in. MCSection *Section; - DwarfUnit(unsigned UID, dwarf::Tag, const DICompileUnit *CU, AsmPrinter *A, - DwarfDebug *DW, DwarfFile *DWU); + DwarfUnit(dwarf::Tag, const DICompileUnit *CU, AsmPrinter *A, DwarfDebug *DW, + DwarfFile *DWU); bool applySubprogramDefinitionAttributes(const DISubprogram *SP, DIE &SPDie); @@ -127,14 +121,10 @@ public: // Accessors. AsmPrinter* getAsmPrinter() const { return Asm; } - unsigned getUniqueID() const { return UniqueID; } uint16_t getLanguage() const { return CUNode->getSourceLanguage(); } const DICompileUnit *getCUNode() const { return CUNode; } DIE &getUnitDie() { return UnitDie; } - unsigned getDebugInfoOffset() const { return DebugInfoOffset; } - void setDebugInfoOffset(unsigned DbgInfoOff) { DebugInfoOffset = DbgInfoOff; } - /// Return true if this compile unit has something to write out. bool hasContent() const { return UnitDie.hasChildren(); } @@ -221,7 +211,7 @@ public: void addDIEEntry(DIE &Die, dwarf::Attribute Attribute, DIEEntry Entry); /// Add a type's DW_AT_signature and set the declaration flag. - void addDIETypeSignature(DIE &Die, const DwarfTypeUnit &Type); + void addDIETypeSignature(DIE &Die, uint64_t Signature); /// Add an attribute containing the type signature for a unique identifier. void addDIETypeSignature(DIE &Die, dwarf::Attribute Attribute, StringRef Identifier); @@ -338,7 +328,7 @@ protected: /// Look in the DwarfDebug map for the MDNode that corresponds to the /// reference. template <typename T> T *resolve(TypedDINodeRef<T> Ref) const { - return DD->resolve(Ref); + return Ref.resolve(); } private: @@ -383,12 +373,10 @@ class DwarfTypeUnit : public DwarfUnit { bool isDwoUnit() const override; public: - DwarfTypeUnit(unsigned UID, DwarfCompileUnit &CU, AsmPrinter *A, - DwarfDebug *DW, DwarfFile *DWU, - MCDwarfDwoLineTable *SplitLineTable = nullptr); + DwarfTypeUnit(DwarfCompileUnit &CU, AsmPrinter *A, DwarfDebug *DW, + DwarfFile *DWU, MCDwarfDwoLineTable *SplitLineTable = nullptr); void setTypeSignature(uint64_t Signature) { TypeSignature = Signature; } - uint64_t getTypeSignature() const { return TypeSignature; } void setType(const DIE *Ty) { this->Ty = Ty; } /// Emit the header for this unit, not including the initial length field. diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h b/contrib/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h index c6a0e9d..080fdd1 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -22,7 +22,6 @@ struct LandingPadInfo; class MachineModuleInfo; class MachineInstr; class MachineFunction; -class AsmPrinter; class MCSymbol; class MCSymbolRefExpr; diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp deleted file mode 100644 index 1e2f55b..0000000 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp +++ /dev/null @@ -1,411 +0,0 @@ -//===-- llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp --*- C++ -*--===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains support for writing line tables info into COFF files. -// -//===----------------------------------------------------------------------===// - -#include "WinCodeViewLineTables.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/Support/COFF.h" - -namespace llvm { - -StringRef WinCodeViewLineTables::getFullFilepath(const MDNode *S) { - assert(S); - assert((isa<DICompileUnit>(S) || isa<DIFile>(S) || isa<DISubprogram>(S) || - isa<DILexicalBlockBase>(S)) && - "Unexpected scope info"); - - auto *Scope = cast<DIScope>(S); - StringRef Dir = Scope->getDirectory(), - Filename = Scope->getFilename(); - std::string &Filepath = - DirAndFilenameToFilepathMap[std::make_pair(Dir, Filename)]; - if (!Filepath.empty()) - return Filepath; - - // Clang emits directory and relative filename info into the IR, but CodeView - // operates on full paths. We could change Clang to emit full paths too, but - // that would increase the IR size and probably not needed for other users. - // For now, just concatenate and canonicalize the path here. - if (Filename.find(':') == 1) - Filepath = Filename; - else - Filepath = (Dir + "\\" + Filename).str(); - - // Canonicalize the path. We have to do it textually because we may no longer - // have access the file in the filesystem. - // First, replace all slashes with backslashes. - std::replace(Filepath.begin(), Filepath.end(), '/', '\\'); - - // Remove all "\.\" with "\". - size_t Cursor = 0; - while ((Cursor = Filepath.find("\\.\\", Cursor)) != std::string::npos) - Filepath.erase(Cursor, 2); - - // Replace all "\XXX\..\" with "\". Don't try too hard though as the original - // path should be well-formatted, e.g. start with a drive letter, etc. - Cursor = 0; - while ((Cursor = Filepath.find("\\..\\", Cursor)) != std::string::npos) { - // Something's wrong if the path starts with "\..\", abort. - if (Cursor == 0) - break; - - size_t PrevSlash = Filepath.rfind('\\', Cursor - 1); - if (PrevSlash == std::string::npos) - // Something's wrong, abort. - break; - - Filepath.erase(PrevSlash, Cursor + 3 - PrevSlash); - // The next ".." might be following the one we've just erased. - Cursor = PrevSlash; - } - - // Remove all duplicate backslashes. - Cursor = 0; - while ((Cursor = Filepath.find("\\\\", Cursor)) != std::string::npos) - Filepath.erase(Cursor, 1); - - return Filepath; -} - -void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL, - const MachineFunction *MF) { - const MDNode *Scope = DL.getScope(); - if (!Scope) - return; - unsigned LineNumber = DL.getLine(); - // Skip this line if it is longer than the maximum we can record. - if (LineNumber > COFF::CVL_MaxLineNumber) - return; - - unsigned ColumnNumber = DL.getCol(); - // Truncate the column number if it is longer than the maximum we can record. - if (ColumnNumber > COFF::CVL_MaxColumnNumber) - ColumnNumber = 0; - - StringRef Filename = getFullFilepath(Scope); - - // Skip this instruction if it has the same file:line as the previous one. - assert(CurFn); - if (!CurFn->Instrs.empty()) { - const InstrInfoTy &LastInstr = InstrInfo[CurFn->Instrs.back()]; - if (LastInstr.Filename == Filename && LastInstr.LineNumber == LineNumber && - LastInstr.ColumnNumber == ColumnNumber) - return; - } - FileNameRegistry.add(Filename); - - MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol(); - Asm->OutStreamer->EmitLabel(MCL); - CurFn->Instrs.push_back(MCL); - InstrInfo[MCL] = InstrInfoTy(Filename, LineNumber, ColumnNumber); -} - -WinCodeViewLineTables::WinCodeViewLineTables(AsmPrinter *AP) - : Asm(nullptr), CurFn(nullptr) { - MachineModuleInfo *MMI = AP->MMI; - - // 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()) - return; - - // Tell MMI that we have debug info. - MMI->setDebugInfoAvailability(true); - Asm = AP; -} - -void WinCodeViewLineTables::endModule() { - if (FnDebugInfo.empty()) - return; - - assert(Asm != nullptr); - Asm->OutStreamer->SwitchSection( - Asm->getObjFileLowering().getCOFFDebugSymbolsSection()); - Asm->EmitInt32(COFF::DEBUG_SECTION_MAGIC); - - // 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 - // aligned. - - // Emit per-function debug information. This code is extracted into a - // separate function for readability. - for (size_t I = 0, E = VisitedFunctions.size(); I != E; ++I) - emitDebugInfoForFunction(VisitedFunctions[I]); - - // This subsection holds a file index to offset in string table table. - Asm->OutStreamer->AddComment("File index to string table offset subsection"); - Asm->EmitInt32(COFF::DEBUG_INDEX_SUBSECTION); - size_t NumFilenames = FileNameRegistry.Infos.size(); - Asm->EmitInt32(8 * NumFilenames); - for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) { - StringRef Filename = FileNameRegistry.Filenames[I]; - // For each unique filename, just write its offset in the string table. - Asm->EmitInt32(FileNameRegistry.Infos[Filename].StartOffset); - // The function name offset is not followed by any additional data. - Asm->EmitInt32(0); - } - - // This subsection holds the string table. - Asm->OutStreamer->AddComment("String table"); - Asm->EmitInt32(COFF::DEBUG_STRING_TABLE_SUBSECTION); - Asm->EmitInt32(FileNameRegistry.LastOffset); - // The payload starts with a null character. - Asm->EmitInt8(0); - - for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) { - // Just emit unique filenames one by one, separated by a null character. - Asm->OutStreamer->EmitBytes(FileNameRegistry.Filenames[I]); - Asm->EmitInt8(0); - } - - // No more subsections. Fill with zeros to align the end of the section by 4. - Asm->OutStreamer->EmitFill((-FileNameRegistry.LastOffset) % 4, 0); - - clear(); -} - -static void EmitLabelDiff(MCStreamer &Streamer, - const MCSymbol *From, const MCSymbol *To, - unsigned int Size = 4) { - MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; - MCContext &Context = Streamer.getContext(); - const MCExpr *FromRef = MCSymbolRefExpr::create(From, Variant, Context), - *ToRef = MCSymbolRefExpr::create(To, Variant, Context); - const MCExpr *AddrDelta = - MCBinaryExpr::create(MCBinaryExpr::Sub, ToRef, FromRef, Context); - Streamer.EmitValue(AddrDelta, Size); -} - -void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) { - // For each function there is a separate subsection - // which holds the PC to file:line table. - const MCSymbol *Fn = Asm->getSymbol(GV); - assert(Fn); - - const FunctionInfo &FI = FnDebugInfo[GV]; - if (FI.Instrs.empty()) - return; - assert(FI.End && "Don't know where the function ends?"); - - StringRef GVName = GV->getName(); - StringRef FuncName; - if (auto *SP = getDISubprogram(GV)) - FuncName = SP->getDisplayName(); - - // FIXME Clang currently sets DisplayName to "bar" for a C++ - // "namespace_foo::bar" function, see PR21528. Luckily, dbghelp.dll is trying - // to demangle display names anyways, so let's just put a mangled name into - // the symbols subsection until Clang gives us what we need. - if (GVName.startswith("\01?")) - FuncName = GVName.substr(1); - // Emit a symbol subsection, required by VS2012+ to find function boundaries. - MCSymbol *SymbolsBegin = Asm->MMI->getContext().createTempSymbol(), - *SymbolsEnd = Asm->MMI->getContext().createTempSymbol(); - Asm->OutStreamer->AddComment("Symbol subsection for " + Twine(FuncName)); - Asm->EmitInt32(COFF::DEBUG_SYMBOL_SUBSECTION); - EmitLabelDiff(*Asm->OutStreamer, SymbolsBegin, SymbolsEnd); - Asm->OutStreamer->EmitLabel(SymbolsBegin); - { - MCSymbol *ProcSegmentBegin = Asm->MMI->getContext().createTempSymbol(), - *ProcSegmentEnd = Asm->MMI->getContext().createTempSymbol(); - EmitLabelDiff(*Asm->OutStreamer, ProcSegmentBegin, ProcSegmentEnd, 2); - Asm->OutStreamer->EmitLabel(ProcSegmentBegin); - - Asm->EmitInt16(COFF::DEBUG_SYMBOL_TYPE_PROC_START); - // Some bytes of this segment don't seem to be required for basic debugging, - // so just fill them with zeroes. - Asm->OutStreamer->EmitFill(12, 0); - // This is the important bit that tells the debugger where the function - // code is located and what's its size: - EmitLabelDiff(*Asm->OutStreamer, Fn, FI.End); - Asm->OutStreamer->EmitFill(12, 0); - Asm->OutStreamer->EmitCOFFSecRel32(Fn); - Asm->OutStreamer->EmitCOFFSectionIndex(Fn); - Asm->EmitInt8(0); - // Emit the function display name as a null-terminated string. - Asm->OutStreamer->EmitBytes(FuncName); - Asm->EmitInt8(0); - Asm->OutStreamer->EmitLabel(ProcSegmentEnd); - - // We're done with this function. - Asm->EmitInt16(0x0002); - Asm->EmitInt16(COFF::DEBUG_SYMBOL_TYPE_PROC_END); - } - Asm->OutStreamer->EmitLabel(SymbolsEnd); - // Every subsection must be aligned to a 4-byte boundary. - Asm->OutStreamer->EmitFill((-FuncName.size()) % 4, 0); - - // PCs/Instructions are grouped into segments sharing the same filename. - // Pre-calculate the lengths (in instructions) of these segments and store - // them in a map for convenience. Each index in the map is the sequential - // number of the respective instruction that starts a new segment. - DenseMap<size_t, size_t> FilenameSegmentLengths; - size_t LastSegmentEnd = 0; - StringRef PrevFilename = InstrInfo[FI.Instrs[0]].Filename; - for (size_t J = 1, F = FI.Instrs.size(); J != F; ++J) { - if (PrevFilename == InstrInfo[FI.Instrs[J]].Filename) - continue; - FilenameSegmentLengths[LastSegmentEnd] = J - LastSegmentEnd; - LastSegmentEnd = J; - PrevFilename = InstrInfo[FI.Instrs[J]].Filename; - } - FilenameSegmentLengths[LastSegmentEnd] = FI.Instrs.size() - LastSegmentEnd; - - // Emit a line table subsection, required to do PC-to-file:line lookup. - Asm->OutStreamer->AddComment("Line table subsection for " + Twine(FuncName)); - Asm->EmitInt32(COFF::DEBUG_LINE_TABLE_SUBSECTION); - MCSymbol *LineTableBegin = Asm->MMI->getContext().createTempSymbol(), - *LineTableEnd = Asm->MMI->getContext().createTempSymbol(); - EmitLabelDiff(*Asm->OutStreamer, LineTableBegin, LineTableEnd); - Asm->OutStreamer->EmitLabel(LineTableBegin); - - // Identify the function this subsection is for. - Asm->OutStreamer->EmitCOFFSecRel32(Fn); - Asm->OutStreamer->EmitCOFFSectionIndex(Fn); - // Insert flags after a 16-bit section index. - Asm->EmitInt16(COFF::DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS); - - // Length of the function's code, in bytes. - EmitLabelDiff(*Asm->OutStreamer, Fn, FI.End); - - // PC-to-linenumber lookup table: - MCSymbol *FileSegmentEnd = nullptr; - - // The start of the last segment: - size_t LastSegmentStart = 0; - - auto FinishPreviousChunk = [&] { - if (!FileSegmentEnd) - return; - for (size_t ColSegI = LastSegmentStart, - ColSegEnd = ColSegI + FilenameSegmentLengths[LastSegmentStart]; - ColSegI != ColSegEnd; ++ColSegI) { - unsigned ColumnNumber = InstrInfo[FI.Instrs[ColSegI]].ColumnNumber; - assert(ColumnNumber <= COFF::CVL_MaxColumnNumber); - Asm->EmitInt16(ColumnNumber); // Start column - Asm->EmitInt16(0); // End column - } - Asm->OutStreamer->EmitLabel(FileSegmentEnd); - }; - - for (size_t J = 0, F = FI.Instrs.size(); J != F; ++J) { - MCSymbol *Instr = FI.Instrs[J]; - assert(InstrInfo.count(Instr)); - - if (FilenameSegmentLengths.count(J)) { - // We came to a beginning of a new filename segment. - FinishPreviousChunk(); - StringRef CurFilename = InstrInfo[FI.Instrs[J]].Filename; - assert(FileNameRegistry.Infos.count(CurFilename)); - size_t IndexInStringTable = - FileNameRegistry.Infos[CurFilename].FilenameID; - // Each segment starts with the offset of the filename - // in the string table. - Asm->OutStreamer->AddComment( - "Segment for file '" + Twine(CurFilename) + "' begins"); - MCSymbol *FileSegmentBegin = Asm->MMI->getContext().createTempSymbol(); - Asm->OutStreamer->EmitLabel(FileSegmentBegin); - Asm->EmitInt32(8 * IndexInStringTable); - - // Number of PC records in the lookup table. - size_t SegmentLength = FilenameSegmentLengths[J]; - Asm->EmitInt32(SegmentLength); - - // Full size of the segment for this filename, including the prev two - // records. - FileSegmentEnd = Asm->MMI->getContext().createTempSymbol(); - EmitLabelDiff(*Asm->OutStreamer, FileSegmentBegin, FileSegmentEnd); - LastSegmentStart = J; - } - - // The first PC with the given linenumber and the linenumber itself. - EmitLabelDiff(*Asm->OutStreamer, Fn, Instr); - uint32_t LineNumber = InstrInfo[Instr].LineNumber; - assert(LineNumber <= COFF::CVL_MaxLineNumber); - uint32_t LineData = LineNumber | COFF::CVL_IsStatement; - Asm->EmitInt32(LineData); - } - - FinishPreviousChunk(); - Asm->OutStreamer->EmitLabel(LineTableEnd); -} - -void WinCodeViewLineTables::beginFunction(const MachineFunction *MF) { - assert(!CurFn && "Can't process two functions at once!"); - - if (!Asm || !Asm->MMI->hasDebugInfo()) - return; - - const Function *GV = MF->getFunction(); - assert(FnDebugInfo.count(GV) == false); - VisitedFunctions.push_back(GV); - CurFn = &FnDebugInfo[GV]; - - // Find the end of the function prolog. - // FIXME: is there a simpler a way to do this? Can we just search - // for the first instruction of the function, not the last of the prolog? - DebugLoc PrologEndLoc; - bool EmptyPrologue = true; - for (const auto &MBB : *MF) { - if (PrologEndLoc) - break; - for (const auto &MI : MBB) { - if (MI.isDebugValue()) - continue; - - // First known non-DBG_VALUE and non-frame setup location marks - // the beginning of the function body. - // FIXME: do we need the first subcondition? - if (!MI.getFlag(MachineInstr::FrameSetup) && MI.getDebugLoc()) { - PrologEndLoc = MI.getDebugLoc(); - break; - } - EmptyPrologue = false; - } - } - // Record beginning of function if we have a non-empty prologue. - if (PrologEndLoc && !EmptyPrologue) { - DebugLoc FnStartDL = PrologEndLoc.getFnDebugLoc(); - maybeRecordLocation(FnStartDL, MF); - } -} - -void WinCodeViewLineTables::endFunction(const MachineFunction *MF) { - if (!Asm || !CurFn) // We haven't created any debug info for this function. - return; - - const Function *GV = MF->getFunction(); - assert(FnDebugInfo.count(GV)); - assert(CurFn == &FnDebugInfo[GV]); - - if (CurFn->Instrs.empty()) { - FnDebugInfo.erase(GV); - VisitedFunctions.pop_back(); - } else { - CurFn->End = Asm->getFunctionEnd(); - } - CurFn = nullptr; -} - -void WinCodeViewLineTables::beginInstruction(const MachineInstr *MI) { - // Ignore DBG_VALUE locations and function prologue. - if (!Asm || MI->isDebugValue() || MI->getFlag(MachineInstr::FrameSetup)) - return; - DebugLoc DL = MI->getDebugLoc(); - if (DL == PrevInstLoc || !DL) - return; - maybeRecordLocation(DL, Asm->MF); -} -} diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h b/contrib/llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h deleted file mode 100644 index 78068e0..0000000 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h +++ /dev/null @@ -1,138 +0,0 @@ -//===-- llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h ----*- C++ -*--===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains support for writing line tables info into COFF files. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_WINCODEVIEWLINETABLES_H -#define LLVM_LIB_CODEGEN_ASMPRINTER_WINCODEVIEWLINETABLES_H - -#include "AsmPrinterHandler.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/LexicalScopes.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/IR/DebugLoc.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/Target/TargetLoweringObjectFile.h" - -namespace llvm { -/// \brief Collects and handles line tables information in a CodeView format. -class LLVM_LIBRARY_VISIBILITY WinCodeViewLineTables : public AsmPrinterHandler { - AsmPrinter *Asm; - DebugLoc PrevInstLoc; - - // For each function, store a vector of labels to its instructions, as well as - // to the end of the function. - struct FunctionInfo { - SmallVector<MCSymbol *, 10> Instrs; - MCSymbol *End; - FunctionInfo() : End(nullptr) {} - } *CurFn; - - typedef DenseMap<const Function *, FunctionInfo> FnDebugInfoTy; - FnDebugInfoTy FnDebugInfo; - // Store the functions we've visited in a vector so we can maintain a stable - // order while emitting subsections. - SmallVector<const Function *, 10> VisitedFunctions; - - // InstrInfoTy - Holds the Filename:LineNumber information for every - // instruction with a unique debug location. - struct InstrInfoTy { - StringRef Filename; - unsigned LineNumber; - unsigned ColumnNumber; - - InstrInfoTy() : LineNumber(0), ColumnNumber(0) {} - - InstrInfoTy(StringRef Filename, unsigned LineNumber, unsigned ColumnNumber) - : Filename(Filename), LineNumber(LineNumber), - ColumnNumber(ColumnNumber) {} - }; - DenseMap<MCSymbol *, InstrInfoTy> InstrInfo; - - // FileNameRegistry - Manages filenames observed while generating debug info - // by filtering out duplicates and bookkeeping the offsets in the string - // table to be generated. - struct FileNameRegistryTy { - SmallVector<StringRef, 10> Filenames; - struct PerFileInfo { - size_t FilenameID, StartOffset; - }; - StringMap<PerFileInfo> Infos; - - // The offset in the string table where we'll write the next unique - // filename. - size_t LastOffset; - - FileNameRegistryTy() { - clear(); - } - - // Add Filename to the registry, if it was not observed before. - void add(StringRef Filename) { - if (Infos.count(Filename)) - return; - size_t OldSize = Infos.size(); - Infos[Filename].FilenameID = OldSize; - Infos[Filename].StartOffset = LastOffset; - LastOffset += Filename.size() + 1; - Filenames.push_back(Filename); - } - - void clear() { - LastOffset = 1; - Infos.clear(); - Filenames.clear(); - } - } FileNameRegistry; - - typedef std::map<std::pair<StringRef, StringRef>, std::string> - DirAndFilenameToFilepathMapTy; - DirAndFilenameToFilepathMapTy DirAndFilenameToFilepathMap; - StringRef getFullFilepath(const MDNode *S); - - void maybeRecordLocation(DebugLoc DL, const MachineFunction *MF); - - void clear() { - assert(CurFn == nullptr); - FileNameRegistry.clear(); - InstrInfo.clear(); - } - - void emitDebugInfoForFunction(const Function *GV); - -public: - WinCodeViewLineTables(AsmPrinter *Asm); - - void setSymbolSize(const llvm::MCSymbol *, uint64_t) override {} - - /// \brief Emit the COFF section that holds the line table information. - void endModule() override; - - /// \brief Gather pre-function debug information. - void beginFunction(const MachineFunction *MF) override; - - /// \brief Gather post-function debug information. - void endFunction(const MachineFunction *) override; - - /// \brief Process beginning of an instruction. - void beginInstruction(const MachineInstr *MI) override; - - /// \brief Process end of an instruction. - void endInstruction() override {} -}; -} // End of namespace llvm - -#endif diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index 4da5b58..e5933d8 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "WinException.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" @@ -35,6 +34,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -125,10 +125,9 @@ void WinException::endFunction(const MachineFunction *MF) { if (shouldEmitPersonality || shouldEmitLSDA) { Asm->OutStreamer->PushSection(); - // Just switch sections to the right xdata section. This use of CurrentFnSym - // assumes that we only emit the LSDA when ending the parent function. - MCSection *XData = WinEH::UnwindEmitter::getXDataSection(Asm->CurrentFnSym, - Asm->OutContext); + // Just switch sections to the right xdata section. + MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection( + Asm->OutStreamer->getCurrentSectionOnly()); Asm->OutStreamer->SwitchSection(XData); // Emit the tables appropriate to the personality function in use. If we @@ -303,8 +302,17 @@ int WinException::getFrameIndexOffset(int FrameIndex, const WinEHFuncInfo &FuncInfo) { const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering(); unsigned UnusedReg; - if (Asm->MAI->usesWindowsCFI()) - return TFI.getFrameIndexReferenceFromSP(*Asm->MF, FrameIndex, UnusedReg); + if (Asm->MAI->usesWindowsCFI()) { + int Offset = + TFI.getFrameIndexReferencePreferSP(*Asm->MF, FrameIndex, UnusedReg, + /*IgnoreSPUpdates*/ true); + assert(UnusedReg == + Asm->MF->getSubtarget() + .getTargetLowering() + ->getStackPointerRegisterToSaveRestore()); + return Offset; + } + // 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); @@ -793,6 +801,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { const MCExpr *FrameAllocOffsetRef = nullptr; if (HT.CatchObj.FrameIndex != INT_MAX) { int Offset = getFrameIndexOffset(HT.CatchObj.FrameIndex, FuncInfo); + assert(Offset != 0 && "Illegal offset for catch object!"); FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext); } else { FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext); @@ -945,15 +954,42 @@ void WinException::emitExceptHandlerTable(const MachineFunction *MF) { // ScopeTableEntry ScopeRecord[]; // }; // - // Only the EHCookieOffset field appears to vary, and it appears to be the - // offset from the final saved SP value to the retaddr. + // Offsets are %ebp relative. + // + // The GS cookie is present only if the function needs stack protection. + // GSCookieOffset = -2 means that GS cookie is not used. + // + // The EH cookie is always present. + // + // Check is done the following way: + // (ebp+CookieXOROffset) ^ [ebp+CookieOffset] == _security_cookie + + // Retrieve the Guard Stack slot. + int GSCookieOffset = -2; + const MachineFrameInfo *MFI = MF->getFrameInfo(); + if (MFI->hasStackProtectorIndex()) { + unsigned UnusedReg; + const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); + int SSPIdx = MFI->getStackProtectorIndex(); + GSCookieOffset = TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg); + } + + // Retrieve the EH Guard slot. + // TODO(etienneb): Get rid of this value and change it for and assertion. + int EHCookieOffset = 9999; + if (FuncInfo.EHGuardFrameIndex != INT_MAX) { + unsigned UnusedReg; + const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); + int EHGuardIdx = FuncInfo.EHGuardFrameIndex; + EHCookieOffset = TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg); + } + AddComment("GSCookieOffset"); - OS.EmitIntValue(-2, 4); + OS.EmitIntValue(GSCookieOffset, 4); AddComment("GSCookieXOROffset"); OS.EmitIntValue(0, 4); - // FIXME: Calculate. AddComment("EHCookieOffset"); - OS.EmitIntValue(9999, 4); + OS.EmitIntValue(EHCookieOffset, 4); AddComment("EHCookieXOROffset"); OS.EmitIntValue(0, 4); BaseState = -2; |