diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /llvm/lib/MC | |
parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) |
Notes
Diffstat (limited to 'llvm/lib/MC')
29 files changed, 709 insertions, 782 deletions
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index 6f160e491cea5..6b4b45eb8effa 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -569,26 +569,6 @@ void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, IsReserved); } -// True if the assembler knows nothing about the final value of the symbol. -// This doesn't cover the comdat issues, since in those cases the assembler -// can at least know that all symbols in the section will move together. -static bool isWeak(const MCSymbolELF &Sym) { - if (Sym.getType() == ELF::STT_GNU_IFUNC) - return true; - - switch (Sym.getBinding()) { - default: - llvm_unreachable("Unknown binding"); - case ELF::STB_LOCAL: - return false; - case ELF::STB_GLOBAL: - return false; - case ELF::STB_WEAK: - case ELF::STB_GNU_UNIQUE: - return true; - } -} - bool ELFWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, bool Used, bool Renamed) { if (Symbol.isVariable()) { @@ -615,9 +595,6 @@ bool ELFWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, return false; } - if (Symbol.isUndefined() && !Symbol.isBindingSet()) - return false; - if (Symbol.isTemporary()) return false; @@ -1537,7 +1514,8 @@ bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( const auto &SymA = cast<MCSymbolELF>(SA); if (IsPCRel) { assert(!InSet); - if (isWeak(SymA)) + if (SymA.getBinding() != ELF::STB_LOCAL || + SymA.getType() == ELF::STT_GNU_IFUNC) return false; } return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB, diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp index b800e9caee22a..cf110345df3de 100644 --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -9,7 +9,6 @@ #include "llvm/MC/MCAsmBackend.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/MC/MCCodePadder.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCMachObjectWriter.h" @@ -23,8 +22,7 @@ using namespace llvm; -MCAsmBackend::MCAsmBackend(support::endianness Endian) - : CodePadder(new MCCodePadder()), Endian(Endian) {} +MCAsmBackend::MCAsmBackend(support::endianness Endian) : Endian(Endian) {} MCAsmBackend::~MCAsmBackend() = default; @@ -113,25 +111,3 @@ bool MCAsmBackend::fixupNeedsRelaxationAdvanced( return true; return fixupNeedsRelaxation(Fixup, Value, DF, Layout); } - -void MCAsmBackend::handleCodePaddingBasicBlockStart( - MCObjectStreamer *OS, const MCCodePaddingContext &Context) { - CodePadder->handleBasicBlockStart(OS, Context); -} - -void MCAsmBackend::handleCodePaddingBasicBlockEnd( - const MCCodePaddingContext &Context) { - CodePadder->handleBasicBlockEnd(Context); -} - -void MCAsmBackend::handleCodePaddingInstructionBegin(const MCInst &Inst) { - CodePadder->handleInstructionBegin(Inst); -} - -void MCAsmBackend::handleCodePaddingInstructionEnd(const MCInst &Inst) { - CodePadder->handleInstructionEnd(Inst); -} - -bool MCAsmBackend::relaxFragment(MCPaddingFragment *PF, MCAsmLayout &Layout) { - return CodePadder->relaxFragment(PF, Layout); -} diff --git a/llvm/lib/MC/MCAsmInfo.cpp b/llvm/lib/MC/MCAsmInfo.cpp index 71e51e320f8bd..420dbaa80ae90 100644 --- a/llvm/lib/MC/MCAsmInfo.cpp +++ b/llvm/lib/MC/MCAsmInfo.cpp @@ -100,7 +100,7 @@ MCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym, return MCBinaryExpr::createSub(Res, PC, Context); } -static bool isAcceptableChar(char C) { +bool MCAsmInfo::isAcceptableChar(char C) const { return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || (C >= '0' && C <= '9') || C == '_' || C == '$' || C == '.' || C == '@'; } diff --git a/llvm/lib/MC/MCAsmInfoELF.cpp b/llvm/lib/MC/MCAsmInfoELF.cpp index a5e8aff7f129d..9b8b8db794f0d 100644 --- a/llvm/lib/MC/MCAsmInfoELF.cpp +++ b/llvm/lib/MC/MCAsmInfoELF.cpp @@ -21,8 +21,6 @@ using namespace llvm; void MCAsmInfoELF::anchor() {} MCSection *MCAsmInfoELF::getNonexecutableStackSection(MCContext &Ctx) const { - if (!UsesNonexecutableStackSection) - return nullptr; return Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0); } diff --git a/llvm/lib/MC/MCAsmInfoXCOFF.cpp b/llvm/lib/MC/MCAsmInfoXCOFF.cpp index 65fe8848e20fb..c51cdff59fa0a 100644 --- a/llvm/lib/MC/MCAsmInfoXCOFF.cpp +++ b/llvm/lib/MC/MCAsmInfoXCOFF.cpp @@ -26,10 +26,11 @@ MCAsmInfoXCOFF::MCAsmInfoXCOFF() { SupportsQuotedNames = false; } -bool MCAsmInfoXCOFF::isValidUnquotedName(StringRef Name) const { - // FIXME: Remove this function when we stop using "TOC[TC0]" as a symbol name. - if (Name.equals("TOC[TC0]")) +bool MCAsmInfoXCOFF::isAcceptableChar(char C) const { + // QualName is allowed for a MCSymbolXCOFF, and + // QualName contains '[' and ']'. + if (C == '[' || C == ']') return true; - return MCAsmInfo::isValidUnquotedName(Name); + return MCAsmInfo::isAcceptableChar(C); } diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 2d9c2cb21255b..5d369503995b3 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -77,6 +77,8 @@ public: assert(InstPrinter); if (IsVerboseAsm) InstPrinter->setCommentStream(CommentStream); + if (Assembler->getBackendPtr()) + setAllowAutoPadding(Assembler->getBackend().allowAutoPadding()); } MCAssembler &getAssembler() { return *Assembler; } @@ -164,7 +166,8 @@ public: void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override; - void EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + void EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlign) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, @@ -765,16 +768,18 @@ void MCAsmStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) { // We need an XCOFF-specific version of this directive as the AIX syntax // requires a QualName argument identifying the csect name and storage mapping // class to appear before the alignment if we are specifying it. -void MCAsmStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, +void MCAsmStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, + uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlignment) { assert(MAI->getLCOMMDirectiveAlignmentType() == LCOMM::Log2Alignment && "We only support writing log base-2 alignment format with XCOFF."); assert(isPowerOf2_32(ByteAlignment) && "Alignment must be a power of 2."); OS << "\t.lcomm\t"; - Symbol->print(OS, MAI); - OS << ',' << Size; - OS << ',' << Symbol->getName(); + LabelSym->print(OS, MAI); + OS << ',' << Size << ','; + CsectSym->print(OS, MAI); OS << ',' << Log2_32(ByteAlignment); EmitEOL(); @@ -1941,9 +1946,9 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst, } if(getTargetStreamer()) - getTargetStreamer()->prettyPrintAsm(*InstPrinter, OS, Inst, STI); + getTargetStreamer()->prettyPrintAsm(*InstPrinter, 0, Inst, STI, OS); else - InstPrinter->printInst(&Inst, OS, "", STI); + InstPrinter->printInst(&Inst, 0, "", STI, OS); StringRef Comments = CommentToEmit; if (Comments.size() && Comments.back() != '\n') diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index cf42fe85b8e5d..b30137aafb8d1 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -68,10 +68,6 @@ STATISTIC(FragmentLayouts, "Number of fragment layouts"); STATISTIC(ObjectBytes, "Number of emitted object file bytes"); STATISTIC(RelaxationSteps, "Number of assembler layout and relaxation steps"); STATISTIC(RelaxedInstructions, "Number of relaxed instructions"); -STATISTIC(PaddingFragmentsRelaxations, - "Number of Padding Fragments relaxations"); -STATISTIC(PaddingFragmentsBytes, - "Total size of all padding from adding Fragments"); } // end namespace stats } // end anonymous namespace @@ -167,10 +163,6 @@ bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const { if (!Symbol.isTemporary()) return true; - // Absolute temporary labels are never visible. - if (!Symbol.isInSection()) - return false; - if (Symbol.isUsedInReloc()) return true; @@ -313,8 +305,8 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, case MCFragment::FT_LEB: return cast<MCLEBFragment>(F).getContents().size(); - case MCFragment::FT_Padding: - return cast<MCPaddingFragment>(F).getSize(); + case MCFragment::FT_BoundaryAlign: + return cast<MCBoundaryAlignFragment>(F).getSize(); case MCFragment::FT_SymbolId: return 4; @@ -580,6 +572,7 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm, unsigned VSize = FF.getValueSize(); const unsigned MaxChunkSize = 16; char Data[MaxChunkSize]; + assert(0 < VSize && VSize <= MaxChunkSize && "Illegal fragment fill size"); // Duplicate V into Data as byte vector to reduce number of // writes done. As such, do endian conversion here. for (unsigned I = 0; I != VSize; ++I) { @@ -612,7 +605,7 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm, break; } - case MCFragment::FT_Padding: { + case MCFragment::FT_BoundaryAlign: { if (!Asm.getBackend().writeNopData(OS, FragmentSize)) report_fatal_error("unable to write nop sequence of " + Twine(FragmentSize) + " bytes"); @@ -935,20 +928,6 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, return true; } -bool MCAssembler::relaxPaddingFragment(MCAsmLayout &Layout, - MCPaddingFragment &PF) { - assert(getBackendPtr() && "Expected assembler backend"); - uint64_t OldSize = PF.getSize(); - if (!getBackend().relaxFragment(&PF, Layout)) - return false; - uint64_t NewSize = PF.getSize(); - - ++stats::PaddingFragmentsRelaxations; - stats::PaddingFragmentsBytes += NewSize; - stats::PaddingFragmentsBytes -= OldSize; - return true; -} - bool MCAssembler::relaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) { uint64_t OldSize = LF.getContents().size(); int64_t Value; @@ -969,6 +948,72 @@ bool MCAssembler::relaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) { return OldSize != LF.getContents().size(); } +/// Check if the branch crosses the boundary. +/// +/// \param StartAddr start address of the fused/unfused branch. +/// \param Size size of the fused/unfused branch. +/// \param BoundaryAlignment alignment requirement of the branch. +/// \returns true if the branch cross the boundary. +static bool mayCrossBoundary(uint64_t StartAddr, uint64_t Size, + Align BoundaryAlignment) { + uint64_t EndAddr = StartAddr + Size; + return (StartAddr >> Log2(BoundaryAlignment)) != + ((EndAddr - 1) >> Log2(BoundaryAlignment)); +} + +/// Check if the branch is against the boundary. +/// +/// \param StartAddr start address of the fused/unfused branch. +/// \param Size size of the fused/unfused branch. +/// \param BoundaryAlignment alignment requirement of the branch. +/// \returns true if the branch is against the boundary. +static bool isAgainstBoundary(uint64_t StartAddr, uint64_t Size, + Align BoundaryAlignment) { + uint64_t EndAddr = StartAddr + Size; + return (EndAddr & (BoundaryAlignment.value() - 1)) == 0; +} + +/// Check if the branch needs padding. +/// +/// \param StartAddr start address of the fused/unfused branch. +/// \param Size size of the fused/unfused branch. +/// \param BoundaryAlignment alignment requirement of the branch. +/// \returns true if the branch needs padding. +static bool needPadding(uint64_t StartAddr, uint64_t Size, + Align BoundaryAlignment) { + return mayCrossBoundary(StartAddr, Size, BoundaryAlignment) || + isAgainstBoundary(StartAddr, Size, BoundaryAlignment); +} + +bool MCAssembler::relaxBoundaryAlign(MCAsmLayout &Layout, + MCBoundaryAlignFragment &BF) { + // The MCBoundaryAlignFragment that doesn't emit NOP should not be relaxed. + if (!BF.canEmitNops()) + return false; + + uint64_t AlignedOffset = Layout.getFragmentOffset(BF.getNextNode()); + uint64_t AlignedSize = 0; + const MCFragment *F = BF.getNextNode(); + // If the branch is unfused, it is emitted into one fragment, otherwise it is + // emitted into two fragments at most, the next MCBoundaryAlignFragment(if + // exists) also marks the end of the branch. + for (auto i = 0, N = BF.isFused() ? 2 : 1; + i != N && !isa<MCBoundaryAlignFragment>(F); ++i, F = F->getNextNode()) { + AlignedSize += computeFragmentSize(Layout, *F); + } + uint64_t OldSize = BF.getSize(); + AlignedOffset -= OldSize; + Align BoundaryAlignment = BF.getAlignment(); + uint64_t NewSize = needPadding(AlignedOffset, AlignedSize, BoundaryAlignment) + ? offsetToAlignment(AlignedOffset, BoundaryAlignment) + : 0U; + if (NewSize == OldSize) + return false; + BF.setSize(NewSize); + Layout.invalidateFragmentsFrom(&BF); + return true; +} + bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF) { MCContext &Context = Layout.getAssembler().getContext(); @@ -1085,8 +1130,9 @@ bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) { case MCFragment::FT_LEB: RelaxedFrag = relaxLEB(Layout, *cast<MCLEBFragment>(I)); break; - case MCFragment::FT_Padding: - RelaxedFrag = relaxPaddingFragment(Layout, *cast<MCPaddingFragment>(I)); + case MCFragment::FT_BoundaryAlign: + RelaxedFrag = + relaxBoundaryAlign(Layout, *cast<MCBoundaryAlignFragment>(I)); break; case MCFragment::FT_CVInlineLines: RelaxedFrag = @@ -1124,8 +1170,8 @@ void MCAssembler::finishLayout(MCAsmLayout &Layout) { // The layout is done. Mark every fragment as valid. for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { MCSection &Section = *Layout.getSectionOrder()[i]; - Layout.getFragmentOffset(&*Section.rbegin()); - computeFragmentSize(Layout, *Section.rbegin()); + Layout.getFragmentOffset(&*Section.getFragmentList().rbegin()); + computeFragmentSize(Layout, *Section.getFragmentList().rbegin()); } getBackend().finishLayout(*this, Layout); } diff --git a/llvm/lib/MC/MCCodePadder.cpp b/llvm/lib/MC/MCCodePadder.cpp deleted file mode 100644 index 27a62f95a5294..0000000000000 --- a/llvm/lib/MC/MCCodePadder.cpp +++ /dev/null @@ -1,370 +0,0 @@ -//===- MCCodePadder.cpp - Target MC Code Padder ---------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/MC/MCAsmLayout.h" -#include "llvm/MC/MCCodePadder.h" -#include "llvm/MC/MCObjectStreamer.h" -#include <algorithm> -#include <limits> -#include <numeric> - -using namespace llvm; - -//--------------------------------------------------------------------------- -// MCCodePadder -// - -MCCodePadder::~MCCodePadder() { - for (auto *Policy : CodePaddingPolicies) - delete Policy; -} - -bool MCCodePadder::addPolicy(MCCodePaddingPolicy *Policy) { - assert(Policy && "Policy must be valid"); - return CodePaddingPolicies.insert(Policy).second; -} - -void MCCodePadder::handleBasicBlockStart(MCObjectStreamer *OS, - const MCCodePaddingContext &Context) { - assert(OS != nullptr && "OS must be valid"); - assert(this->OS == nullptr && "Still handling another basic block"); - this->OS = OS; - - ArePoliciesActive = usePoliciesForBasicBlock(Context); - - bool InsertionPoint = basicBlockRequiresInsertionPoint(Context); - assert((!InsertionPoint || - OS->getCurrentFragment()->getKind() != MCFragment::FT_Align) && - "Cannot insert padding nops right after an alignment fragment as it " - "will ruin the alignment"); - - uint64_t PoliciesMask = MCPaddingFragment::PFK_None; - if (ArePoliciesActive) { - PoliciesMask = std::accumulate( - CodePaddingPolicies.begin(), CodePaddingPolicies.end(), - MCPaddingFragment::PFK_None, - [&Context](uint64_t Mask, - const MCCodePaddingPolicy *Policy) -> uint64_t { - return Policy->basicBlockRequiresPaddingFragment(Context) - ? (Mask | Policy->getKindMask()) - : Mask; - }); - } - - if (InsertionPoint || PoliciesMask != MCPaddingFragment::PFK_None) { - MCPaddingFragment *PaddingFragment = OS->getOrCreatePaddingFragment(); - if (InsertionPoint) - PaddingFragment->setAsInsertionPoint(); - PaddingFragment->setPaddingPoliciesMask( - PaddingFragment->getPaddingPoliciesMask() | PoliciesMask); - } -} - -void MCCodePadder::handleBasicBlockEnd(const MCCodePaddingContext &Context) { - assert(this->OS != nullptr && "Not handling a basic block"); - OS = nullptr; -} - -void MCCodePadder::handleInstructionBegin(const MCInst &Inst) { - if (!OS) - return; // instruction was emitted outside a function - - assert(CurrHandledInstFragment == nullptr && "Can't start handling an " - "instruction while still " - "handling another instruction"); - - bool InsertionPoint = instructionRequiresInsertionPoint(Inst); - assert((!InsertionPoint || - OS->getCurrentFragment()->getKind() != MCFragment::FT_Align) && - "Cannot insert padding nops right after an alignment fragment as it " - "will ruin the alignment"); - - uint64_t PoliciesMask = MCPaddingFragment::PFK_None; - if (ArePoliciesActive) { - PoliciesMask = std::accumulate( - CodePaddingPolicies.begin(), CodePaddingPolicies.end(), - MCPaddingFragment::PFK_None, - [&Inst](uint64_t Mask, const MCCodePaddingPolicy *Policy) -> uint64_t { - return Policy->instructionRequiresPaddingFragment(Inst) - ? (Mask | Policy->getKindMask()) - : Mask; - }); - } - MCFragment *CurrFragment = OS->getCurrentFragment(); - // CurrFragment can be a previously created MCPaddingFragment. If so, let's - // update it with the information we have, such as the instruction that it - // should point to. - bool needToUpdateCurrFragment = - CurrFragment != nullptr && - CurrFragment->getKind() == MCFragment::FT_Padding; - if (InsertionPoint || PoliciesMask != MCPaddingFragment::PFK_None || - needToUpdateCurrFragment) { - // temporarily holding the fragment as CurrHandledInstFragment, to be - // updated after the instruction will be written - CurrHandledInstFragment = OS->getOrCreatePaddingFragment(); - if (InsertionPoint) - CurrHandledInstFragment->setAsInsertionPoint(); - CurrHandledInstFragment->setPaddingPoliciesMask( - CurrHandledInstFragment->getPaddingPoliciesMask() | PoliciesMask); - } -} - -void MCCodePadder::handleInstructionEnd(const MCInst &Inst) { - if (!OS) - return; // instruction was emitted outside a function - if (CurrHandledInstFragment == nullptr) - return; - - MCFragment *InstFragment = OS->getCurrentFragment(); - if (MCDataFragment *InstDataFragment = - dyn_cast_or_null<MCDataFragment>(InstFragment)) - // Inst is a fixed size instruction and was encoded into a MCDataFragment. - // Let the fragment hold it and its size. Its size is the current size of - // the data fragment, as the padding fragment was inserted right before it - // and nothing was written yet except Inst - CurrHandledInstFragment->setInstAndInstSize( - Inst, InstDataFragment->getContents().size()); - else if (MCRelaxableFragment *InstRelaxableFragment = - dyn_cast_or_null<MCRelaxableFragment>(InstFragment)) - // Inst may be relaxed and its size may vary. - // Let the fragment hold the instruction and the MCRelaxableFragment - // that's holding it. - CurrHandledInstFragment->setInstAndInstFragment(Inst, - InstRelaxableFragment); - else - llvm_unreachable("After encoding an instruction current fragment must be " - "either a MCDataFragment or a MCRelaxableFragment"); - - CurrHandledInstFragment = nullptr; -} - -MCPFRange &MCCodePadder::getJurisdiction(MCPaddingFragment *Fragment, - MCAsmLayout &Layout) { - auto JurisdictionLocation = FragmentToJurisdiction.find(Fragment); - if (JurisdictionLocation != FragmentToJurisdiction.end()) - return JurisdictionLocation->second; - - MCPFRange Jurisdiction; - - // Forward scanning the fragments in this section, starting from the given - // fragments, and adding relevant MCPaddingFragments to the Jurisdiction - for (MCFragment *CurrFragment = Fragment; CurrFragment != nullptr; - CurrFragment = CurrFragment->getNextNode()) { - - MCPaddingFragment *CurrPaddingFragment = - dyn_cast<MCPaddingFragment>(CurrFragment); - if (CurrPaddingFragment == nullptr) - continue; - - if (CurrPaddingFragment != Fragment && - CurrPaddingFragment->isInsertionPoint()) - // Found next insertion point Fragment. From now on it's its jurisdiction. - break; - for (const auto *Policy : CodePaddingPolicies) { - if (CurrPaddingFragment->hasPaddingPolicy(Policy->getKindMask())) { - Jurisdiction.push_back(CurrPaddingFragment); - break; - } - } - } - - auto InsertionResult = - FragmentToJurisdiction.insert(std::make_pair(Fragment, Jurisdiction)); - assert(InsertionResult.second && - "Insertion to FragmentToJurisdiction failed"); - return InsertionResult.first->second; -} - -uint64_t MCCodePadder::getMaxWindowSize(MCPaddingFragment *Fragment, - MCAsmLayout &Layout) { - auto MaxFragmentSizeLocation = FragmentToMaxWindowSize.find(Fragment); - if (MaxFragmentSizeLocation != FragmentToMaxWindowSize.end()) - return MaxFragmentSizeLocation->second; - - MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout); - uint64_t JurisdictionMask = MCPaddingFragment::PFK_None; - for (const auto *Protege : Jurisdiction) - JurisdictionMask |= Protege->getPaddingPoliciesMask(); - - uint64_t MaxFragmentSize = UINT64_C(0); - for (const auto *Policy : CodePaddingPolicies) - if ((JurisdictionMask & Policy->getKindMask()) != - MCPaddingFragment::PFK_None) - MaxFragmentSize = std::max(MaxFragmentSize, Policy->getWindowSize()); - - auto InsertionResult = - FragmentToMaxWindowSize.insert(std::make_pair(Fragment, MaxFragmentSize)); - assert(InsertionResult.second && - "Insertion to FragmentToMaxWindowSize failed"); - return InsertionResult.first->second; -} - -bool MCCodePadder::relaxFragment(MCPaddingFragment *Fragment, - MCAsmLayout &Layout) { - if (!Fragment->isInsertionPoint()) - return false; - uint64_t OldSize = Fragment->getSize(); - - uint64_t MaxWindowSize = getMaxWindowSize(Fragment, Layout); - if (MaxWindowSize == UINT64_C(0)) - return false; - assert(isPowerOf2_64(MaxWindowSize) && - "MaxWindowSize must be an integer power of 2"); - uint64_t SectionAlignment = Fragment->getParent()->getAlignment(); - assert(isPowerOf2_64(SectionAlignment) && - "SectionAlignment must be an integer power of 2"); - - MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout); - uint64_t OptimalSize = UINT64_C(0); - double OptimalWeight = std::numeric_limits<double>::max(); - uint64_t MaxFragmentSize = MaxWindowSize - UINT16_C(1); - for (uint64_t Size = UINT64_C(0); Size <= MaxFragmentSize; ++Size) { - Fragment->setSize(Size); - Layout.invalidateFragmentsFrom(Fragment); - double SizeWeight = 0.0; - // The section is guaranteed to be aligned to SectionAlignment, but that - // doesn't guarantee the exact section offset w.r.t. the policies window - // size. - // As a concrete example, the section could be aligned to 16B, but a - // policy's window size can be 32B. That means that the section actual start - // address can either be 0mod32 or 16mod32. The said policy will act - // differently for each case, so we need to take both into consideration. - for (uint64_t Offset = UINT64_C(0); Offset < MaxWindowSize; - Offset += SectionAlignment) { - double OffsetWeight = std::accumulate( - CodePaddingPolicies.begin(), CodePaddingPolicies.end(), 0.0, - [&Jurisdiction, &Offset, &Layout]( - double Weight, const MCCodePaddingPolicy *Policy) -> double { - double PolicyWeight = - Policy->computeRangePenaltyWeight(Jurisdiction, Offset, Layout); - assert(PolicyWeight >= 0.0 && "A penalty weight must be positive"); - return Weight + PolicyWeight; - }); - SizeWeight = std::max(SizeWeight, OffsetWeight); - } - if (SizeWeight < OptimalWeight) { - OptimalWeight = SizeWeight; - OptimalSize = Size; - } - if (OptimalWeight == 0.0) - break; - } - - Fragment->setSize(OptimalSize); - Layout.invalidateFragmentsFrom(Fragment); - return OldSize != OptimalSize; -} - -//--------------------------------------------------------------------------- -// MCCodePaddingPolicy -// - -uint64_t MCCodePaddingPolicy::getNextFragmentOffset(const MCFragment *Fragment, - const MCAsmLayout &Layout) { - assert(Fragment != nullptr && "Fragment cannot be null"); - MCFragment const *NextFragment = Fragment->getNextNode(); - return NextFragment == nullptr - ? Layout.getSectionAddressSize(Fragment->getParent()) - : Layout.getFragmentOffset(NextFragment); -} - -uint64_t -MCCodePaddingPolicy::getFragmentInstByte(const MCPaddingFragment *Fragment, - MCAsmLayout &Layout) const { - uint64_t InstByte = getNextFragmentOffset(Fragment, Layout); - if (InstByteIsLastByte) - InstByte += Fragment->getInstSize() - UINT64_C(1); - return InstByte; -} - -uint64_t -MCCodePaddingPolicy::computeWindowEndAddress(const MCPaddingFragment *Fragment, - uint64_t Offset, - MCAsmLayout &Layout) const { - uint64_t InstByte = getFragmentInstByte(Fragment, Layout); - return alignTo(InstByte + UINT64_C(1) + Offset, WindowSize) - Offset; -} - -double MCCodePaddingPolicy::computeRangePenaltyWeight( - const MCPFRange &Range, uint64_t Offset, MCAsmLayout &Layout) const { - - SmallVector<MCPFRange, 8> Windows; - SmallVector<MCPFRange, 8>::iterator CurrWindowLocation = Windows.end(); - for (const MCPaddingFragment *Fragment : Range) { - if (!Fragment->hasPaddingPolicy(getKindMask())) - continue; - uint64_t FragmentWindowEndAddress = - computeWindowEndAddress(Fragment, Offset, Layout); - if (CurrWindowLocation == Windows.end() || - FragmentWindowEndAddress != - computeWindowEndAddress(*CurrWindowLocation->begin(), Offset, - Layout)) { - // next window is starting - Windows.push_back(MCPFRange()); - CurrWindowLocation = Windows.end() - 1; - } - CurrWindowLocation->push_back(Fragment); - } - - if (Windows.empty()) - return 0.0; - - double RangeWeight = 0.0; - SmallVector<MCPFRange, 8>::iterator I = Windows.begin(); - RangeWeight += computeFirstWindowPenaltyWeight(*I, Offset, Layout); - ++I; - RangeWeight += std::accumulate( - I, Windows.end(), 0.0, - [this, &Layout, &Offset](double Weight, MCPFRange &Window) -> double { - return Weight += computeWindowPenaltyWeight(Window, Offset, Layout); - }); - return RangeWeight; -} - -double MCCodePaddingPolicy::computeFirstWindowPenaltyWeight( - const MCPFRange &Window, uint64_t Offset, MCAsmLayout &Layout) const { - if (Window.empty()) - return 0.0; - uint64_t WindowEndAddress = - computeWindowEndAddress(*Window.begin(), Offset, Layout); - - MCPFRange FullWindowFirstPart; // will hold all the fragments that are in the - // same window as the fragments in the given - // window but their penalty weight should not - // be added - for (const MCFragment *Fragment = (*Window.begin())->getPrevNode(); - Fragment != nullptr; Fragment = Fragment->getPrevNode()) { - const MCPaddingFragment *PaddingNopFragment = - dyn_cast<MCPaddingFragment>(Fragment); - if (PaddingNopFragment == nullptr || - !PaddingNopFragment->hasPaddingPolicy(getKindMask())) - continue; - if (WindowEndAddress != - computeWindowEndAddress(PaddingNopFragment, Offset, Layout)) - break; - - FullWindowFirstPart.push_back(PaddingNopFragment); - } - - std::reverse(FullWindowFirstPart.begin(), FullWindowFirstPart.end()); - double FullWindowFirstPartWeight = - computeWindowPenaltyWeight(FullWindowFirstPart, Offset, Layout); - - MCPFRange FullWindow( - FullWindowFirstPart); // will hold all the fragments that are in the - // same window as the fragments in the given - // window, whether their weight should be added - // or not - FullWindow.append(Window.begin(), Window.end()); - double FullWindowWeight = - computeWindowPenaltyWeight(FullWindow, Offset, Layout); - - assert(FullWindowWeight >= FullWindowFirstPartWeight && - "More fragments necessarily means bigger weight"); - return FullWindowWeight - FullWindowFirstPartWeight; -} diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp index a69ee19e1a1ae..a6417113fd384 100644 --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCDwarf.h" @@ -550,13 +551,15 @@ MCSectionXCOFF *MCContext::getXCOFFSection(StringRef Section, // Otherwise, return a new section. StringRef CachedName = Entry.first.SectionName; + MCSymbol *QualName = getOrCreateSymbol( + CachedName + "[" + XCOFF::getMappingClassString(SMC) + "]"); MCSymbol *Begin = nullptr; if (BeginSymName) Begin = createTempSymbol(BeginSymName, false); - MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate()) - MCSectionXCOFF(CachedName, SMC, Type, SC, Kind, Begin); + MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate()) MCSectionXCOFF( + CachedName, SMC, Type, SC, Kind, cast<MCSymbolXCOFF>(QualName), Begin); Entry.second = Result; auto *F = new MCDataFragment(); diff --git a/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/llvm/lib/MC/MCDisassembler/Disassembler.cpp index 21bdc2eaea3e4..ff56695e8cc46 100644 --- a/llvm/lib/MC/MCDisassembler/Disassembler.cpp +++ b/llvm/lib/MC/MCDisassembler/Disassembler.cpp @@ -24,6 +24,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSchedule.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" @@ -56,8 +57,10 @@ LLVMCreateDisasmCPUFeatures(const char *TT, const char *CPU, if (!MRI) return nullptr; + MCTargetOptions MCOptions; // Get the assembler info needed to setup the MCContext. - std::unique_ptr<const MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); + std::unique_ptr<const MCAsmInfo> MAI( + TheTarget->createMCAsmInfo(*MRI, TT, MCOptions)); if (!MAI) return nullptr; @@ -260,8 +263,7 @@ size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes, MCDisassembler::DecodeStatus S; SmallVector<char, 64> InsnStr; raw_svector_ostream Annotations(InsnStr); - S = DisAsm->getInstruction(Inst, Size, Data, PC, - /*REMOVE*/ nulls(), Annotations); + S = DisAsm->getInstruction(Inst, Size, Data, PC, Annotations); switch (S) { case MCDisassembler::Fail: case MCDisassembler::SoftFail: @@ -274,7 +276,8 @@ size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes, SmallVector<char, 64> InsnStr; raw_svector_ostream OS(InsnStr); formatted_raw_ostream FormattedOS(OS); - IP->printInst(&Inst, FormattedOS, AnnotationsStr, *DC->getSubtargetInfo()); + IP->printInst(&Inst, PC, AnnotationsStr, *DC->getSubtargetInfo(), + FormattedOS); if (DC->getOptions() & LLVMDisassembler_Option_PrintLatency) emitLatency(DC, Inst); diff --git a/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp b/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp index 063f7e706024b..373916fbed785 100644 --- a/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp +++ b/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp @@ -16,9 +16,10 @@ using namespace llvm; MCDisassembler::~MCDisassembler() = default; -MCDisassembler::DecodeStatus MCDisassembler::onSymbolStart( - StringRef Name, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address, - raw_ostream &VStream, raw_ostream &CStream) const { +MCDisassembler::DecodeStatus +MCDisassembler::onSymbolStart(StringRef Name, uint64_t &Size, + ArrayRef<uint8_t> Bytes, uint64_t Address, + raw_ostream &CStream) const { Size = 0; return MCDisassembler::Success; } @@ -27,18 +28,16 @@ bool MCDisassembler::tryAddingSymbolicOperand(MCInst &Inst, int64_t Value, uint64_t Address, bool IsBranch, uint64_t Offset, uint64_t InstSize) const { - raw_ostream &cStream = CommentStream ? *CommentStream : nulls(); if (Symbolizer) - return Symbolizer->tryAddingSymbolicOperand(Inst, cStream, Value, Address, - IsBranch, Offset, InstSize); + return Symbolizer->tryAddingSymbolicOperand( + Inst, *CommentStream, Value, Address, IsBranch, Offset, InstSize); return false; } void MCDisassembler::tryAddingPcLoadReferenceComment(int64_t Value, uint64_t Address) const { - raw_ostream &cStream = CommentStream ? *CommentStream : nulls(); if (Symbolizer) - Symbolizer->tryAddingPcLoadReferenceComment(cStream, Value, Address); + Symbolizer->tryAddingPcLoadReferenceComment(*CommentStream, Value, Address); } void MCDisassembler::setSymbolizer(std::unique_ptr<MCSymbolizer> Symzer) { diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp index bcc7c45afc01b..b4b3c9956cc2d 100644 --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -1701,7 +1701,8 @@ void FrameEmitterImpl::EmitFDE(const MCSymbol &cieStart, MakeStartMinusEndExpr(Streamer, SectionStart, cieStart, 0); emitAbsValue(Streamer, offset, 4); } else { - Streamer.EmitSymbolValue(&cieStart, 4); + Streamer.EmitSymbolValue(&cieStart, 4, + asmInfo->needsDwarfSectionOffsetDirective()); } // PC Begin diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp index fa2133078bfea..0a0c30df9c07f 100644 --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -106,9 +106,10 @@ void MCELFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc) { Symbol->setType(ELF::STT_TLS); } -void MCELFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc, MCFragment *F) { +void MCELFStreamer::EmitLabelAtPos(MCSymbol *S, SMLoc Loc, MCFragment *F, + uint64_t Offset) { auto *Symbol = cast<MCSymbolELF>(S); - MCObjectStreamer::EmitLabel(Symbol, Loc, F); + MCObjectStreamer::EmitLabelAtPos(Symbol, Loc, F, Offset); const MCSectionELF &Section = static_cast<const MCSectionELF &>(*getCurrentSectionOnly()); @@ -307,10 +308,6 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, EmitLabel(Symbol); EmitZeros(Size); - // Update the maximum alignment of the section if necessary. - if (ByteAlignment > Section.getAlignment()) - Section.setAlignment(Align(ByteAlignment)); - SwitchSection(P.first, P.second); } else { if(Symbol->declareCommon(Size, ByteAlignment)) diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp index 813c00f6f3bb3..7f25fd4e90a78 100644 --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -601,7 +601,7 @@ static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A, /// and /// Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). /// -/// This routine attempts to aggresively fold the operands such that the result +/// This routine attempts to aggressively fold the operands such that the result /// is representable in an MCValue, but may not always succeed. /// /// \returns True on success, false if the result is not representable in an diff --git a/llvm/lib/MC/MCFragment.cpp b/llvm/lib/MC/MCFragment.cpp index ae5bd65507bc9..a96b8e86aed3c 100644 --- a/llvm/lib/MC/MCFragment.cpp +++ b/llvm/lib/MC/MCFragment.cpp @@ -232,13 +232,11 @@ uint64_t llvm::computeBundlePadding(const MCAssembler &Assembler, void ilist_alloc_traits<MCFragment>::deleteNode(MCFragment *V) { V->destroy(); } -MCFragment::~MCFragment() = default; - MCFragment::MCFragment(FragmentType Kind, bool HasInstructions, MCSection *Parent) - : Kind(Kind), HasInstructions(HasInstructions), LayoutOrder(0), - Parent(Parent), Atom(nullptr), Offset(~UINT64_C(0)) { - if (Parent && !isDummy()) + : Parent(Parent), Atom(nullptr), Offset(~UINT64_C(0)), LayoutOrder(0), + Kind(Kind), HasInstructions(HasInstructions) { + if (Parent && !isa<MCDummyFragment>(*this)) Parent->getFragmentList().push_back(this); } @@ -277,8 +275,8 @@ void MCFragment::destroy() { case FT_LEB: delete cast<MCLEBFragment>(this); return; - case FT_Padding: - delete cast<MCPaddingFragment>(this); + case FT_BoundaryAlign: + delete cast<MCBoundaryAlignFragment>(this); return; case FT_SymbolId: delete cast<MCSymbolIdFragment>(this); @@ -324,7 +322,7 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break; case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break; case MCFragment::FT_LEB: OS << "MCLEBFragment"; break; - case MCFragment::FT_Padding: OS << "MCPaddingFragment"; break; + case MCFragment::FT_BoundaryAlign: OS<<"MCBoundaryAlignFragment"; break; case MCFragment::FT_SymbolId: OS << "MCSymbolIdFragment"; break; case MCFragment::FT_CVInlineLines: OS << "MCCVInlineLineTableFragment"; break; case MCFragment::FT_CVDefRange: OS << "MCCVDefRangeTableFragment"; break; @@ -333,13 +331,13 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { OS << "<MCFragment " << (const void *)this << " LayoutOrder:" << LayoutOrder << " Offset:" << Offset << " HasInstructions:" << hasInstructions(); - if (const MCEncodedFragment *EF = dyn_cast<MCEncodedFragment>(this)) + if (const auto *EF = dyn_cast<MCEncodedFragment>(this)) OS << " BundlePadding:" << static_cast<unsigned>(EF->getBundlePadding()); OS << ">"; switch (getKind()) { case MCFragment::FT_Align: { - const MCAlignFragment *AF = cast<MCAlignFragment>(this); + const auto *AF = cast<MCAlignFragment>(this); if (AF->hasEmitNops()) OS << " (emit nops)"; OS << "\n "; @@ -349,7 +347,7 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { break; } case MCFragment::FT_Data: { - const MCDataFragment *DF = cast<MCDataFragment>(this); + const auto *DF = cast<MCDataFragment>(this); OS << "\n "; OS << " Contents:["; const SmallVectorImpl<char> &Contents = DF->getContents(); @@ -372,7 +370,7 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { break; } case MCFragment::FT_CompactEncodedInst: { - const MCCompactEncodedInstFragment *CEIF = + const auto *CEIF = cast<MCCompactEncodedInstFragment>(this); OS << "\n "; OS << " Contents:["; @@ -385,60 +383,60 @@ LLVM_DUMP_METHOD void MCFragment::dump() const { break; } case MCFragment::FT_Fill: { - const MCFillFragment *FF = cast<MCFillFragment>(this); + const auto *FF = cast<MCFillFragment>(this); OS << " Value:" << static_cast<unsigned>(FF->getValue()) << " ValueSize:" << static_cast<unsigned>(FF->getValueSize()) << " NumValues:" << FF->getNumValues(); break; } case MCFragment::FT_Relaxable: { - const MCRelaxableFragment *F = cast<MCRelaxableFragment>(this); + const auto *F = cast<MCRelaxableFragment>(this); OS << "\n "; OS << " Inst:"; F->getInst().dump_pretty(OS); break; } case MCFragment::FT_Org: { - const MCOrgFragment *OF = cast<MCOrgFragment>(this); + const auto *OF = cast<MCOrgFragment>(this); OS << "\n "; OS << " Offset:" << OF->getOffset() << " Value:" << static_cast<unsigned>(OF->getValue()); break; } case MCFragment::FT_Dwarf: { - const MCDwarfLineAddrFragment *OF = cast<MCDwarfLineAddrFragment>(this); + const auto *OF = cast<MCDwarfLineAddrFragment>(this); OS << "\n "; OS << " AddrDelta:" << OF->getAddrDelta() << " LineDelta:" << OF->getLineDelta(); break; } case MCFragment::FT_DwarfFrame: { - const MCDwarfCallFrameFragment *CF = cast<MCDwarfCallFrameFragment>(this); + const auto *CF = cast<MCDwarfCallFrameFragment>(this); OS << "\n "; OS << " AddrDelta:" << CF->getAddrDelta(); break; } case MCFragment::FT_LEB: { - const MCLEBFragment *LF = cast<MCLEBFragment>(this); + const auto *LF = cast<MCLEBFragment>(this); OS << "\n "; OS << " Value:" << LF->getValue() << " Signed:" << LF->isSigned(); break; } - case MCFragment::FT_Padding: { - const MCPaddingFragment *F = cast<MCPaddingFragment>(this); - OS << "\n "; - OS << " PaddingPoliciesMask:" << F->getPaddingPoliciesMask() - << " IsInsertionPoint:" << F->isInsertionPoint() - << " Size:" << F->getSize(); - OS << "\n "; - OS << " Inst:"; - F->getInst().dump_pretty(OS); - OS << " InstSize:" << F->getInstSize(); + case MCFragment::FT_BoundaryAlign: { + const auto *BF = cast<MCBoundaryAlignFragment>(this); + if (BF->canEmitNops()) + OS << " (can emit nops to align"; + if (BF->isFused()) + OS << " fused branch)"; + else + OS << " unfused branch)"; OS << "\n "; + OS << " BoundarySize:" << BF->getAlignment().value() + << " Size:" << BF->getSize(); break; } case MCFragment::FT_SymbolId: { - const MCSymbolIdFragment *F = cast<MCSymbolIdFragment>(this); + const auto *F = cast<MCSymbolIdFragment>(this); OS << "\n "; OS << " Sym:" << F->getSymbol(); break; diff --git a/llvm/lib/MC/MCInstPrinter.cpp b/llvm/lib/MC/MCInstPrinter.cpp index c5c06f323e680..8bf699279ada4 100644 --- a/llvm/lib/MC/MCInstPrinter.cpp +++ b/llvm/lib/MC/MCInstPrinter.cpp @@ -10,7 +10,9 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -57,6 +59,94 @@ void MCInstPrinter::printAnnotation(raw_ostream &OS, StringRef Annot) { } } +static bool matchAliasCondition(const MCInst &MI, const MCSubtargetInfo *STI, + const MCRegisterInfo &MRI, unsigned &OpIdx, + const AliasMatchingData &M, + const AliasPatternCond &C) { + // Feature tests are special, they don't consume operands. + if (C.Kind == AliasPatternCond::K_Feature) + return STI->getFeatureBits().test(C.Value); + if (C.Kind == AliasPatternCond::K_NegFeature) + return !STI->getFeatureBits().test(C.Value); + + // Get and consume an operand. + const MCOperand &Opnd = MI.getOperand(OpIdx); + ++OpIdx; + + // Check the specific condition for the operand. + switch (C.Kind) { + case AliasPatternCond::K_Imm: + // Operand must be a specific immediate. + return Opnd.isImm() && Opnd.getImm() == int32_t(C.Value); + case AliasPatternCond::K_Reg: + // Operand must be a specific register. + return Opnd.isReg() && Opnd.getReg() == C.Value; + case AliasPatternCond::K_TiedReg: + // Operand must match the register of another operand. + return Opnd.isReg() && Opnd.getReg() == MI.getOperand(C.Value).getReg(); + case AliasPatternCond::K_RegClass: + // Operand must be a register in this class. Value is a register class id. + return Opnd.isReg() && MRI.getRegClass(C.Value).contains(Opnd.getReg()); + case AliasPatternCond::K_Custom: + // Operand must match some custom criteria. + return M.ValidateMCOperand(Opnd, *STI, C.Value); + case AliasPatternCond::K_Ignore: + // Operand can be anything. + return true; + case AliasPatternCond::K_Feature: + case AliasPatternCond::K_NegFeature: + llvm_unreachable("handled earlier"); + } + llvm_unreachable("invalid kind"); +} + +const char *MCInstPrinter::matchAliasPatterns(const MCInst *MI, + const MCSubtargetInfo *STI, + const AliasMatchingData &M) { + // Binary search by opcode. Return false if there are no aliases for this + // opcode. + auto It = lower_bound(M.OpToPatterns, MI->getOpcode(), + [](const PatternsForOpcode &L, unsigned Opcode) { + return L.Opcode < Opcode; + }); + if (It == M.OpToPatterns.end() || It->Opcode != MI->getOpcode()) + return nullptr; + + // Try all patterns for this opcode. + uint32_t AsmStrOffset = ~0U; + ArrayRef<AliasPattern> Patterns = + M.Patterns.slice(It->PatternStart, It->NumPatterns); + for (const AliasPattern &P : Patterns) { + // Check operand count first. + if (MI->getNumOperands() != P.NumOperands) + return nullptr; + + // Test all conditions for this pattern. + ArrayRef<AliasPatternCond> Conds = + M.PatternConds.slice(P.AliasCondStart, P.NumConds); + unsigned OpIdx = 0; + if (llvm::all_of(Conds, [&](const AliasPatternCond &C) { + return matchAliasCondition(*MI, STI, MRI, OpIdx, M, C); + })) { + // If all conditions matched, use this asm string. + AsmStrOffset = P.AsmStrOffset; + break; + } + } + + // If no alias matched, don't print an alias. + if (AsmStrOffset == ~0U) + return nullptr; + + // Go to offset AsmStrOffset and use the null terminated string there. The + // offset should point to the beginning of an alias string, so it should + // either be zero or be preceded by a null byte. + assert(AsmStrOffset < M.AsmStrings.size() && + (AsmStrOffset == 0 || M.AsmStrings[AsmStrOffset - 1] == '\0') && + "bad asm string offset"); + return M.AsmStrings.data() + AsmStrOffset; +} + /// Utility functions to make adding mark ups simpler. StringRef MCInstPrinter::markup(StringRef s) const { if (getUseMarkup()) diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp index 70c0409ece7a9..d567cc14a8306 100644 --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -40,8 +40,7 @@ static bool useCompactUnwind(const Triple &T) { return true; // And the iOS simulator. - if (T.isiOS() && - (T.getArch() == Triple::x86_64 || T.getArch() == Triple::x86)) + if (T.isiOS() && T.isX86()) return true; return false; @@ -192,7 +191,7 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { Ctx->getMachOSection("__LD", "__compact_unwind", MachO::S_ATTR_DEBUG, SectionKind::getReadOnly()); - if (T.getArch() == Triple::x86_64 || T.getArch() == Triple::x86) + if (T.isX86()) CompactUnwindDwarfEHFrameOnly = 0x04000000; // UNWIND_X86_64_MODE_DWARF else if (T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32) CompactUnwindDwarfEHFrameOnly = 0x03000000; // UNWIND_ARM64_MODE_DWARF @@ -304,9 +303,14 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { case Triple::mipsel: case Triple::mips64: case Triple::mips64el: - FDECFIEncoding = Ctx->getAsmInfo()->getCodePointerSize() == 4 - ? dwarf::DW_EH_PE_sdata4 - : dwarf::DW_EH_PE_sdata8; + // We cannot use DW_EH_PE_sdata8 for the large PositionIndependent case + // since there is no R_MIPS_PC64 relocation (only a 32-bit version). + if (PositionIndependent && !Large) + FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + else + FDECFIEncoding = Ctx->getAsmInfo()->getCodePointerSize() == 4 + ? dwarf::DW_EH_PE_sdata4 + : dwarf::DW_EH_PE_sdata8; break; case Triple::ppc64: case Triple::ppc64le: @@ -463,6 +467,11 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { DebugSecType, ELF::SHF_EXCLUDE); DwarfRnglistsDWOSection = Ctx->getELFSection(".debug_rnglists.dwo", DebugSecType, ELF::SHF_EXCLUDE); + DwarfMacinfoDWOSection = + Ctx->getELFSection(".debug_macinfo.dwo", DebugSecType, ELF::SHF_EXCLUDE); + + DwarfLoclistsDWOSection = + Ctx->getELFSection(".debug_loclists.dwo", DebugSecType, ELF::SHF_EXCLUDE); // DWP Sections DwarfCUIndexSection = @@ -480,9 +489,6 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { Ctx->getELFSection(".eh_frame", EHSectionType, EHSectionFlags); StackSizesSection = Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, 0); - - RemarksSection = - Ctx->getELFSection(".remarks", ELF::SHT_PROGBITS, ELF::SHF_EXCLUDE); } void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { @@ -619,6 +625,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getMetadata(), "debug_macinfo"); + DwarfMacinfoDWOSection = Ctx->getCOFFSection( + ".debug_macinfo.dwo", + COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata(), "debug_macinfo.dwo"); DwarfInfoDWOSection = Ctx->getCOFFSection( ".debug_info.dwo", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | @@ -715,6 +726,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { COFF::IMAGE_SCN_MEM_READ, SectionKind::getMetadata()); + GLJMPSection = Ctx->getCOFFSection(".gljmp$y", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + TLSDataSection = Ctx->getCOFFSection( ".tls$", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, @@ -775,6 +791,10 @@ void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) { DataSection = Ctx->getXCOFFSection( ".data", XCOFF::StorageMappingClass::XMC_RW, XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData()); + + ReadOnlySection = Ctx->getXCOFFSection( + ".rodata", XCOFF::StorageMappingClass::XMC_RO, XCOFF::XTY_SD, + XCOFF::C_HIDEXT, SectionKind::getReadOnly()); } void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC, diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 83f6ab8fe332e..3d1358df475f1 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -29,7 +29,10 @@ MCObjectStreamer::MCObjectStreamer(MCContext &Context, : MCStreamer(Context), Assembler(std::make_unique<MCAssembler>( Context, std::move(TAB), std::move(Emitter), std::move(OW))), - EmitEHFrame(true), EmitDebugFrame(false) {} + EmitEHFrame(true), EmitDebugFrame(false) { + if (Assembler->getBackendPtr()) + setAllowAutoPadding(Assembler->getBackend().allowAutoPadding()); +} MCObjectStreamer::~MCObjectStreamer() {} @@ -42,20 +45,64 @@ MCAssembler *MCObjectStreamer::getAssemblerPtr() { return nullptr; } +void MCObjectStreamer::addPendingLabel(MCSymbol* S) { + MCSection *CurSection = getCurrentSectionOnly(); + if (CurSection) { + // Register labels that have not yet been assigned to a Section. + if (!PendingLabels.empty()) { + for (MCSymbol* Sym : PendingLabels) + CurSection->addPendingLabel(Sym); + PendingLabels.clear(); + } + + // Add this label to the current Section / Subsection. + CurSection->addPendingLabel(S, CurSubsectionIdx); + + // Add this Section to the list of PendingLabelSections. + auto SecIt = std::find(PendingLabelSections.begin(), + PendingLabelSections.end(), CurSection); + if (SecIt == PendingLabelSections.end()) + PendingLabelSections.push_back(CurSection); + } + else + // There is no Section / Subsection for this label yet. + PendingLabels.push_back(S); +} + void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) { - if (PendingLabels.empty()) + MCSection *CurSection = getCurrentSectionOnly(); + if (!CurSection) { + assert(PendingLabels.empty()); return; - if (!F) { - F = new MCDataFragment(); - MCSection *CurSection = getCurrentSectionOnly(); - CurSection->getFragmentList().insert(CurInsertionPoint, F); - F->setParent(CurSection); } - for (MCSymbol *Sym : PendingLabels) { - Sym->setFragment(F); - Sym->setOffset(FOffset); + // Register labels that have not yet been assigned to a Section. + if (!PendingLabels.empty()) { + for (MCSymbol* Sym : PendingLabels) + CurSection->addPendingLabel(Sym, CurSubsectionIdx); + PendingLabels.clear(); } - PendingLabels.clear(); + + // Associate a fragment with this label, either the supplied fragment + // or an empty data fragment. + if (F) + CurSection->flushPendingLabels(F, FOffset, CurSubsectionIdx); + else + CurSection->flushPendingLabels(nullptr, 0, CurSubsectionIdx); +} + +void MCObjectStreamer::flushPendingLabels() { + // Register labels that have not yet been assigned to a Section. + if (!PendingLabels.empty()) { + MCSection *CurSection = getCurrentSectionOnly(); + assert(CurSection); + for (MCSymbol* Sym : PendingLabels) + CurSection->addPendingLabel(Sym, CurSubsectionIdx); + PendingLabels.clear(); + } + + // Assign an empty data fragment to all remaining pending labels. + for (MCSection* Section : PendingLabelSections) + Section->flushPendingLabels(); } // When fixup's offset is a forward declared label, e.g.: @@ -120,6 +167,7 @@ void MCObjectStreamer::reset() { EmitEHFrame = true; EmitDebugFrame = false; PendingLabels.clear(); + PendingLabelSections.clear(); MCStreamer::reset(); } @@ -167,16 +215,6 @@ MCObjectStreamer::getOrCreateDataFragment(const MCSubtargetInfo *STI) { return F; } -MCPaddingFragment *MCObjectStreamer::getOrCreatePaddingFragment() { - MCPaddingFragment *F = - dyn_cast_or_null<MCPaddingFragment>(getCurrentFragment()); - if (!F) { - F = new MCPaddingFragment(); - insert(F); - } - return F; -} - void MCObjectStreamer::visitUsedSymbol(const MCSymbol &Sym) { Assembler->registerSymbol(Sym); } @@ -243,18 +281,32 @@ void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) { Symbol->setFragment(F); Symbol->setOffset(F->getContents().size()); } else { - PendingLabels.push_back(Symbol); + // Assign all pending labels to offset 0 within the dummy "pending" + // fragment. (They will all be reassigned to a real fragment in + // flushPendingLabels()) + Symbol->setOffset(0); + addPendingLabel(Symbol); } } -void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) { +// Emit a label at a previously emitted fragment/offset position. This must be +// within the currently-active section. +void MCObjectStreamer::EmitLabelAtPos(MCSymbol *Symbol, SMLoc Loc, + MCFragment *F, uint64_t Offset) { + assert(F->getParent() == getCurrentSectionOnly()); + MCStreamer::EmitLabel(Symbol, Loc); getAssembler().registerSymbol(*Symbol); auto *DF = dyn_cast_or_null<MCDataFragment>(F); - if (DF) + Symbol->setOffset(Offset); + if (DF) { Symbol->setFragment(F); - else - PendingLabels.push_back(Symbol); + } else { + assert(isa<MCDummyFragment>(F) && + "F must either be an MCDataFragment or the pending MCDummyFragment"); + assert(Offset == 0); + addPendingLabel(Symbol); + } } void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) { @@ -288,7 +340,6 @@ void MCObjectStreamer::ChangeSection(MCSection *Section, bool MCObjectStreamer::changeSectionImpl(MCSection *Section, const MCExpr *Subsection) { assert(Section && "Cannot switch to a null section!"); - flushPendingLabels(nullptr); getContext().clearDwarfLocSeen(); bool Created = getAssembler().registerSection(*Section); @@ -299,8 +350,9 @@ bool MCObjectStreamer::changeSectionImpl(MCSection *Section, report_fatal_error("Cannot evaluate subsection number"); if (IntSubsection < 0 || IntSubsection > 8192) report_fatal_error("Subsection number out of range"); + CurSubsectionIdx = unsigned(IntSubsection); CurInsertionPoint = - Section->getSubsectionInsertionPoint(unsigned(IntSubsection)); + Section->getSubsectionInsertionPoint(CurSubsectionIdx); return Created; } @@ -315,9 +367,9 @@ bool MCObjectStreamer::mayHaveInstructions(MCSection &Sec) const { void MCObjectStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) { - getAssembler().getBackend().handleCodePaddingInstructionBegin(Inst); + getAssembler().getBackend().alignBranchesBegin(*this, Inst); EmitInstructionImpl(Inst, STI); - getAssembler().getBackend().handleCodePaddingInstructionEnd(Inst); + getAssembler().getBackend().alignBranchesEnd(*this, Inst); } void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst, @@ -520,12 +572,6 @@ void MCObjectStreamer::EmitBytes(StringRef Data) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getContents().append(Data.begin(), Data.end()); - - // EmitBytes might not cover all possible ways we emit data (or could be used - // to emit executable code in some cases), but is the best method we have - // right now for checking this. - MCSection *Sec = getCurrentSectionOnly(); - Sec->setHasData(true); } void MCObjectStreamer::EmitValueToAlignment(unsigned ByteAlignment, @@ -554,16 +600,6 @@ void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset, insert(new MCOrgFragment(*Offset, Value, Loc)); } -void MCObjectStreamer::EmitCodePaddingBasicBlockStart( - const MCCodePaddingContext &Context) { - getAssembler().getBackend().handleCodePaddingBasicBlockStart(this, Context); -} - -void MCObjectStreamer::EmitCodePaddingBasicBlockEnd( - const MCCodePaddingContext &Context) { - getAssembler().getBackend().handleCodePaddingBasicBlockEnd(Context); -} - // Associate DTPRel32 fixup with data and resize data area void MCObjectStreamer::EmitDTPRel32Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); @@ -725,7 +761,9 @@ void MCObjectStreamer::FinishImpl() { // Dump out the dwarf file & directory tables and line tables. MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams()); + // Update any remaining pending labels with empty data fragments. flushPendingLabels(); + resolvePendingFixups(); getAssembler().Finish(); } diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index b59ac08ad6cc4..94a44c1f93b18 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -91,16 +91,13 @@ struct MacroInstantiation { SMLoc InstantiationLoc; /// The buffer where parsing should resume upon instantiation completion. - int ExitBuffer; + unsigned ExitBuffer; /// The location where parsing should resume upon instantiation completion. SMLoc ExitLoc; /// The depth of TheCondStack at the start of the instantiation. size_t CondStackDepth; - -public: - MacroInstantiation(SMLoc IL, int EB, SMLoc EL, size_t CondStackDepth); }; struct ParseStatementInfo { @@ -916,13 +913,12 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // While we have input, parse each statement. while (Lexer.isNot(AsmToken::Eof)) { ParseStatementInfo Info(&AsmStrRewrites); - if (!parseStatement(Info, nullptr)) - continue; + bool Parsed = parseStatement(Info, nullptr); // If we have a Lexer Error we are on an Error Token. Load in Lexer Error // for printing ErrMsg via Lex() only if no (presumably better) parser error // exists. - if (!hasPendingError() && Lexer.getTok().is(AsmToken::Error)) { + if (Parsed && !hasPendingError() && Lexer.getTok().is(AsmToken::Error)) { Lex(); } @@ -930,7 +926,7 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { printPendingErrors(); // Skipping to the next line if needed. - if (!getLexer().isAtStartOfStatement()) + if (Parsed && !getLexer().isAtStartOfStatement()) eatToEndOfStatement(); } @@ -2521,11 +2517,6 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, return false; } -MacroInstantiation::MacroInstantiation(SMLoc IL, int EB, SMLoc EL, - size_t CondStackDepth) - : InstantiationLoc(IL), ExitBuffer(EB), ExitLoc(EL), - CondStackDepth(CondStackDepth) {} - static bool isOperator(AsmToken::TokenKind kind) { switch (kind) { default: @@ -2800,8 +2791,8 @@ bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { // Create the macro instantiation object and add to the current macro // instantiation stack. - MacroInstantiation *MI = new MacroInstantiation( - NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()); + MacroInstantiation *MI = new MacroInstantiation{ + NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()}; ActiveMacros.push_back(MI); ++NumOfMacroInstantiations; @@ -3139,8 +3130,9 @@ bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) { Value = APFloat::getNaN(Semantics, false, ~0); else return TokError("invalid floating point literal"); - } else if (Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven) == - APFloat::opInvalidOp) + } else if (errorToBool( + Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven) + .takeError())) return TokError("invalid floating point literal"); if (IsNeg) Value.changeSign(); @@ -5545,8 +5537,8 @@ void AsmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc, // Create the macro instantiation object and add to the current macro // instantiation stack. - MacroInstantiation *MI = new MacroInstantiation( - DirectiveLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()); + MacroInstantiation *MI = new MacroInstantiation{ + DirectiveLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()}; ActiveMacros.push_back(MI); // Jump to the macro instantiation and prime the lexer. @@ -5813,10 +5805,6 @@ bool AsmParser::parseMSInlineAsm( for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) { MCParsedAsmOperand &Operand = *Info.ParsedOperands[i]; - // Immediate. - if (Operand.isImm()) - continue; - // Register operand. if (Operand.isReg() && !Operand.needAddressOf() && !getTargetParser().OmitRegisterFromClobberLists(Operand.getReg())) { @@ -5836,19 +5824,31 @@ bool AsmParser::parseMSInlineAsm( if (!OpDecl) continue; + StringRef Constraint = Operand.getConstraint(); + if (Operand.isImm()) { + // Offset as immediate + if (Operand.isOffsetOfLocal()) + Constraint = "r"; + else + Constraint = "i"; + } + bool isOutput = (i == 1) && Desc.mayStore(); SMLoc Start = SMLoc::getFromPointer(SymName.data()); if (isOutput) { ++InputIdx; OutputDecls.push_back(OpDecl); OutputDeclsAddressOf.push_back(Operand.needAddressOf()); - OutputConstraints.push_back(("=" + Operand.getConstraint()).str()); + OutputConstraints.push_back(("=" + Constraint).str()); AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size()); } else { InputDecls.push_back(OpDecl); InputDeclsAddressOf.push_back(Operand.needAddressOf()); - InputConstraints.push_back(Operand.getConstraint().str()); - AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size()); + InputConstraints.push_back(Constraint.str()); + if (Desc.OpInfo[i - 1].isBranchTarget()) + AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size()); + else + AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size()); } } @@ -5895,7 +5895,11 @@ bool AsmParser::parseMSInlineAsm( const char *AsmStart = ASMString.begin(); const char *AsmEnd = ASMString.end(); array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort); - for (const AsmRewrite &AR : AsmStrRewrites) { + for (auto it = AsmStrRewrites.begin(); it != AsmStrRewrites.end(); ++it) { + const AsmRewrite &AR = *it; + // Check if this has already been covered by another rewrite... + if (AR.Done) + continue; AsmRewriteKind Kind = AR.Kind; const char *Loc = AR.Loc.getPointer(); @@ -5926,9 +5930,32 @@ bool AsmParser::parseMSInlineAsm( OS << (AR.IntelExp.hasBaseReg() ? " + " : "") << AR.IntelExp.IndexReg; if (AR.IntelExp.Scale > 1) - OS << " * $$" << AR.IntelExp.Scale; - if (AR.IntelExp.Imm || !AR.IntelExp.hasRegs()) - OS << (AR.IntelExp.hasRegs() ? " + $$" : "$$") << AR.IntelExp.Imm; + OS << " * $$" << AR.IntelExp.Scale; + if (AR.IntelExp.hasOffset()) { + if (AR.IntelExp.hasRegs()) + OS << " + "; + // Fuse this rewrite with a rewrite of the offset name, if present. + StringRef OffsetName = AR.IntelExp.OffsetName; + SMLoc OffsetLoc = SMLoc::getFromPointer(AR.IntelExp.OffsetName.data()); + size_t OffsetLen = OffsetName.size(); + auto rewrite_it = std::find_if( + it, AsmStrRewrites.end(), [&](const AsmRewrite &FusingAR) { + return FusingAR.Loc == OffsetLoc && FusingAR.Len == OffsetLen && + (FusingAR.Kind == AOK_Input || + FusingAR.Kind == AOK_CallInput); + }); + if (rewrite_it == AsmStrRewrites.end()) { + OS << "offset " << OffsetName; + } else if (rewrite_it->Kind == AOK_CallInput) { + OS << "${" << InputIdx++ << ":P}"; + rewrite_it->Done = true; + } else { + OS << '$' << InputIdx++; + rewrite_it->Done = true; + } + } + if (AR.IntelExp.Imm || AR.IntelExp.emitImm()) + OS << (AR.IntelExp.emitImm() ? "$$" : " + $$") << AR.IntelExp.Imm; if (AR.IntelExp.NeedBracs) OS << "]"; break; @@ -5938,6 +5965,9 @@ bool AsmParser::parseMSInlineAsm( case AOK_Input: OS << '$' << InputIdx++; break; + case AOK_CallInput: + OS << "${" << InputIdx++ << ":P}"; + break; case AOK_Output: OS << '$' << OutputIdx++; break; diff --git a/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/llvm/lib/MC/MCParser/COFFAsmParser.cpp index 06f8310ae0615..51bb1fe92b73d 100644 --- a/llvm/lib/MC/MCParser/COFFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -144,7 +144,7 @@ public: COFFAsmParser() = default; }; -} // end annonomous namespace. +} // end anonymous namespace. static SectionKind computeSectionKind(unsigned Flags) { if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) diff --git a/llvm/lib/MC/MCSection.cpp b/llvm/lib/MC/MCSection.cpp index 2c892ab816081..074534bd73dbd 100644 --- a/llvm/lib/MC/MCSection.cpp +++ b/llvm/lib/MC/MCSection.cpp @@ -22,8 +22,7 @@ using namespace llvm; MCSection::MCSection(SectionVariant V, SectionKind K, MCSymbol *Begin) : Begin(Begin), BundleGroupBeforeFirstInst(false), HasInstructions(false), - HasData(false), IsRegistered(false), DummyFragment(this), Variant(V), - Kind(K) {} + IsRegistered(false), DummyFragment(this), Variant(V), Kind(K) {} MCSymbol *MCSection::getEndSymbol(MCContext &Ctx) { if (!End) @@ -86,6 +85,41 @@ MCSection::getSubsectionInsertionPoint(unsigned Subsection) { return IP; } +void MCSection::addPendingLabel(MCSymbol* label, unsigned Subsection) { + PendingLabels.push_back(PendingLabel(label, Subsection)); +} + +void MCSection::flushPendingLabels(MCFragment *F, uint64_t FOffset, + unsigned Subsection) { + if (PendingLabels.empty()) + return; + + // Set the fragment and fragment offset for all pending symbols in the + // specified Subsection, and remove those symbols from the pending list. + for (auto It = PendingLabels.begin(); It != PendingLabels.end(); ++It) { + PendingLabel& Label = *It; + if (Label.Subsection == Subsection) { + Label.Sym->setFragment(F); + Label.Sym->setOffset(FOffset); + PendingLabels.erase(It--); + } + } +} + +void MCSection::flushPendingLabels() { + // Make sure all remaining pending labels point to data fragments, by + // creating new empty data fragments for each Subsection with labels pending. + while (!PendingLabels.empty()) { + PendingLabel& Label = PendingLabels[0]; + iterator CurInsertionPoint = + this->getSubsectionInsertionPoint(Label.Subsection); + MCFragment *F = new MCDataFragment(); + getFragmentList().insert(CurInsertionPoint, F); + F->setParent(this); + flushPendingLabels(F, 0, Label.Subsection); + } +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCSection::dump() const { raw_ostream &OS = errs(); diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp index d52959f15f928..8377e295532ae 100644 --- a/llvm/lib/MC/MCSectionXCOFF.cpp +++ b/llvm/lib/MC/MCSectionXCOFF.cpp @@ -15,18 +15,6 @@ using namespace llvm; MCSectionXCOFF::~MCSectionXCOFF() = default; -static StringRef getMappingClassString(XCOFF::StorageMappingClass SMC) { - switch (SMC) { - case XCOFF::XMC_DS: - return "DS"; - case XCOFF::XMC_RW: - return "RW"; - case XCOFF::XMC_PR: - return "PR"; - default: - report_fatal_error("Unhandled storage-mapping class."); - } -} void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, @@ -35,9 +23,14 @@ void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, if (getMappingClass() != XCOFF::XMC_PR) report_fatal_error("Unhandled storage-mapping class for .text csect"); - OS << "\t.csect " << getSectionName() << "[" - << getMappingClassString(getMappingClass()) - << "]" << '\n'; + OS << "\t.csect " << QualName->getName() << '\n'; + return; + } + + if (getKind().isReadOnly()) { + if (getMappingClass() != XCOFF::XMC_RO) + report_fatal_error("Unhandled storage-mapping class for .rodata csect."); + OS << "\t.csect " << QualName->getName() << '\n'; return; } @@ -45,8 +38,9 @@ void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, switch (getMappingClass()) { case XCOFF::XMC_RW: case XCOFF::XMC_DS: - OS << "\t.csect " << getSectionName() << "[" - << getMappingClassString(getMappingClass()) << "]" << '\n'; + OS << "\t.csect " << QualName->getName() << '\n'; + break; + case XCOFF::XMC_TC: break; case XCOFF::XMC_TC0: OS << "\t.toc\n"; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index b8278cb110799..0ab8835367798 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -977,9 +977,10 @@ void MCStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { } void MCTargetStreamer::prettyPrintAsm(MCInstPrinter &InstPrinter, - raw_ostream &OS, const MCInst &Inst, - const MCSubtargetInfo &STI) { - InstPrinter.printInst(&Inst, OS, "", STI); + uint64_t Address, const MCInst &Inst, + const MCSubtargetInfo &STI, + raw_ostream &OS) { + InstPrinter.printInst(&Inst, Address, "", STI, OS); } void MCStreamer::visitUsedSymbol(const MCSymbol &Sym) { @@ -1063,7 +1064,8 @@ void MCStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { void MCStreamer::EmitCOFFSymbolType(int Type) { llvm_unreachable("this directive only supported on COFF targets"); } -void MCStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, +void MCStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlign) { llvm_unreachable("this directive only supported on XCOFF targets"); } diff --git a/llvm/lib/MC/MCSymbolELF.cpp b/llvm/lib/MC/MCSymbolELF.cpp index a07c56c64f841..1830b87fd8567 100644 --- a/llvm/lib/MC/MCSymbolELF.cpp +++ b/llvm/lib/MC/MCSymbolELF.cpp @@ -40,8 +40,6 @@ enum { void MCSymbolELF::setBinding(unsigned Binding) const { setIsBindingSet(); - if (getType() == ELF::STT_SECTION && Binding != ELF::STB_LOCAL) - setType(ELF::STT_NOTYPE); unsigned Val; switch (Binding) { default: @@ -93,8 +91,6 @@ unsigned MCSymbolELF::getBinding() const { void MCSymbolELF::setType(unsigned Type) const { unsigned Val; - if (Type == ELF::STT_SECTION && getBinding() != ELF::STB_LOCAL) - return; switch (Type) { default: llvm_unreachable("Unsupported Binding"); diff --git a/llvm/lib/MC/MCTargetOptions.cpp b/llvm/lib/MC/MCTargetOptions.cpp index 96bb094134fe8..5848e3ecadbe1 100644 --- a/llvm/lib/MC/MCTargetOptions.cpp +++ b/llvm/lib/MC/MCTargetOptions.cpp @@ -15,8 +15,8 @@ MCTargetOptions::MCTargetOptions() : MCRelaxAll(false), MCNoExecStack(false), MCFatalWarnings(false), MCNoWarn(false), MCNoDeprecatedWarn(false), MCSaveTempLabels(false), MCUseDwarfDirectory(false), MCIncrementalLinkerCompatible(false), - MCPIECopyRelocations(false), ShowMCEncoding(false), ShowMCInst(false), - AsmVerbose(false), PreserveAsmComments(true) {} + ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false), + PreserveAsmComments(true) {} StringRef MCTargetOptions::getABIName() const { return ABIName; diff --git a/llvm/lib/MC/MCValue.cpp b/llvm/lib/MC/MCValue.cpp index 81da47b2eced2..b6bcec9b2ca07 100644 --- a/llvm/lib/MC/MCValue.cpp +++ b/llvm/lib/MC/MCValue.cpp @@ -54,8 +54,5 @@ MCSymbolRefExpr::VariantKind MCValue::getAccessVariant() const { if (!A) return MCSymbolRefExpr::VK_None; - MCSymbolRefExpr::VariantKind Kind = A->getKind(); - if (Kind == MCSymbolRefExpr::VK_WEAKREF) - return MCSymbolRefExpr::VK_None; - return Kind; + return A->getKind(); } diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp index 50937d6adc0c8..6efa167ced42a 100644 --- a/llvm/lib/MC/MCXCOFFStreamer.cpp +++ b/llvm/lib/MC/MCXCOFFStreamer.cpp @@ -50,12 +50,6 @@ void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, XCOFF::C_HIDEXT); Symbol->setCommon(Size, ByteAlignment); - // Need to add this symbol to the current Fragment which will belong to the - // containing CSECT. - auto *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); - assert(F && "Expected a valid section with a fragment set."); - Symbol->setFragment(F); - // Emit the alignment and storage for the variable to the section. EmitValueToAlignment(ByteAlignment); EmitZeros(Size); @@ -94,8 +88,9 @@ MCStreamer *llvm::createXCOFFStreamer(MCContext &Context, return S; } -void MCXCOFFStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, +void MCXCOFFStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlignment) { - EmitCommonSymbol(Symbol, Size, ByteAlignment); + EmitCommonSymbol(CsectSym, Size, ByteAlignment); } diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index c1ff3cc2480cd..321f93d76092b 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -1324,6 +1324,14 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, Comdats[C->getName()].emplace_back( WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index}); } + + if (WS.hasExportName()) { + wasm::WasmExport Export; + Export.Name = WS.getExportName(); + Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; + Export.Index = Index; + Exports.push_back(Export); + } } else { // An import; the index was assigned above. Index = WasmIndices.find(&WS)->second; @@ -1452,8 +1460,10 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, Flags |= wasm::WASM_SYMBOL_EXPORTED; } } - if (WS.getName() != WS.getImportName()) + if (WS.hasImportName()) Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME; + if (WS.hasExportName()) + Flags |= wasm::WASM_SYMBOL_EXPORTED; wasm::WasmSymbolInfo Info; Info.Name = WS.getName(); diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp index 353c21068735b..e584c6222a5a2 100644 --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -44,6 +44,7 @@ using namespace llvm; namespace { constexpr unsigned DefaultSectionAlign = 4; +constexpr int16_t MaxSectionIndex = INT16_MAX; // Packs the csect's alignment and type into a byte. uint8_t getEncodedType(const MCSectionXCOFF *); @@ -73,6 +74,14 @@ struct ControlSection { : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {} }; +// Type to be used for a container representing a set of csects with +// (approximately) the same storage mapping class. For example all the csects +// with a storage mapping class of `xmc_pr` will get placed into the same +// container. +using CsectGroup = std::deque<ControlSection>; + +using CsectGroups = std::deque<CsectGroup *>; + // Represents the data related to a section excluding the csects that make up // the raw data of the section. The csects are stored separately as not all // sections contain csects, and some sections contain csects which are better @@ -94,49 +103,70 @@ struct Section { // Virtual sections do not need storage allocated in the object file. const bool IsVirtual; + // XCOFF has special section numbers for symbols: + // -2 Specifies N_DEBUG, a special symbolic debugging symbol. + // -1 Specifies N_ABS, an absolute symbol. The symbol has a value but is not + // relocatable. + // 0 Specifies N_UNDEF, an undefined external symbol. + // Therefore, we choose -3 (N_DEBUG - 1) to represent a section index that + // hasn't been initialized. + static constexpr int16_t UninitializedIndex = + XCOFF::ReservedSectionNum::N_DEBUG - 1; + + CsectGroups Groups; + void reset() { Address = 0; Size = 0; FileOffsetToData = 0; FileOffsetToRelocations = 0; RelocationCount = 0; - Index = -1; + Index = UninitializedIndex; + // Clear any csects we have stored. + for (auto *Group : Groups) + Group->clear(); } - Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual) + Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual, + CsectGroups Groups) : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0), - RelocationCount(0), Flags(Flags), Index(-1), IsVirtual(IsVirtual) { + RelocationCount(0), Flags(Flags), Index(UninitializedIndex), + IsVirtual(IsVirtual), Groups(Groups) { strncpy(Name, N, XCOFF::NameSize); } }; class XCOFFObjectWriter : public MCObjectWriter { - // Type to be used for a container representing a set of csects with - // (approximately) the same storage mapping class. For example all the csects - // with a storage mapping class of `xmc_pr` will get placed into the same - // container. - using CsectGroup = std::deque<ControlSection>; + + uint32_t SymbolTableEntryCount = 0; + uint32_t SymbolTableOffset = 0; + uint16_t SectionCount = 0; support::endian::Writer W; std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter; StringTableBuilder Strings; - // The non-empty sections, in the order they will appear in the section header - // table. - std::vector<Section *> Sections; - - // The Predefined sections. - Section Text; - Section BSS; - // CsectGroups. These store the csects which make up different parts of // the sections. Should have one for each set of csects that get mapped into // the same section and get handled in a 'similar' way. + CsectGroup UndefinedCsects; CsectGroup ProgramCodeCsects; + CsectGroup ReadOnlyCsects; + CsectGroup DataCsects; + CsectGroup FuncDSCsects; + CsectGroup TOCCsects; CsectGroup BSSCsects; - uint32_t SymbolTableEntryCount = 0; - uint32_t SymbolTableOffset = 0; + // The Predefined sections. + Section Text; + Section Data; + Section BSS; + + // All the XCOFF sections, in the order they will appear in the section header + // table. + std::array<Section *const, 3> Sections{{&Text, &Data, &BSS}}; + + CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec); virtual void reset() override; @@ -190,27 +220,72 @@ XCOFFObjectWriter::XCOFFObjectWriter( std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) : W(OS, support::big), TargetObjectWriter(std::move(MOTW)), Strings(StringTableBuilder::XCOFF), - Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false), - BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true) {} + Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false, + CsectGroups{&ProgramCodeCsects, &ReadOnlyCsects}), + Data(".data", XCOFF::STYP_DATA, /* IsVirtual */ false, + CsectGroups{&DataCsects, &FuncDSCsects, &TOCCsects}), + BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true, + CsectGroups{&BSSCsects}) {} void XCOFFObjectWriter::reset() { + UndefinedCsects.clear(); + // Reset any sections we have written to, and empty the section header table. for (auto *Sec : Sections) Sec->reset(); - Sections.clear(); - - // Clear any csects we have stored. - ProgramCodeCsects.clear(); - BSSCsects.clear(); // Reset the symbol table and string table. SymbolTableEntryCount = 0; SymbolTableOffset = 0; + SectionCount = 0; Strings.clear(); MCObjectWriter::reset(); } +CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) { + switch (MCSec->getMappingClass()) { + case XCOFF::XMC_PR: + assert(XCOFF::XTY_SD == MCSec->getCSectType() && + "Only an initialized csect can contain program code."); + return ProgramCodeCsects; + case XCOFF::XMC_RO: + assert(XCOFF::XTY_SD == MCSec->getCSectType() && + "Only an initialized csect can contain read only data."); + return ReadOnlyCsects; + case XCOFF::XMC_RW: + if (XCOFF::XTY_CM == MCSec->getCSectType()) + return BSSCsects; + + if (XCOFF::XTY_SD == MCSec->getCSectType()) + return DataCsects; + + report_fatal_error("Unhandled mapping of read-write csect to section."); + case XCOFF::XMC_DS: + return FuncDSCsects; + case XCOFF::XMC_BS: + assert(XCOFF::XTY_CM == MCSec->getCSectType() && + "Mapping invalid csect. CSECT with bss storage class must be " + "common type."); + return BSSCsects; + case XCOFF::XMC_TC0: + assert(XCOFF::XTY_SD == MCSec->getCSectType() && + "Only an initialized csect can contain TOC-base."); + assert(TOCCsects.empty() && + "We should have only one TOC-base, and it should be the first csect " + "in this CsectGroup."); + return TOCCsects; + case XCOFF::XMC_TC: + assert(XCOFF::XTY_SD == MCSec->getCSectType() && + "Only an initialized csect can contain TC entry."); + assert(!TOCCsects.empty() && + "We should at least have a TOC-base in this CsectGroup."); + return TOCCsects; + default: + report_fatal_error("Unhandled mapping of csect to section."); + } +} + void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { if (TargetObjectWriter->is64Bit()) @@ -225,49 +300,38 @@ void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const auto *MCSec = cast<const MCSectionXCOFF>(&S); assert(WrapperMap.find(MCSec) == WrapperMap.end() && "Cannot add a csect twice."); + assert(XCOFF::XTY_ER != MCSec->getCSectType() && + "An undefined csect should not get registered."); // If the name does not fit in the storage provided in the symbol table // entry, add it to the string table. if (nameShouldBeInStringTable(MCSec->getSectionName())) Strings.add(MCSec->getSectionName()); - switch (MCSec->getMappingClass()) { - case XCOFF::XMC_PR: - assert(XCOFF::XTY_SD == MCSec->getCSectType() && - "Only an initialized csect can contain program code."); - ProgramCodeCsects.emplace_back(MCSec); - WrapperMap[MCSec] = &ProgramCodeCsects.back(); - break; - case XCOFF::XMC_RW: - if (XCOFF::XTY_CM == MCSec->getCSectType()) { - BSSCsects.emplace_back(MCSec); - WrapperMap[MCSec] = &BSSCsects.back(); - break; - } - report_fatal_error("Unhandled mapping of read-write csect to section."); - case XCOFF::XMC_TC0: - // TODO FIXME Handle emiting the TOC base. - break; - case XCOFF::XMC_BS: - assert(XCOFF::XTY_CM == MCSec->getCSectType() && - "Mapping invalid csect. CSECT with bss storage class must be " - "common type."); - BSSCsects.emplace_back(MCSec); - WrapperMap[MCSec] = &BSSCsects.back(); - break; - default: - report_fatal_error("Unhandled mapping of csect to section."); - } + CsectGroup &Group = getCsectGroup(MCSec); + Group.emplace_back(MCSec); + WrapperMap[MCSec] = &Group.back(); } for (const MCSymbol &S : Asm.symbols()) { // Nothing to do for temporary symbols. if (S.isTemporary()) continue; - const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S); - // Map the symbol into its containing csect. + const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S); const MCSectionXCOFF *ContainingCsect = XSym->getContainingCsect(); + + // Handle undefined symbol. + if (ContainingCsect->getCSectType() == XCOFF::XTY_ER) { + UndefinedCsects.emplace_back(ContainingCsect); + continue; + } + + // If the symbol is the csect itself, we don't need to put the symbol + // into csect's Syms. + if (XSym == ContainingCsect->getQualNameSymbol()) + continue; + assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() && "Expected containing csect to exist in map"); @@ -287,27 +351,37 @@ void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *, const MCFixup &, MCValue, uint64_t &) { - report_fatal_error("XCOFF relocations not supported."); + // TODO: recordRelocation is not yet implemented. } void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout) { - // Write the program code control sections one at a time. - uint32_t CurrentAddressLocation = Text.Address; - for (const auto &Csect : ProgramCodeCsects) { - if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation) - W.OS.write_zeros(PaddingSize); - Asm.writeSectionData(W.OS, Csect.MCCsect, Layout); - CurrentAddressLocation = Csect.Address + Csect.Size; - } + uint32_t CurrentAddressLocation = 0; + for (const auto *Section : Sections) { + // Nothing to write for this Section. + if (Section->Index == Section::UninitializedIndex || Section->IsVirtual) + continue; + + assert(CurrentAddressLocation == Section->Address && + "Sections should be written consecutively."); + for (const auto *Group : Section->Groups) { + for (const auto &Csect : *Group) { + if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation) + W.OS.write_zeros(PaddingSize); + if (Csect.Size) + Asm.writeSectionData(W.OS, Csect.MCCsect, Layout); + CurrentAddressLocation = Csect.Address + Csect.Size; + } + } - if (Text.Index != -1) { // The size of the tail padding in a section is the end virtual address of // the current section minus the the end virtual address of the last csect // in that section. if (uint32_t PaddingSize = - Text.Address + Text.Size - CurrentAddressLocation) + Section->Address + Section->Size - CurrentAddressLocation) { W.OS.write_zeros(PaddingSize); + CurrentAddressLocation += PaddingSize; + } } } @@ -345,7 +419,7 @@ void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) { W.write<int32_t>(0); W.write<uint32_t>(Strings.getOffset(SymbolName)); } else { - char Name[XCOFF::NameSize]; + char Name[XCOFF::NameSize+1]; std::strncpy(Name, SymbolName.data(), XCOFF::NameSize); ArrayRef<char> NameRef(Name, XCOFF::NameSize); W.write(NameRef); @@ -431,7 +505,7 @@ void XCOFFObjectWriter::writeFileHeader() { // Magic. W.write<uint16_t>(0x01df); // Number of sections. - W.write<uint16_t>(Sections.size()); + W.write<uint16_t>(SectionCount); // Timestamp field. For reproducible output we write a 0, which represents no // timestamp. W.write<int32_t>(0); @@ -447,6 +521,10 @@ void XCOFFObjectWriter::writeFileHeader() { void XCOFFObjectWriter::writeSectionHeaderTable() { for (const auto *Sec : Sections) { + // Nothing to write for this Section. + if (Sec->Index == Section::UninitializedIndex) + continue; + // Write Name. ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize); W.write(NameRef); @@ -472,104 +550,112 @@ void XCOFFObjectWriter::writeSectionHeaderTable() { } void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { - // Print out symbol table for the program code. - for (const auto &Csect : ProgramCodeCsects) { - // Write out the control section first and then each symbol in it. - writeSymbolTableEntryForControlSection(Csect, Text.Index, - Csect.MCCsect->getStorageClass()); - for (const auto &Sym : Csect.Syms) - writeSymbolTableEntryForCsectMemberLabel( - Sym, Csect, Text.Index, Layout.getSymbolOffset(*Sym.MCSym)); + for (const auto &Csect : UndefinedCsects) { + writeSymbolTableEntryForControlSection( + Csect, XCOFF::ReservedSectionNum::N_UNDEF, Csect.MCCsect->getStorageClass()); } - // The BSS Section is special in that the csects must contain a single symbol, - // and the contained symbol cannot be represented in the symbol table as a - // label definition. - for (auto &Csect : BSSCsects) { - assert(Csect.Syms.size() == 1 && - "Uninitialized csect cannot contain more then 1 symbol."); - Symbol &Sym = Csect.Syms.back(); - writeSymbolTableEntryForControlSection(Csect, BSS.Index, - Sym.getStorageClass()); + for (const auto *Section : Sections) { + // Nothing to write for this Section. + if (Section->Index == Section::UninitializedIndex) + continue; + + for (const auto *Group : Section->Groups) { + if (Group->empty()) + continue; + + const int16_t SectionIndex = Section->Index; + for (const auto &Csect : *Group) { + // Write out the control section first and then each symbol in it. + writeSymbolTableEntryForControlSection( + Csect, SectionIndex, Csect.MCCsect->getStorageClass()); + + for (const auto &Sym : Csect.Syms) + writeSymbolTableEntryForCsectMemberLabel( + Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym))); + } + } } } void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { + // The first symbol table entry is for the file name. We are not emitting it + // yet, so start at index 0. + uint32_t SymbolTableIndex = 0; + + // Calculate indices for undefined symbols. + for (auto &Csect : UndefinedCsects) { + Csect.Size = 0; + Csect.Address = 0; + Csect.SymbolTableIndex = SymbolTableIndex; + // 1 main and 1 auxiliary symbol table entry for each contained symbol. + SymbolTableIndex += 2; + } + // The address corrresponds to the address of sections and symbols in the // object file. We place the shared address 0 immediately after the // section header table. uint32_t Address = 0; // Section indices are 1-based in XCOFF. - int16_t SectionIndex = 1; - // The first symbol table entry is for the file name. We are not emitting it - // yet, so start at index 0. - uint32_t SymbolTableIndex = 0; + int32_t SectionIndex = 1; - // Text section comes first. - if (!ProgramCodeCsects.empty()) { - Sections.push_back(&Text); - Text.Index = SectionIndex++; - for (auto &Csect : ProgramCodeCsects) { - const MCSectionXCOFF *MCSec = Csect.MCCsect; - Csect.Address = alignTo(Address, MCSec->getAlignment()); - Csect.Size = Layout.getSectionAddressSize(MCSec); - Address = Csect.Address + Csect.Size; - Csect.SymbolTableIndex = SymbolTableIndex; - // 1 main and 1 auxiliary symbol table entry for the csect. - SymbolTableIndex += 2; - for (auto &Sym : Csect.Syms) { - Sym.SymbolTableIndex = SymbolTableIndex; - // 1 main and 1 auxiliary symbol table entry for each contained symbol + for (auto *Section : Sections) { + const bool IsEmpty = + llvm::all_of(Section->Groups, + [](const CsectGroup *Group) { return Group->empty(); }); + if (IsEmpty) + continue; + + if (SectionIndex > MaxSectionIndex) + report_fatal_error("Section index overflow!"); + Section->Index = SectionIndex++; + SectionCount++; + + bool SectionAddressSet = false; + for (auto *Group : Section->Groups) { + if (Group->empty()) + continue; + + for (auto &Csect : *Group) { + const MCSectionXCOFF *MCSec = Csect.MCCsect; + Csect.Address = alignTo(Address, MCSec->getAlignment()); + Csect.Size = Layout.getSectionAddressSize(MCSec); + Address = Csect.Address + Csect.Size; + Csect.SymbolTableIndex = SymbolTableIndex; + // 1 main and 1 auxiliary symbol table entry for the csect. SymbolTableIndex += 2; + + for (auto &Sym : Csect.Syms) { + Sym.SymbolTableIndex = SymbolTableIndex; + // 1 main and 1 auxiliary symbol table entry for each contained + // symbol. + SymbolTableIndex += 2; + } } - } - Address = alignTo(Address, DefaultSectionAlign); - // The first csect of a section can be aligned by adjusting the virtual - // address of its containing section instead of writing zeroes into the - // object file. - Text.Address = ProgramCodeCsects.front().Address; - - Text.Size = Address - Text.Address; - } - - // Data section Second. TODO - - // BSS Section third. - if (!BSSCsects.empty()) { - Sections.push_back(&BSS); - BSS.Index = SectionIndex++; - for (auto &Csect : BSSCsects) { - const MCSectionXCOFF *MCSec = Csect.MCCsect; - Csect.Address = alignTo(Address, MCSec->getAlignment()); - Csect.Size = Layout.getSectionAddressSize(MCSec); - Address = Csect.Address + Csect.Size; - Csect.SymbolTableIndex = SymbolTableIndex; - // 1 main and 1 auxiliary symbol table entry for the csect. - SymbolTableIndex += 2; - - assert(Csect.Syms.size() == 1 && - "csect in the BSS can only contain a single symbol."); - Csect.Syms[0].SymbolTableIndex = Csect.SymbolTableIndex; + if (!SectionAddressSet) { + Section->Address = Group->front().Address; + SectionAddressSet = true; + } } - // Pad out Address to the default alignment. This is to match how the system - // assembler handles the .bss section. Its size is always a multiple of 4. - Address = alignTo(Address, DefaultSectionAlign); - BSS.Address = BSSCsects.front().Address; - BSS.Size = Address - BSS.Address; + // Make sure the address of the next section aligned to + // DefaultSectionAlign. + Address = alignTo(Address, DefaultSectionAlign); + Section->Size = Address - Section->Address; } SymbolTableEntryCount = SymbolTableIndex; // Calculate the RawPointer value for each section. uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() + - Sections.size() * sizeof(XCOFF::SectionHeader32); + SectionCount * sizeof(XCOFF::SectionHeader32); for (auto *Sec : Sections) { - if (!Sec->IsVirtual) { - Sec->FileOffsetToData = RawPointer; - RawPointer += Sec->Size; - } + if (Sec->Index == Section::UninitializedIndex || Sec->IsVirtual) + continue; + + Sec->FileOffsetToData = RawPointer; + RawPointer += Sec->Size; } // TODO Add in Relocation storage to the RawPointer Calculation. |