diff options
Diffstat (limited to 'lib/CodeGen/AsmPrinter')
33 files changed, 1465 insertions, 1388 deletions
diff --git a/lib/CodeGen/AsmPrinter/ARMException.cpp b/lib/CodeGen/AsmPrinter/ARMException.cpp index 66c6c63..6fe75ad 100644 --- a/lib/CodeGen/AsmPrinter/ARMException.cpp +++ b/lib/CodeGen/AsmPrinter/ARMException.cpp @@ -88,8 +88,7 @@ void ARMException::endFunction(const MachineFunction *) { Asm->getFunctionNumber())); if (!MMI->getLandingPads().empty()) { // Emit references to personality. - if (const Function * Personality = - MMI->getPersonalities()[MMI->getPersonalityIndex()]) { + if (const Function *Personality = MMI->getPersonality()) { MCSymbol *PerSym = Asm->getSymbol(Personality); Asm->OutStreamer.EmitSymbolAttribute(PerSym, MCSA_Global); ATS.emitPersonality(PerSym); diff --git a/lib/CodeGen/AsmPrinter/Android.mk b/lib/CodeGen/AsmPrinter/Android.mk index cb8e96a..0ce457f 100644 --- a/lib/CodeGen/AsmPrinter/Android.mk +++ b/lib/CodeGen/AsmPrinter/Android.mk @@ -13,6 +13,7 @@ codegen_asmprinter_SRC_FILES := \ DwarfCFIException.cpp \ DwarfCompileUnit.cpp \ DwarfDebug.cpp \ + DwarfExpression.cpp \ DwarfFile.cpp \ DwarfStringPool.cpp \ DwarfUnit.cpp \ diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 8a32713..988381d 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -41,9 +41,11 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Timer.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetInstrInfo.h" @@ -98,15 +100,17 @@ static unsigned getGVAlignmentLog2(const GlobalValue *GV, const DataLayout &TD, return NumBits; } -AsmPrinter::AsmPrinter(TargetMachine &tm, MCStreamer &Streamer) +AsmPrinter::AsmPrinter(TargetMachine &tm, std::unique_ptr<MCStreamer> Streamer) : MachineFunctionPass(ID), TM(tm), MAI(tm.getMCAsmInfo()), - MII(tm.getSubtargetImpl()->getInstrInfo()), - OutContext(Streamer.getContext()), OutStreamer(Streamer), LastMI(nullptr), - LastFn(0), Counter(~0U), SetCounter(0) { - DD = nullptr; MMI = nullptr; LI = nullptr; MF = nullptr; + OutContext(Streamer->getContext()), OutStreamer(*Streamer.release()), + LastMI(nullptr), LastFn(0), Counter(~0U), SetCounter(0) { + DD = nullptr; + MMI = nullptr; + LI = nullptr; + MF = nullptr; CurrentFnSym = CurrentFnSymForSize = nullptr; GCMetadataPrinters = nullptr; - VerboseAsm = Streamer.isVerboseAsm(); + VerboseAsm = OutStreamer.isVerboseAsm(); } AsmPrinter::~AsmPrinter() { @@ -129,16 +133,17 @@ unsigned AsmPrinter::getFunctionNumber() const { } const TargetLoweringObjectFile &AsmPrinter::getObjFileLowering() const { - return TM.getSubtargetImpl()->getTargetLowering()->getObjFileLowering(); + return *TM.getObjFileLowering(); } /// getDataLayout - Return information about data layout. const DataLayout &AsmPrinter::getDataLayout() const { - return *TM.getSubtargetImpl()->getDataLayout(); + return *TM.getDataLayout(); } const MCSubtargetInfo &AsmPrinter::getSubtargetInfo() const { - return TM.getSubtarget<MCSubtargetInfo>(); + assert(MF && "getSubtargetInfo requires a valid MachineFunction!"); + return MF->getSubtarget<MCSubtargetInfo>(); } void AsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { @@ -175,7 +180,7 @@ bool AsmPrinter::doInitialization(Module &M) { OutStreamer.InitSections(false); - Mang = new Mangler(TM.getSubtargetImpl()->getDataLayout()); + Mang = new Mangler(TM.getDataLayout()); // Emit the version-min deplyment target directive if needed. // @@ -210,7 +215,7 @@ bool AsmPrinter::doInitialization(Module &M) { assert(MI && "AsmPrinter didn't require GCModuleInfo?"); for (auto &I : *MI) if (GCMetadataPrinter *MP = GetOrCreateGCPrinter(*I)) - MP->beginAssembly(*this); + MP->beginAssembly(M, *MI, *this); // Emit module-level inline asm if it exists. if (!M.getModuleInlineAsm().empty()) { @@ -222,12 +227,25 @@ bool AsmPrinter::doInitialization(Module &M) { } if (MAI->doesSupportDebugInformation()) { - if (Triple(TM.getTargetTriple()).isKnownWindowsMSVCEnvironment()) + bool skip_dwarf = false; + if (Triple(TM.getTargetTriple()).isKnownWindowsMSVCEnvironment()) { Handlers.push_back(HandlerInfo(new WinCodeViewLineTables(this), DbgTimerName, CodeViewLineTablesGroupName)); - DD = new DwarfDebug(this, &M); - Handlers.push_back(HandlerInfo(DD, DbgTimerName, DWARFGroupName)); + // FIXME: Don't emit DWARF debug info if there's at least one function + // with AddressSanitizer instrumentation. + // This is a band-aid fix for PR22032. + for (auto &F : M.functions()) { + if (F.hasFnAttribute(Attribute::SanitizeAddress)) { + skip_dwarf = true; + break; + } + } + } + if (!skip_dwarf) { + DD = new DwarfDebug(this, &M); + Handlers.push_back(HandlerInfo(DD, DbgTimerName, DWARFGroupName)); + } } EHStreamer *ES = nullptr; @@ -241,7 +259,7 @@ bool AsmPrinter::doInitialization(Module &M) { case ExceptionHandling::ARM: ES = new ARMException(this); break; - case ExceptionHandling::ItaniumWinEH: + case ExceptionHandling::WinEH: switch (MAI->getWinEHEncodingType()) { default: llvm_unreachable("unsupported unwinding information encoding"); case WinEH::EncodingType::Itanium: @@ -323,6 +341,11 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { if (EmitSpecialLLVMGlobal(GV)) return; + // Skip the emission of global equivalents. The symbol can be emitted later + // on by emitGlobalGOTEquivs in case it turns out to be needed. + if (GlobalGOTEquivs.count(getSymbol(GV))) + return; + if (isVerbose()) { GV->printAsOperand(OutStreamer.GetCommentOS(), /*PrintType=*/false, GV->getParent()); @@ -336,12 +359,17 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { if (!GV->hasInitializer()) // External globals require no extra code. return; + GVSym->redefineIfPossible(); + if (GVSym->isDefined() || GVSym->isVariable()) + report_fatal_error("symbol '" + Twine(GVSym->getName()) + + "' is already defined"); + if (MAI->hasDotTypeDotSizeDirective()) OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject); SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM); - const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); + const DataLayout *DL = TM.getDataLayout(); uint64_t Size = DL->getTypeAllocSize(GV->getType()->getElementType()); // If the alignment is specified, we *must* obey it. Overaligning a global @@ -508,6 +536,10 @@ void AsmPrinter::EmitFunctionHeader() { OutStreamer.GetCommentOS() << '\n'; } + // Emit the prefix data. + if (F->hasPrefixData()) + EmitGlobalConstant(F->getPrefixData()); + // Emit the CurrentFnSym. This is a virtual function to allow targets to // do their wild and crazy things as required. EmitFunctionEntryLabel(); @@ -528,27 +560,32 @@ void AsmPrinter::EmitFunctionHeader() { HI.Handler->beginFunction(MF); } - // Emit the prefix data. - if (F->hasPrefixData()) - EmitGlobalConstant(F->getPrefixData()); + // Emit the prologue data. + if (F->hasPrologueData()) + EmitGlobalConstant(F->getPrologueData()); } /// EmitFunctionEntryLabel - Emit the label that is the entrypoint for the /// function. This can be overridden by targets as required to do custom stuff. void AsmPrinter::EmitFunctionEntryLabel() { + CurrentFnSym->redefineIfPossible(); + // The function label could have already been emitted if two symbols end up // conflicting due to asm renaming. Detect this and emit an error. - if (CurrentFnSym->isUndefined()) - return OutStreamer.EmitLabel(CurrentFnSym); + if (CurrentFnSym->isVariable()) + report_fatal_error("'" + Twine(CurrentFnSym->getName()) + + "' is a protected alias"); + if (CurrentFnSym->isDefined()) + report_fatal_error("'" + Twine(CurrentFnSym->getName()) + + "' label emitted multiple times to assembly file"); - report_fatal_error("'" + Twine(CurrentFnSym->getName()) + - "' label emitted multiple times to assembly file"); + return OutStreamer.EmitLabel(CurrentFnSym); } /// emitComments - Pretty-print comments for instructions. static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) { const MachineFunction *MF = MI.getParent()->getParent(); - const TargetMachine &TM = MF->getTarget(); + const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); // Check for spills and reloads int FI; @@ -558,24 +595,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 (TM.getSubtargetImpl()->getInstrInfo()->isLoadFromStackSlotPostFE(&MI, - FI)) { + if (TII->isLoadFromStackSlotPostFE(&MI, FI)) { if (FrameInfo->isSpillSlotObjectIndex(FI)) { MMO = *MI.memoperands_begin(); CommentOS << MMO->getSize() << "-byte Reload\n"; } - } else if (TM.getSubtargetImpl()->getInstrInfo()->hasLoadFromStackSlot( - &MI, MMO, FI)) { + } else if (TII->hasLoadFromStackSlot(&MI, MMO, FI)) { if (FrameInfo->isSpillSlotObjectIndex(FI)) CommentOS << MMO->getSize() << "-byte Folded Reload\n"; - } else if (TM.getSubtargetImpl()->getInstrInfo()->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 (TM.getSubtargetImpl()->getInstrInfo()->hasStoreToStackSlot( - &MI, MMO, FI)) { + } else if (TII->hasStoreToStackSlot(&MI, MMO, FI)) { if (FrameInfo->isSpillSlotObjectIndex(FI)) CommentOS << MMO->getSize() << "-byte Folded Spill\n"; } @@ -589,9 +622,8 @@ static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) { /// that is an implicit def. void AsmPrinter::emitImplicitDef(const MachineInstr *MI) const { unsigned RegNo = MI->getOperand(0).getReg(); - OutStreamer.AddComment( - Twine("implicit-def: ") + - TM.getSubtargetImpl()->getRegisterInfo()->getName(RegNo)); + OutStreamer.AddComment(Twine("implicit-def: ") + + MMI->getContext().getRegisterInfo()->getName(RegNo)); OutStreamer.AddBlankLine(); } @@ -601,7 +633,7 @@ static void emitKill(const MachineInstr *MI, AsmPrinter &AP) { const MachineOperand &Op = MI->getOperand(i); assert(Op.isReg() && "KILL instruction must have only register operands"); Str += ' '; - Str += AP.TM.getSubtargetImpl()->getRegisterInfo()->getName(Op.getReg()); + Str += AP.MMI->getContext().getRegisterInfo()->getName(Op.getReg()); Str += (Op.isDef() ? "<def>" : "<kill>"); } AP.OutStreamer.AddComment(Str); @@ -629,9 +661,9 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { OS << V.getName(); DIExpression Expr = MI->getDebugExpression(); - if (Expr.isVariablePiece()) - OS << " [piece offset=" << Expr.getPieceOffset() - << " size=" << Expr.getPieceSize() << "]"; + if (Expr.isBitPiece()) + OS << " [bit_piece offset=" << Expr.getBitPieceOffset() + << " size=" << Expr.getBitPieceSize() << "]"; OS << " <- "; // The second operand is only an offset if it's an immediate. @@ -663,8 +695,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { Reg = MI->getOperand(0).getReg(); } else { assert(MI->getOperand(0).isFI() && "Unknown operand type"); - const TargetFrameLowering *TFI = - AP.TM.getSubtargetImpl()->getFrameLowering(); + const TargetFrameLowering *TFI = AP.MF->getSubtarget().getFrameLowering(); Offset += TFI->getFrameIndexReference(*AP.MF, MI->getOperand(0).getIndex(), Reg); Deref = true; @@ -678,7 +709,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { } if (Deref) OS << '['; - OS << AP.TM.getSubtargetImpl()->getRegisterInfo()->getName(Reg); + OS << AP.MMI->getContext().getRegisterInfo()->getName(Reg); } if (Deref) @@ -701,8 +732,7 @@ AsmPrinter::CFIMoveType AsmPrinter::needsCFIMoves() { } bool AsmPrinter::needsSEHMoves() { - return MAI->getExceptionHandlingType() == ExceptionHandling::ItaniumWinEH && - MF->getFunction()->needsUnwindTableEntry(); + return MAI->usesWindowsCFI() && MF->getFunction()->needsUnwindTableEntry(); } void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) { @@ -721,6 +751,16 @@ void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) { emitCFIInstruction(CFI); } +void AsmPrinter::emitFrameAlloc(const MachineInstr &MI) { + // The operands are the MCSymbol and the frame offset of the allocation. + MCSymbol *FrameAllocSym = MI.getOperand(0).getMCSymbol(); + int FrameOffset = MI.getOperand(1).getImm(); + + // Emit a symbol assignment. + OutStreamer.EmitAssignment(FrameAllocSym, + MCConstantExpr::Create(FrameOffset, OutContext)); +} + /// EmitFunctionBody - This method emits the body and trailer for a /// function. void AsmPrinter::EmitFunctionBody() { @@ -759,6 +799,10 @@ void AsmPrinter::EmitFunctionBody() { emitCFIInstruction(MI); break; + case TargetOpcode::FRAME_ALLOC: + emitFrameAlloc(MI); + break; + case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: OutStreamer.EmitLabel(MI.getOperand(0).getMCSymbol()); @@ -800,7 +844,7 @@ void AsmPrinter::EmitFunctionBody() { // labels from collapsing together. Just emit a noop. if ((MAI->hasSubsectionsViaSymbols() && !HasAnyRealCode)) { MCInst Noop; - TM.getSubtargetImpl()->getInstrInfo()->getNoopForMachoTarget(Noop); + MF->getSubtarget().getInstrInfo()->getNoopForMachoTarget(Noop); OutStreamer.AddComment("avoids zero-length function"); // Targets can opt-out of emitting the noop here by leaving the opcode @@ -852,13 +896,95 @@ void AsmPrinter::EmitFunctionBody() { OutStreamer.AddBlankLine(); } -static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP); +/// \brief Compute the number of Global Variables that uses a Constant. +static unsigned getNumGlobalVariableUses(const Constant *C) { + if (!C) + return 0; + + if (isa<GlobalVariable>(C)) + return 1; + + unsigned NumUses = 0; + for (auto *CU : C->users()) + NumUses += getNumGlobalVariableUses(dyn_cast<Constant>(CU)); + + return NumUses; +} + +/// \brief Only consider global GOT equivalents if at least one user is a +/// cstexpr inside an initializer of another global variables. Also, don't +/// handle cstexpr inside instructions. During global variable emission, +/// candidates are skipped and are emitted later in case at least one cstexpr +/// isn't replaced by a PC relative GOT entry access. +static bool isGOTEquivalentCandidate(const GlobalVariable *GV, + unsigned &NumGOTEquivUsers) { + // 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))) + return false; + + // To be a got equivalent, at least one of its users need to be a constant + // expression used by another global variable. + for (auto *U : GV->users()) + NumGOTEquivUsers += getNumGlobalVariableUses(cast<Constant>(U)); + + return NumGOTEquivUsers > 0; +} + +/// \brief Unnamed constant global variables solely contaning a pointer to +/// another globals variable is equivalent to a GOT table entry; it contains the +/// the address of another symbol. Optimize it and replace accesses to these +/// "GOT equivalents" by using the GOT entry for the final global instead. +/// Compute GOT equivalent candidates among all global variables to avoid +/// emitting them if possible later on, after it use is replaced by a GOT entry +/// access. +void AsmPrinter::computeGlobalGOTEquivs(Module &M) { + if (!getObjFileLowering().supportIndirectSymViaGOTPCRel()) + return; + + for (const auto &G : M.globals()) { + unsigned NumGOTEquivUsers = 0; + if (!isGOTEquivalentCandidate(&G, NumGOTEquivUsers)) + continue; + + const MCSymbol *GOTEquivSym = getSymbol(&G); + GlobalGOTEquivs[GOTEquivSym] = std::make_pair(&G, NumGOTEquivUsers); + } +} + +/// \brief Constant expressions using GOT equivalent globals may not be eligible +/// for PC relative GOT entry conversion, in such cases we need to emit such +/// globals we previously omitted in EmitGlobalVariable. +void AsmPrinter::emitGlobalGOTEquivs() { + if (!getObjFileLowering().supportIndirectSymViaGOTPCRel()) + return; + + while (!GlobalGOTEquivs.empty()) { + DenseMap<const MCSymbol *, GOTEquivUsePair>::iterator I = + GlobalGOTEquivs.begin(); + const MCSymbol *S = I->first; + const GlobalVariable *GV = I->second.first; + GlobalGOTEquivs.erase(S); + EmitGlobalVariable(GV); + } +} bool AsmPrinter::doFinalization(Module &M) { + // Gather all GOT equivalent globals in the module. We really need two + // passes over the globals: one to compute and another to avoid its emission + // in EmitGlobalVariable, otherwise we would not be able to handle cases + // where the got equivalent shows up before its use. + computeGlobalGOTEquivs(M); + // Emit global variables. for (const auto &G : M.globals()) EmitGlobalVariable(&G); + // Emit remaining GOT equivalent globals. + emitGlobalGOTEquivs(); + // Emit visibility info for declarations for (const Function &F : M) { if (!F.isDeclaration()) @@ -875,10 +1001,15 @@ bool AsmPrinter::doFinalization(Module &M) { JumpInstrTableInfo *JITI = getAnalysisIfAvailable<JumpInstrTableInfo>(); if (JITI && !JITI->getTables().empty()) { + // Since we're at the module level we can't use a function specific + // MCSubtargetInfo - instead create one with the module defaults. + std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo( + TM.getTargetTriple(), TM.getTargetCPU(), TM.getTargetFeatureString())); unsigned Arch = Triple(getTargetTriple()).getArch(); bool IsThumb = (Arch == Triple::thumb || Arch == Triple::thumbeb); + const TargetInstrInfo *TII = TM.getSubtargetImpl()->getInstrInfo(); MCInst TrapInst; - TM.getSubtargetImpl()->getInstrInfo()->getTrap(TrapInst); + TII->getTrap(TrapInst); unsigned LogAlignment = llvm::Log2_64(JITI->entryByteAlignment()); // Emit the right section for these functions. @@ -904,9 +1035,8 @@ bool AsmPrinter::doFinalization(Module &M) { const MCSymbolRefExpr *TargetSymRef = MCSymbolRefExpr::Create(TargetSymbol, MCSymbolRefExpr::VK_PLT, OutContext); - TM.getSubtargetImpl()->getInstrInfo()->getUnconditionalBranch( - JumpToFun, TargetSymRef); - OutStreamer.EmitInstruction(JumpToFun, getSubtargetInfo()); + TII->getUnconditionalBranch(JumpToFun, TargetSymRef); + OutStreamer.EmitInstruction(JumpToFun, *STI); ++Count; } @@ -914,7 +1044,7 @@ bool AsmPrinter::doFinalization(Module &M) { uint64_t Remaining = NextPowerOf2(Count) - Count; for (uint64_t C = 0; C < Remaining; ++C) { EmitAlignment(LogAlignment); - OutStreamer.EmitInstruction(TrapInst, getSubtargetInfo()); + OutStreamer.EmitInstruction(TrapInst, *STI); } } @@ -974,18 +1104,34 @@ bool AsmPrinter::doFinalization(Module &M) { EmitVisibility(Name, Alias.getVisibility()); // Emit the directives as assignments aka .set: - OutStreamer.EmitAssignment(Name, lowerConstant(Alias.getAliasee(), *this)); + OutStreamer.EmitAssignment(Name, lowerConstant(Alias.getAliasee())); } GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>(); assert(MI && "AsmPrinter didn't require GCModuleInfo?"); for (GCModuleInfo::iterator I = MI->end(), E = MI->begin(); I != E; ) if (GCMetadataPrinter *MP = GetOrCreateGCPrinter(**--I)) - MP->finishAssembly(*this); + MP->finishAssembly(M, *MI, *this); // Emit llvm.ident metadata in an '.ident' directive. EmitModuleIdents(M); + // Emit __morestack address if needed for indirect calls. + if (MMI->usesMorestackAddr()) { + const MCSection *ReadOnlySection = + getObjFileLowering().getSectionForConstant(SectionKind::getReadOnly(), + /*C=*/nullptr); + OutStreamer.SwitchSection(ReadOnlySection); + + MCSymbol *AddrSymbol = + OutContext.GetOrCreateSymbol(StringRef("__morestack_addr")); + OutStreamer.EmitLabel(AddrSymbol); + + unsigned PtrSize = TM.getDataLayout()->getPointerSize(0); + OutStreamer.EmitSymbolValue(GetExternalSymbolSymbol("__morestack"), + PtrSize); + } + // If we don't have any trampolines, then we don't require stack memory // to be executable. Some targets have a directive to declare this. Function *InitTrampolineIntrinsic = M.getFunction("llvm.init.trampoline"); @@ -1044,7 +1190,7 @@ void AsmPrinter::EmitConstantPool() { unsigned Align = CPE.getAlignment(); SectionKind Kind = - CPE.getSectionKind(TM.getSubtargetImpl()->getDataLayout()); + CPE.getSectionKind(TM.getDataLayout()); const Constant *C = nullptr; if (!CPE.isMachineConstantPoolEntry()) @@ -1098,7 +1244,7 @@ void AsmPrinter::EmitConstantPool() { Type *Ty = CPE.getType(); Offset = NewOffset + - TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(Ty); + TM.getDataLayout()->getTypeAllocSize(Ty); OutStreamer.EmitLabel(Sym); if (CPE.isMachineConstantPoolEntry()) @@ -1113,7 +1259,7 @@ void AsmPrinter::EmitConstantPool() { /// by the current function to the current output stream. /// void AsmPrinter::EmitJumpTableInfo() { - const DataLayout *DL = MF->getSubtarget().getDataLayout(); + const DataLayout *DL = MF->getTarget().getDataLayout(); const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); if (!MJTI) return; if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_Inline) return; @@ -1123,29 +1269,21 @@ void AsmPrinter::EmitJumpTableInfo() { // Pick the directive to use to print the jump table entries, and switch to // the appropriate section. const Function *F = MF->getFunction(); - bool JTInDiffSection = false; - if (// In PIC mode, we need to emit the jump table to the same section as the - // function body itself, otherwise the label differences won't make sense. - // FIXME: Need a better predicate for this: what about custom entries? - MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 || - // We should also do if the section name is NULL or function is declared - // in discardable section - // FIXME: this isn't the right predicate, should be based on the MCSection - // for the function. - F->isWeakForLinker()) { - OutStreamer.SwitchSection( - getObjFileLowering().SectionForGlobal(F, *Mang, TM)); + const TargetLoweringObjectFile &TLOF = getObjFileLowering(); + bool JTInDiffSection = !TLOF.shouldPutJumpTableInFunctionSection( + MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32, + *F); + if (!JTInDiffSection) { + OutStreamer.SwitchSection(TLOF.SectionForGlobal(F, *Mang, TM)); } else { // Otherwise, drop it in the readonly section. const MCSection *ReadOnlySection = - getObjFileLowering().getSectionForConstant(SectionKind::getReadOnly(), - /*C=*/nullptr); + TLOF.getSectionForJumpTable(*F, *Mang, TM); OutStreamer.SwitchSection(ReadOnlySection); - JTInDiffSection = true; } EmitAlignment(Log2_32( - MJTI->getEntryAlignment(*TM.getSubtargetImpl()->getDataLayout()))); + MJTI->getEntryAlignment(*TM.getDataLayout()))); // Jump tables in code sections are marked with a data_region directive // where that's supported. @@ -1163,7 +1301,7 @@ void AsmPrinter::EmitJumpTableInfo() { if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 && MAI->doesSetDirectiveSuppressesReloc()) { SmallPtrSet<const MachineBasicBlock*, 16> EmittedSets; - const TargetLowering *TLI = TM.getSubtargetImpl()->getTargetLowering(); + const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF,JTI,OutContext); for (unsigned ii = 0, ee = JTBBs.size(); ii != ee; ++ii) { const MachineBasicBlock *MBB = JTBBs[ii]; @@ -1207,9 +1345,8 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, case MachineJumpTableInfo::EK_Inline: llvm_unreachable("Cannot emit EK_Inline jump table entry"); case MachineJumpTableInfo::EK_Custom32: - Value = - TM.getSubtargetImpl()->getTargetLowering()->LowerCustomJumpTableEntry( - MJTI, MBB, UID, OutContext); + Value = MF->getSubtarget().getTargetLowering()->LowerCustomJumpTableEntry( + MJTI, MBB, UID, OutContext); break; case MachineJumpTableInfo::EK_BlockAddress: // EK_BlockAddress - Each entry is a plain address of block, e.g.: @@ -1248,7 +1385,7 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, break; } Value = MCSymbolRefExpr::Create(MBB->getSymbol(), OutContext); - const TargetLowering *TLI = TM.getSubtargetImpl()->getTargetLowering(); + const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF, UID, OutContext); Value = MCBinaryExpr::CreateSub(Value, Base, OutContext); break; @@ -1258,7 +1395,7 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, assert(Value && "Unknown entry kind!"); unsigned EntrySize = - MJTI->getEntrySize(*TM.getSubtargetImpl()->getDataLayout()); + MJTI->getEntrySize(*TM.getDataLayout()); OutStreamer.EmitValue(Value, EntrySize); } @@ -1368,7 +1505,7 @@ void AsmPrinter::EmitXXStructorList(const Constant *List, bool isCtor) { } // Emit the function pointers in the target-specific order - const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); + const DataLayout *DL = TM.getDataLayout(); unsigned Align = Log2_32(DL->getPointerPrefAlignment()); std::stable_sort(Structors.begin(), Structors.end(), [](const Structor &L, @@ -1483,25 +1620,26 @@ void AsmPrinter::EmitLabelPlusOffset(const MCSymbol *Label, uint64_t Offset, // void AsmPrinter::EmitAlignment(unsigned NumBits, const GlobalObject *GV) const { if (GV) - NumBits = getGVAlignmentLog2(GV, *TM.getSubtargetImpl()->getDataLayout(), + NumBits = getGVAlignmentLog2(GV, *TM.getDataLayout(), NumBits); if (NumBits == 0) return; // 1-byte aligned: no need to emit alignment. + assert(NumBits < + static_cast<unsigned>(std::numeric_limits<unsigned>::digits) && + "undefined behavior"); if (getCurrentSection()->getKind().isText()) - OutStreamer.EmitCodeAlignment(1 << NumBits); + OutStreamer.EmitCodeAlignment(1u << NumBits); else - OutStreamer.EmitValueToAlignment(1 << NumBits); + OutStreamer.EmitValueToAlignment(1u << NumBits); } //===----------------------------------------------------------------------===// // Constant emission. //===----------------------------------------------------------------------===// -/// lowerConstant - Lower the specified LLVM Constant to an MCExpr. -/// -static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP) { - MCContext &Ctx = AP.OutContext; +const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { + MCContext &Ctx = OutContext; if (CV->isNullValue() || isa<UndefValue>(CV)) return MCConstantExpr::Create(0, Ctx); @@ -1510,19 +1648,18 @@ static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP) { return MCConstantExpr::Create(CI->getZExtValue(), Ctx); if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) - return MCSymbolRefExpr::Create(AP.getSymbol(GV), Ctx); + return MCSymbolRefExpr::Create(getSymbol(GV), Ctx); if (const BlockAddress *BA = dyn_cast<BlockAddress>(CV)) - return MCSymbolRefExpr::Create(AP.GetBlockAddressSymbol(BA), Ctx); + return MCSymbolRefExpr::Create(GetBlockAddressSymbol(BA), Ctx); const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV); if (!CE) { llvm_unreachable("Unknown constant value to lower!"); } - if (const MCExpr *RelocExpr = - AP.getObjFileLowering().getExecutableRelativeSymbol(CE, *AP.Mang, - AP.TM)) + if (const MCExpr *RelocExpr + = getObjFileLowering().getExecutableRelativeSymbol(CE, *Mang, TM)) return RelocExpr; switch (CE->getOpcode()) { @@ -1531,9 +1668,9 @@ static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP) { // opportunities. Attempt to fold the expression using DataLayout as a // last resort before giving up. if (Constant *C = ConstantFoldConstantExpression( - CE, AP.TM.getSubtargetImpl()->getDataLayout())) + CE, TM.getDataLayout())) if (C != CE) - return lowerConstant(C, AP); + return lowerConstant(C); // Otherwise report the problem to the user. { @@ -1541,16 +1678,17 @@ static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP) { raw_string_ostream OS(S); OS << "Unsupported expression in static initializer: "; CE->printAsOperand(OS, /*PrintType=*/false, - !AP.MF ? nullptr : AP.MF->getFunction()->getParent()); + !MF ? nullptr : MF->getFunction()->getParent()); report_fatal_error(OS.str()); } case Instruction::GetElementPtr: { - const DataLayout &DL = *AP.TM.getSubtargetImpl()->getDataLayout(); + const DataLayout &DL = *TM.getDataLayout(); + // Generate a symbolic expression for the byte address APInt OffsetAI(DL.getPointerTypeSizeInBits(CE->getType()), 0); cast<GEPOperator>(CE)->accumulateConstantOffset(DL, OffsetAI); - const MCExpr *Base = lowerConstant(CE->getOperand(0), AP); + const MCExpr *Base = lowerConstant(CE->getOperand(0)); if (!OffsetAI) return Base; @@ -1566,26 +1704,28 @@ static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP) { // is reasonable to treat their delta as a 32-bit value. // FALL THROUGH. case Instruction::BitCast: - return lowerConstant(CE->getOperand(0), AP); + return lowerConstant(CE->getOperand(0)); case Instruction::IntToPtr: { - const DataLayout &DL = *AP.TM.getSubtargetImpl()->getDataLayout(); + const DataLayout &DL = *TM.getDataLayout(); + // Handle casts to pointers by changing them into casts to the appropriate // integer type. This promotes constant folding and simplifies this code. Constant *Op = CE->getOperand(0); Op = ConstantExpr::getIntegerCast(Op, DL.getIntPtrType(CV->getType()), false/*ZExt*/); - return lowerConstant(Op, AP); + return lowerConstant(Op); } case Instruction::PtrToInt: { - const DataLayout &DL = *AP.TM.getSubtargetImpl()->getDataLayout(); + const DataLayout &DL = *TM.getDataLayout(); + // Support only foldable casts to/from pointers that can be eliminated by // changing the pointer to the appropriately sized integer type. Constant *Op = CE->getOperand(0); Type *Ty = CE->getType(); - const MCExpr *OpExpr = lowerConstant(Op, AP); + const MCExpr *OpExpr = lowerConstant(Op); // We can emit the pointer value into this slot if the slot is an // integer slot equal to the size of the pointer. @@ -1611,8 +1751,8 @@ static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP) { case Instruction::And: case Instruction::Or: case Instruction::Xor: { - const MCExpr *LHS = lowerConstant(CE->getOperand(0), AP); - const MCExpr *RHS = lowerConstant(CE->getOperand(1), AP); + const MCExpr *LHS = lowerConstant(CE->getOperand(0)); + const MCExpr *RHS = lowerConstant(CE->getOperand(1)); switch (CE->getOpcode()) { default: llvm_unreachable("Unknown binary operator constant cast expr"); case Instruction::Add: return MCBinaryExpr::CreateAdd(LHS, RHS, Ctx); @@ -1629,7 +1769,9 @@ static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP) { } } -static void emitGlobalConstantImpl(const Constant *C, AsmPrinter &AP); +static void emitGlobalConstantImpl(const Constant *C, AsmPrinter &AP, + const Constant *BaseCV = nullptr, + uint64_t Offset = 0); /// isRepeatedByteSequence - Determine whether the given value is /// composed of a repeated sequence of identical bytes and return the @@ -1653,7 +1795,7 @@ static int isRepeatedByteSequence(const Value *V, TargetMachine &TM) { if (CI->getBitWidth() > 64) return -1; uint64_t Size = - TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(V->getType()); + TM.getDataLayout()->getTypeAllocSize(V->getType()); uint64_t Value = CI->getZExtValue(); // Make sure the constant is at least 8 bits long and has a power @@ -1698,7 +1840,7 @@ static void emitGlobalConstantDataSequential(const ConstantDataSequential *CDS, int Value = isRepeatedByteSequence(CDS, AP.TM); if (Value != -1) { uint64_t Bytes = - AP.TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize( + AP.TM.getDataLayout()->getTypeAllocSize( CDS->getType()); // Don't emit a 1-byte object as a .fill. if (Bytes > 1) @@ -1749,7 +1891,7 @@ static void emitGlobalConstantDataSequential(const ConstantDataSequential *CDS, } } - const DataLayout &DL = *AP.TM.getSubtargetImpl()->getDataLayout(); + const DataLayout &DL = *AP.TM.getDataLayout(); unsigned Size = DL.getTypeAllocSize(CDS->getType()); unsigned EmittedSize = DL.getTypeAllocSize(CDS->getType()->getElementType()) * CDS->getNumElements(); @@ -1758,20 +1900,22 @@ static void emitGlobalConstantDataSequential(const ConstantDataSequential *CDS, } -static void emitGlobalConstantArray(const ConstantArray *CA, AsmPrinter &AP) { +static void emitGlobalConstantArray(const ConstantArray *CA, AsmPrinter &AP, + const Constant *BaseCV, uint64_t Offset) { // See if we can aggregate some values. Make sure it can be // represented as a series of bytes of the constant value. int Value = isRepeatedByteSequence(CA, AP.TM); + const DataLayout &DL = *AP.TM.getDataLayout(); if (Value != -1) { - uint64_t Bytes = - AP.TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize( - CA->getType()); + uint64_t Bytes = DL.getTypeAllocSize(CA->getType()); AP.OutStreamer.EmitFill(Bytes, Value); } else { - for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) - emitGlobalConstantImpl(CA->getOperand(i), AP); + for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { + emitGlobalConstantImpl(CA->getOperand(i), AP, BaseCV, Offset); + Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType()); + } } } @@ -1779,7 +1923,7 @@ static void emitGlobalConstantVector(const ConstantVector *CV, AsmPrinter &AP) { for (unsigned i = 0, e = CV->getType()->getNumElements(); i != e; ++i) emitGlobalConstantImpl(CV->getOperand(i), AP); - const DataLayout &DL = *AP.TM.getSubtargetImpl()->getDataLayout(); + const DataLayout &DL = *AP.TM.getDataLayout(); unsigned Size = DL.getTypeAllocSize(CV->getType()); unsigned EmittedSize = DL.getTypeAllocSize(CV->getType()->getElementType()) * CV->getType()->getNumElements(); @@ -1787,24 +1931,25 @@ static void emitGlobalConstantVector(const ConstantVector *CV, AsmPrinter &AP) { AP.OutStreamer.EmitZeros(Padding); } -static void emitGlobalConstantStruct(const ConstantStruct *CS, AsmPrinter &AP) { +static void emitGlobalConstantStruct(const ConstantStruct *CS, AsmPrinter &AP, + const Constant *BaseCV, uint64_t Offset) { // Print the fields in successive locations. Pad to align if needed! - const DataLayout *DL = AP.TM.getSubtargetImpl()->getDataLayout(); + const DataLayout *DL = AP.TM.getDataLayout(); unsigned Size = DL->getTypeAllocSize(CS->getType()); const StructLayout *Layout = DL->getStructLayout(CS->getType()); uint64_t SizeSoFar = 0; for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { const Constant *Field = CS->getOperand(i); + // Print the actual field value. + emitGlobalConstantImpl(Field, AP, BaseCV, Offset+SizeSoFar); + // Check if padding is needed and insert one or more 0s. uint64_t FieldSize = DL->getTypeAllocSize(Field->getType()); uint64_t PadSize = ((i == e-1 ? Size : Layout->getElementOffset(i+1)) - Layout->getElementOffset(i)) - FieldSize; SizeSoFar += FieldSize + PadSize; - // Now print the actual field value. - emitGlobalConstantImpl(Field, AP); - // Insert padding - this may include padding to increase the size of the // current field up to the ABI size (if the struct is not packed) as well // as padding to ensure that the next field starts at the right offset. @@ -1839,7 +1984,7 @@ static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) { // PPC's long double has odd notions of endianness compared to how LLVM // handles it: p[0] goes first for *big* endian on PPC. - if (AP.TM.getSubtargetImpl()->getDataLayout()->isBigEndian() && + if (AP.TM.getDataLayout()->isBigEndian() && !CFP->getType()->isPPC_FP128Ty()) { int Chunk = API.getNumWords() - 1; @@ -1858,13 +2003,13 @@ static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) { } // Emit the tail padding for the long double. - const DataLayout &DL = *AP.TM.getSubtargetImpl()->getDataLayout(); + const DataLayout &DL = *AP.TM.getDataLayout(); AP.OutStreamer.EmitZeros(DL.getTypeAllocSize(CFP->getType()) - DL.getTypeStoreSize(CFP->getType())); } static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) { - const DataLayout *DL = AP.TM.getSubtargetImpl()->getDataLayout(); + const DataLayout *DL = AP.TM.getDataLayout(); unsigned BitWidth = CI->getBitWidth(); // Copy the value as we may massage the layout for constants whose bit width @@ -1910,7 +2055,7 @@ static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) { // Emit the extra bits after the 64-bits chunks. // Emit a directive that fills the expected size. - uint64_t Size = AP.TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize( + uint64_t Size = AP.TM.getDataLayout()->getTypeAllocSize( CI->getType()); Size -= (BitWidth / 64) * 8; assert(Size && Size * 8 >= ExtraBitsSize && @@ -1920,9 +2065,100 @@ static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) { } } -static void emitGlobalConstantImpl(const Constant *CV, AsmPrinter &AP) { - const DataLayout *DL = AP.TM.getSubtargetImpl()->getDataLayout(); +/// \brief Transform a not absolute MCExpr containing a reference to a GOT +/// equivalent global, by a target specific GOT pc relative access to the +/// final symbol. +static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME, + const Constant *BaseCst, + uint64_t Offset) { + // The global @foo below illustrates a global that uses a got equivalent. + // + // @bar = global i32 42 + // @gotequiv = private unnamed_addr constant i32* @bar + // @foo = i32 trunc (i64 sub (i64 ptrtoint (i32** @gotequiv to i64), + // i64 ptrtoint (i32* @foo to i64)) + // to i32) + // + // The cstexpr in @foo is converted into the MCExpr `ME`, where we actually + // check whether @foo is suitable to use a GOTPCREL. `ME` is usually in the + // form: + // + // foo = cstexpr, where + // cstexpr := <gotequiv> - "." + <cst> + // cstexpr := <gotequiv> - (<foo> - <offset from @foo base>) + <cst> + // + // After canonicalization by EvaluateAsRelocatable `ME` turns into: + // + // cstexpr := <gotequiv> - <foo> + gotpcrelcst, where + // gotpcrelcst := <offset from @foo base> + <cst> + // + MCValue MV; + if (!(*ME)->EvaluateAsRelocatable(MV, nullptr, nullptr) || MV.isAbsolute()) + return; + + const MCSymbol *GOTEquivSym = &MV.getSymA()->getSymbol(); + if (!AP.GlobalGOTEquivs.count(GOTEquivSym)) + return; + + const GlobalValue *BaseGV = dyn_cast<GlobalValue>(BaseCst); + if (!BaseGV) + return; + + const MCSymbol *BaseSym = AP.getSymbol(BaseGV); + if (BaseSym != &MV.getSymB()->getSymbol()) + return; + + // Make sure to match: + // + // gotpcrelcst := <offset from @foo base> + <cst> + // + int64_t GOTPCRelCst = Offset + MV.getConstant(); + if (GOTPCRelCst < 0) + return; + + // Emit the GOT PC relative to replace the got equivalent global, i.e.: + // + // bar: + // .long 42 + // gotequiv: + // .quad bar + // foo: + // .long gotequiv - "." + <cst> + // + // is replaced by the target specific equivalent to: + // + // bar: + // .long 42 + // foo: + // .long bar@GOTPCREL+<gotpcrelcst> + // + AsmPrinter::GOTEquivUsePair Result = AP.GlobalGOTEquivs[GOTEquivSym]; + const GlobalVariable *GV = Result.first; + unsigned NumUses = Result.second; + const GlobalValue *FinalGV = dyn_cast<GlobalValue>(GV->getOperand(0)); + const MCSymbol *FinalSym = AP.getSymbol(FinalGV); + *ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel(FinalSym, + GOTPCRelCst); + + // Update GOT equivalent usage information + --NumUses; + if (NumUses) + AP.GlobalGOTEquivs[GOTEquivSym] = std::make_pair(GV, NumUses); + else + AP.GlobalGOTEquivs.erase(GOTEquivSym); +} + +static void emitGlobalConstantImpl(const Constant *CV, AsmPrinter &AP, + const Constant *BaseCV, uint64_t Offset) { + const DataLayout *DL = AP.TM.getDataLayout(); uint64_t Size = DL->getTypeAllocSize(CV->getType()); + + // Globals with sub-elements such as combinations of arrays and structs + // are handled recursively by emitGlobalConstantImpl. Keep track of the + // constant symbol base and the current position with BaseCV and Offset. + if (!BaseCV && CV->hasOneUse()) + BaseCV = dyn_cast<Constant>(CV->user_back()); + if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV)) return AP.OutStreamer.EmitZeros(Size); @@ -1955,10 +2191,10 @@ static void emitGlobalConstantImpl(const Constant *CV, AsmPrinter &AP) { return emitGlobalConstantDataSequential(CDS, AP); if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) - return emitGlobalConstantArray(CVA, AP); + return emitGlobalConstantArray(CVA, AP, BaseCV, Offset); if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) - return emitGlobalConstantStruct(CVS, AP); + return emitGlobalConstantStruct(CVS, AP, BaseCV, Offset); if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) { // Look through bitcasts, which might not be able to be MCExpr'ized (e.g. of @@ -1981,13 +2217,21 @@ static void emitGlobalConstantImpl(const Constant *CV, AsmPrinter &AP) { // Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it // thread the streamer with EmitValue. - AP.OutStreamer.EmitValue(lowerConstant(CV, AP), Size); + const MCExpr *ME = AP.lowerConstant(CV); + + // Since lowerConstant already folded and got rid of all IR pointer and + // integer casts, detect GOT equivalent accesses by looking into the MCExpr + // directly. + if (AP.getObjFileLowering().supportIndirectSymViaGOTPCRel()) + handleIndirectSymViaGOTPCRel(AP, &ME, BaseCV, Offset); + + AP.OutStreamer.EmitValue(ME, Size); } /// EmitGlobalConstant - Print a general LLVM constant to the .s file. void AsmPrinter::EmitGlobalConstant(const Constant *CV) { uint64_t Size = - TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(CV->getType()); + TM.getDataLayout()->getTypeAllocSize(CV->getType()); if (Size) emitGlobalConstantImpl(CV, *this); else if (MAI->hasSubsectionsViaSymbols()) { @@ -2015,16 +2259,16 @@ void AsmPrinter::printOffset(int64_t Offset, raw_ostream &OS) const { /// GetTempSymbol - Return the MCSymbol corresponding to the assembler /// temporary label with the specified stem and unique ID. -MCSymbol *AsmPrinter::GetTempSymbol(Twine Name, unsigned ID) const { - const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); +MCSymbol *AsmPrinter::GetTempSymbol(const Twine &Name, unsigned ID) const { + const DataLayout *DL = TM.getDataLayout(); return OutContext.GetOrCreateSymbol(Twine(DL->getPrivateGlobalPrefix()) + Name + Twine(ID)); } /// GetTempSymbol - Return an assembler temporary label with the specified /// stem. -MCSymbol *AsmPrinter::GetTempSymbol(Twine Name) const { - const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); +MCSymbol *AsmPrinter::GetTempSymbol(const Twine &Name) const { + const DataLayout *DL = TM.getDataLayout(); return OutContext.GetOrCreateSymbol(Twine(DL->getPrivateGlobalPrefix())+ Name); } @@ -2040,7 +2284,7 @@ MCSymbol *AsmPrinter::GetBlockAddressSymbol(const BasicBlock *BB) const { /// GetCPISymbol - Return the symbol for the specified constant pool entry. MCSymbol *AsmPrinter::GetCPISymbol(unsigned CPID) const { - const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); + const DataLayout *DL = TM.getDataLayout(); return OutContext.GetOrCreateSymbol (Twine(DL->getPrivateGlobalPrefix()) + "CPI" + Twine(getFunctionNumber()) + "_" + Twine(CPID)); @@ -2054,7 +2298,7 @@ MCSymbol *AsmPrinter::GetJTISymbol(unsigned JTID, bool isLinkerPrivate) const { /// GetJTSetSymbol - Return the symbol for the specified jump table .set /// FIXME: privatize to AsmPrinter. MCSymbol *AsmPrinter::GetJTSetSymbol(unsigned UID, unsigned MBBID) const { - const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); + const DataLayout *DL = TM.getDataLayout(); return OutContext.GetOrCreateSymbol (Twine(DL->getPrivateGlobalPrefix()) + Twine(getFunctionNumber()) + "_" + Twine(UID) + "_set_" + Twine(MBBID)); @@ -2252,6 +2496,11 @@ GCMetadataPrinter *AsmPrinter::GetOrCreateGCPrinter(GCStrategy &S) { if (!S.usesMetadata()) return nullptr; + assert(!S.useStatepoints() && "statepoints do not currently support custom" + " stackmap formats, please see the documentation for a description of" + " the default format. If you really need a custom serialized format," + " please file a bug"); + gcp_map_type &GCMap = getGCMap(GCMetadataPrinters); gcp_map_type::iterator GCPI = GCMap.find(&S); if (GCPI != GCMap.end()) diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index 05f6a68..d0958c1 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -12,26 +12,44 @@ //===----------------------------------------------------------------------===// #include "ByteStreamer.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/ADT/SmallBitVector.h" +#include "DwarfExpression.h" #include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MachineLocation.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; #define DEBUG_TYPE "asm-printer" +void DebugLocDwarfExpression::EmitOp(uint8_t Op, const char *Comment) { + BS.EmitInt8( + Op, Comment ? Twine(Comment) + " " + dwarf::OperationEncodingString(Op) + : dwarf::OperationEncodingString(Op)); +} + +void DebugLocDwarfExpression::EmitSigned(int Value) { + BS.EmitSLEB128(Value, Twine(Value)); +} + +void DebugLocDwarfExpression::EmitUnsigned(unsigned Value) { + BS.EmitULEB128(Value, Twine(Value)); +} + +bool DebugLocDwarfExpression::isFrameRegister(unsigned MachineReg) { + // This information is not available while emitting .debug_loc entries. + return false; +} + //===----------------------------------------------------------------------===// // Dwarf Emission Helper Routines //===----------------------------------------------------------------------===// @@ -131,7 +149,7 @@ unsigned AsmPrinter::GetSizeOfEncodedValue(unsigned Encoding) const { default: llvm_unreachable("Invalid encoded value."); case dwarf::DW_EH_PE_absptr: - return TM.getSubtargetImpl()->getDataLayout()->getPointerSize(); + return TM.getDataLayout()->getPointerSize(); case dwarf::DW_EH_PE_udata2: return 2; case dwarf::DW_EH_PE_udata4: @@ -187,57 +205,6 @@ void AsmPrinter::EmitSectionOffset(const MCSymbol *Label, EmitLabelDifference(Label, SectionLabel, 4); } -/// Emit a dwarf register operation. -static void emitDwarfRegOp(ByteStreamer &Streamer, int Reg) { - assert(Reg >= 0); - if (Reg < 32) { - Streamer.EmitInt8(dwarf::DW_OP_reg0 + Reg, - dwarf::OperationEncodingString(dwarf::DW_OP_reg0 + Reg)); - } else { - Streamer.EmitInt8(dwarf::DW_OP_regx, "DW_OP_regx"); - Streamer.EmitULEB128(Reg, Twine(Reg)); - } -} - -/// Emit an (double-)indirect dwarf register operation. -static void emitDwarfRegOpIndirect(ByteStreamer &Streamer, int Reg, int Offset, - bool Deref) { - assert(Reg >= 0); - if (Reg < 32) { - Streamer.EmitInt8(dwarf::DW_OP_breg0 + Reg, - dwarf::OperationEncodingString(dwarf::DW_OP_breg0 + Reg)); - } else { - Streamer.EmitInt8(dwarf::DW_OP_bregx, "DW_OP_bregx"); - Streamer.EmitULEB128(Reg, Twine(Reg)); - } - Streamer.EmitSLEB128(Offset); - if (Deref) - Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref"); -} - -void AsmPrinter::EmitDwarfOpPiece(ByteStreamer &Streamer, unsigned SizeInBits, - unsigned OffsetInBits) const { - assert(SizeInBits > 0 && "piece has size zero"); - const unsigned SizeOfByte = 8; - if (OffsetInBits > 0 || SizeInBits % SizeOfByte) { - Streamer.EmitInt8(dwarf::DW_OP_bit_piece, "DW_OP_bit_piece"); - Streamer.EmitULEB128(SizeInBits, Twine(SizeInBits)); - Streamer.EmitULEB128(OffsetInBits, Twine(OffsetInBits)); - } else { - Streamer.EmitInt8(dwarf::DW_OP_piece, "DW_OP_piece"); - unsigned ByteSize = SizeInBits / SizeOfByte; - Streamer.EmitULEB128(ByteSize, Twine(ByteSize)); - } -} - -/// Emit a shift-right dwarf expression. -static void emitDwarfOpShr(ByteStreamer &Streamer, - unsigned ShiftBy) { - Streamer.EmitInt8(dwarf::DW_OP_constu, "DW_OP_constu"); - Streamer.EmitULEB128(ShiftBy); - Streamer.EmitInt8(dwarf::DW_OP_shr, "DW_OP_shr"); -} - // Some targets do not provide a DWARF register number for every // register. This function attempts to emit a DWARF register by // emitting a piece of a super-register or by piecing together @@ -247,112 +214,44 @@ void AsmPrinter::EmitDwarfRegOpPiece(ByteStreamer &Streamer, unsigned PieceSizeInBits, unsigned PieceOffsetInBits) const { assert(MLoc.isReg() && "MLoc must be a register"); - const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo(); - int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); - - // If this is a valid register number, emit it. - if (Reg >= 0) { - emitDwarfRegOp(Streamer, Reg); - EmitDwarfOpPiece(Streamer, PieceSizeInBits, PieceOffsetInBits); - return; - } - - // Walk up the super-register chain until we find a valid number. - // For example, EAX on x86_64 is a 32-bit piece of RAX with offset 0. - for (MCSuperRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) { - Reg = TRI->getDwarfRegNum(*SR, false); - if (Reg >= 0) { - unsigned Idx = TRI->getSubRegIndex(*SR, MLoc.getReg()); - unsigned Size = TRI->getSubRegIdxSize(Idx); - unsigned RegOffset = TRI->getSubRegIdxOffset(Idx); - OutStreamer.AddComment("super-register"); - emitDwarfRegOp(Streamer, Reg); - if (PieceOffsetInBits == RegOffset) { - EmitDwarfOpPiece(Streamer, Size, RegOffset); - } else { - // If this is part of a variable in a sub-register at a - // non-zero offset, we need to manually shift the value into - // place, since the DW_OP_piece describes the part of the - // variable, not the position of the subregister. - if (RegOffset) - emitDwarfOpShr(Streamer, RegOffset); - EmitDwarfOpPiece(Streamer, Size, PieceOffsetInBits); - } - return; - } - } - - // Otherwise, attempt to find a covering set of sub-register numbers. - // For example, Q0 on ARM is a composition of D0+D1. - // - // Keep track of the current position so we can emit the more - // efficient DW_OP_piece. - unsigned CurPos = PieceOffsetInBits; - // The size of the register in bits, assuming 8 bits per byte. - unsigned RegSize = TRI->getMinimalPhysRegClass(MLoc.getReg())->getSize() * 8; - // Keep track of the bits in the register we already emitted, so we - // can avoid emitting redundant aliasing subregs. - SmallBitVector Coverage(RegSize, false); - for (MCSubRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) { - unsigned Idx = TRI->getSubRegIndex(MLoc.getReg(), *SR); - unsigned Size = TRI->getSubRegIdxSize(Idx); - unsigned Offset = TRI->getSubRegIdxOffset(Idx); - Reg = TRI->getDwarfRegNum(*SR, false); - - // Intersection between the bits we already emitted and the bits - // covered by this subregister. - SmallBitVector Intersection(RegSize, false); - Intersection.set(Offset, Offset + Size); - Intersection ^= Coverage; - - // If this sub-register has a DWARF number and we haven't covered - // its range, emit a DWARF piece for it. - if (Reg >= 0 && Intersection.any()) { - OutStreamer.AddComment("sub-register"); - emitDwarfRegOp(Streamer, Reg); - EmitDwarfOpPiece(Streamer, Size, Offset == CurPos ? 0 : Offset); - CurPos = Offset + Size; - - // Mark it as emitted. - Coverage.set(Offset, Offset + Size); - } - } + DebugLocDwarfExpression Expr(*this, Streamer); + Expr.AddMachineRegPiece(MLoc.getReg(), PieceSizeInBits, PieceOffsetInBits); +} - if (CurPos == PieceOffsetInBits) { - // FIXME: We have no reasonable way of handling errors in here. - Streamer.EmitInt8(dwarf::DW_OP_nop, - "nop (could not find a dwarf register number)"); - } +void AsmPrinter::EmitDwarfOpPiece(ByteStreamer &Streamer, + unsigned PieceSizeInBits, + unsigned PieceOffsetInBits) const { + DebugLocDwarfExpression Expr(*this, Streamer); + Expr.AddOpPiece(PieceSizeInBits, PieceOffsetInBits); } /// EmitDwarfRegOp - Emit dwarf register operation. void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer, - const MachineLocation &MLoc, - bool Indirect) const { - const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo(); - int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); + const MachineLocation &MLoc) const { + DebugLocDwarfExpression Expr(*this, Streamer); + const MCRegisterInfo *MRI = MMI->getContext().getRegisterInfo(); + int Reg = MRI->getDwarfRegNum(MLoc.getReg(), false); if (Reg < 0) { // We assume that pointers are always in an addressable register. - if (Indirect || MLoc.isIndirect()) { + if (MLoc.isIndirect()) // FIXME: We have no reasonable way of handling errors in here. The // caller might be in the middle of a dwarf expression. We should // probably assert that Reg >= 0 once debug info generation is more // mature. - Streamer.EmitInt8(dwarf::DW_OP_nop, - "nop (invalid dwarf register number for indirect loc)"); - return; - } + return Expr.EmitOp(dwarf::DW_OP_nop, + "nop (could not find a dwarf register number)"); // Attempt to find a valid super- or sub-register. - return EmitDwarfRegOpPiece(Streamer, MLoc); + if (!Expr.AddMachineRegPiece(MLoc.getReg())) + Expr.EmitOp(dwarf::DW_OP_nop, + "nop (could not find a dwarf register number)"); + return; } if (MLoc.isIndirect()) - emitDwarfRegOpIndirect(Streamer, Reg, MLoc.getOffset(), Indirect); - else if (Indirect) - emitDwarfRegOpIndirect(Streamer, Reg, 0, false); + Expr.AddRegIndirect(Reg, MLoc.getOffset()); else - emitDwarfRegOp(Streamer, Reg); + Expr.AddReg(Reg); } //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index cca5f22..e6e7c97 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -32,6 +32,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" @@ -64,7 +65,7 @@ static void srcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) { if (LocInfo->getNumOperands() != 0) if (const ConstantInt *CI = - dyn_cast<ConstantInt>(LocInfo->getOperand(ErrorLine))) + mdconst::dyn_extract<ConstantInt>(LocInfo->getOperand(ErrorLine))) LocCookie = CI->getZExtValue(); } @@ -90,8 +91,19 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MDNode *LocMDNode, assert(MCAI && "No MCAsmInfo"); if (!MCAI->useIntegratedAssembler() && !OutStreamer.isIntegratedAssemblerRequired()) { + emitInlineAsmStart(); OutStreamer.EmitRawText(Str); - emitInlineAsmEnd(TM.getSubtarget<MCSubtargetInfo>(), nullptr); + // If we have a machine function then grab the MCSubtarget off of that, + // otherwise we're at the module level and want to construct one from + // the default CPU and target triple. + if (MF) { + emitInlineAsmEnd(MF->getSubtarget<MCSubtargetInfo>(), nullptr); + } else { + std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo( + TM.getTargetTriple(), TM.getTargetCPU(), + TM.getTargetFeatureString())); + emitInlineAsmEnd(*STI, nullptr); + } return; } @@ -137,11 +149,13 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MDNode *LocMDNode, // emitInlineAsmEnd(). MCSubtargetInfo STIOrig = *STI; - MCTargetOptions MCOptions; - if (MF) - MCOptions = MF->getTarget().Options.MCOptions; - std::unique_ptr<MCTargetAsmParser> TAP( - TM.getTarget().createMCAsmParser(*STI, *Parser, *MII, MCOptions)); + // We create a new MCInstrInfo here since we might be at the module level + // and not have a MachineFunction to initialize the TargetInstrInfo from and + // we only need MCInstrInfo for asm parsing. We create one unconditionally + // because it's not subtarget dependent. + std::unique_ptr<MCInstrInfo> MII(TM.getTarget().createMCInstrInfo()); + std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser( + *STI, *Parser, *MII, TM.Options.MCOptions)); if (!TAP) report_fatal_error("Inline asm not supported by this streamer because" " we don't have an asm parser for this target\n"); @@ -152,6 +166,7 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MDNode *LocMDNode, TAP->SetFrameRegister(TRI->getFrameRegister(*MF)); } + emitInlineAsmStart(); // Don't implicitly switch to the text section before the asm. int Res = Parser->Run(/*NoInitialTextSection*/ true, /*NoFinalize*/ true); @@ -467,7 +482,8 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { if (MI->getOperand(i-1).isMetadata() && (LocMD = MI->getOperand(i-1).getMetadata()) && LocMD->getNumOperands() != 0) { - if (const ConstantInt *CI = dyn_cast<ConstantInt>(LocMD->getOperand(0))) { + if (const ConstantInt *CI = + mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) { LocCookie = CI->getZExtValue(); break; } @@ -505,7 +521,7 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { /// for their own strange codes. void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, const char *Code) const { - const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); + const DataLayout *DL = TM.getDataLayout(); if (!strcmp(Code, "private")) { OS << DL->getPrivateGlobalPrefix(); } else if (!strcmp(Code, "comment")) { @@ -566,5 +582,7 @@ bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, return true; } +void AsmPrinter::emitInlineAsmStart() const {} + void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, const MCSubtargetInfo *EndInfo) const {} diff --git a/lib/CodeGen/AsmPrinter/ByteStreamer.h b/lib/CodeGen/AsmPrinter/ByteStreamer.h index 0cc8353..42be114 100644 --- a/lib/CodeGen/AsmPrinter/ByteStreamer.h +++ b/lib/CodeGen/AsmPrinter/ByteStreamer.h @@ -15,10 +15,10 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_BYTESTREAMER_H #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 "DIEHash.h" namespace llvm { class ByteStreamer { diff --git a/lib/CodeGen/AsmPrinter/CMakeLists.txt b/lib/CodeGen/AsmPrinter/CMakeLists.txt index e6b7d64..01d2c72 100644 --- a/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ b/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_library(LLVMAsmPrinter DwarfCFIException.cpp DwarfCompileUnit.cpp DwarfDebug.cpp + DwarfExpression.cpp DwarfFile.cpp DwarfStringPool.cpp DwarfUnit.cpp diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp index 50ea369..64ba56b 100644 --- a/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/lib/CodeGen/AsmPrinter/DIE.cpp @@ -11,8 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "DIE.h" - +#include "llvm/CodeGen/DIE.h" #include "DwarfCompileUnit.h" #include "DwarfDebug.h" #include "DwarfUnit.h" diff --git a/lib/CodeGen/AsmPrinter/DIE.h b/lib/CodeGen/AsmPrinter/DIE.h deleted file mode 100644 index e310aef..0000000 --- a/lib/CodeGen/AsmPrinter/DIE.h +++ /dev/null @@ -1,587 +0,0 @@ -//===--- lib/CodeGen/DIE.h - DWARF Info Entries -----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Data structures for DWARF info entries. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DIE_H -#define LLVM_LIB_CODEGEN_ASMPRINTER_DIE_H - -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Dwarf.h" -#include <vector> - -namespace llvm { -class AsmPrinter; -class MCExpr; -class MCSymbol; -class raw_ostream; -class DwarfTypeUnit; - -//===--------------------------------------------------------------------===// -/// DIEAbbrevData - Dwarf abbreviation data, describes one attribute of a -/// Dwarf abbreviation. -class DIEAbbrevData { - /// Attribute - Dwarf attribute code. - /// - dwarf::Attribute Attribute; - - /// Form - Dwarf form code. - /// - dwarf::Form Form; - -public: - DIEAbbrevData(dwarf::Attribute A, dwarf::Form F) : Attribute(A), Form(F) {} - - // Accessors. - dwarf::Attribute getAttribute() const { return Attribute; } - dwarf::Form getForm() const { return Form; } - - /// Profile - Used to gather unique data for the abbreviation folding set. - /// - void Profile(FoldingSetNodeID &ID) const; -}; - -//===--------------------------------------------------------------------===// -/// DIEAbbrev - Dwarf abbreviation, describes the organization of a debug -/// information object. -class DIEAbbrev : public FoldingSetNode { - /// Unique number for node. - /// - unsigned Number; - - /// Tag - Dwarf tag code. - /// - dwarf::Tag Tag; - - /// Children - Whether or not this node has children. - /// - // This cheats a bit in all of the uses since the values in the standard - // are 0 and 1 for no children and children respectively. - bool Children; - - /// Data - Raw data bytes for abbreviation. - /// - SmallVector<DIEAbbrevData, 12> Data; - -public: - DIEAbbrev(dwarf::Tag T, bool C) : Tag(T), Children(C), Data() {} - - // Accessors. - dwarf::Tag getTag() const { return Tag; } - unsigned getNumber() const { return Number; } - bool hasChildren() const { return Children; } - const SmallVectorImpl<DIEAbbrevData> &getData() const { return Data; } - void setChildrenFlag(bool hasChild) { Children = hasChild; } - void setNumber(unsigned N) { Number = N; } - - /// AddAttribute - Adds another set of attribute information to the - /// abbreviation. - void AddAttribute(dwarf::Attribute Attribute, dwarf::Form Form) { - Data.push_back(DIEAbbrevData(Attribute, Form)); - } - - /// Profile - Used to gather unique data for the abbreviation folding set. - /// - void Profile(FoldingSetNodeID &ID) const; - - /// Emit - Print the abbreviation using the specified asm printer. - /// - void Emit(AsmPrinter *AP) const; - -#ifndef NDEBUG - void print(raw_ostream &O); - void dump(); -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIE - A structured debug information entry. Has an abbreviation which -/// describes its organization. -class DIEValue; - -class DIE { -protected: - /// Offset - Offset in debug info section. - /// - unsigned Offset; - - /// Size - Size of instance + children. - /// - unsigned Size; - - /// Abbrev - Buffer for constructing abbreviation. - /// - DIEAbbrev Abbrev; - - /// Children DIEs. - /// - // This can't be a vector<DIE> because pointer validity is requirent for the - // Parent pointer and DIEEntry. - // It can't be a list<DIE> because some clients need pointer validity before - // the object has been added to any child list - // (eg: DwarfUnit::constructVariableDIE). These aren't insurmountable, but may - // be more convoluted than beneficial. - std::vector<std::unique_ptr<DIE>> Children; - - DIE *Parent; - - /// Attribute values. - /// - SmallVector<DIEValue *, 12> Values; - -protected: - DIE() - : Offset(0), Size(0), Abbrev((dwarf::Tag)0, dwarf::DW_CHILDREN_no), - Parent(nullptr) {} - -public: - explicit DIE(dwarf::Tag Tag) - : Offset(0), Size(0), Abbrev((dwarf::Tag)Tag, dwarf::DW_CHILDREN_no), - Parent(nullptr) {} - - // Accessors. - DIEAbbrev &getAbbrev() { return Abbrev; } - const DIEAbbrev &getAbbrev() const { return Abbrev; } - unsigned getAbbrevNumber() const { return Abbrev.getNumber(); } - dwarf::Tag getTag() const { return Abbrev.getTag(); } - unsigned getOffset() const { return Offset; } - unsigned getSize() const { return Size; } - const std::vector<std::unique_ptr<DIE>> &getChildren() const { - return Children; - } - const SmallVectorImpl<DIEValue *> &getValues() const { return Values; } - DIE *getParent() const { return Parent; } - /// Climb up the parent chain to get the compile or type unit DIE this DIE - /// belongs to. - const DIE *getUnit() const; - /// Similar to getUnit, returns null when DIE is not added to an - /// owner yet. - const DIE *getUnitOrNull() const; - void setOffset(unsigned O) { Offset = O; } - void setSize(unsigned S) { Size = S; } - - /// addValue - Add a value and attributes to a DIE. - /// - void addValue(dwarf::Attribute Attribute, dwarf::Form Form, DIEValue *Value) { - Abbrev.AddAttribute(Attribute, Form); - Values.push_back(Value); - } - - /// addChild - Add a child to the DIE. - /// - void addChild(std::unique_ptr<DIE> Child) { - assert(!Child->getParent()); - Abbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes); - Child->Parent = this; - Children.push_back(std::move(Child)); - } - - /// findAttribute - Find a value in the DIE with the attribute given, - /// returns NULL if no such attribute exists. - DIEValue *findAttribute(dwarf::Attribute Attribute) const; - -#ifndef NDEBUG - void print(raw_ostream &O, unsigned IndentCount = 0) const; - void dump(); -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIEValue - A debug information entry value. Some of these roughly correlate -/// to DWARF attribute classes. -/// -class DIEValue { - virtual void anchor(); - -public: - enum Type { - isInteger, - isString, - isExpr, - isLabel, - isDelta, - isEntry, - isTypeSignature, - isBlock, - isLoc, - isLocList, - }; - -protected: - /// Ty - Type of data stored in the value. - /// - Type Ty; - - explicit DIEValue(Type T) : Ty(T) {} - virtual ~DIEValue() {} - -public: - // Accessors - Type getType() const { return Ty; } - - /// EmitValue - Emit value via the Dwarf writer. - /// - virtual void EmitValue(AsmPrinter *AP, dwarf::Form Form) const = 0; - - /// SizeOf - Return the size of a value in bytes. - /// - virtual unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const = 0; - -#ifndef NDEBUG - virtual void print(raw_ostream &O) const = 0; - void dump() const; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIEInteger - An integer value DIE. -/// -class DIEInteger : public DIEValue { - uint64_t Integer; - -public: - explicit DIEInteger(uint64_t I) : DIEValue(isInteger), Integer(I) {} - - /// BestForm - Choose the best form for integer. - /// - static dwarf::Form BestForm(bool IsSigned, uint64_t Int) { - if (IsSigned) { - const int64_t SignedInt = Int; - if ((char)Int == SignedInt) - return dwarf::DW_FORM_data1; - if ((short)Int == SignedInt) - return dwarf::DW_FORM_data2; - if ((int)Int == SignedInt) - return dwarf::DW_FORM_data4; - } else { - if ((unsigned char)Int == Int) - return dwarf::DW_FORM_data1; - if ((unsigned short)Int == Int) - return dwarf::DW_FORM_data2; - if ((unsigned int)Int == Int) - return dwarf::DW_FORM_data4; - } - return dwarf::DW_FORM_data8; - } - - /// EmitValue - Emit integer of appropriate size. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - uint64_t getValue() const { return Integer; } - - /// SizeOf - Determine size of integer value in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override; - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *I) { return I->getType() == isInteger; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIEExpr - An expression DIE. -// -class DIEExpr : public DIEValue { - const MCExpr *Expr; - -public: - explicit DIEExpr(const MCExpr *E) : DIEValue(isExpr), Expr(E) {} - - /// EmitValue - Emit expression value. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - /// getValue - Get MCExpr. - /// - const MCExpr *getValue() const { return Expr; } - - /// SizeOf - Determine size of expression value in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override; - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *E) { return E->getType() == isExpr; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIELabel - A label DIE. -// -class DIELabel : public DIEValue { - const MCSymbol *Label; - -public: - explicit DIELabel(const MCSymbol *L) : DIEValue(isLabel), Label(L) {} - - /// EmitValue - Emit label value. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - /// getValue - Get MCSymbol. - /// - const MCSymbol *getValue() const { return Label; } - - /// SizeOf - Determine size of label value in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override; - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *L) { return L->getType() == isLabel; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIEDelta - A simple label difference DIE. -/// -class DIEDelta : public DIEValue { - const MCSymbol *LabelHi; - const MCSymbol *LabelLo; - -public: - DIEDelta(const MCSymbol *Hi, const MCSymbol *Lo) - : DIEValue(isDelta), LabelHi(Hi), LabelLo(Lo) {} - - /// EmitValue - Emit delta value. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - /// SizeOf - Determine size of delta value in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override; - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *D) { return D->getType() == isDelta; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIEString - A container for string values. -/// -class DIEString : public DIEValue { - const DIEValue *Access; - StringRef Str; - -public: - DIEString(const DIEValue *Acc, StringRef S) - : DIEValue(isString), Access(Acc), Str(S) {} - - /// getString - Grab the string out of the object. - StringRef getString() const { return Str; } - - /// EmitValue - Emit delta value. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - /// SizeOf - Determine size of delta value in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override; - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *D) { return D->getType() == isString; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIEEntry - A pointer to another debug information entry. An instance of -/// this class can also be used as a proxy for a debug information entry not -/// yet defined (ie. types.) -class DIEEntry : public DIEValue { - DIE &Entry; - -public: - explicit DIEEntry(DIE &E) : DIEValue(isEntry), Entry(E) { - } - - DIE &getEntry() const { return Entry; } - - /// EmitValue - Emit debug information entry offset. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - /// SizeOf - Determine size of debug information entry in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override { - return Form == dwarf::DW_FORM_ref_addr ? getRefAddrSize(AP) - : sizeof(int32_t); - } - - /// Returns size of a ref_addr entry. - static unsigned getRefAddrSize(AsmPrinter *AP); - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *E) { return E->getType() == isEntry; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -//===--------------------------------------------------------------------===// -/// \brief A signature reference to a type unit. -class DIETypeSignature : public DIEValue { - const DwarfTypeUnit &Unit; - -public: - explicit DIETypeSignature(const DwarfTypeUnit &Unit) - : DIEValue(isTypeSignature), Unit(Unit) {} - - /// \brief Emit type unit signature. - void EmitValue(AsmPrinter *Asm, dwarf::Form Form) const override; - - /// Returns size of a ref_sig8 entry. - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override { - assert(Form == dwarf::DW_FORM_ref_sig8); - return 8; - } - - // \brief Implement isa/cast/dyncast. - static bool classof(const DIEValue *E) { - return E->getType() == isTypeSignature; - } -#ifndef NDEBUG - void print(raw_ostream &O) const override; - void dump() const; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIELoc - Represents an expression location. -// -class DIELoc : public DIEValue, public DIE { - mutable unsigned Size; // Size in bytes excluding size header. -public: - DIELoc() : DIEValue(isLoc), Size(0) {} - - /// ComputeSize - Calculate the size of the location expression. - /// - unsigned ComputeSize(AsmPrinter *AP) const; - - /// BestForm - Choose the best form for data. - /// - dwarf::Form BestForm(unsigned DwarfVersion) const { - if (DwarfVersion > 3) - return dwarf::DW_FORM_exprloc; - // Pre-DWARF4 location expressions were blocks and not exprloc. - if ((unsigned char)Size == Size) - return dwarf::DW_FORM_block1; - if ((unsigned short)Size == Size) - return dwarf::DW_FORM_block2; - if ((unsigned int)Size == Size) - return dwarf::DW_FORM_block4; - return dwarf::DW_FORM_block; - } - - /// EmitValue - Emit location data. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - /// SizeOf - Determine size of location data in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override; - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *E) { return E->getType() == isLoc; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIEBlock - Represents a block of values. -// -class DIEBlock : public DIEValue, public DIE { - mutable unsigned Size; // Size in bytes excluding size header. -public: - DIEBlock() : DIEValue(isBlock), Size(0) {} - - /// ComputeSize - Calculate the size of the location expression. - /// - unsigned ComputeSize(AsmPrinter *AP) const; - - /// BestForm - Choose the best form for data. - /// - dwarf::Form BestForm() const { - if ((unsigned char)Size == Size) - return dwarf::DW_FORM_block1; - if ((unsigned short)Size == Size) - return dwarf::DW_FORM_block2; - if ((unsigned int)Size == Size) - return dwarf::DW_FORM_block4; - return dwarf::DW_FORM_block; - } - - /// EmitValue - Emit location data. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - /// SizeOf - Determine size of location data in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override; - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *E) { return E->getType() == isBlock; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -//===--------------------------------------------------------------------===// -/// DIELocList - Represents a pointer to a location list in the debug_loc -/// section. -// -class DIELocList : public DIEValue { - // Index into the .debug_loc vector. - size_t Index; - -public: - DIELocList(size_t I) : DIEValue(isLocList), Index(I) {} - - /// getValue - Grab the current index out. - size_t getValue() const { return Index; } - - /// EmitValue - Emit location data. - /// - void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override; - - /// SizeOf - Determine size of location data in bytes. - /// - unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override; - - // Implement isa/cast/dyncast. - static bool classof(const DIEValue *E) { return E->getType() == isLocList; } - -#ifndef NDEBUG - void print(raw_ostream &O) const override; -#endif -}; - -} // end llvm namespace - -#endif diff --git a/lib/CodeGen/AsmPrinter/DIEHash.cpp b/lib/CodeGen/AsmPrinter/DIEHash.cpp index b2a3ba8..1e2ba2c 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -13,11 +13,11 @@ #include "ByteStreamer.h" #include "DIEHash.h" -#include "DIE.h" #include "DwarfDebug.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Endian.h" diff --git a/lib/CodeGen/AsmPrinter/DIEHash.h b/lib/CodeGen/AsmPrinter/DIEHash.h index 872aa0e..ac014b7 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.h +++ b/lib/CodeGen/AsmPrinter/DIEHash.h @@ -14,8 +14,8 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DIEHASH_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DIEHASH_H -#include "DIE.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/Support/MD5.h" namespace llvm { diff --git a/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/lib/CodeGen/AsmPrinter/DebugLocEntry.h index 6cca985..6d55c03 100644 --- a/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ b/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -11,8 +11,8 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" -#include "llvm/MC/MachineLocation.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MachineLocation.h" namespace llvm { class MDNode; @@ -74,7 +74,7 @@ public: MachineLocation getLoc() const { return Loc; } const MDNode *getVariableNode() const { return Variable; } DIVariable getVariable() const { return DIVariable(Variable); } - bool isVariablePiece() const { return getExpression().isVariablePiece(); } + bool isBitPiece() const { return getExpression().isBitPiece(); } DIExpression getExpression() const { return DIExpression(Expression); } friend bool operator==(const Value &, const Value &); friend bool operator<(const Value &, const Value &); @@ -101,8 +101,8 @@ public: DIVariable Var(Values[0].Variable); DIExpression NextExpr(Next.Values[0].Expression); DIVariable NextVar(Next.Values[0].Variable); - if (Var == NextVar && Expr.isVariablePiece() && - NextExpr.isVariablePiece()) { + if (Var == NextVar && Expr.isBitPiece() && + NextExpr.isBitPiece()) { addValues(Next.Values); End = Next.End; return true; @@ -131,7 +131,7 @@ public: Values.append(Vals.begin(), Vals.end()); sortUniqueValues(); assert(std::all_of(Values.begin(), Values.end(), [](DebugLocEntry::Value V){ - return V.isVariablePiece(); + return V.isBitPiece(); }) && "value must be a piece"); } @@ -176,8 +176,8 @@ inline bool operator==(const DebugLocEntry::Value &A, /// Compare two pieces based on their offset. inline bool operator<(const DebugLocEntry::Value &A, const DebugLocEntry::Value &B) { - return A.getExpression().getPieceOffset() < - B.getExpression().getPieceOffset(); + return A.getExpression().getBitPieceOffset() < + B.getExpression().getBitPieceOffset(); } } diff --git a/lib/CodeGen/AsmPrinter/DebugLocList.h b/lib/CodeGen/AsmPrinter/DebugLocList.h index 2a4f58f..0f1d2ed 100644 --- a/lib/CodeGen/AsmPrinter/DebugLocList.h +++ b/lib/CodeGen/AsmPrinter/DebugLocList.h @@ -10,8 +10,8 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCLIST_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCLIST_H -#include "llvm/ADT/SmallVector.h" #include "DebugLocEntry.h" +#include "llvm/ADT/SmallVector.h" namespace llvm { class DwarfCompileUnit; diff --git a/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp b/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp index 7e87566..a71f35e 100644 --- a/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp @@ -12,12 +12,12 @@ //===----------------------------------------------------------------------===// #include "DwarfAccelTable.h" -#include "DIE.h" #include "DwarfCompileUnit.h" #include "DwarfDebug.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" diff --git a/lib/CodeGen/AsmPrinter/DwarfAccelTable.h b/lib/CodeGen/AsmPrinter/DwarfAccelTable.h index 3cdf678..74963da 100644 --- a/lib/CodeGen/AsmPrinter/DwarfAccelTable.h +++ b/lib/CodeGen/AsmPrinter/DwarfAccelTable.h @@ -14,9 +14,9 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H -#include "DIE.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" @@ -215,8 +215,8 @@ private: #endif }; - DwarfAccelTable(const DwarfAccelTable &) LLVM_DELETED_FUNCTION; - void operator=(const DwarfAccelTable &) LLVM_DELETED_FUNCTION; + DwarfAccelTable(const DwarfAccelTable &) = delete; + void operator=(const DwarfAccelTable &) = delete; // Internal Functions void EmitHeader(AsmPrinter *); diff --git a/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp index 0dc52da..f45b24c 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -51,7 +51,8 @@ void DwarfCFIException::endModule() { if (moveTypeModule == AsmPrinter::CFI_M_Debug) Asm->OutStreamer.EmitCFISections(false, true); - if (!Asm->MAI->usesItaniumLSDAForExceptions()) + // SjLj uses this pass and it doesn't need this info. + if (!Asm->MAI->usesCFIForEH()) return; const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); @@ -90,7 +91,7 @@ void DwarfCFIException::beginFunction(const MachineFunction *MF) { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); unsigned PerEncoding = TLOF.getPersonalityEncoding(); - const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()]; + const Function *Per = MMI->getPersonality(); shouldEmitPersonality = hasLandingPads && PerEncoding != dwarf::DW_EH_PE_omit && Per; diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 2f1b0e5..dcc5fe4 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -1,5 +1,5 @@ #include "DwarfCompileUnit.h" - +#include "DwarfExpression.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GlobalValue.h" @@ -10,8 +10,8 @@ #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetSubtargetInfo.h" #include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" namespace llvm { @@ -103,7 +103,7 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(DIGlobalVariable GV) { assert(GV.isGlobalVariable()); - DIScope GVContext = DD->resolve(GV.getContext()); + DIScope GVContext = GV.getContext(); DIType GTy = DD->resolve(GV.getType()); // Construct the context before querying for the existence of the DIE in @@ -122,7 +122,7 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(DIGlobalVariable GV) { DIE *VariableSpecDIE = getOrCreateStaticMemberDIE(SDMDecl); addDIEEntry(*VariableDIE, dwarf::DW_AT_specification, *VariableSpecDIE); } else { - DeclContext = resolve(GV.getContext()); + DeclContext = GV.getContext(); // Add name and type. addString(*VariableDIE, dwarf::DW_AT_name, GV.getDisplayName()); addType(*VariableDIE, GTy); @@ -292,10 +292,10 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(DISubprogram SP) { // Only include DW_AT_frame_base in full debug info if (!includeMinimalInlineScopes()) { - const TargetRegisterInfo *RI = - Asm->TM.getSubtargetImpl()->getRegisterInfo(); + const TargetRegisterInfo *RI = Asm->MF->getSubtarget().getRegisterInfo(); MachineLocation Location(RI->getFrameRegister(*Asm->MF)); - addAddress(*SPDie, dwarf::DW_AT_frame_base, Location); + if (RI->isPhysicalRegister(Location.getReg())) + addAddress(*SPDie, dwarf::DW_AT_frame_base, Location); } // Add name to the name table, we do this here because we're guaranteed @@ -515,15 +515,23 @@ DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, } // .. else use frame index. - int FI = DV.getFrameIndex(); - if (FI != ~0) { + if (DV.getFrameIndex().back() == ~0) + return VariableDie; + + auto Expr = DV.getExpression().begin(); + DIELoc *Loc = new (DIEValueAllocator) DIELoc(); + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + for (auto FI : DV.getFrameIndex()) { unsigned FrameReg = 0; - const TargetFrameLowering *TFI = - Asm->TM.getSubtargetImpl()->getFrameLowering(); + const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg); - MachineLocation Location(FrameReg, Offset); - addVariableAddress(DV, *VariableDie, Location); + assert(Expr != DV.getExpression().end() && + "Wrong number of expressions"); + DwarfExpr.AddMachineRegIndirect(FrameReg, Offset); + DwarfExpr.AddExpression(Expr->begin(), Expr->end()); + ++Expr; } + addBlock(*VariableDie, dwarf::DW_AT_location, Loc); return VariableDie; } @@ -694,7 +702,7 @@ void DwarfCompileUnit::collectDeadVariables(DISubprogram SP) { for (unsigned vi = 0, ve = Variables.getNumElements(); vi != ve; ++vi) { DIVariable DV(Variables.getElement(vi)); assert(DV.isVariable()); - DbgVariable NewVar(DV, DIExpression(nullptr), DD); + DbgVariable NewVar(DV, DIExpression(), DD); auto VariableDie = constructVariableDIE(NewVar); applyVariableAttributes(NewVar, *VariableDie); SPDIE->addChild(std::move(VariableDie)); @@ -736,24 +744,22 @@ void DwarfCompileUnit::addVariableAddress(const DbgVariable &DV, DIE &Die, else if (DV.isBlockByrefVariable()) addBlockByrefAddress(DV, Die, dwarf::DW_AT_location, Location); else - addAddress(Die, dwarf::DW_AT_location, Location, - DV.getVariable().isIndirect()); + addAddress(Die, dwarf::DW_AT_location, Location); } /// Add an address attribute to a die based on the location provided. void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute, - const MachineLocation &Location, - bool Indirect) { + const MachineLocation &Location) { DIELoc *Loc = new (DIEValueAllocator) DIELoc(); - if (Location.isReg() && !Indirect) - addRegisterOpPiece(*Loc, Location.getReg()); - else { - addRegisterOffset(*Loc, Location.getReg(), Location.getOffset()); - if (Indirect && !Location.isReg()) { - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); - } - } + bool validReg; + if (Location.isReg()) + validReg = addRegisterOpPiece(*Loc, Location.getReg()); + else + validReg = addRegisterOffset(*Loc, Location.getReg(), Location.getOffset()); + + if (!validReg) + return; // Now attach the location information to the DIE. addBlock(Die, Attribute, Loc); @@ -767,53 +773,21 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die, dwarf::Attribute Attribute, const MachineLocation &Location) { DIELoc *Loc = new (DIEValueAllocator) DIELoc(); - unsigned N = DV.getNumAddrElements(); - unsigned i = 0; - if (Location.isReg()) { - if (N >= 2 && DV.getAddrElement(0) == dwarf::DW_OP_plus) { - assert(!DV.getVariable().isIndirect() && - "double indirection not handled"); - // If first address element is OpPlus then emit - // DW_OP_breg + Offset instead of DW_OP_reg + Offset. - addRegisterOffset(*Loc, Location.getReg(), DV.getAddrElement(1)); - i = 2; - } else if (N >= 2 && DV.getAddrElement(0) == dwarf::DW_OP_deref) { - assert(!DV.getVariable().isIndirect() && - "double indirection not handled"); - addRegisterOpPiece(*Loc, Location.getReg(), - DV.getExpression().getPieceSize(), - DV.getExpression().getPieceOffset()); - i = 3; - } else - addRegisterOpPiece(*Loc, Location.getReg()); + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + assert(DV.getExpression().size() == 1); + DIExpression Expr = DV.getExpression().back(); + bool ValidReg; + if (Location.getOffset()) { + ValidReg = DwarfExpr.AddMachineRegIndirect(Location.getReg(), + Location.getOffset()); + if (ValidReg) + DwarfExpr.AddExpression(Expr.begin(), Expr.end()); } else - addRegisterOffset(*Loc, Location.getReg(), Location.getOffset()); - - for (; i < N; ++i) { - uint64_t Element = DV.getAddrElement(i); - if (Element == dwarf::DW_OP_plus) { - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); - addUInt(*Loc, dwarf::DW_FORM_udata, DV.getAddrElement(++i)); - - } else if (Element == dwarf::DW_OP_deref) { - if (!Location.isReg()) - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); - - } else if (Element == dwarf::DW_OP_piece) { - const unsigned SizeOfByte = 8; - unsigned PieceOffsetInBits = DV.getAddrElement(++i) * SizeOfByte; - unsigned PieceSizeInBits = DV.getAddrElement(++i) * SizeOfByte; - // Emit DW_OP_bit_piece Size Offset. - assert(PieceSizeInBits > 0 && "piece has zero size"); - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_bit_piece); - addUInt(*Loc, dwarf::DW_FORM_udata, PieceSizeInBits); - addUInt(*Loc, dwarf::DW_FORM_udata, PieceOffsetInBits); - } else - llvm_unreachable("unknown DIBuilder Opcode"); - } + ValidReg = DwarfExpr.AddMachineRegExpression(Expr, Location.getReg()); // Now attach the location information to the DIE. - addBlock(Die, Attribute, Loc); + if (ValidReg) + addBlock(Die, Attribute, Loc); } /// Add a Dwarf loclistptr attribute data and value. diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index e521f39..c66af65 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -15,9 +15,9 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFCOMPILEUNIT_H #include "DwarfUnit.h" -#include "llvm/Support/Dwarf.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/Support/Dwarf.h" namespace llvm { @@ -213,7 +213,7 @@ public: MachineLocation Location); /// Add an address attribute to a die based on the location provided. void addAddress(DIE &Die, dwarf::Attribute Attribute, - const MachineLocation &Location, bool Indirect = false); + const MachineLocation &Location); /// Start with the address based on the location provided, and generate the /// DWARF information necessary to find the actual variable (navigating the diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 230ea46..aa1f79f 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -12,16 +12,16 @@ //===----------------------------------------------------------------------===// #include "DwarfDebug.h" - #include "ByteStreamer.h" -#include "DwarfCompileUnit.h" -#include "DIE.h" #include "DIEHash.h" +#include "DwarfCompileUnit.h" +#include "DwarfExpression.h" #include "DwarfUnit.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/IR/Constants.h" @@ -490,9 +490,6 @@ void DwarfDebug::beginModule() { // Tell MMI that we have debug info. MMI->setDebugInfoAvailability(true); - - // Prime section data. - SectionMap[Asm->getObjFileLowering().getTextSection()]; } void DwarfDebug::finishVariableDefinitions() { @@ -608,53 +605,6 @@ void DwarfDebug::finalizeModuleInfo() { SkeletonHolder.computeSizeAndOffsets(); } -void DwarfDebug::endSections() { - // Filter labels by section. - for (const SymbolCU &SCU : ArangeLabels) { - if (SCU.Sym->isInSection()) { - // Make a note of this symbol and it's section. - const MCSection *Section = &SCU.Sym->getSection(); - if (!Section->getKind().isMetadata()) - SectionMap[Section].push_back(SCU); - } else { - // Some symbols (e.g. common/bss on mach-o) can have no section but still - // appear in the output. This sucks as we rely on sections to build - // arange spans. We can do it without, but it's icky. - SectionMap[nullptr].push_back(SCU); - } - } - - // Build a list of sections used. - std::vector<const MCSection *> Sections; - for (const auto &it : SectionMap) { - const MCSection *Section = it.first; - Sections.push_back(Section); - } - - // Sort the sections into order. - // This is only done to ensure consistent output order across different runs. - std::sort(Sections.begin(), Sections.end(), SectionSort); - - // Add terminating symbols for each section. - for (unsigned ID = 0, E = Sections.size(); ID != E; ID++) { - const MCSection *Section = Sections[ID]; - MCSymbol *Sym = nullptr; - - if (Section) { - // We can't call MCSection::getLabelEndName, as it's only safe to do so - // if we know the section name up-front. For user-created sections, the - // resulting label may not be valid to use as a label. (section names can - // use a greater set of characters on some systems) - Sym = Asm->GetTempSymbol("debug_end", ID); - Asm->OutStreamer.SwitchSection(Section); - Asm->OutStreamer.EmitLabel(Sym); - } - - // Insert a final terminator. - SectionMap[Section].push_back(SymbolCU(nullptr, Sym)); - } -} - // Emit all Dwarf sections that should come after the content. void DwarfDebug::endModule() { assert(CurFn == nullptr); @@ -666,10 +616,6 @@ void DwarfDebug::endModule() { if (!DwarfInfoSectionSym) return; - // End any existing sections. - // TODO: Does this need to happen? - endSections(); - // Finalize the debug info for the module. finalizeModuleInfo(); @@ -783,10 +729,9 @@ void DwarfDebug::collectVariableInfoFromMMITable( DIVariable DV(VI.Var); DIExpression Expr(VI.Expr); ensureAbstractVariableIsCreatedIfScoped(DV, Scope->getScopeNode()); - ConcreteVariables.push_back(make_unique<DbgVariable>(DV, Expr, this)); - DbgVariable *RegVar = ConcreteVariables.back().get(); - RegVar->setFrameIndex(VI.Slot); - InfoHolder.addScopeVariable(Scope, RegVar); + auto RegVar = make_unique<DbgVariable>(DV, Expr, this, VI.Slot); + if (InfoHolder.addScopeVariable(Scope, RegVar.get())) + ConcreteVariables.push_back(std::move(RegVar)); } } @@ -818,12 +763,12 @@ static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { /// Determine whether two variable pieces overlap. static bool piecesOverlap(DIExpression P1, DIExpression P2) { - if (!P1.isVariablePiece() || !P2.isVariablePiece()) + if (!P1.isBitPiece() || !P2.isBitPiece()) return true; - unsigned l1 = P1.getPieceOffset(); - unsigned l2 = P2.getPieceOffset(); - unsigned r1 = l1 + P1.getPieceSize(); - unsigned r2 = l2 + P2.getPieceSize(); + unsigned l1 = P1.getBitPieceOffset(); + unsigned l2 = P2.getBitPieceOffset(); + unsigned r1 = l1 + P1.getBitPieceSize(); + unsigned r2 = l2 + P2.getBitPieceSize(); // True where [l1,r1[ and [r1,r2[ overlap. return (l1 < r2) && (l2 < r1); } @@ -842,7 +787,8 @@ static bool piecesOverlap(DIExpression P1, DIExpression P2) { // 1 | | [x, (reg1, piece 32, 32)] <- IsPieceOfPrevEntry // 2 | | ... // 3 | [clobber reg0] -// 4 [x, (mem, piece 0, 64)] <- overlapping with both previous pieces of x. +// 4 [x, (mem, piece 0, 64)] <- overlapping with both previous pieces of +// x. // // Output: // @@ -894,7 +840,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, bool couldMerge = false; // If this is a piece, it may belong to the current DebugLocEntry. - if (DIExpr.isVariablePiece()) { + if (DIExpr.isBitPiece()) { // Add this value to the list of open ranges. OpenRanges.push_back(Value); @@ -950,11 +896,9 @@ DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, DISubprogram SP, continue; LexicalScope *Scope = nullptr; - if (MDNode *IA = DV.getInlinedAt()) { - DebugLoc DL = DebugLoc::getFromDILocation(IA); - Scope = LScopes.findInlinedScope(DebugLoc::get( - DL.getLine(), DL.getCol(), DV.getContext(), IA)); - } else + if (MDNode *IA = DV.getInlinedAt()) + Scope = LScopes.findInlinedScope(DV.getContext(), IA); + else Scope = LScopes.findLexicalScope(DV.getContext()); // If variable scope is not found then skip this variable. if (!Scope) @@ -1026,8 +970,10 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { if (DL == PrologEndLoc) { Flags |= DWARF2_FLAG_PROLOGUE_END; PrologEndLoc = DebugLoc(); + Flags |= DWARF2_FLAG_IS_STMT; } - if (PrologEndLoc.isUnknown()) + if (DL.getLine() != + Asm->OutStreamer.getContext().getCurrentDwarfLoc().getLine()) Flags |= DWARF2_FLAG_IS_STMT; if (!DL.isUnknown()) { @@ -1117,8 +1063,12 @@ static DebugLoc findPrologueEndLoc(const MachineFunction *MF) { for (const auto &MBB : *MF) for (const auto &MI : MBB) if (!MI.isDebugValue() && !MI.getFlag(MachineInstr::FrameSetup) && - !MI.getDebugLoc().isUnknown()) + !MI.getDebugLoc().isUnknown()) { + // Did the target forget to set the FrameSetup flag for CFI insns? + assert(!MI.isCFIInstruction() && + "First non-frame-setup instruction is a CFI instruction."); return MI.getDebugLoc(); + } return DebugLoc(); } @@ -1172,7 +1122,7 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { Asm->OutStreamer.EmitLabel(FunctionBeginSym); // Calculate history for local variables. - calculateDbgValueHistory(MF, Asm->TM.getSubtargetImpl()->getRegisterInfo(), + calculateDbgValueHistory(MF, Asm->MF->getSubtarget().getRegisterInfo(), DbgValues); // Request labels for the full history. @@ -1187,7 +1137,7 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { if (DIVar.isVariable() && DIVar.getTag() == dwarf::DW_TAG_arg_variable && getDISubprogram(DIVar.getContext()).describes(MF->getFunction())) { LabelsBeforeInsn[Ranges.front().first] = FunctionBeginSym; - if (Ranges.front().first->getDebugExpression().isVariablePiece()) { + if (Ranges.front().first->getDebugExpression().isBitPiece()) { // Mark all non-overlapping initial pieces. for (auto I = Ranges.begin(); I != Ranges.end(); ++I) { DIExpression Piece = I->first->getDebugExpression(); @@ -1217,12 +1167,12 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { if (!PrologEndLoc.isUnknown()) { DebugLoc FnStartDL = PrologEndLoc.getFnDebugLoc(MF->getFunction()->getContext()); - recordSourceLine( - FnStartDL.getLine(), FnStartDL.getCol(), - FnStartDL.getScope(MF->getFunction()->getContext()), - // We'd like to list the prologue as "not statements" but GDB behaves - // poorly if we do that. Revisit this with caution/GDB (7.5+) testing. - DWARF2_FLAG_IS_STMT); + + // We'd like to list the prologue as "not statements" but GDB behaves + // poorly if we do that. Revisit this with caution/GDB (7.5+) testing. + recordSourceLine(FnStartDL.getLine(), FnStartDL.getCol(), + FnStartDL.getScope(MF->getFunction()->getContext()), + DWARF2_FLAG_IS_STMT); } } @@ -1350,8 +1300,8 @@ void DwarfDebug::emitSectionLabels() { if (useSplitDwarf()) { DwarfInfoDWOSectionSym = emitSectionSym(Asm, TLOF.getDwarfInfoDWOSection(), "section_info_dwo"); - DwarfTypesDWOSectionSym = - emitSectionSym(Asm, TLOF.getDwarfTypesDWOSection(), "section_types_dwo"); + DwarfTypesDWOSectionSym = emitSectionSym( + Asm, TLOF.getDwarfTypesDWOSection(), "section_types_dwo"); } DwarfAbbrevSectionSym = emitSectionSym(Asm, TLOF.getDwarfAbbrevSection(), "section_abbrev"); @@ -1553,7 +1503,6 @@ static dwarf::PubIndexEntryDescriptor computeIndexValue(DwarfUnit *CU, return dwarf::GIEK_TYPE; case dwarf::DW_TAG_subprogram: return dwarf::PubIndexEntryDescriptor(dwarf::GIEK_FUNCTION, Linkage); - case dwarf::DW_TAG_constant: case dwarf::DW_TAG_variable: return dwarf::PubIndexEntryDescriptor(dwarf::GIEK_VARIABLE, Linkage); case dwarf::DW_TAG_enumerator: @@ -1656,7 +1605,7 @@ void DwarfDebug::emitLocPieces(ByteStreamer &Streamer, const DITypeIdentifierMap &Map, ArrayRef<DebugLocEntry::Value> Values) { assert(std::all_of(Values.begin(), Values.end(), [](DebugLocEntry::Value P) { - return P.isVariablePiece(); + return P.isBitPiece(); }) && "all values are expected to be pieces"); assert(std::is_sorted(Values.begin(), Values.end()) && "pieces are expected to be sorted"); @@ -1664,35 +1613,25 @@ void DwarfDebug::emitLocPieces(ByteStreamer &Streamer, unsigned Offset = 0; for (auto Piece : Values) { DIExpression Expr = Piece.getExpression(); - unsigned PieceOffset = Expr.getPieceOffset(); - unsigned PieceSize = Expr.getPieceSize(); + unsigned PieceOffset = Expr.getBitPieceOffset(); + unsigned PieceSize = Expr.getBitPieceSize(); assert(Offset <= PieceOffset && "overlapping or duplicate pieces"); if (Offset < PieceOffset) { // The DWARF spec seriously mandates pieces with no locations for gaps. - Asm->EmitDwarfOpPiece(Streamer, (PieceOffset-Offset)*8); + Asm->EmitDwarfOpPiece(Streamer, PieceOffset-Offset); Offset += PieceOffset-Offset; } - Offset += PieceSize; - const unsigned SizeOfByte = 8; #ifndef NDEBUG DIVariable Var = Piece.getVariable(); - assert(!Var.isIndirect() && "indirect address for piece"); unsigned VarSize = Var.getSizeInBits(Map); - assert(PieceSize+PieceOffset <= VarSize/SizeOfByte + assert(PieceSize+PieceOffset <= VarSize && "piece is larger than or outside of variable"); - assert(PieceSize*SizeOfByte != VarSize + assert(PieceSize != VarSize && "piece covers entire variable"); #endif - if (Piece.isLocation() && Piece.getLoc().isReg()) - Asm->EmitDwarfRegOpPiece(Streamer, - Piece.getLoc(), - PieceSize*SizeOfByte); - else { - emitDebugLocValue(Streamer, Piece); - Asm->EmitDwarfOpPiece(Streamer, PieceSize*SizeOfByte); - } + emitDebugLocValue(Streamer, Piece, PieceOffset); } } @@ -1700,7 +1639,7 @@ void DwarfDebug::emitLocPieces(ByteStreamer &Streamer, void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, const DebugLocEntry &Entry) { const DebugLocEntry::Value Value = Entry.getValues()[0]; - if (Value.isVariablePiece()) + if (Value.isBitPiece()) // Emit all pieces that belong to the same variable and range. return emitLocPieces(Streamer, TypeIdentifierMap, Entry.getValues()); @@ -1709,62 +1648,33 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, } void DwarfDebug::emitDebugLocValue(ByteStreamer &Streamer, - const DebugLocEntry::Value &Value) { + const DebugLocEntry::Value &Value, + unsigned PieceOffsetInBits) { DIVariable DV = Value.getVariable(); + DebugLocDwarfExpression DwarfExpr(*Asm, Streamer); + // Regular entry. if (Value.isInt()) { DIBasicType BTy(resolve(DV.getType())); if (BTy.Verify() && (BTy.getEncoding() == dwarf::DW_ATE_signed || - BTy.getEncoding() == dwarf::DW_ATE_signed_char)) { - Streamer.EmitInt8(dwarf::DW_OP_consts, "DW_OP_consts"); - Streamer.EmitSLEB128(Value.getInt()); - } else { - Streamer.EmitInt8(dwarf::DW_OP_constu, "DW_OP_constu"); - Streamer.EmitULEB128(Value.getInt()); - } + BTy.getEncoding() == dwarf::DW_ATE_signed_char)) + DwarfExpr.AddSignedConstant(Value.getInt()); + else + DwarfExpr.AddUnsignedConstant(Value.getInt()); } else if (Value.isLocation()) { MachineLocation Loc = Value.getLoc(); DIExpression Expr = Value.getExpression(); - if (!Expr) + if (!Expr || (Expr.getNumElements() == 0)) // Regular entry. - Asm->EmitDwarfRegOp(Streamer, Loc, DV.isIndirect()); + Asm->EmitDwarfRegOp(Streamer, Loc); else { // Complex address entry. - unsigned N = Expr.getNumElements(); - unsigned i = 0; - if (N >= 2 && Expr.getElement(0) == dwarf::DW_OP_plus) { - if (Loc.getOffset()) { - i = 2; - Asm->EmitDwarfRegOp(Streamer, Loc, DV.isIndirect()); - Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref"); - Streamer.EmitInt8(dwarf::DW_OP_plus_uconst, "DW_OP_plus_uconst"); - Streamer.EmitSLEB128(Expr.getElement(1)); - } else { - // If first address element is OpPlus then emit - // DW_OP_breg + Offset instead of DW_OP_reg + Offset. - MachineLocation TLoc(Loc.getReg(), Expr.getElement(1)); - Asm->EmitDwarfRegOp(Streamer, TLoc, DV.isIndirect()); - i = 2; - } - } else { - Asm->EmitDwarfRegOp(Streamer, Loc, DV.isIndirect()); - } - - // Emit remaining complex address elements. - for (; i < N; ++i) { - uint64_t Element = Expr.getElement(i); - if (Element == dwarf::DW_OP_plus) { - Streamer.EmitInt8(dwarf::DW_OP_plus_uconst, "DW_OP_plus_uconst"); - Streamer.EmitULEB128(Expr.getElement(++i)); - } else if (Element == dwarf::DW_OP_deref) { - if (!Loc.isReg()) - Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref"); - } else if (Element == dwarf::DW_OP_piece) { - i += 3; - // handled in emitDebugLocEntry. - } else - llvm_unreachable("unknown Opcode found in complex address"); - } + if (Loc.getOffset()) { + DwarfExpr.AddMachineRegIndirect(Loc.getReg(), Loc.getOffset()); + DwarfExpr.AddExpression(Expr.begin(), Expr.end(), PieceOffsetInBits); + } else + DwarfExpr.AddMachineRegExpression(Expr, Loc.getReg(), + PieceOffsetInBits); } } // else ... ignore constant fp. There is not any good way to @@ -1841,13 +1751,26 @@ struct ArangeSpan { // Emit a debug aranges section, containing a CU lookup for any // address we can tie back to a CU. void DwarfDebug::emitDebugARanges() { - // Start the dwarf aranges section. - Asm->OutStreamer.SwitchSection( - Asm->getObjFileLowering().getDwarfARangesSection()); + // Provides a unique id per text section. + DenseMap<const MCSection *, SmallVector<SymbolCU, 8>> SectionMap; - typedef DenseMap<DwarfCompileUnit *, std::vector<ArangeSpan>> SpansType; + // Prime section data. + SectionMap[Asm->getObjFileLowering().getTextSection()]; - SpansType Spans; + // Filter labels by section. + for (const SymbolCU &SCU : ArangeLabels) { + if (SCU.Sym->isInSection()) { + // Make a note of this symbol and it's section. + const MCSection *Section = &SCU.Sym->getSection(); + if (!Section->getKind().isMetadata()) + SectionMap[Section].push_back(SCU); + } else { + // Some symbols (e.g. common/bss on mach-o) can have no section but still + // appear in the output. This sucks as we rely on sections to build + // arange spans. We can do it without, but it's icky. + SectionMap[nullptr].push_back(SCU); + } + } // Build a list of sections used. std::vector<const MCSection *> Sections; @@ -1860,12 +1783,45 @@ void DwarfDebug::emitDebugARanges() { // This is only done to ensure consistent output order across different runs. std::sort(Sections.begin(), Sections.end(), SectionSort); - // Build a set of address spans, sorted by CU. + // Add terminating symbols for each section. + for (unsigned ID = 0, E = Sections.size(); ID != E; ID++) { + const MCSection *Section = Sections[ID]; + MCSymbol *Sym = nullptr; + + if (Section) { + // We can't call MCSection::getLabelEndName, as it's only safe to do so + // if we know the section name up-front. For user-created sections, the + // resulting label may not be valid to use as a label. (section names can + // use a greater set of characters on some systems) + Sym = Asm->GetTempSymbol("debug_end", ID); + Asm->OutStreamer.SwitchSection(Section); + Asm->OutStreamer.EmitLabel(Sym); + } + + // Insert a final terminator. + SectionMap[Section].push_back(SymbolCU(nullptr, Sym)); + } + + DenseMap<DwarfCompileUnit *, std::vector<ArangeSpan>> Spans; + for (const MCSection *Section : Sections) { SmallVector<SymbolCU, 8> &List = SectionMap[Section]; if (List.size() < 2) continue; + // If we have no section (e.g. common), just write out + // individual spans for each symbol. + if (!Section) { + for (const SymbolCU &Cur : List) { + ArangeSpan Span; + Span.Start = Cur.Sym; + Span.End = nullptr; + if (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) { @@ -1881,35 +1837,27 @@ void DwarfDebug::emitDebugARanges() { return IA < IB; }); - // If we have no section (e.g. common), just write out - // individual spans for each symbol. - if (!Section) { - for (const SymbolCU &Cur : List) { + // Build spans between each label. + const MCSymbol *StartSym = List[0].Sym; + for (size_t n = 1, e = List.size(); n < e; n++) { + const SymbolCU &Prev = List[n - 1]; + const SymbolCU &Cur = List[n]; + + // Try and build the longest span we can within the same CU. + if (Cur.CU != Prev.CU) { ArangeSpan Span; - Span.Start = Cur.Sym; - Span.End = nullptr; - if (Cur.CU) - Spans[Cur.CU].push_back(Span); - } - } else { - // Build spans between each label. - const MCSymbol *StartSym = List[0].Sym; - for (size_t n = 1, e = List.size(); n < e; n++) { - const SymbolCU &Prev = List[n - 1]; - const SymbolCU &Cur = List[n]; - - // Try and build the longest span we can within the same CU. - if (Cur.CU != Prev.CU) { - ArangeSpan Span; - Span.Start = StartSym; - Span.End = Cur.Sym; - Spans[Prev.CU].push_back(Span); - StartSym = Cur.Sym; - } + Span.Start = StartSym; + Span.End = Cur.Sym; + Spans[Prev.CU].push_back(Span); + StartSym = Cur.Sym; } } } + // Start the dwarf aranges section. + Asm->OutStreamer.SwitchSection( + Asm->getObjFileLowering().getDwarfARangesSection()); + unsigned PtrSize = Asm->getDataLayout().getPointerSize(); // Build a list of CUs used. diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 48c2809..1c0e163 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -14,26 +14,25 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H -#include "DwarfFile.h" #include "AsmPrinterHandler.h" -#include "DIE.h" #include "DbgValueHistoryCalculator.h" #include "DebugLocEntry.h" #include "DebugLocList.h" #include "DwarfAccelTable.h" +#include "DwarfFile.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/FoldingSet.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugLoc.h" -#include "llvm/MC/MachineLocation.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MachineLocation.h" #include "llvm/Support/Allocator.h" - #include <memory> namespace llvm { @@ -68,41 +67,67 @@ public: //===----------------------------------------------------------------------===// /// \brief This class is used to track local variable information. +/// +/// - Variables whose location changes over time have a DotDebugLocOffset and +/// the other fields are not used. +/// +/// - Variables that are described by multiple MMI table entries have multiple +/// expressions and frame indices. class DbgVariable { - DIVariable Var; // Variable Descriptor. - DIExpression Expr; // Complex address location expression. - DIE *TheDIE; // Variable DIE. - unsigned DotDebugLocOffset; // Offset in DotDebugLocEntries. - const MachineInstr *MInsn; // DBG_VALUE instruction of the variable. - int FrameIndex; + DIVariable Var; /// Variable Descriptor. + SmallVector<DIExpression, 1> Expr; /// Complex address location expression. + DIE *TheDIE; /// Variable DIE. + unsigned DotDebugLocOffset; /// Offset in DotDebugLocEntries. + const MachineInstr *MInsn; /// DBG_VALUE instruction of the variable. + SmallVector<int, 1> FrameIndex; /// Frame index of the variable. DwarfDebug *DD; public: /// Construct a DbgVariable from a DIVariable. - DbgVariable(DIVariable V, DIExpression E, DwarfDebug *DD) - : Var(V), Expr(E), TheDIE(nullptr), DotDebugLocOffset(~0U), - MInsn(nullptr), FrameIndex(~0), DD(DD) { - assert(Var.Verify() && Expr.Verify()); + DbgVariable(DIVariable V, DIExpression E, DwarfDebug *DD, int FI = ~0) + : Var(V), Expr(1, E), TheDIE(nullptr), DotDebugLocOffset(~0U), + MInsn(nullptr), DD(DD) { + FrameIndex.push_back(FI); + assert(Var.Verify() && E.Verify()); } /// Construct a DbgVariable from a DEBUG_VALUE. /// AbstractVar may be NULL. DbgVariable(const MachineInstr *DbgValue, DwarfDebug *DD) - : Var(DbgValue->getDebugVariable()), Expr(DbgValue->getDebugExpression()), - TheDIE(nullptr), DotDebugLocOffset(~0U), MInsn(DbgValue), - FrameIndex(~0), DD(DD) {} + : Var(DbgValue->getDebugVariable()), + Expr(1, DbgValue->getDebugExpression()), TheDIE(nullptr), + DotDebugLocOffset(~0U), MInsn(DbgValue), DD(DD) { + FrameIndex.push_back(~0); + } // Accessors. DIVariable getVariable() const { return Var; } - DIExpression getExpression() const { return Expr; } + const ArrayRef<DIExpression> getExpression() const { return Expr; } void setDIE(DIE &D) { TheDIE = &D; } DIE *getDIE() const { return TheDIE; } void setDotDebugLocOffset(unsigned O) { DotDebugLocOffset = O; } unsigned getDotDebugLocOffset() const { return DotDebugLocOffset; } StringRef getName() const { return Var.getName(); } const MachineInstr *getMInsn() const { return MInsn; } - int getFrameIndex() const { return FrameIndex; } - void setFrameIndex(int FI) { FrameIndex = FI; } + const ArrayRef<int> getFrameIndex() const { return FrameIndex; } + + void addMMIEntry(const DbgVariable &V) { + assert( DotDebugLocOffset == ~0U && !MInsn && "not an MMI entry"); + assert(V.DotDebugLocOffset == ~0U && !V.MInsn && "not an MMI entry"); + assert(V.Var == Var && "conflicting DIVariable"); + + if (V.getFrameIndex().back() != ~0) { + auto E = V.getExpression(); + auto FI = V.getFrameIndex(); + Expr.append(E.begin(), E.end()); + FrameIndex.append(FI.begin(), FI.end()); + } + assert(Expr.size() > 1 + ? std::all_of(Expr.begin(), Expr.end(), + [](DIExpression &E) { return E.isBitPiece(); }) + : (true && "conflicting locations for variable")); + } + // Translate tag to proper Dwarf tag. dwarf::Tag getTag() const { if (Var.getTag() == dwarf::DW_TAG_arg_variable) @@ -129,14 +154,11 @@ public: bool variableHasComplexAddress() const { assert(Var.isVariable() && "Invalid complex DbgVariable!"); - return Expr.getNumElements() > 0; + assert(Expr.size() == 1 && + "variableHasComplexAddress() invoked on multi-FI variable"); + return Expr.back().getNumElements() > 0; } bool isBlockByrefVariable() const; - unsigned getNumAddrElements() const { - assert(Var.isVariable() && "Invalid complex DbgVariable!"); - return Expr.getNumElements(); - } - uint64_t getAddrElement(unsigned i) const { return Expr.getElement(i); } DIType getType() const; private: @@ -179,10 +201,6 @@ class DwarfDebug : public AsmPrinterHandler { // Size of each symbol emitted (for those symbols that have a specific size). DenseMap<const MCSymbol *, uint64_t> SymSize; - // Provides a unique id per text section. - typedef DenseMap<const MCSection *, SmallVector<SymbolCU, 8> > SectionMapType; - SectionMapType SectionMap; - LexicalScopes LScopes; // Collection of abstract variables. @@ -259,7 +277,8 @@ class DwarfDebug : public AsmPrinterHandler { // them. DenseMap<const MDNode *, const DwarfTypeUnit *> DwarfTypeUnits; - SmallVector<std::pair<std::unique_ptr<DwarfTypeUnit>, DICompositeType>, 1> TypeUnitsUnderConstruction; + SmallVector<std::pair<std::unique_ptr<DwarfTypeUnit>, DICompositeType>, 1> + TypeUnitsUnderConstruction; // Whether to emit the pubnames/pubtypes sections. bool HasDwarfPubSections; @@ -348,10 +367,6 @@ class DwarfDebug : public AsmPrinterHandler { /// processed. void finalizeModuleInfo(); - /// \brief Emit labels to close any remaining sections that have been left - /// open. - void endSections(); - /// \brief Emit the debug info section. void emitDebugInfo(); @@ -565,7 +580,8 @@ public: void emitDebugLocEntry(ByteStreamer &Streamer, const DebugLocEntry &Entry); /// \brief emit a single value for the debug loc section. void emitDebugLocValue(ByteStreamer &Streamer, - const DebugLocEntry::Value &Value); + const DebugLocEntry::Value &Value, + unsigned PieceOffsetInBits = 0); /// Emits an optimal (=sorted) sequence of DW_OP_pieces. void emitLocPieces(ByteStreamer &Streamer, const DITypeIdentifierMap &Map, diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp new file mode 100644 index 0000000..fcab067 --- /dev/null +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -0,0 +1,269 @@ +//===-- llvm/CodeGen/DwarfExpression.cpp - Dwarf Debug Framework ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing dwarf debug info into asm files. +// +//===----------------------------------------------------------------------===// + +#include "DwarfExpression.h" +#include "DwarfDebug.h" +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +using namespace llvm; + +const TargetRegisterInfo *DwarfExpression::getTRI() const { + return AP.TM.getSubtargetImpl()->getRegisterInfo(); +} + +unsigned DwarfExpression::getDwarfVersion() const { + return AP.getDwarfDebug()->getDwarfVersion(); +} + +void DwarfExpression::AddReg(int DwarfReg, const char *Comment) { + assert(DwarfReg >= 0 && "invalid negative dwarf register number"); + if (DwarfReg < 32) { + EmitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment); + } else { + EmitOp(dwarf::DW_OP_regx, Comment); + EmitUnsigned(DwarfReg); + } +} + +void DwarfExpression::AddRegIndirect(int DwarfReg, int Offset, bool Deref) { + assert(DwarfReg >= 0 && "invalid negative dwarf register number"); + if (DwarfReg < 32) { + EmitOp(dwarf::DW_OP_breg0 + DwarfReg); + } else { + EmitOp(dwarf::DW_OP_bregx); + EmitUnsigned(DwarfReg); + } + EmitSigned(Offset); + if (Deref) + EmitOp(dwarf::DW_OP_deref); +} + +void DwarfExpression::AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits) { + assert(SizeInBits > 0 && "piece has size zero"); + const unsigned SizeOfByte = 8; + if (OffsetInBits > 0 || SizeInBits % SizeOfByte) { + EmitOp(dwarf::DW_OP_bit_piece); + EmitUnsigned(SizeInBits); + EmitUnsigned(OffsetInBits); + } else { + EmitOp(dwarf::DW_OP_piece); + unsigned ByteSize = SizeInBits / SizeOfByte; + EmitUnsigned(ByteSize); + } +} + +void DwarfExpression::AddShr(unsigned ShiftBy) { + EmitOp(dwarf::DW_OP_constu); + EmitUnsigned(ShiftBy); + EmitOp(dwarf::DW_OP_shr); +} + +bool DwarfExpression::AddMachineRegIndirect(unsigned MachineReg, int Offset) { + int DwarfReg = getTRI()->getDwarfRegNum(MachineReg, false); + if (DwarfReg < 0) + return false; + + if (isFrameRegister(MachineReg)) { + // If variable offset is based in frame register then use fbreg. + EmitOp(dwarf::DW_OP_fbreg); + EmitSigned(Offset); + } else { + AddRegIndirect(DwarfReg, Offset); + } + return true; +} + +bool DwarfExpression::AddMachineRegPiece(unsigned MachineReg, + unsigned PieceSizeInBits, + unsigned PieceOffsetInBits) { + const TargetRegisterInfo *TRI = getTRI(); + if (!TRI->isPhysicalRegister(MachineReg)) + return false; + + int Reg = TRI->getDwarfRegNum(MachineReg, false); + + // If this is a valid register number, emit it. + if (Reg >= 0) { + AddReg(Reg); + if (PieceSizeInBits) + AddOpPiece(PieceSizeInBits, PieceOffsetInBits); + return true; + } + + // Walk up the super-register chain until we find a valid number. + // For example, EAX on x86_64 is a 32-bit piece of RAX with offset 0. + for (MCSuperRegIterator SR(MachineReg, TRI); SR.isValid(); ++SR) { + Reg = TRI->getDwarfRegNum(*SR, false); + if (Reg >= 0) { + unsigned Idx = TRI->getSubRegIndex(*SR, MachineReg); + unsigned Size = TRI->getSubRegIdxSize(Idx); + unsigned RegOffset = TRI->getSubRegIdxOffset(Idx); + AddReg(Reg, "super-register"); + if (PieceOffsetInBits == RegOffset) { + AddOpPiece(Size, RegOffset); + } else { + // If this is part of a variable in a sub-register at a + // non-zero offset, we need to manually shift the value into + // place, since the DW_OP_piece describes the part of the + // variable, not the position of the subregister. + if (RegOffset) + AddShr(RegOffset); + AddOpPiece(Size, PieceOffsetInBits); + } + return true; + } + } + + // Otherwise, attempt to find a covering set of sub-register numbers. + // For example, Q0 on ARM is a composition of D0+D1. + // + // Keep track of the current position so we can emit the more + // efficient DW_OP_piece. + unsigned CurPos = PieceOffsetInBits; + // The size of the register in bits, assuming 8 bits per byte. + unsigned RegSize = TRI->getMinimalPhysRegClass(MachineReg)->getSize() * 8; + // Keep track of the bits in the register we already emitted, so we + // can avoid emitting redundant aliasing subregs. + SmallBitVector Coverage(RegSize, false); + for (MCSubRegIterator SR(MachineReg, TRI); SR.isValid(); ++SR) { + unsigned Idx = TRI->getSubRegIndex(MachineReg, *SR); + unsigned Size = TRI->getSubRegIdxSize(Idx); + unsigned Offset = TRI->getSubRegIdxOffset(Idx); + Reg = TRI->getDwarfRegNum(*SR, false); + + // Intersection between the bits we already emitted and the bits + // covered by this subregister. + SmallBitVector Intersection(RegSize, false); + Intersection.set(Offset, Offset + Size); + Intersection ^= Coverage; + + // If this sub-register has a DWARF number and we haven't covered + // its range, emit a DWARF piece for it. + if (Reg >= 0 && Intersection.any()) { + AddReg(Reg, "sub-register"); + AddOpPiece(Size, Offset == CurPos ? 0 : Offset); + CurPos = Offset + Size; + + // Mark it as emitted. + Coverage.set(Offset, Offset + Size); + } + } + + 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. + if (getDwarfVersion() >= 4) + EmitOp(dwarf::DW_OP_stack_value); +} + +void DwarfExpression::AddUnsignedConstant(unsigned Value) { + EmitOp(dwarf::DW_OP_constu); + EmitUnsigned(Value); + // cf. comment in DwarfExpression::AddSignedConstant(). + if (getDwarfVersion() >= 4) + EmitOp(dwarf::DW_OP_stack_value); +} + +static unsigned getOffsetOrZero(unsigned OffsetInBits, + unsigned PieceOffsetInBits) { + if (OffsetInBits == PieceOffsetInBits) + return 0; + assert(OffsetInBits >= PieceOffsetInBits && "overlapping pieces"); + return OffsetInBits; +} + +bool DwarfExpression::AddMachineRegExpression(DIExpression Expr, + unsigned MachineReg, + unsigned PieceOffsetInBits) { + auto I = Expr.begin(); + // Pattern-match combinations for which more efficient representations exist + // first. + if (I == Expr.end()) + return AddMachineRegPiece(MachineReg); + + bool ValidReg = false; + switch (*I) { + case dwarf::DW_OP_bit_piece: { + unsigned OffsetInBits = I->getArg(1); + unsigned SizeInBits = I->getArg(2); + // Piece always comes at the end of the expression. + return AddMachineRegPiece(MachineReg, SizeInBits, + getOffsetOrZero(OffsetInBits, PieceOffsetInBits)); + } + case dwarf::DW_OP_plus: + // [DW_OP_reg,Offset,DW_OP_plus,DW_OP_deref] --> [DW_OP_breg,Offset]. + if (I->getNext() == dwarf::DW_OP_deref) { + unsigned Offset = I->getArg(1); + ValidReg = AddMachineRegIndirect(MachineReg, Offset); + std::advance(I, 2); + break; + } else + ValidReg = AddMachineRegPiece(MachineReg); + case dwarf::DW_OP_deref: + // [DW_OP_reg,DW_OP_deref] --> [DW_OP_breg]. + ValidReg = AddMachineRegIndirect(MachineReg); + ++I; + break; + default: + llvm_unreachable("unsupported operand"); + } + + if (!ValidReg) + return false; + + // Emit remaining elements of the expression. + AddExpression(I, Expr.end(), PieceOffsetInBits); + return true; +} + +void DwarfExpression::AddExpression(DIExpression::iterator I, + DIExpression::iterator E, + unsigned PieceOffsetInBits) { + for (; I != E; ++I) { + switch (*I) { + case dwarf::DW_OP_bit_piece: { + unsigned OffsetInBits = I->getArg(1); + unsigned SizeInBits = I->getArg(2); + AddOpPiece(SizeInBits, getOffsetOrZero(OffsetInBits, PieceOffsetInBits)); + break; + } + case dwarf::DW_OP_plus: + EmitOp(dwarf::DW_OP_plus_uconst); + EmitUnsigned(I->getArg(1)); + break; + case dwarf::DW_OP_deref: + EmitOp(dwarf::DW_OP_deref); + break; + default: + llvm_unreachable("unhandled opcode found in DIExpression"); + } + } +} diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.h b/lib/CodeGen/AsmPrinter/DwarfExpression.h new file mode 100644 index 0000000..b90b7b6 --- /dev/null +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -0,0 +1,133 @@ +//===-- llvm/CodeGen/DwarfExpression.h - Dwarf Compile Unit ---*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing dwarf compile unit. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H + +#include "llvm/IR/DebugInfo.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { + +class AsmPrinter; +class ByteStreamer; +class TargetRegisterInfo; +class DwarfUnit; +class DIELoc; + +/// Base class containing the logic for constructing DWARF expressions +/// independently of whether they are emitted into a DIE or into a .debug_loc +/// entry. +class DwarfExpression { +protected: + const AsmPrinter &AP; + // Various convenience accessors that extract things out of AsmPrinter. + const TargetRegisterInfo *getTRI() const; + unsigned getDwarfVersion() const; + +public: + DwarfExpression(const AsmPrinter &AP) : AP(AP) {} + virtual ~DwarfExpression() {} + + /// Output a dwarf operand and an optional assembler comment. + virtual void EmitOp(uint8_t Op, const char *Comment = nullptr) = 0; + /// Emit a raw signed value. + virtual void EmitSigned(int Value) = 0; + /// Emit a raw unsigned value. + virtual void EmitUnsigned(unsigned Value) = 0; + /// Return whether the given machine register is the frame register in the + /// current function. + virtual bool isFrameRegister(unsigned MachineReg) = 0; + + /// Emit a dwarf register operation. + void AddReg(int DwarfReg, const char *Comment = nullptr); + /// Emit an (double-)indirect dwarf register operation. + void AddRegIndirect(int DwarfReg, int Offset, bool Deref = false); + + /// Emit a dwarf register operation for describing + /// - a small value occupying only part of a register or + /// - a register representing only part of a value. + void AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits = 0); + /// Emit a shift-right dwarf expression. + void AddShr(unsigned ShiftBy); + + /// 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); + + /// \brief Emit a partial DWARF register operation. + /// \param MachineReg the register + /// \param PieceSizeInBits size and + /// \param PieceOffsetInBits offset of the piece in bits, if this is one + /// piece of an aggregate value. + /// + /// If size and offset is zero an operation for the entire + /// register is emitted: Some targets do not provide a DWARF + /// register number for every register. If this is the case, this + /// function will attempt to emit a DWARF register by emitting a + /// piece of a super-register or by piecing together multiple + /// subregisters that alias the register. + /// + /// \return false if no DWARF register exists for MachineReg. + bool AddMachineRegPiece(unsigned MachineReg, unsigned PieceSizeInBits = 0, + unsigned PieceOffsetInBits = 0); + + /// Emit a signed constant. + void AddSignedConstant(int Value); + /// Emit an unsigned constant. + void AddUnsignedConstant(unsigned Value); + + /// Emit an entire DIExpression 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(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 + /// location, this is the offset of the piece inside the entire variable. + void AddExpression(DIExpression::iterator I, DIExpression::iterator E, + unsigned PieceOffsetInBits = 0); +}; + +/// DwarfExpression implementation for .debug_loc entries. +class DebugLocDwarfExpression : public DwarfExpression { + ByteStreamer &BS; + +public: + DebugLocDwarfExpression(const AsmPrinter &AP, ByteStreamer &BS) + : DwarfExpression(AP), BS(BS) {} + + void EmitOp(uint8_t Op, const char *Comment = nullptr) override; + void EmitSigned(int Value) override; + void EmitUnsigned(unsigned Value) override; + bool isFrameRegister(unsigned MachineReg) override; +}; + +/// DwarfExpression implementation for singular DW_AT_location. +class DIEDwarfExpression : public DwarfExpression { + DwarfUnit &DU; + DIELoc &DIE; + +public: + DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU, DIELoc &DIE) + : DwarfExpression(AP), DU(DU), DIE(DIE) {} + + void EmitOp(uint8_t Op, const char *Comment = nullptr) override; + void EmitSigned(int Value) override; + void EmitUnsigned(unsigned Value) override; + bool isFrameRegister(unsigned MachineReg) override; +}; +} + +#endif diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/lib/CodeGen/AsmPrinter/DwarfFile.cpp index 50180ea..3988f0d 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -8,13 +8,12 @@ //===----------------------------------------------------------------------===// #include "DwarfFile.h" - #include "DwarfDebug.h" #include "DwarfUnit.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/DataLayout.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Support/LEB128.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Target/TargetLoweringObjectFile.h" namespace llvm { @@ -147,7 +146,7 @@ void DwarfFile::emitStrings(const MCSection *StrSection, StrPool.emit(*Asm, StrSection, OffsetSection); } -void DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) { +bool DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) { SmallVectorImpl<DbgVariable *> &Vars = ScopeVariables[LS]; DIVariable DV = Var->getVariable(); // Variables with positive arg numbers are parameters. @@ -169,18 +168,17 @@ void DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) { // A later indexed parameter has been found, insert immediately before it. if (CurNum > ArgNum) break; - // FIXME: There are still some cases where two inlined functions are - // conflated together (two calls to the same function at the same - // location (eg: via a macro, or without column info, etc)) and then - // their arguments are conflated as well. - assert((LS->getParent() || CurNum != ArgNum) && - "Duplicate argument for top level (non-inlined) function"); + if (CurNum == ArgNum) { + (*I)->addMMIEntry(*Var); + return false; + } ++I; } Vars.insert(I, Var); - return; + return true; } Vars.push_back(Var); + return true; } } diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.h b/lib/CodeGen/AsmPrinter/DwarfFile.h index 9d64bfc..35bf33a 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -10,17 +10,16 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFFILE_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFFILE_H +#include "AddressPool.h" +#include "DwarfStringPool.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Allocator.h" -#include "AddressPool.h" -#include "DwarfStringPool.h" - -#include <vector> -#include <string> #include <memory> +#include <string> +#include <vector> namespace llvm { class AsmPrinter; @@ -96,7 +95,8 @@ public: /// \brief Returns the string pool. DwarfStringPool &getStringPool() { return StrPool; } - void addScopeVariable(LexicalScope *LS, DbgVariable *Var); + /// \returns false if the variable was merged with a previous one. + bool addScopeVariable(LexicalScope *LS, DbgVariable *Var); DenseMap<LexicalScope *, SmallVector<DbgVariable *, 8>> &getScopeVariables() { return ScopeVariables; diff --git a/lib/CodeGen/AsmPrinter/DwarfStringPool.h b/lib/CodeGen/AsmPrinter/DwarfStringPool.h index ab32c1b..63e3412 100644 --- a/lib/CodeGen/AsmPrinter/DwarfStringPool.h +++ b/lib/CodeGen/AsmPrinter/DwarfStringPool.h @@ -13,7 +13,6 @@ #include "llvm/ADT/StringMap.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/Support/Allocator.h" - #include <utility> namespace llvm { diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 919d9d2..b0c7d48 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -12,10 +12,10 @@ //===----------------------------------------------------------------------===// #include "DwarfUnit.h" - #include "DwarfAccelTable.h" #include "DwarfCompileUnit.h" #include "DwarfDebug.h" +#include "DwarfExpression.h" #include "llvm/ADT/APFloat.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DIBuilder.h" @@ -43,6 +43,20 @@ GenerateDwarfTypeUnits("generate-type-units", cl::Hidden, cl::desc("Generate DWARF4 type units."), cl::init(false)); +void DIEDwarfExpression::EmitOp(uint8_t Op, const char* Comment) { + DU.addUInt(DIE, dwarf::DW_FORM_data1, Op); +} +void DIEDwarfExpression::EmitSigned(int Value) { + DU.addSInt(DIE, dwarf::DW_FORM_sdata, Value); +} +void DIEDwarfExpression::EmitUnsigned(unsigned Value) { + DU.addUInt(DIE, dwarf::DW_FORM_udata, Value); +} +bool DIEDwarfExpression::isFrameRegister(unsigned MachineReg) { + return MachineReg == getTRI()->getFrameRegister(*AP.MF); +} + + /// Unit - Unit constructor. DwarfUnit::DwarfUnit(unsigned UID, dwarf::Tag UnitTag, DICompileUnit Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU) @@ -116,6 +130,30 @@ int64_t DwarfUnit::getDefaultLowerBound() const { if (dwarf::DWARF_VERSION >= 4) return 1; break; + + // The languages below have valid values only if the DWARF version >= 5. + case dwarf::DW_LANG_OpenCL: + case dwarf::DW_LANG_Go: + case dwarf::DW_LANG_Haskell: + case dwarf::DW_LANG_C_plus_plus_03: + case dwarf::DW_LANG_C_plus_plus_11: + case dwarf::DW_LANG_OCaml: + case dwarf::DW_LANG_Rust: + case dwarf::DW_LANG_C11: + case dwarf::DW_LANG_Swift: + case dwarf::DW_LANG_Dylan: + case dwarf::DW_LANG_C_plus_plus_14: + if (dwarf::DWARF_VERSION >= 5) + return 0; + break; + + case dwarf::DW_LANG_Modula3: + case dwarf::DW_LANG_Julia: + case dwarf::DW_LANG_Fortran03: + case dwarf::DW_LANG_Fortran08: + if (dwarf::DWARF_VERSION >= 5) + return 1; + break; } return -1; @@ -399,85 +437,18 @@ void DwarfUnit::addSourceLine(DIE &Die, DINameSpace NS) { } /// addRegisterOp - Add register operand. -// FIXME: Ideally, this would share the implementation with -// AsmPrinter::EmitDwarfRegOpPiece. -void DwarfUnit::addRegisterOpPiece(DIELoc &TheDie, unsigned Reg, +bool DwarfUnit::addRegisterOpPiece(DIELoc &TheDie, unsigned Reg, unsigned SizeInBits, unsigned OffsetInBits) { - const TargetRegisterInfo *RI = Asm->TM.getSubtargetImpl()->getRegisterInfo(); - int DWReg = RI->getDwarfRegNum(Reg, false); - bool isSubRegister = DWReg < 0; - - unsigned Idx = 0; - - // Go up the super-register chain until we hit a valid dwarf register number. - for (MCSuperRegIterator SR(Reg, RI); SR.isValid() && DWReg < 0; ++SR) { - DWReg = RI->getDwarfRegNum(*SR, false); - if (DWReg >= 0) - Idx = RI->getSubRegIndex(*SR, Reg); - } - - if (DWReg < 0) { - DEBUG(dbgs() << "Invalid Dwarf register number.\n"); - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_nop); - return; - } - - // Emit register. - if (DWReg < 32) - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + DWReg); - else { - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_regx); - addUInt(TheDie, dwarf::DW_FORM_udata, DWReg); - } - - // Emit mask. - bool isPiece = SizeInBits > 0; - if (isSubRegister || isPiece) { - const unsigned SizeOfByte = 8; - unsigned RegSizeInBits = RI->getSubRegIdxSize(Idx); - unsigned RegOffsetInBits = RI->getSubRegIdxOffset(Idx); - unsigned PieceSizeInBits = std::max(SizeInBits, RegSizeInBits); - unsigned PieceOffsetInBits = OffsetInBits ? OffsetInBits : RegOffsetInBits; - assert(RegSizeInBits >= SizeInBits && "register smaller than value"); - - if (RegOffsetInBits != PieceOffsetInBits) { - // Manually shift the value into place, since the DW_OP_piece - // describes the part of the variable, not the position of the - // subregister. - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); - addUInt(TheDie, dwarf::DW_FORM_data1, RegOffsetInBits); - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_shr); - } - - if (PieceOffsetInBits > 0 || PieceSizeInBits % SizeOfByte) { - assert(PieceSizeInBits > 0 && "piece has zero size"); - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_bit_piece); - addUInt(TheDie, dwarf::DW_FORM_data1, PieceSizeInBits); - addUInt(TheDie, dwarf::DW_FORM_data1, PieceOffsetInBits); - } else { - assert(PieceSizeInBits > 0 && "piece has zero size"); - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_piece); - addUInt(TheDie, dwarf::DW_FORM_data1, PieceSizeInBits/SizeOfByte); - } - } + DIEDwarfExpression Expr(*Asm, *this, TheDie); + Expr.AddMachineRegPiece(Reg, SizeInBits, OffsetInBits); + return true; } /// addRegisterOffset - Add register offset. -void DwarfUnit::addRegisterOffset(DIELoc &TheDie, unsigned Reg, +bool DwarfUnit::addRegisterOffset(DIELoc &TheDie, unsigned Reg, int64_t Offset) { - const TargetRegisterInfo *RI = Asm->TM.getSubtargetImpl()->getRegisterInfo(); - unsigned DWReg = RI->getDwarfRegNum(Reg, false); - const TargetRegisterInfo *TRI = Asm->TM.getSubtargetImpl()->getRegisterInfo(); - if (Reg == TRI->getFrameRegister(*Asm->MF)) - // If variable offset is based in frame register then use fbreg. - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_fbreg); - else if (DWReg < 32) - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + DWReg); - else { - addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_bregx); - addUInt(TheDie, dwarf::DW_FORM_udata, DWReg); - } - addSInt(TheDie, dwarf::DW_FORM_sdata, Offset); + DIEDwarfExpression Expr(*Asm, *this, TheDie); + return Expr.AddMachineRegIndirect(Reg, Offset); } /* Byref variables, in Blocks, are declared by the programmer as "SomeType @@ -581,10 +552,14 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die, // variable's location. DIELoc *Loc = new (DIEValueAllocator) DIELoc(); + bool validReg; if (Location.isReg()) - addRegisterOpPiece(*Loc, Location.getReg()); + validReg = addRegisterOpPiece(*Loc, Location.getReg()); else - addRegisterOffset(*Loc, Location.getReg(), Location.getOffset()); + validReg = addRegisterOffset(*Loc, Location.getReg(), Location.getOffset()); + + if (!validReg) + return; // If we started with a pointer to the __Block_byref... struct, then // the first thing we need to do is dereference the pointer (DW_OP_deref). @@ -622,13 +597,19 @@ static bool isUnsignedDIType(DwarfDebug *DD, DIType Ty) { dwarf::Tag T = (dwarf::Tag)Ty.getTag(); // Encode pointer constants as unsigned bytes. This is used at least for // null pointer constant emission. + // (Pieces of) aggregate types that get hacked apart by SROA may also be + // represented by a constant. Encode them as unsigned bytes. // FIXME: reference and rvalue_reference /probably/ shouldn't be allowed // here, but accept them for now due to a bug in SROA producing bogus // dbg.values. - if (T == dwarf::DW_TAG_pointer_type || + if (T == dwarf::DW_TAG_array_type || + T == dwarf::DW_TAG_class_type || + T == dwarf::DW_TAG_pointer_type || T == dwarf::DW_TAG_ptr_to_member_type || T == dwarf::DW_TAG_reference_type || - T == dwarf::DW_TAG_rvalue_reference_type) + T == dwarf::DW_TAG_rvalue_reference_type || + T == dwarf::DW_TAG_structure_type || + T == dwarf::DW_TAG_union_type) return true; assert(T == dwarf::DW_TAG_typedef || T == dwarf::DW_TAG_const_type || T == dwarf::DW_TAG_volatile_type || @@ -649,11 +630,15 @@ static bool isUnsignedDIType(DwarfDebug *DD, DIType Ty) { Encoding == dwarf::DW_ATE_unsigned_char || Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char || - Encoding == dwarf::DW_ATE_UTF || Encoding == dwarf::DW_ATE_boolean) && + Encoding == dwarf::DW_ATE_float || + Encoding == dwarf::DW_ATE_UTF || Encoding == dwarf::DW_ATE_boolean || + (Ty.getTag() == dwarf::DW_TAG_unspecified_type && + Ty.getName() == "decltype(nullptr)")) && "Unsupported encoding"); return (Encoding == dwarf::DW_ATE_unsigned || Encoding == dwarf::DW_ATE_unsigned_char || - Encoding == dwarf::DW_ATE_UTF || Encoding == dwarf::DW_ATE_boolean); + Encoding == dwarf::DW_ATE_UTF || Encoding == dwarf::DW_ATE_boolean || + Ty.getTag() == dwarf::DW_TAG_unspecified_type); } /// If this type is derived from a base type then return base type size. @@ -667,10 +652,7 @@ static uint64_t getBaseTypeSize(DwarfDebug *DD, DIDerivedType Ty) { DIType BaseType = DD->resolve(Ty.getTypeDerivedFrom()); - // If this type is not derived from any type or the type is a declaration then - // take conservative approach. - if (!BaseType.isValid() || BaseType.isForwardDecl()) - return Ty.getSizeInBits(); + assert(BaseType.isValid() && "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 @@ -977,7 +959,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, DIDerivedType DTy) { addString(Buffer, dwarf::DW_AT_name, Name); // Add size if non-zero (derived types might be zero-sized.) - if (Size && Tag != dwarf::DW_TAG_pointer_type) + if (Size && Tag != dwarf::DW_TAG_pointer_type + && Tag != dwarf::DW_TAG_ptr_to_member_type) addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size); if (Tag == dwarf::DW_TAG_ptr_to_member_type) @@ -1110,6 +1093,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { if (CTy.isAppleBlockExtension()) addFlag(Buffer, dwarf::DW_AT_APPLE_block); + // This is outside the DWARF spec, but GDB expects a DW_AT_containing_type + // inside C++ composite types to point to the base class with the vtable. DICompositeType ContainingType(resolve(CTy.getContainingType())); if (ContainingType) addDIEEntry(Buffer, dwarf::DW_AT_containing_type, @@ -1187,10 +1172,10 @@ DwarfUnit::constructTemplateValueParameterDIE(DIE &Buffer, addType(ParamDIE, resolve(VP.getType())); if (!VP.getName().empty()) addString(ParamDIE, dwarf::DW_AT_name, VP.getName()); - if (Value *Val = VP.getValue()) { - if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) + if (Metadata *Val = VP.getValue()) { + if (ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Val)) addConstantValue(ParamDIE, CI, resolve(VP.getType())); - else if (GlobalValue *GV = dyn_cast<GlobalValue>(Val)) { + 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(); @@ -1359,7 +1344,7 @@ void DwarfUnit::applySubprogramAttributes(DISubprogram SP, DIE &SPDie, if (SP.isOptimized()) addFlag(SPDie, dwarf::DW_AT_APPLE_optimized); - if (unsigned isa = Asm->getISAEncoding()) { + if (unsigned isa = Asm->getISAEncoding(SP.getFunction())) { addUInt(SPDie, dwarf::DW_AT_APPLE_isa, dwarf::DW_FORM_flag, isa); } @@ -1511,7 +1496,7 @@ void DwarfUnit::constructMemberDIE(DIE &Buffer, DIDerivedType DT) { uint64_t FieldSize = getBaseTypeSize(DD, DT); uint64_t OffsetInBytes; - if (Size != FieldSize) { + if (FieldSize && Size != FieldSize) { // Handle bitfield, assume bytes are 8 bits. addUInt(MemberDie, dwarf::DW_AT_byte_size, None, FieldSize/8); addUInt(MemberDie, dwarf::DW_AT_bit_size, None, Size); diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.h b/lib/CodeGen/AsmPrinter/DwarfUnit.h index f40c937..7a5e47d 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -14,17 +14,17 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFUNIT_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFUNIT_H -#include "DIE.h" #include "DwarfDebug.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringMap.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSection.h" -#include "llvm/MC/MCDwarf.h" namespace llvm { @@ -138,6 +138,7 @@ public: } // Accessors. + AsmPrinter* getAsmPrinter() const { return Asm; } unsigned getUniqueID() const { return UniqueID; } uint16_t getLanguage() const { return CUNode.getLanguage(); } DICompileUnit getCUNode() const { return CUNode; } @@ -253,12 +254,16 @@ public: /// addTemplateParams - Add template parameters in buffer. void addTemplateParams(DIE &Buffer, DIArray TParams); - /// addRegisterOp - Add register operand. - void addRegisterOpPiece(DIELoc &TheDie, unsigned Reg, + /// \brief Add register operand. + /// \returns false if the register does not exist, e.g., because it was never + /// materialized. + bool addRegisterOpPiece(DIELoc &TheDie, unsigned Reg, unsigned SizeInBits = 0, unsigned OffsetInBits = 0); - /// addRegisterOffset - Add register offset. - void addRegisterOffset(DIELoc &TheDie, unsigned Reg, int64_t Offset); + /// \brief Add register offset. + /// \returns false if the register does not exist, e.g., because it was never + /// materialized. + bool addRegisterOffset(DIELoc &TheDie, unsigned Reg, int64_t Offset); // FIXME: Should be reformulated in terms of addComplexAddress. /// addBlockByrefAddress - Start with the address based on the location diff --git a/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/lib/CodeGen/AsmPrinter/EHStreamer.cpp index 2bbffb3..4841814 100644 --- a/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -121,7 +121,8 @@ computeActionsTable(const SmallVectorImpl<const LandingPadInfo*> &LandingPads, for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) { int TypeID = TypeIds[J]; assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!"); - int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID; + int ValueForTypeID = + isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID; unsigned SizeTypeID = getSLEB128Size(ValueForTypeID); int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0; @@ -195,9 +196,22 @@ bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) { /// table. Entries must be ordered by try-range address. void EHStreamer:: computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, - const RangeMapType &PadMap, const SmallVectorImpl<const LandingPadInfo *> &LandingPads, const SmallVectorImpl<unsigned> &FirstActions) { + // Invokes and nounwind calls have entries in PadMap (due to being bracketed + // by try-range labels when lowered). Ordinary calls do not, so appropriate + // try-ranges for them need be deduced so we can put them in the LSDA. + RangeMapType PadMap; + for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { + const LandingPadInfo *LandingPad = LandingPads[i]; + for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { + MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; + assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); + PadRange P = { i, j }; + PadMap[BeginLabel] = P; + } + } + // The end label of the previous invoke or nounwind try-range. MCSymbol *LastLabel = nullptr; @@ -208,6 +222,8 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, // Whether the last CallSite entry was for an invoke. bool PreviousIsInvoke = false; + bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; + // Visit all instructions in order of address. for (const auto &MBB : *Asm->MF) { for (const auto &MI : MBB) { @@ -237,7 +253,7 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, // instruction between the previous try-range and this one may throw, // create a call-site entry with no landing pad for the region between the // try-ranges. - if (SawPotentiallyThrowing && Asm->MAI->usesItaniumLSDAForExceptions()) { + if (SawPotentiallyThrowing && Asm->MAI->usesCFIForEH()) { CallSiteEntry Site = { LastLabel, BeginLabel, nullptr, 0 }; CallSites.push_back(Site); PreviousIsInvoke = false; @@ -254,14 +270,14 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, CallSiteEntry Site = { BeginLabel, LastLabel, - LandingPad->LandingPadLabel, + LandingPad, FirstActions[P.PadIndex] }; // Try to merge with the previous call-site. SJLJ doesn't do this - if (PreviousIsInvoke && Asm->MAI->usesItaniumLSDAForExceptions()) { + if (PreviousIsInvoke && !IsSJLJ) { CallSiteEntry &Prev = CallSites.back(); - if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) { + if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) { // Extend the range of the previous entry. Prev.EndLabel = Site.EndLabel; continue; @@ -269,7 +285,7 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, } // Otherwise, create a new call-site. - if (Asm->MAI->usesItaniumLSDAForExceptions()) + if (!IsSJLJ) CallSites.push_back(Site); else { // SjLj EH must maintain the call sites in the order assigned @@ -287,7 +303,7 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, // If some instruction between the previous try-range and the end of the // function may throw, create a call-site entry with no landing pad for the // region following the try-range. - if (SawPotentiallyThrowing && Asm->MAI->usesItaniumLSDAForExceptions()) { + if (SawPotentiallyThrowing && !IsSJLJ) { CallSiteEntry Site = { LastLabel, nullptr, nullptr, 0 }; CallSites.push_back(Site); } @@ -338,23 +354,9 @@ void EHStreamer::emitExceptionTable() { unsigned SizeActions = computeActionsTable(LandingPads, Actions, FirstActions); - // Invokes and nounwind calls have entries in PadMap (due to being bracketed - // by try-range labels when lowered). Ordinary calls do not, so appropriate - // try-ranges for them need be deduced when using DWARF exception handling. - RangeMapType PadMap; - for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { - const LandingPadInfo *LandingPad = LandingPads[i]; - for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { - MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; - assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); - PadRange P = { i, j }; - PadMap[BeginLabel] = P; - } - } - // Compute the call-site table. SmallVector<CallSiteEntry, 64> CallSites; - computeCallSiteTable(CallSites, PadMap, LandingPads, FirstActions); + computeCallSiteTable(CallSites, LandingPads, FirstActions); // Final tallies. @@ -519,8 +521,7 @@ void EHStreamer::emitExceptionTable() { Asm->EmitULEB128(S.Action); } } else { - // DWARF Exception handling - assert(Asm->MAI->usesItaniumLSDAForExceptions()); + // Itanium LSDA exception handling // The call-site table is a list of all call sites that may throw an // exception (including C++ 'throw' statements) in the procedure @@ -576,15 +577,15 @@ void EHStreamer::emitExceptionTable() { // Offset of the landing pad, counted in 16-byte bundles relative to the // @LPStart address. - if (!S.PadLabel) { + if (!S.LPad) { if (VerboseAsm) Asm->OutStreamer.AddComment(" has no landing pad"); Asm->OutStreamer.EmitIntValue(0, 4/*size*/); } else { if (VerboseAsm) Asm->OutStreamer.AddComment(Twine(" jumps to ") + - S.PadLabel->getName()); - Asm->EmitLabelDifference(S.PadLabel, EHFuncBeginSym, 4); + S.LPad->LandingPadLabel->getName()); + Asm->EmitLabelDifference(S.LPad->LandingPadLabel, EHFuncBeginSym, 4); } // Offset of the first associated action record, relative to the start of @@ -681,7 +682,7 @@ void EHStreamer::emitTypeInfos(unsigned TTypeEncoding) { unsigned TypeID = *I; if (VerboseAsm) { --Entry; - if (TypeID != 0) + if (isFilterEHSelector(TypeID)) Asm->OutStreamer.AddComment("FilterInfo " + Twine(Entry)); } diff --git a/lib/CodeGen/AsmPrinter/EHStreamer.h b/lib/CodeGen/AsmPrinter/EHStreamer.h index 7e9549d..9b316ff 100644 --- a/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -23,6 +23,8 @@ class MachineModuleInfo; class MachineInstr; class MachineFunction; class AsmPrinter; +class MCSymbol; +class MCSymbolRefExpr; template <typename T> class SmallVectorImpl; @@ -60,11 +62,11 @@ protected: /// Structure describing an entry in the call-site table. struct CallSiteEntry { // The 'try-range' is BeginLabel .. EndLabel. - MCSymbol *BeginLabel; // zero indicates the start of the function. - MCSymbol *EndLabel; // zero indicates the end of the function. + MCSymbol *BeginLabel; // Null indicates the start of the function. + MCSymbol *EndLabel; // Null indicates the end of the function. - // The landing pad starts at PadLabel. - MCSymbol *PadLabel; // zero indicates that there is no landing pad. + // LPad contains the landing pad start labels. + const LandingPadInfo *LPad; // Null indicates that there is no landing pad. unsigned Action; }; @@ -86,7 +88,6 @@ protected: /// form gaps in the table. Entries must be ordered by try-range address. void computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, - const RangeMapType &PadMap, const SmallVectorImpl<const LandingPadInfo *> &LPs, const SmallVectorImpl<unsigned> &FirstActions); @@ -113,6 +114,13 @@ protected: virtual void emitTypeInfos(unsigned TTypeEncoding); + // Helpers for for identifying what kind of clause an EH typeid or selector + // corresponds to. Negative selectors are for filter clauses, the zero + // selector is for cleanups, and positive selectors are for catch clauses. + static bool isFilterEHSelector(int Selector) { return Selector < 0; } + static bool isCleanupEHSelector(int Selector) { return Selector == 0; } + static bool isCatchEHSelector(int Selector) { return Selector > 0; } + public: EHStreamer(AsmPrinter *A); virtual ~EHStreamer(); diff --git a/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp b/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp index 5bda5a9..97a3234 100644 --- a/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp @@ -34,35 +34,35 @@ using namespace llvm; namespace { - class ErlangGCPrinter : public GCMetadataPrinter { - public: - void beginAssembly(AsmPrinter &AP) override; - void finishAssembly(AsmPrinter &AP) override; - }; - +class ErlangGCPrinter : public GCMetadataPrinter { +public: + void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override; +}; } static GCMetadataPrinterRegistry::Add<ErlangGCPrinter> -X("erlang", "erlang-compatible garbage collector"); - -void llvm::linkErlangGCPrinter() { } + X("erlang", "erlang-compatible garbage collector"); -void ErlangGCPrinter::beginAssembly(AsmPrinter &AP) { } +void llvm::linkErlangGCPrinter() {} -void ErlangGCPrinter::finishAssembly(AsmPrinter &AP) { +void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info, + AsmPrinter &AP) { MCStreamer &OS = AP.OutStreamer; - unsigned IntPtrSize = - AP.TM.getSubtargetImpl()->getDataLayout()->getPointerSize(); + unsigned IntPtrSize = AP.TM.getDataLayout()->getPointerSize(); // Put this in a custom .note section. - AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getContext() - .getELFSection(".note.gc", ELF::SHT_PROGBITS, 0, - SectionKind::getDataRel())); + AP.OutStreamer.SwitchSection( + AP.getObjFileLowering().getContext().getELFSection(".note.gc", + ELF::SHT_PROGBITS, 0)); // For each function... - for (iterator FI = begin(), FE = end(); FI != FE; ++FI) { + for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(), + IE = Info.funcinfo_end(); + FI != IE; ++FI) { GCFunctionInfo &MD = **FI; - + if (MD.getStrategy().getName() != getStrategy().getName()) + // this function is managed by some other GC + continue; /** A compact GC layout. Emit this data structure: * * struct { @@ -88,7 +88,7 @@ void ErlangGCPrinter::finishAssembly(AsmPrinter &AP) { // Emit the address of the safe point. OS.AddComment("safe point address"); MCSymbol *Label = PI->Label; - AP.EmitLabelPlusOffset(Label/*Hi*/, 0/*Offset*/, 4/*Size*/); + AP.EmitLabelPlusOffset(Label /*Hi*/, 0 /*Offset*/, 4 /*Size*/); } // Stack information never change in safe points! Only print info from the @@ -101,8 +101,9 @@ void ErlangGCPrinter::finishAssembly(AsmPrinter &AP) { // Emit stack arity, i.e. the number of stacked arguments. unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6; - unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs ? - MD.getFunction().arg_size() - RegisteredArgs : 0; + unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs + ? MD.getFunction().arg_size() - RegisteredArgs + : 0; OS.AddComment("stack arity"); AP.EmitInt16(StackArity); @@ -113,7 +114,7 @@ void ErlangGCPrinter::finishAssembly(AsmPrinter &AP) { // And for each live root... for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI), LE = MD.live_end(PI); - LI != LE; ++LI) { + LI != LE; ++LI) { // Emit live root's offset within the stack frame. OS.AddComment("stack index (offset / wordsize)"); AP.EmitInt16(LI->StackOffset / IntPtrSize); diff --git a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp index 6480d048..76d6a06 100644 --- a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp @@ -32,18 +32,17 @@ using namespace llvm; namespace { - class OcamlGCMetadataPrinter : public GCMetadataPrinter { - public: - void beginAssembly(AsmPrinter &AP) override; - void finishAssembly(AsmPrinter &AP) override; - }; - +class OcamlGCMetadataPrinter : public GCMetadataPrinter { +public: + void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override; + void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override; +}; } static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter> -Y("ocaml", "ocaml 3.10-compatible collector"); + Y("ocaml", "ocaml 3.10-compatible collector"); -void llvm::linkOcamlGCPrinter() { } +void llvm::linkOcamlGCPrinter() {} static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) { const std::string &MId = M.getModuleIdentifier(); @@ -67,12 +66,13 @@ static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) { AP.OutStreamer.EmitLabel(Sym); } -void OcamlGCMetadataPrinter::beginAssembly(AsmPrinter &AP) { +void OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info, + AsmPrinter &AP) { AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection()); - EmitCamlGlobal(getModule(), AP, "code_begin"); + EmitCamlGlobal(M, AP, "code_begin"); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); - EmitCamlGlobal(getModule(), AP, "data_begin"); + EmitCamlGlobal(M, AP, "data_begin"); } /// emitAssembly - Print the frametable. The ocaml frametable format is thus: @@ -91,47 +91,59 @@ void OcamlGCMetadataPrinter::beginAssembly(AsmPrinter &AP) { /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if /// either condition is detected in a function which uses the GC. /// -void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) { - unsigned IntPtrSize = - AP.TM.getSubtargetImpl()->getDataLayout()->getPointerSize(); +void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, + AsmPrinter &AP) { + unsigned IntPtrSize = AP.TM.getDataLayout()->getPointerSize(); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection()); - EmitCamlGlobal(getModule(), AP, "code_end"); + EmitCamlGlobal(M, AP, "code_end"); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); - EmitCamlGlobal(getModule(), AP, "data_end"); + EmitCamlGlobal(M, AP, "data_end"); // FIXME: Why does ocaml emit this?? AP.OutStreamer.EmitIntValue(0, IntPtrSize); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); - EmitCamlGlobal(getModule(), AP, "frametable"); + EmitCamlGlobal(M, AP, "frametable"); int NumDescriptors = 0; - for (iterator I = begin(), IE = end(); I != IE; ++I) { + for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), + IE = Info.funcinfo_end(); + I != IE; ++I) { GCFunctionInfo &FI = **I; + if (FI.getStrategy().getName() != getStrategy().getName()) + // this function is managed by some other GC + continue; for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { NumDescriptors++; } } - if (NumDescriptors >= 1<<16) { + if (NumDescriptors >= 1 << 16) { // Very rude! report_fatal_error(" Too much descriptor for ocaml GC"); } AP.EmitInt16(NumDescriptors); AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); - for (iterator I = begin(), IE = end(); I != IE; ++I) { + for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), + IE = Info.funcinfo_end(); + I != IE; ++I) { GCFunctionInfo &FI = **I; + if (FI.getStrategy().getName() != getStrategy().getName()) + // this function is managed by some other GC + continue; uint64_t FrameSize = FI.getFrameSize(); - if (FrameSize >= 1<<16) { + if (FrameSize >= 1 << 16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " - "Frame size " + Twine(FrameSize) + ">= 65536.\n" - "(" + Twine(uintptr_t(&FI)) + ")"); + "Frame size " + + Twine(FrameSize) + ">= 65536.\n" + "(" + + Twine(uintptr_t(&FI)) + ")"); } AP.OutStreamer.AddComment("live roots for " + @@ -140,11 +152,12 @@ void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) { for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { size_t LiveCount = FI.live_size(J); - if (LiveCount >= 1<<16) { + if (LiveCount >= 1 << 16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " - "Live root count "+Twine(LiveCount)+" >= 65536."); + "Live root count " + + Twine(LiveCount) + " >= 65536."); } AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize); @@ -152,12 +165,13 @@ void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) { AP.EmitInt16(LiveCount); for (GCFunctionInfo::live_iterator K = FI.live_begin(J), - KE = FI.live_end(J); K != KE; ++K) { - if (K->StackOffset >= 1<<16) { + KE = FI.live_end(J); + K != KE; ++K) { + if (K->StackOffset >= 1 << 16) { // Very rude! report_fatal_error( - "GC root stack offset is outside of fixed stack frame and out " - "of range for ocaml GC!"); + "GC root stack offset is outside of fixed stack frame and out " + "of range for ocaml GC!"); } AP.EmitInt16(K->StackOffset); } diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/lib/CodeGen/AsmPrinter/Win64Exception.cpp index 0f0ad75..2b03877 100644 --- a/lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ b/lib/CodeGen/AsmPrinter/Win64Exception.cpp @@ -60,7 +60,7 @@ void Win64Exception::beginFunction(const MachineFunction *MF) { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); unsigned PerEncoding = TLOF.getPersonalityEncoding(); - const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()]; + const Function *Per = MF->getMMI().getPersonality(); shouldEmitPersonality = hasLandingPads && PerEncoding != dwarf::DW_EH_PE_omit && Per; @@ -99,9 +99,151 @@ void Win64Exception::endFunction(const MachineFunction *) { if (shouldEmitPersonality) { Asm->OutStreamer.PushSection(); + + // Emit an UNWIND_INFO struct describing the prologue. Asm->OutStreamer.EmitWinEHHandlerData(); - emitExceptionTable(); + + // Emit the tables appropriate to the personality function in use. If we + // don't recognize the personality, assume it uses an Itanium-style LSDA. + EHPersonality Per = MMI->getPersonalityType(); + if (Per == EHPersonality::MSVC_Win64SEH) + emitCSpecificHandlerTable(); + else + emitExceptionTable(); + Asm->OutStreamer.PopSection(); } Asm->OutStreamer.EmitWinCFIEndProc(); } + +const MCSymbolRefExpr *Win64Exception::createImageRel32(const MCSymbol *Value) { + return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32, + Asm->OutContext); +} + +/// Emit the language-specific data that __C_specific_handler expects. This +/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning +/// up after faults with __try, __except, and __finally. The typeinfo values +/// are not really RTTI data, but pointers to filter functions that return an +/// integer (1, 0, or -1) indicating how to handle the exception. For __finally +/// blocks and other cleanups, the landing pad label is zero, and the filter +/// function is actually a cleanup handler with the same prototype. A catch-all +/// entry is modeled with a null filter function field and a non-zero landing +/// pad label. +/// +/// Possible filter function return values: +/// EXCEPTION_EXECUTE_HANDLER (1): +/// Jump to the landing pad label after cleanups. +/// EXCEPTION_CONTINUE_SEARCH (0): +/// Continue searching this table or continue unwinding. +/// EXCEPTION_CONTINUE_EXECUTION (-1): +/// Resume execution at the trapping PC. +/// +/// Inferred table structure: +/// struct Table { +/// int NumEntries; +/// struct Entry { +/// imagerel32 LabelStart; +/// imagerel32 LabelEnd; +/// imagerel32 FilterOrFinally; // One means catch-all. +/// imagerel32 LabelLPad; // Zero means __finally. +/// } Entries[NumEntries]; +/// }; +void Win64Exception::emitCSpecificHandlerTable() { + const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); + + // Simplifying assumptions for first implementation: + // - Cleanups are not implemented. + // - Filters are not implemented. + + // The Itanium LSDA table sorts similar landing pads together to simplify the + // actions table, but we don't need that. + SmallVector<const LandingPadInfo *, 64> LandingPads; + LandingPads.reserve(PadInfos.size()); + for (const auto &LP : PadInfos) + LandingPads.push_back(&LP); + + // Compute label ranges for call sites as we would for the Itanium LSDA, but + // use an all zero action table because we aren't using these actions. + SmallVector<unsigned, 64> FirstActions; + FirstActions.resize(LandingPads.size()); + SmallVector<CallSiteEntry, 64> CallSites; + computeCallSiteTable(CallSites, LandingPads, FirstActions); + + MCSymbol *EHFuncBeginSym = + Asm->GetTempSymbol("eh_func_begin", Asm->getFunctionNumber()); + MCSymbol *EHFuncEndSym = + Asm->GetTempSymbol("eh_func_end", Asm->getFunctionNumber()); + + // Emit the number of table entries. + unsigned NumEntries = 0; + for (const CallSiteEntry &CSE : CallSites) { + if (!CSE.LPad) + continue; // Ignore gaps. + for (int Selector : CSE.LPad->TypeIds) { + // Ignore C++ filter clauses in SEH. + // FIXME: Implement cleanup clauses. + if (isCatchEHSelector(Selector)) + ++NumEntries; + } + } + Asm->OutStreamer.EmitIntValue(NumEntries, 4); + + // Emit the four-label records for each call site entry. The table has to be + // sorted in layout order, and the call sites should already be sorted. + for (const CallSiteEntry &CSE : CallSites) { + // Ignore gaps. Unlike the Itanium model, unwinding through a frame without + // an EH table entry will propagate the exception rather than terminating + // the program. + if (!CSE.LPad) + continue; + const LandingPadInfo *LPad = CSE.LPad; + + // Compute the label range. We may reuse the function begin and end labels + // rather than forming new ones. + const MCExpr *Begin = + createImageRel32(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym); + const MCExpr *End; + if (CSE.EndLabel) { + // The interval is half-open, so we have to add one to include the return + // address of the last invoke in the range. + End = MCBinaryExpr::CreateAdd(createImageRel32(CSE.EndLabel), + MCConstantExpr::Create(1, Asm->OutContext), + Asm->OutContext); + } else { + End = createImageRel32(EHFuncEndSym); + } + + // These aren't really type info globals, they are actually pointers to + // filter functions ordered by selector. The zero selector is used for + // cleanups, so slot zero corresponds to selector 1. + const std::vector<const GlobalValue *> &SelectorToFilter = MMI->getTypeInfos(); + + // Do a parallel iteration across typeids and clause labels, skipping filter + // clauses. + size_t NextClauseLabel = 0; + for (size_t I = 0, E = LPad->TypeIds.size(); I < E; ++I) { + // AddLandingPadInfo stores the clauses in reverse, but there is a FIXME + // to change that. + int Selector = LPad->TypeIds[E - I - 1]; + + // Ignore C++ filter clauses in SEH. + // FIXME: Implement cleanup clauses. + if (!isCatchEHSelector(Selector)) + continue; + + Asm->OutStreamer.EmitValue(Begin, 4); + Asm->OutStreamer.EmitValue(End, 4); + if (isCatchEHSelector(Selector)) { + assert(unsigned(Selector - 1) < SelectorToFilter.size()); + const GlobalValue *TI = SelectorToFilter[Selector - 1]; + if (TI) // Emit the filter function pointer. + Asm->OutStreamer.EmitValue(createImageRel32(Asm->getSymbol(TI)), 4); + else // Otherwise, this is a "catch i8* null", or catch all. + Asm->OutStreamer.EmitIntValue(1, 4); + } + MCSymbol *ClauseLabel = LPad->ClauseLabels[NextClauseLabel++]; + Asm->OutStreamer.EmitValue(createImageRel32(ClauseLabel), 4); + } + } +} diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.h b/lib/CodeGen/AsmPrinter/Win64Exception.h index 538e132..b2d5d1b 100644 --- a/lib/CodeGen/AsmPrinter/Win64Exception.h +++ b/lib/CodeGen/AsmPrinter/Win64Exception.h @@ -29,6 +29,10 @@ class Win64Exception : public EHStreamer { /// Per-function flag to indicate if frame moves info should be emitted. bool shouldEmitMoves; + void emitCSpecificHandlerTable(); + + const MCSymbolRefExpr *createImageRel32(const MCSymbol *Value); + public: //===--------------------------------------------------------------------===// // Main entry points. |