diff options
author | Eli Bendersky <eliben@google.com> | 2012-12-20 19:05:53 +0000 |
---|---|---|
committer | Eli Bendersky <eliben@google.com> | 2012-12-20 19:05:53 +0000 |
commit | 4766ef41b31e4f97bce1179c3b0398303bf65356 (patch) | |
tree | 9c7d834025eea913e5887165099d31af8464cfe0 | |
parent | 5d3cfa6d1f6d3069893d50af39511cbf5576be91 (diff) |
Aligned bundling support. Following the discussion here:
http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-December/056754.html
The proposal and implementation are fully documented here:
https://sites.google.com/a/chromium.org/dev/nativeclient/pnacl/aligned-bundling-support-in-llvm
Tests will follow shortly.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170718 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/MC/MCAsmLayout.h | 5 | ||||
-rw-r--r-- | include/llvm/MC/MCAssembler.h | 87 | ||||
-rw-r--r-- | include/llvm/MC/MCELFStreamer.h | 6 | ||||
-rw-r--r-- | include/llvm/MC/MCObjectStreamer.h | 7 | ||||
-rw-r--r-- | include/llvm/MC/MCStreamer.h | 12 | ||||
-rw-r--r-- | lib/MC/MCAsmStreamer.cpp | 19 | ||||
-rw-r--r-- | lib/MC/MCAssembler.cpp | 81 | ||||
-rw-r--r-- | lib/MC/MCELFStreamer.cpp | 87 | ||||
-rw-r--r-- | lib/MC/MCNullStreamer.cpp | 4 | ||||
-rw-r--r-- | lib/MC/MCObjectStreamer.cpp | 33 | ||||
-rw-r--r-- | lib/MC/MCParser/AsmParser.cpp | 67 | ||||
-rw-r--r-- | tools/lto/LTOModule.cpp | 4 |
12 files changed, 393 insertions, 19 deletions
diff --git a/include/llvm/MC/MCAsmLayout.h b/include/llvm/MC/MCAsmLayout.h index 267e3a57f5..8cb4601283 100644 --- a/include/llvm/MC/MCAsmLayout.h +++ b/include/llvm/MC/MCAsmLayout.h @@ -49,6 +49,11 @@ private: /// \brief Is the layout for this fragment valid? bool isFragmentValid(const MCFragment *F) const; + /// \brief Compute the amount of padding required before this fragment to + /// obey bundling restrictions. + uint64_t computeBundlePadding(const MCFragment *F, + uint64_t FOffset, uint64_t FSize); + public: MCAsmLayout(MCAssembler &_Assembler); diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 8dba3b9c09..6c2fdc5396 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -99,14 +99,35 @@ public: unsigned getLayoutOrder() const { return LayoutOrder; } void setLayoutOrder(unsigned Value) { LayoutOrder = Value; } + /// \brief Does this fragment have instructions emitted into it? By default + /// this is false, but specific fragment types may set it to true. + virtual bool hasInstructions() const { return false; } + + /// \brief Get the padding size that must be inserted before this fragment. + /// Used for bundling. By default, no padding is inserted. + /// Note that padding size is restricted to 8 bits. This is an optimization + /// to reduce the amount of space used for each fragment. In practice, larger + /// padding should never be required. + virtual uint8_t getBundlePadding() const { + return 0; + } + + /// \brief Set the padding size for this fragment. By default it's a no-op, + /// and only some fragments have a meaningful implementation. + virtual void setBundlePadding(uint8_t N) { + } + void dump(); }; class MCEncodedFragment : public MCFragment { virtual void anchor(); + + uint8_t BundlePadding; public: MCEncodedFragment(MCFragment::FragmentType FType, MCSectionData *SD = 0) - : MCFragment(FType, SD) { + : MCFragment(FType, SD), BundlePadding(0) + { } virtual ~MCEncodedFragment(); @@ -124,6 +145,14 @@ public: virtual fixup_iterator fixup_end() = 0; virtual const_fixup_iterator fixup_end() const = 0; + virtual uint8_t getBundlePadding() const { + return BundlePadding; + } + + virtual void setBundlePadding(uint8_t N) { + BundlePadding = N; + } + static bool classof(const MCFragment *F) { MCFragment::FragmentType Kind = F->getKind(); return Kind == MCFragment::FT_Inst || Kind == MCFragment::FT_Data; @@ -132,14 +161,19 @@ public: class MCDataFragment : public MCEncodedFragment { virtual void anchor(); + + /// \brief Does this fragment contain encoded instructions anywhere in it? + bool HasInstructions; + SmallVector<char, 32> Contents; /// Fixups - The list of fixups in this fragment. SmallVector<MCFixup, 4> Fixups; - public: MCDataFragment(MCSectionData *SD = 0) - : MCEncodedFragment(FT_Data, SD) { + : MCEncodedFragment(FT_Data, SD), + HasInstructions(false) + { } virtual SmallVectorImpl<char> &getContents() { return Contents; } @@ -153,6 +187,9 @@ public: return Fixups; } + virtual bool hasInstructions() const { return HasInstructions; } + virtual void setHasInstructions(bool V) { HasInstructions = V; } + fixup_iterator fixup_begin() { return Fixups.begin(); } const_fixup_iterator fixup_begin() const { return Fixups.begin(); } @@ -196,6 +233,8 @@ public: return Fixups; } + virtual bool hasInstructions() const { return true; } + fixup_iterator fixup_begin() { return Fixups.begin(); } const_fixup_iterator fixup_begin() const { return Fixups.begin(); } @@ -450,6 +489,13 @@ private: /// Alignment - The maximum alignment seen in this section. unsigned Alignment; + /// \brief We're currently inside a bundle-locked group. + bool BundleLocked; + + /// \brief We've seen a bundle_lock directive but not its first instruction + /// yet. + bool BundleGroupBeforeFirstInst; + /// @name Assembler Backend Data /// @{ // @@ -502,6 +548,22 @@ public: bool empty() const { return Fragments.empty(); } + bool isBundleLocked() const { + return BundleLocked; + } + + void setBundleLocked(bool IsLocked) { + BundleLocked = IsLocked; + } + + bool isBundleGroupBeforeFirstInst() const { + return BundleGroupBeforeFirstInst; + } + + void setBundleGroupBeforeFirstInst(bool IsFirst) { + BundleGroupBeforeFirstInst = IsFirst; + } + void dump(); /// @} @@ -707,6 +769,11 @@ private: // refactoring too. SmallPtrSet<const MCSymbol*, 64> ThumbFuncs; + /// \brief The bundle alignment size currently set in the assembler. + /// + /// By default it's 0, which means bundling is disabled. + unsigned BundleAlignSize; + unsigned RelaxAll : 1; unsigned NoExecStack : 1; unsigned SubsectionsViaSymbols : 1; @@ -833,6 +900,20 @@ public: bool getNoExecStack() const { return NoExecStack; } void setNoExecStack(bool Value) { NoExecStack = Value; } + bool isBundlingEnabled() const { + return BundleAlignSize != 0; + } + + unsigned getBundleAlignSize() const { + return BundleAlignSize; + } + + void setBundleAlignSize(unsigned Size) { + assert((Size == 0 || !(Size & (Size - 1))) && + "Expect a power-of-two bundle align size"); + BundleAlignSize = Size; + } + /// @name Section List Access /// @{ diff --git a/include/llvm/MC/MCELFStreamer.h b/include/llvm/MC/MCELFStreamer.h index 03a57c7ee3..6608d96e4b 100644 --- a/include/llvm/MC/MCELFStreamer.h +++ b/include/llvm/MC/MCELFStreamer.h @@ -76,6 +76,8 @@ public: virtual void EmitTCEntry(const MCSymbol &S); + virtual void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned); + virtual void FinishImpl(); /// @} @@ -83,6 +85,10 @@ private: virtual void EmitInstToFragment(const MCInst &Inst); virtual void EmitInstToData(const MCInst &Inst); + virtual void EmitBundleAlignMode(unsigned AlignPow2); + virtual void EmitBundleLock(); + virtual void EmitBundleUnlock(); + void fixSymbolsInTLSFixups(const MCExpr *expr); struct LocalCommon { diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index df98fea41c..4bc24d48c7 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -78,7 +78,14 @@ public: virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); virtual void ChangeSection(const MCSection *Section); virtual void EmitInstruction(const MCInst &Inst); + + /// \brief Emit an instruction to a special fragment, because this instruction + /// can change its size during relaxation. virtual void EmitInstToFragment(const MCInst &Inst); + + virtual void EmitBundleAlignMode(unsigned AlignPow2); + virtual void EmitBundleLock(); + virtual void EmitBundleUnlock(); virtual void EmitBytes(StringRef Data, unsigned AddrSpace); virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index ecf5e78b5e..8be46b5f1b 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -437,7 +437,6 @@ namespace llvm { EmitFill(NumBytes, 0, AddrSpace); } - /// EmitValueToAlignment - Emit some number of copies of @p Value until /// the byte alignment @p ByteAlignment is reached. /// @@ -557,6 +556,17 @@ namespace llvm { /// section. virtual void EmitInstruction(const MCInst &Inst) = 0; + /// \brief Set the bundle alignment mode from now on in the section. + /// The argument is the power of 2 to which the alignment is set. The + /// value 0 means turn the bundle alignment off. + virtual void EmitBundleAlignMode(unsigned AlignPow2) = 0; + + /// \brief The following instructions are a bundle-locked group. + virtual void EmitBundleLock() = 0; + + /// \brief Ends a bundle-locked group. + virtual void EmitBundleUnlock() = 0; + /// EmitRawText - If this file is backed by a assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. By default this aborts. diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 6302f970d8..9b7074d3b2 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -259,6 +259,10 @@ public: virtual void EmitInstruction(const MCInst &Inst); + virtual void EmitBundleAlignMode(unsigned AlignPow2); + virtual void EmitBundleLock(); + virtual void EmitBundleUnlock(); + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. @@ -1361,6 +1365,21 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { EmitEOL(); } +void MCAsmStreamer::EmitBundleAlignMode(unsigned AlignPow2) { + OS << "\t.bundle_align_mode " << AlignPow2; + EmitEOL(); +} + +void MCAsmStreamer::EmitBundleLock() { + OS << "\t.bundle_lock"; + EmitEOL(); +} + +void MCAsmStreamer::EmitBundleUnlock() { + OS << "\t.bundle_unlock"; + EmitEOL(); +} + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 2558eff045..f4c3fc55d3 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -160,6 +160,22 @@ uint64_t MCAsmLayout::getSectionFileSize(const MCSectionData *SD) const { return getSectionAddressSize(SD); } +uint64_t MCAsmLayout::computeBundlePadding(const MCFragment *F, + uint64_t FOffset, uint64_t FSize) { + uint64_t BundleSize = Assembler.getBundleAlignSize(); + assert(BundleSize > 0 && + "computeBundlePadding should only be called if bundling is enabled"); + uint64_t BundleMask = BundleSize - 1; + uint64_t OffsetInBundle = FOffset & BundleMask; + + // If the fragment would cross a bundle boundary, add enough padding until + // the end of the current bundle. + if (OffsetInBundle + FSize > BundleSize) + return BundleSize - OffsetInBundle; + else + return 0; +} + /* *** */ MCFragment::MCFragment() : Kind(FragmentType(~0)) { @@ -188,6 +204,7 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) : Section(&_Section), Ordinal(~UINT32_C(0)), Alignment(1), + BundleLocked(false), BundleGroupBeforeFirstInst(false), HasInstructions(false) { if (A) @@ -406,12 +423,42 @@ void MCAsmLayout::layoutFragment(MCFragment *F) { ++stats::FragmentLayouts; // Compute fragment offset and size. - uint64_t Offset = 0; if (Prev) - Offset += Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev); - - F->Offset = Offset; + F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev); + else + F->Offset = 0; LastValidFragment[F->getParent()] = F; + + // If bundling is enabled and this fragment has instructions in it, it has to + // obey the bundling restrictions. With padding, we'll have: + // + // + // BundlePadding + // ||| + // ------------------------------------- + // Prev |##########| F | + // ------------------------------------- + // ^ + // | + // F->Offset + // + // The fragment's offset will point to after the padding, and its computed + // size won't include the padding. + // + if (Assembler.isBundlingEnabled() && F->hasInstructions()) { + assert(isa<MCEncodedFragment>(F) && + "Only MCEncodedFragment implementations have instructions"); + uint64_t FSize = Assembler.computeFragmentSize(*this, *F); + + if (FSize > Assembler.getBundleAlignSize()) + report_fatal_error("Fragment can't be larger than a bundle size"); + + uint64_t RequiredBundlePadding = computeBundlePadding(F, F->Offset, FSize); + if (RequiredBundlePadding > UINT8_MAX) + report_fatal_error("Padding cannot exceed 255 bytes"); + F->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); + F->Offset += RequiredBundlePadding; + } } /// \brief Write the contents of a fragment to the given object writer. Expects @@ -425,6 +472,22 @@ static void writeFragmentContents(const MCFragment &F, MCObjectWriter *OW) { static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment &F) { MCObjectWriter *OW = &Asm.getWriter(); + + // Should NOP padding be written out before this fragment? + unsigned BundlePadding = F.getBundlePadding(); + if (BundlePadding > 0) { + assert(Asm.isBundlingEnabled() && + "Writing bundle padding with disabled bundling"); + assert(F.hasInstructions() && + "Writing bundle padding for a fragment without instructions"); + + if (!Asm.getBackend().writeNopData(BundlePadding, OW)) + report_fatal_error("unable to write NOP sequence of " + + Twine(BundlePadding) + " bytes"); + } + + // This variable (and its dummy usage) is to participate in the assert at + // the end of the function. uint64_t Start = OW->getStream().tell(); (void) Start; @@ -529,7 +592,8 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, } } - assert(OW->getStream().tell() - Start == FragmentSize); + assert(OW->getStream().tell() - Start == FragmentSize && + "The stream should advance by fragment size"); } void MCAssembler::writeSectionData(const MCSectionData *SD, @@ -875,7 +939,9 @@ void MCFragment::dump() { } OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder - << " Offset:" << Offset << ">"; + << " Offset:" << Offset + << " HasInstructions:" << hasInstructions() + << " BundlePadding:" << getBundlePadding() << ">"; switch (getKind()) { case MCFragment::FT_Align: { @@ -957,7 +1023,8 @@ void MCSectionData::dump() { raw_ostream &OS = llvm::errs(); OS << "<MCSectionData"; - OS << " Alignment:" << getAlignment() << " Fragments:[\n "; + OS << " Alignment:" << getAlignment() + << " Fragments:[\n "; for (iterator it = begin(), ie = end(); it != ie; ++it) { if (it != begin()) OS << ",\n "; it->dump(); diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 9771ef0549..e3acc44a85 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -105,6 +105,9 @@ void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { } void MCELFStreamer::ChangeSection(const MCSection *Section) { + MCSectionData *CurSection = getCurrentSectionData(); + if (CurSection && CurSection->isBundleLocked()) + report_fatal_error("Unterminated .bundle_lock when changing a section"); const MCSymbol *Grp = static_cast<const MCSectionELF *>(Section)->getGroup(); if (Grp) getAssembler().getOrCreateSymbolData(*Grp); @@ -262,10 +265,22 @@ void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, void MCELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, unsigned AddrSpace) { + if (getCurrentSectionData()->isBundleLocked()) + report_fatal_error("Emitting values inside a locked bundle is forbidden"); fixSymbolsInTLSFixups(Value); MCObjectStreamer::EmitValueImpl(Value, Size, AddrSpace); } +void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, + int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) { + if (getCurrentSectionData()->isBundleLocked()) + report_fatal_error("Emitting values inside a locked bundle is forbidden"); + MCObjectStreamer::EmitValueToAlignment(ByteAlignment, Value, + ValueSize, MaxBytesToEmit); +} + // Add a symbol for the file name of this module. This is the second // entry in the module's symbol table (the first being the null symbol). @@ -335,25 +350,91 @@ void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { } void MCELFStreamer::EmitInstToData(const MCInst &Inst) { - MCDataFragment *DF = getOrCreateDataFragment(); - + MCAssembler &Assembler = getAssembler(); SmallVector<MCFixup, 4> Fixups; SmallString<256> Code; raw_svector_ostream VecOS(Code); - getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups); VecOS.flush(); for (unsigned i = 0, e = Fixups.size(); i != e; ++i) fixSymbolsInTLSFixups(Fixups[i].getValue()); + // There are several possibilities here: + // + // If bundling is disabled, append the encoded instruction to the current data + // fragment (or create a new such fragment if the current fragment is not a + // data fragment). + // + // If bundling is enabled: + // - If we're not in a bundle-locked group, emit the instruction into a data + // fragment of its own. + // - If we're in a bundle-locked group, append the instruction to the current + // data fragment because we want all the instructions in a group to get into + // the same fragment. Be careful not to do that for the first instruction in + // the group, though. + MCDataFragment *DF; + + if (Assembler.isBundlingEnabled()) { + MCSectionData *SD = getCurrentSectionData(); + if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst()) + DF = getOrCreateDataFragment(); + else + DF = new MCDataFragment(SD); + + // We're now emitting an instruction in a bundle group, so this flag has + // to be turned off. + SD->setBundleGroupBeforeFirstInst(false); + } else { + DF = getOrCreateDataFragment(); + } + // Add the fixups and data. for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); DF->getFixups().push_back(Fixups[i]); } + DF->setHasInstructions(true); DF->getContents().append(Code.begin(), Code.end()); } +void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) { + assert(AlignPow2 <= 30 && "Invalid bundle alignment"); + MCAssembler &Assembler = getAssembler(); + if (Assembler.getBundleAlignSize() == 0 && AlignPow2 > 0) + Assembler.setBundleAlignSize(1 << AlignPow2); + else + report_fatal_error(".bundle_align_mode should be only set once per file"); +} + +void MCELFStreamer::EmitBundleLock() { + MCSectionData *SD = getCurrentSectionData(); + + // Sanity checks + // + if (!getAssembler().isBundlingEnabled()) + report_fatal_error(".bundle_lock forbidden when bundling is disabled"); + else if (SD->isBundleLocked()) + report_fatal_error("Nesting of .bundle_lock is forbidden"); + + SD->setBundleLocked(true); + SD->setBundleGroupBeforeFirstInst(true); +} + +void MCELFStreamer::EmitBundleUnlock() { + MCSectionData *SD = getCurrentSectionData(); + + // Sanity checks + if (!getAssembler().isBundlingEnabled()) + report_fatal_error(".bundle_unlock forbidden when bundling is disabled"); + else if (!SD->isBundleLocked()) + report_fatal_error(".bundle_unlock without matching lock"); + else if (SD->isBundleGroupBeforeFirstInst()) + report_fatal_error("Empty bundle-locked group is forbidden"); + + SD->setBundleLocked(false); +} + void MCELFStreamer::FinishImpl() { EmitFrames(true); diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index bb84c4f22f..d1cd0064ad 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -95,6 +95,10 @@ namespace { StringRef FileName) {} virtual void EmitInstruction(const MCInst &Inst) {} + virtual void EmitBundleAlignMode(unsigned AlignPow2) {} + virtual void EmitBundleLock() {} + virtual void EmitBundleUnlock() {} + virtual void FinishImpl() {} virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 4d6900f7c4..e36e181ff5 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -180,21 +180,27 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst) { if (Inst.getOperand(i).isExpr()) AddValueSymbols(Inst.getOperand(i).getExpr()); - getCurrentSectionData()->setHasInstructions(true); + MCSectionData *SD = getCurrentSectionData(); + SD->setHasInstructions(true); // Now that a machine instruction has been assembled into this section, make // a line entry for any .loc directive that has been seen. MCLineEntry::Make(this, getCurrentSection()); // If this instruction doesn't need relaxation, just emit it as data. - if (!getAssembler().getBackend().mayNeedRelaxation(Inst)) { + MCAssembler &Assembler = getAssembler(); + if (!Assembler.getBackend().mayNeedRelaxation(Inst)) { EmitInstToData(Inst); return; } - // Otherwise, if we are relaxing everything, relax the instruction as much as - // possible and emit it as data. - if (getAssembler().getRelaxAll()) { + // Otherwise, relax and emit it as data if either: + // - The RelaxAll flag was passed + // - Bundling is enabled and this instruction is inside a bundle-locked + // group. We want to emit all such instructions into the same data + // fragment. + if (Assembler.getRelaxAll() || + (Assembler.isBundlingEnabled() && SD->isBundleLocked())) { MCInst Relaxed; getAssembler().getBackend().relaxInstruction(Inst, Relaxed); while (getAssembler().getBackend().mayNeedRelaxation(Relaxed)) @@ -208,6 +214,8 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst) { } void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) { + // Always create a new, separate fragment here, because its size can change + // during relaxation. MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); SmallString<128> Code; @@ -217,6 +225,21 @@ void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) { IF->getContents().append(Code.begin(), Code.end()); } +const char *BundlingNotImplementedMsg = + "Aligned bundling is not implemented for this object format"; + +void MCObjectStreamer::EmitBundleAlignMode(unsigned AlignPow2) { + llvm_unreachable(BundlingNotImplementedMsg); +} + +void MCObjectStreamer::EmitBundleLock() { + llvm_unreachable(BundlingNotImplementedMsg); +} + +void MCObjectStreamer::EmitBundleUnlock() { + llvm_unreachable(BundlingNotImplementedMsg); +} + void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, const MCSymbol *Label, diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 85d31872a7..ab1210302d 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -305,6 +305,13 @@ private: // ".align{,32}", ".p2align{,w,l}" bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize); + // ".bundle_align_mode" + bool ParseDirectiveBundleAlignMode(); + // ".bundle_lock" + bool ParseDirectiveBundleLock(); + // ".bundle_unlock" + bool ParseDirectiveBundleUnlock(); + /// ParseDirectiveSymbolAttribute - Parse a directive like ".globl" which /// accepts a single symbol (which should be a label or an external). bool ParseDirectiveSymbolAttribute(MCSymbolAttr Attr); @@ -1304,6 +1311,13 @@ bool AsmParser::ParseStatement(ParseStatementInfo &Info) { if (IDVal == ".p2alignl") return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + if (IDVal == ".bundle_align_mode") + return ParseDirectiveBundleAlignMode(); + if (IDVal == ".bundle_lock") + return ParseDirectiveBundleLock(); + if (IDVal == ".bundle_unlock") + return ParseDirectiveBundleUnlock(); + if (IDVal == ".org") return ParseDirectiveOrg(); @@ -2429,6 +2443,59 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { return false; } + +/// ParseDirectiveBundleAlignMode +/// ::= {.bundle_align_mode} expression +bool AsmParser::ParseDirectiveBundleAlignMode() { + CheckForValidSection(); + + // Expect a single argument: an expression that evaluates to a constant + // in the inclusive range 0-30. + SMLoc ExprLoc = getLexer().getLoc(); + int64_t AlignSizePow2; + if (ParseAbsoluteExpression(AlignSizePow2)) + return true; + else if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token after expression in" + " '.bundle_align_mode' directive"); + else if (AlignSizePow2 < 0 || AlignSizePow2 > 30) + return Error(ExprLoc, + "invalid bundle alignment size (expected between 0 and 30)"); + + Lex(); + + // Because of AlignSizePow2's verified range we can safely truncate it to + // unsigned. + getStreamer().EmitBundleAlignMode(static_cast<unsigned>(AlignSizePow2)); + return false; +} + +/// ParseDirectiveBundleLock +/// ::= {.bundle_lock} +bool AsmParser::ParseDirectiveBundleLock() { + CheckForValidSection(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.bundle_lock' directive"); + Lex(); + + getStreamer().EmitBundleLock(); + return false; +} + +/// ParseDirectiveBundleLock +/// ::= {.bundle_lock} +bool AsmParser::ParseDirectiveBundleUnlock() { + CheckForValidSection(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.bundle_unlock' directive"); + Lex(); + + getStreamer().EmitBundleUnlock(); + return false; +} + /// ParseDirectiveSymbolAttribute /// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) { diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 9d2f9c7848..9b5917de16 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -765,6 +765,10 @@ namespace { markDefined(*Symbol); } + virtual void EmitBundleAlignMode(unsigned AlignPow2) {} + virtual void EmitBundleLock() {} + virtual void EmitBundleUnlock() {} + // Noop calls. virtual void ChangeSection(const MCSection *Section) {} virtual void InitSections() {} |