diff options
Diffstat (limited to 'llvm/lib/MC')
-rw-r--r-- | llvm/lib/MC/MCAsmStreamer.cpp | 19 | ||||
-rw-r--r-- | llvm/lib/MC/MCAssembler.cpp | 81 | ||||
-rw-r--r-- | llvm/lib/MC/MCELFStreamer.cpp | 87 | ||||
-rw-r--r-- | llvm/lib/MC/MCNullStreamer.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/MC/MCObjectStreamer.cpp | 33 | ||||
-rw-r--r-- | llvm/lib/MC/MCParser/AsmParser.cpp | 67 |
6 files changed, 276 insertions, 15 deletions
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 6302f970d8e..9b7074d3b25 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/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/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index 2558eff0455..f4c3fc55d3d 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/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/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp index 9771ef0549c..e3acc44a859 100644 --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/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/llvm/lib/MC/MCNullStreamer.cpp b/llvm/lib/MC/MCNullStreamer.cpp index bb84c4f22fe..d1cd0064ad2 100644 --- a/llvm/lib/MC/MCNullStreamer.cpp +++ b/llvm/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/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 4d6900f7c46..e36e181ff56 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/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/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 85d31872a73..ab1210302dd 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/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) { |