Index: llvm/include/llvm/MC/MCFragment.h =================================================================== --- llvm/include/llvm/MC/MCFragment.h +++ llvm/include/llvm/MC/MCFragment.h @@ -34,6 +34,7 @@ public: enum FragmentType : uint8_t { FT_Align, + FT_NeverAlign, FT_Data, FT_CompactEncodedInst, FT_Fill, @@ -333,6 +334,41 @@ } }; +class MCNeverAlignFragment : public MCFragment { + /// Alignment - The alignment the end of the next fragment should avoid + unsigned Alignment; + + /// EmitNops - Flag to indicate that (optimal) NOPs should be emitted instead + /// of using the provided value. The exact interpretation of this flag is + /// target dependent. + bool EmitNops : 1; + + /// Value - Value to use for filling padding bytes. + int64_t Value; + + /// ValueSize - The size of the integer (in bytes) of \p Value. + unsigned ValueSize; + +public: + MCNeverAlignFragment(unsigned Alignment, int64_t Value, unsigned ValueSize, + MCSection *Sec = nullptr) + : MCFragment(FT_NeverAlign, false, Sec), Alignment(Alignment), + EmitNops(false), Value(Value), ValueSize(ValueSize) {} + + unsigned getAlignment() const { return Alignment; } + + int64_t getValue() const { return Value; } + + unsigned getValueSize() const { return ValueSize; } + + bool hasEmitNops() const { return EmitNops; } + void setEmitNops(bool Value) { EmitNops = Value; } + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_NeverAlign; + } +}; + class MCFillFragment : public MCFragment { uint8_t ValueSize; /// Value to use for filling bytes. Index: llvm/include/llvm/MC/MCObjectStreamer.h =================================================================== --- llvm/include/llvm/MC/MCObjectStreamer.h +++ llvm/include/llvm/MC/MCObjectStreamer.h @@ -139,6 +139,8 @@ unsigned MaxBytesToEmit = 0) override; void emitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit = 0) override; + void emitNeverAlignCodeAtEnd(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1) override; void emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) override; void emitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, Index: llvm/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/include/llvm/MC/MCStreamer.h +++ llvm/include/llvm/MC/MCStreamer.h @@ -837,6 +837,12 @@ virtual void emitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit = 0); + /// If the end of the following fragment ever gets aligned to + /// \p ByteAlignment, emit a single nop or \t Value to break this alignment. + virtual void emitNeverAlignCodeAtEnd(unsigned ByteAlignment, + int64_t Value = 0, + unsigned ValueSize = 1); + /// Emit some number of copies of \p Value until the byte offset \p /// Offset is reached. /// Index: llvm/lib/MC/MCAssembler.cpp =================================================================== --- llvm/lib/MC/MCAssembler.cpp +++ llvm/lib/MC/MCAssembler.cpp @@ -346,6 +346,34 @@ return Size; } + case MCFragment::FT_NeverAlign: { + const MCNeverAlignFragment &NAF = cast(F); + uint64_t Offset = Layout.getFragmentOffset(&NAF); + unsigned Size = 0; + uint64_t OffsetToAvoid = 0; + // Calculate offset to avoid in order to avoid aligning the end of the + // next fragment + if (const auto *NextFrag = dyn_cast(F.getNextNode())) { + OffsetToAvoid = NAF.getAlignment() - + (NextFrag->getContents().size() % NAF.getAlignment()); + } else if (const auto *NextFrag = + dyn_cast(F.getNextNode())) { + OffsetToAvoid = NAF.getAlignment() - + (NextFrag->getContents().size() % NAF.getAlignment()); + } + // Check if the current offset matches the alignment plus offset we want to + // avoid + if (Offset % NAF.getAlignment() == OffsetToAvoid) { + // Avoid this alignment by introducing one extra byte + Size = 1; + if (Size > 0 && NAF.hasEmitNops()) { + while (Size % getBackend().getMinimumNopSize()) + Size += 1; + } + } + return Size; + } + case MCFragment::FT_Org: { const MCOrgFragment &OF = cast(F); MCValue Value; @@ -569,6 +597,44 @@ break; } + case MCFragment::FT_NeverAlign: { + const MCNeverAlignFragment &NAF = cast(F); + assert(NAF.getValueSize() && "Invalid virtual align in concrete fragment!"); + + uint64_t Count = FragmentSize / NAF.getValueSize(); + if (Count == 0) + break; + assert(Count * NAF.getValueSize() == FragmentSize); + + if (NAF.hasEmitNops()) { + if (!Asm.getBackend().writeNopData(OS, Count)) + report_fatal_error("unable to write nop sequence of " + Twine(Count) + + " bytes"); + break; + } + + // Otherwise, write out in multiples of the value size. + for (uint64_t i = 0; i != Count; ++i) { + switch (NAF.getValueSize()) { + default: + llvm_unreachable("Invalid size!"); + case 1: + OS << char(NAF.getValue()); + break; + case 2: + support::endian::write(OS, NAF.getValue(), Endian); + break; + case 4: + support::endian::write(OS, NAF.getValue(), Endian); + break; + case 8: + support::endian::write(OS, NAF.getValue(), Endian); + break; + } + } + break; + } + case MCFragment::FT_Data: ++stats::EmittedDataFragments; OS << cast(F).getContents(); @@ -757,6 +823,11 @@ cast(F).getValue() == 0) && "Invalid align in virtual section!"); break; + case MCFragment::FT_NeverAlign: + assert((cast(F).getValueSize() == 0 || + cast(F).getValue() == 0) && + "Invalid neveralign in virtual section!"); + break; case MCFragment::FT_Fill: assert((cast(F).getValue() == 0) && "Invalid fill in virtual section!"); Index: llvm/lib/MC/MCFragment.cpp =================================================================== --- llvm/lib/MC/MCFragment.cpp +++ llvm/lib/MC/MCFragment.cpp @@ -270,6 +270,9 @@ case FT_Align: delete cast(this); return; + case FT_NeverAlign: + delete cast(this); + return; case FT_Data: delete cast(this); return; @@ -338,6 +341,9 @@ OS << "<"; switch (getKind()) { case MCFragment::FT_Align: OS << "MCAlignFragment"; break; + case MCFragment::FT_NeverAlign: + OS << "MCNeverAlignFragment"; + break; case MCFragment::FT_Data: OS << "MCDataFragment"; break; case MCFragment::FT_CompactEncodedInst: OS << "MCCompactEncodedInstFragment"; break; @@ -377,6 +383,15 @@ << " MaxBytesToEmit:" << AF->getMaxBytesToEmit() << ">"; break; } + case MCFragment::FT_NeverAlign: { + const MCNeverAlignFragment *NAF = cast(this); + if (NAF->hasEmitNops()) + OS << " (emit nops)"; + OS << "\n "; + OS << " Alignment:" << NAF->getAlignment() << " Value:" << NAF->getValue() + << " ValueSize:" << NAF->getValueSize(); + break; + } case MCFragment::FT_Data: { const auto *DF = cast(this); OS << "\n "; Index: llvm/lib/MC/MCObjectStreamer.cpp =================================================================== --- llvm/lib/MC/MCObjectStreamer.cpp +++ llvm/lib/MC/MCObjectStreamer.cpp @@ -599,6 +599,13 @@ cast(getCurrentFragment())->setEmitNops(true); } +void MCObjectStreamer::emitNeverAlignCodeAtEnd(unsigned ByteAlignment, + int64_t Value, + unsigned ValueSize) { + insert(new MCNeverAlignFragment(ByteAlignment, 0, 1)); + cast(getCurrentFragment())->setEmitNops(true); +} + void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) { Index: llvm/lib/MC/MCStreamer.cpp =================================================================== --- llvm/lib/MC/MCStreamer.cpp +++ llvm/lib/MC/MCStreamer.cpp @@ -1158,6 +1158,8 @@ unsigned MaxBytesToEmit) {} void MCStreamer::emitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit) {} +void MCStreamer::emitNeverAlignCodeAtEnd(unsigned ByteAlignment, int64_t Value, + unsigned ValueSize) {} void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) {} void MCStreamer::emitBundleAlignMode(unsigned AlignPow2) {}